ソースを参照

courtesy commit

Paul Klumpp 5 日 前
コミット
c9b5cb7432
99 ファイル変更17969 行追加224 行削除
  1. 17 0
      .gitignore
  2. 91 0
      VENDORING.md
  3. 378 208
      adapter.py
  4. 70 0
      platform_config.py
  5. 8 6
      pyproject.toml
  6. 42 10
      test_adapter.py
  7. 1 0
      vendor/chattolib-0.4.19.post1.dist-info/INSTALLER
  8. 131 0
      vendor/chattolib-0.4.19.post1.dist-info/METADATA
  9. 92 0
      vendor/chattolib-0.4.19.post1.dist-info/RECORD
  10. 0 0
      vendor/chattolib-0.4.19.post1.dist-info/REQUESTED
  11. 5 0
      vendor/chattolib-0.4.19.post1.dist-info/WHEEL
  12. 373 0
      vendor/chattolib-0.4.19.post1.dist-info/licenses/LICENSE
  13. 202 0
      vendor/chattolib-0.4.19.post1.dist-info/licenses/LICENSES/Apache-2.0.txt
  14. 373 0
      vendor/chattolib-0.4.19.post1.dist-info/licenses/LICENSES/MPL-2.0.txt
  15. 1 0
      vendor/chattolib-0.4.19.post1.dist-info/top_level.txt
  16. 1 0
      vendor/chattolib/__init__.py
  17. 21 0
      vendor/chattolib/_pb/__init__.py
  18. 0 0
      vendor/chattolib/_pb/buf/__init__.py
  19. 0 0
      vendor/chattolib/_pb/buf/validate/__init__.py
  20. 30 0
      vendor/chattolib/_pb/buf/validate/validate_pb2.py
  21. 0 0
      vendor/chattolib/_pb/chatto/__init__.py
  22. 0 0
      vendor/chattolib/_pb/chatto/admin/__init__.py
  23. 0 0
      vendor/chattolib/_pb/chatto/admin/v1/__init__.py
  24. 123 0
      vendor/chattolib/_pb/chatto/admin/v1/diagnostics_connect.py
  25. 26 0
      vendor/chattolib/_pb/chatto/admin/v1/diagnostics_pb2.py
  26. 253 0
      vendor/chattolib/_pb/chatto/admin/v1/event_log_connect.py
  27. 28 0
      vendor/chattolib/_pb/chatto/admin/v1/event_log_pb2.py
  28. 643 0
      vendor/chattolib/_pb/chatto/admin/v1/members_connect.py
  29. 32 0
      vendor/chattolib/_pb/chatto/admin/v1/members_pb2.py
  30. 578 0
      vendor/chattolib/_pb/chatto/admin/v1/permissions_connect.py
  31. 28 0
      vendor/chattolib/_pb/chatto/admin/v1/permissions_pb2.py
  32. 448 0
      vendor/chattolib/_pb/chatto/admin/v1/roles_connect.py
  33. 29 0
      vendor/chattolib/_pb/chatto/admin/v1/roles_pb2.py
  34. 773 0
      vendor/chattolib/_pb/chatto/admin/v1/room_layout_connect.py
  35. 29 0
      vendor/chattolib/_pb/chatto/admin/v1/room_layout_pb2.py
  36. 578 0
      vendor/chattolib/_pb/chatto/admin/v1/server_connect.py
  37. 29 0
      vendor/chattolib/_pb/chatto/admin/v1/server_pb2.py
  38. 0 0
      vendor/chattolib/_pb/chatto/api/__init__.py
  39. 0 0
      vendor/chattolib/_pb/chatto/api/v1/__init__.py
  40. 906 0
      vendor/chattolib/_pb/chatto/api/v1/account_connect.py
  41. 33 0
      vendor/chattolib/_pb/chatto/api/v1/account_pb2.py
  42. 383 0
      vendor/chattolib/_pb/chatto/api/v1/asset_uploads_connect.py
  43. 29 0
      vendor/chattolib/_pb/chatto/api/v1/asset_uploads_pb2.py
  44. 188 0
      vendor/chattolib/_pb/chatto/api/v1/attachments_connect.py
  45. 30 0
      vendor/chattolib/_pb/chatto/api/v1/attachments_pb2.py
  46. 49 0
      vendor/chattolib/_pb/chatto/api/v1/common_pb2.py
  47. 56 0
      vendor/chattolib/_pb/chatto/api/v1/external_identities_pb2.py
  48. 43 0
      vendor/chattolib/_pb/chatto/api/v1/link_previews_pb2.py
  49. 253 0
      vendor/chattolib/_pb/chatto/api/v1/member_directory_connect.py
  50. 30 0
      vendor/chattolib/_pb/chatto/api/v1/member_directory_pb2.py
  51. 28 0
      vendor/chattolib/_pb/chatto/api/v1/message_types_pb2.py
  52. 710 0
      vendor/chattolib/_pb/chatto/api/v1/messages_connect.py
  53. 30 0
      vendor/chattolib/_pb/chatto/api/v1/messages_pb2.py
  54. 318 0
      vendor/chattolib/_pb/chatto/api/v1/notification_preferences_connect.py
  55. 27 0
      vendor/chattolib/_pb/chatto/api/v1/notification_preferences_pb2.py
  56. 578 0
      vendor/chattolib/_pb/chatto/api/v1/notifications_connect.py
  57. 31 0
      vendor/chattolib/_pb/chatto/api/v1/notifications_pb2.py
  58. 43 0
      vendor/chattolib/_pb/chatto/api/v1/pagination_pb2.py
  59. 38 0
      vendor/chattolib/_pb/chatto/api/v1/permissions_pb2.py
  60. 43 0
      vendor/chattolib/_pb/chatto/api/v1/presence_pb2.py
  61. 188 0
      vendor/chattolib/_pb/chatto/api/v1/push_notifications_connect.py
  62. 55 0
      vendor/chattolib/_pb/chatto/api/v1/push_notifications_pb2.py
  63. 56 0
      vendor/chattolib/_pb/chatto/api/v1/reactions_pb2.py
  64. 50 0
      vendor/chattolib/_pb/chatto/api/v1/read_state_pb2.py
  65. 253 0
      vendor/chattolib/_pb/chatto/api/v1/roles_connect.py
  66. 55 0
      vendor/chattolib/_pb/chatto/api/v1/roles_pb2.py
  67. 448 0
      vendor/chattolib/_pb/chatto/api/v1/room_directory_connect.py
  68. 29 0
      vendor/chattolib/_pb/chatto/api/v1/room_directory_pb2.py
  69. 30 0
      vendor/chattolib/_pb/chatto/api/v1/room_timeline_pb2.py
  70. 1426 0
      vendor/chattolib/_pb/chatto/api/v1/rooms_connect.py
  71. 34 0
      vendor/chattolib/_pb/chatto/api/v1/rooms_pb2.py
  72. 39 0
      vendor/chattolib/_pb/chatto/api/v1/server_pb2.py
  73. 188 0
      vendor/chattolib/_pb/chatto/api/v1/server_state_connect.py
  74. 46 0
      vendor/chattolib/_pb/chatto/api/v1/server_state_pb2.py
  75. 450 0
      vendor/chattolib/_pb/chatto/api/v1/threads_connect.py
  76. 32 0
      vendor/chattolib/_pb/chatto/api/v1/threads_pb2.py
  77. 50 0
      vendor/chattolib/_pb/chatto/api/v1/user_status_pb2.py
  78. 38 0
      vendor/chattolib/_pb/chatto/api/v1/users_pb2.py
  79. 123 0
      vendor/chattolib/_pb/chatto/api/v1/viewer_connect.py
  80. 30 0
      vendor/chattolib/_pb/chatto/api/v1/viewer_pb2.py
  81. 513 0
      vendor/chattolib/_pb/chatto/api/v1/voice_calls_connect.py
  82. 30 0
      vendor/chattolib/_pb/chatto/api/v1/voice_calls_pb2.py
  83. 0 0
      vendor/chattolib/_pb/chatto/auth/__init__.py
  84. 0 0
      vendor/chattolib/_pb/chatto/auth/v1/__init__.py
  85. 318 0
      vendor/chattolib/_pb/chatto/auth/v1/external_identity_auth_connect.py
  86. 28 0
      vendor/chattolib/_pb/chatto/auth/v1/external_identity_auth_pb2.py
  87. 0 0
      vendor/chattolib/_pb/chatto/discovery/__init__.py
  88. 0 0
      vendor/chattolib/_pb/chatto/discovery/v1/__init__.py
  89. 123 0
      vendor/chattolib/_pb/chatto/discovery/v1/server_connect.py
  90. 41 0
      vendor/chattolib/_pb/chatto/discovery/v1/server_pb2.py
  91. 0 0
      vendor/chattolib/_pb/chatto/realtime/__init__.py
  92. 0 0
      vendor/chattolib/_pb/chatto/realtime/v1/__init__.py
  93. 30 0
      vendor/chattolib/_pb/chatto/realtime/v1/realtime_pb2.py
  94. 179 0
      vendor/chattolib/_transport.py
  95. 2306 0
      vendor/chattolib/client.py
  96. 37 0
      vendor/chattolib/exceptions.py
  97. 306 0
      vendor/chattolib/realtime.py
  98. 1121 0
      vendor/chattolib/types.py
  99. 38 0
      vendor_chattolib.sh

+ 17 - 0
.gitignore

@@ -0,0 +1,17 @@
+# Vendored dependencies (generated by vendor_chattolib.sh)
+chattolib_vendor/
+
+# IDE
+.idea/
+.vscode/
+*.swp
+*.swo
+
+# Python
+__pycache__/
+*.py[cod]
+*$py.class
+
+# OS
+.DS_Store
+Thumbs.db

+ 91 - 0
VENDORING.md

@@ -0,0 +1,91 @@
+# Vendoring chattolib
+
+This plugin includes a **vendored copy of chattolib** in the `chattolib_vendor/` directory.
+This means you don't need to install chattolib separately — it's bundled with the plugin.
+
+## Why Vendoring?
+
+- **No dependencies to install**: `hermes plugin install` works immediately
+- **No lazy-import complexity**: No need for `ensure()` or `lazy_import` mechanisms
+- **Isolated**: The vendored chattolib won't conflict with any system-installed version
+- **Offline-friendly**: Works in air-gapped environments
+
+## Updating the Vendored chattolib
+
+To update to a new version of chattolib:
+
+```bash
+# Run the vendoring script
+./vendor_chattolib.sh [version]
+
+# Example: update to 0.5.0
+./vendor_chattolib.sh 0.5.0
+
+# Or use default (latest known stable)
+./vendor_chattolib.sh
+```
+
+The script will:
+1. Download the chattolib wheel from PyPI
+2. Extract it to `chattolib_vendor/`
+3. Also download the `websockets` dependency (needed for realtime features)
+
+## Development without Vendoring
+
+If you're developing and want to use your system-installed chattolib instead:
+
+```bash
+pip install chattolib[realtime]
+```
+
+The adapter will automatically fall back to the system-installed version if the vendored copy is not found.
+
+## Structure
+
+```
+chattolib_vendor/
+├── __init__.py           # Marker file
+├── chattolib/           # The chattolib package
+│   ├── __init__.py
+│   ├── src/
+│   │   └── chattolib/
+│   │       ├── _pb/        # Protobuf generated files
+│   │       ├── _transport.py
+│   │       ├── client.py
+│   │       ├── realtime.py
+│   │       ├── types.py
+│   │       └── ...
+│   └── ...
+└── websockets/          # Dependency for realtime features
+    └── ...
+```
+
+## License
+
+The vendored chattolib is licensed under **MPL-2.0 + Apache-2.0** (see `chattolib/LICENSE`).
+The original source is available at: https://github.com/chattocorp/chatto
+
+## Manual Vendoring (Alternative)
+
+If the script doesn't work for your environment:
+
+```bash
+# Create directory
+mkdir -p chattolib_vendor
+
+# Download and extract chattolib
+pip download chattolib==0.4.19 --no-deps -d /tmp
+cd /tmp
+unzip chattolib-*.whl -d chattolib_extracted
+cp -r chattolib_extracted/chattolib* ../chattolib_vendor/
+
+# Download websockets
+pip download websockets -d /tmp
+cd /tmp
+unzip websockets-*.whl -d websockets_extracted
+mkdir -p ../chattolib_vendor/websockets
+cp -r websockets_extracted/websockets* ../chattolib_vendor/websockets/
+
+# Add __init__.py
+echo "# Vendored chattolib" > chattolib_vendor/__init__.py
+```

ファイルの差分が大きいため隠しています
+ 378 - 208
adapter.py


+ 70 - 0
platform_config.py

@@ -0,0 +1,70 @@
+"""
+Chatto Platform Config
+
+
+"""
+from dataclasses import dataclass
+import os
+from typing import Optional
+
+import utils
+
+
+
+
+@dataclass
+class ChattoConfig:
+    """
+    Chatto Platform Config
+
+    Some constants and getting from environment/config.yaml
+    """
+
+    _token: Optional[str] = None
+    _PLATFORM: str = "CHATTO"
+
+    def __init__(self, extra: dict = {}):
+
+        self._base_url = os.getenv("CHATTO_BASE_URL", "").strip() # todo: add config.yaml support
+        self._token = os.getenv("CHATTO_TOKEN", "").strip() # todo: add config.yaml support 
+        self._login = os.getenv("CHATTO_LOGIN", "").strip() # todo: add config.yaml support
+        self._password = os.getenv("CHATTO_PASSWORD", "").strip() # todo: add config.yaml support
+
+        self._raw_channels = os.getenv("CHATTO_CHANNELS", "").strip() # todo: add config.yaml support
+
+        if self._raw_channels:
+            self._channel_ids = [c.strip() for c in self._raw_channels.split(",") if c.strip()]
+        elif isinstance(extra.get("channels"), list):
+            self._channel_ids = [str(c) for c in extra["channels"]]
+        else:
+            self._channel_ids = []
+
+
+        self._home_channel = (
+            os.getenv("CHATTO_HOME_CHANNEL", "").strip()
+            or str(extra.get("home_channel", "")).strip()
+        )
+
+        self._require_mention = os.getenv("CHATTO_REQUIRE_MENTION", "").strip().lower()
+        if self._require_mention:
+            self._require_mention = self._require_mention in ("true", "1", "yes")
+        else:
+            self._require_mention = bool(extra.get("require_mention", True))
+
+        # free_response_channels: room IDs where the bot responds without being mentioned via "@botname"
+        _free_response = os.getenv("CHATTO_FREE_RESPONSE_CHANNELS", "").strip()
+        if _free_response:
+            self._free_response_channels = set(c.strip() for c in _free_response.split(",") if c.strip())
+        else:
+            self._free_response_channels = set(
+                str(c) for c in extra.get("free_response_channels", []) if str(c).strip()
+            )
+
+        # Auto-thread: by default, Chatto creates a thread for replies to room
+        # messages (not DMs, not already in a thread). This keeps conversations
+        # organized in the room. Can be disabled via extra.auto_thread=false.
+        self._auto_thread = utils.is_truthy_value(os.getenv("CHATTO_AUTO_THREAD", "").strip().lower()) # todo: add config.yaml support
+
+
+
+

+ 8 - 6
pyproject.toml

@@ -5,20 +5,22 @@ build-backend = "setuptools.build_meta"
 [project]
 name = "hermes-chatto-plugin"
 version = "1.0.0"
-description = "Chatto platform adapter for Hermes Agent"
+description = "Chatto platform adapter for Hermes Agent (includes vendored chattolib)"
 requires-python = ">=3.11"
 license = {text = "MIT"}
+
 authors = [
-    {name = "liv", email = ""},
-]
-dependencies = [
-    "chattolib[realtime]>=0.4.19",
+    {name = "liv", email = "paul@klumpp.de"},
 ]
 
-[project.optional-dependencies]
+[project.entry-points."hermes_agent.plugins"]
+hermes-chatto-plugin = "hermes-chatto-plugin"
+
+[dependency-groups]
 dev = [
     "pytest>=8.0",
     "pytest-asyncio>=0.24",
+    "chattolib[realtime]>=0.4.19"
 ]
 
 [tool.setuptools.packages.find]

+ 42 - 10
test_adapter.py

@@ -22,14 +22,12 @@ from collections import OrderedDict
 import pytest
 import pytest_asyncio
 
-# Lazy imports for chattolib (required by Hermes plugin system)
-from tools.lazy_deps import lazy_import
+# Import chattolib types for tests - using vendored chattolib from adapter
 
 # -- Path setup --
 sys.path.insert(0, "/opt/hermes")
 sys.path.insert(0, "/root/.hermes/plugins/platforms/chatto")
 
-import adapter as chatto_adapter
 from adapter import (
     _EMOJI_TO_SHORTCODE,
     _MAX_MESSAGE_LENGTH,
@@ -40,7 +38,7 @@ from adapter import (
     register,
 )
 
-from gateway.config import Platform, PlatformConfig
+from gateway.config import PlatformConfig
 from gateway.platforms.base import SendResult, MessageEvent, MessageType
 
 
@@ -298,8 +296,17 @@ class TestUserLookup:
         return adapter
 
     async def test_get_user_calls_chattolib(self, adapter):
-        User = lazy_import("chattolib.types", "User")
-        GetUserResponse = lazy_import("chattolib.types", "GetUserResponse")
+        # Import chattolib types for testing (try vendored first)
+        try:
+            from chattolib_vendor.chattolib.types import User, GetUserResponse
+        except ImportError:
+            try:
+                from chattolib.types import User, GetUserResponse
+            except ImportError:
+                # Fallback to mocked types if chattolib not installed
+                from unittest.mock import MagicMock
+                User = MagicMock
+                GetUserResponse = MagicMock
         mock_user = User(id="user-1", login="testuser", display_name="Test User")
         adapter._chatto_client.get_user.return_value = GetUserResponse(user=mock_user)
         result = await adapter.get_user("user-1")
@@ -308,8 +315,17 @@ class TestUserLookup:
         assert result["login"] == "testuser"
 
     async def test_get_user_caching(self, adapter):
-        User = lazy_import("chattolib.types", "User")
-        GetUserResponse = lazy_import("chattolib.types", "GetUserResponse")
+        # Import chattolib types for testing (try vendored first)
+        try:
+            from chattolib_vendor.chattolib.types import User, GetUserResponse
+        except ImportError:
+            try:
+                from chattolib.types import User, GetUserResponse
+            except ImportError:
+                # Fallback to mocked types if chattolib not installed
+                from unittest.mock import MagicMock
+                User = MagicMock
+                GetUserResponse = MagicMock
         mock_user = User(id="user-1", login="testuser", display_name="Test User")
         adapter._chatto_client.get_user.return_value = GetUserResponse(user=mock_user)
         result1 = await adapter.get_user("user-1")
@@ -381,7 +397,15 @@ class TestRoomOperations:
         return adapter
 
     async def test_create_room(self, adapter):
-        Room = lazy_import("chattolib.types", "Room")
+        # Import chattolib types for testing (try vendored first)
+        try:
+            from chattolib_vendor.chattolib.types import Room
+        except ImportError:
+            try:
+                from chattolib.types import Room
+            except ImportError:
+                from unittest.mock import MagicMock
+                Room = MagicMock
         mock_room = Room(id="room-123", name="Test Room", kind="ROOM_KIND_GROUP",
                         description="", archived=False, group_id="", universal=True)
         adapter._chatto_client.create_room.return_value = mock_room
@@ -390,7 +414,15 @@ class TestRoomOperations:
         adapter._chatto_client.create_room.assert_called_once()
 
     async def test_start_dm(self, adapter):
-        Room = lazy_import("chattolib.types", "Room")
+        # Import chattolib types for testing (try vendored first)
+        try:
+            from chattolib_vendor.chattolib.types import Room
+        except ImportError:
+            try:
+                from chattolib.types import Room
+            except ImportError:
+                from unittest.mock import MagicMock
+                Room = MagicMock
         mock_room = Room(id="dm-123", name="DM with user", kind="ROOM_KIND_DM",
                         description="", archived=False, group_id="", universal=False)
         adapter._chatto_client.start_dm.return_value = mock_room

+ 1 - 0
vendor/chattolib-0.4.19.post1.dist-info/INSTALLER

@@ -0,0 +1 @@
+uv

+ 131 - 0
vendor/chattolib-0.4.19.post1.dist-info/METADATA

@@ -0,0 +1,131 @@
+Metadata-Version: 2.4
+Name: chattolib
+Version: 0.4.19.post1
+Summary: Async Python client library for the Chatto webchat Connect API
+Author-email: Felix <chatto@f3l1x.it>
+License-Expression: MPL-2.0 AND Apache-2.0
+Project-URL: Homepage, https://chat.chatto.run
+Keywords: chatto,connect,connectrpc,async,webchat,client
+Classifier: Development Status :: 3 - Alpha
+Classifier: Intended Audience :: Developers
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Topic :: Communications :: Chat
+Classifier: Framework :: AsyncIO
+Requires-Python: >=3.11
+Description-Content-Type: text/markdown
+License-File: LICENSE
+License-File: LICENSES/Apache-2.0.txt
+License-File: LICENSES/MPL-2.0.txt
+Requires-Dist: connectrpc>=0.11
+Requires-Dist: protobuf>=5.28
+Requires-Dist: httpx>=0.27
+Provides-Extra: realtime
+Requires-Dist: websockets>=13.0; extra == "realtime"
+Provides-Extra: dev
+Requires-Dist: pytest>=8.0; extra == "dev"
+Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
+Requires-Dist: respx>=0.22; extra == "dev"
+Requires-Dist: ruff>=0.8; extra == "dev"
+Requires-Dist: mypy>=1.13; extra == "dev"
+Dynamic: license-file
+
+# chattolib
+
+**Unofficial** async Python client library for the [Chatto](https://chat.chatto.run) webchat API.
+
+> Chattolib versions track the Chatto server version they target. The current
+> release targets Chatto's ConnectRPC API. Request/response traffic uses the
+> official [`connectrpc`](https://pypi.org/project/connectrpc/) Python
+> package; the realtime channel is a binary protobuf WebSocket at
+> `/api/realtime` (needs the ``[realtime]`` extra).
+
+## Install
+
+```bash
+pip install chattolib
+```
+
+## Quick start
+
+```python
+import asyncio
+from chattolib import ChattoClient
+
+async def main():
+    # Public discovery — no auth required
+    async with ChattoClient() as anon:
+        profile, login = await anon.get_server()
+        print(f"Chatto {profile.version}: {profile.name}")
+
+    # Authenticated calls
+    async with await ChattoClient.login("username", "password") as client:
+        me = await client.me()
+        print(f"Logged in as {me.display_name}")
+
+        for entry in await client.list_rooms():
+            if entry.room:
+                print(f"  - {entry.room.name}")
+
+asyncio.run(main())
+```
+
+## Realtime
+
+Install with the extra:
+
+```bash
+pip install 'chattolib[realtime]'
+```
+
+Then stream live events:
+
+```python
+from chattolib import stream_events
+
+async with await ChattoClient.login("username", "password") as client:
+    async for event in stream_events(client):
+        print(event.kind, event.actor_id, event.payload)
+```
+
+`event.kind` names the protobuf ``oneof`` case (`message_posted`,
+`reaction_added`, `presence_changed`, `notification_created`, …).
+`event.payload` is the concrete protobuf sub-message — access its fields
+directly (e.g. `event.payload.room_id`). Realtime events are invalidation
+signals; use the corresponding Connect RPC (`GetRoomEventsAround`,
+`GetNotification`, `GetUser`, …) to hydrate the referenced resource.
+
+## Escape hatch
+
+`ChattoClient.services` exposes the underlying `connectrpc` service clients
+directly (one per Chatto service), for anything the Pythonic wrappers don't
+yet cover. For example:
+
+```python
+from chattolib._pb.chatto.api.v1 import messages_pb2
+
+resp = await client.services.messages.get_message(
+    messages_pb2.GetMessageRequest(room_id=..., event_id=...)
+)
+```
+
+## License
+
+- chattolib's own code is licensed under **MPL-2.0** (Mozilla Public License
+  2.0) — a weak, file-level copyleft. You can use, distribute, and embed
+  chattolib in commercial or proprietary software; modifications to the
+  library's own files must be released under MPL-2.0.
+- Vendored Chatto protobuf definitions under `proto/chatto/**` and the
+  generated bindings under `src/chattolib/_pb/chatto/**` are **Apache-2.0**,
+  matching upstream [`chattocorp/chatto`](https://github.com/chattocorp/chatto).
+- Vendored `buf.validate` material is Apache-2.0 (from
+  [`bufbuild/protovalidate`](https://github.com/bufbuild/protovalidate)).
+
+See [LICENSING.md](LICENSING.md) for the full picture and
+[REUSE.toml](REUSE.toml) for the machine-readable licence map.
+
+Note: chattolib versions **0.0.1 through 0.4.9** were released under **MIT**.
+Those releases remain MIT-licensed forever on PyPI; the MPL-2.0 relicence
+applies to newly published releases only.

+ 92 - 0
vendor/chattolib-0.4.19.post1.dist-info/RECORD

@@ -0,0 +1,92 @@
+chattolib-0.4.19.post1.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
+chattolib-0.4.19.post1.dist-info/METADATA,sha256=6D00DIrQje1U01KqxOc_5-hM9DUBVsTUZyiiW1ki1WU,4497
+chattolib-0.4.19.post1.dist-info/RECORD,,
+chattolib-0.4.19.post1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib-0.4.19.post1.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
+chattolib-0.4.19.post1.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
+chattolib-0.4.19.post1.dist-info/licenses/LICENSES/Apache-2.0.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
+chattolib-0.4.19.post1.dist-info/licenses/LICENSES/MPL-2.0.txt,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
+chattolib-0.4.19.post1.dist-info/top_level.txt,sha256=vgsGOu_BQfCunqwDpfv3epJ86-g6s0va3aAYlwUW1Cg,10
+chattolib/__init__.py,sha256=xtAjLswYOs5mf8KTLZUaYxn2OYgBOUPDenARfqdTnhI,2749
+chattolib/_pb/__init__.py,sha256=GV3XqAxMp6Bi5eDOXC5gq2pdg5fSKGOqyBm-ZGnVnEI,781
+chattolib/_pb/buf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/buf/validate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/buf/validate/validate_pb2.py,sha256=dgb7eKOiT0TDcOhrlQdwPJIPRlw-1rD2XlS1V8fjgDU,153828
+chattolib/_pb/chatto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/admin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/admin/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/admin/v1/diagnostics_connect.py,sha256=IEWUzqyHfC38zCyo7SGV3eyjIDT_m8nxMY0xf5APjUo,5919
+chattolib/_pb/chatto/admin/v1/diagnostics_pb2.py,sha256=4UkuL6hRvHl72plBYKH3mieXR7X7Pj7WOmN5apt1dgI,6726
+chattolib/_pb/chatto/admin/v1/event_log_connect.py,sha256=pLtjXUT5gwBrAHP4i8qyEtZzI1VQDxu25dsS0kN1aHc,12502
+chattolib/_pb/chatto/admin/v1/event_log_pb2.py,sha256=BJSXqf7rNSx-Js38eq2ebIUaEwjPcWtvQm64QxMLiFk,4851
+chattolib/_pb/chatto/admin/v1/members_connect.py,sha256=QThbaIJqCohIHKu_RY_CNaUgV16eR-r9QRKCvcIo_3s,32485
+chattolib/_pb/chatto/admin/v1/members_pb2.py,sha256=zWjo_5a3zlLSeZKs9PrkfZKB2z8k5OCzS1YgLY7vJ1M,11615
+chattolib/_pb/chatto/admin/v1/permissions_connect.py,sha256=k1JBbuqzzWnz1X27Osw_KzOlpEL7OwNcvbwhvXAjUCk,32258
+chattolib/_pb/chatto/admin/v1/permissions_pb2.py,sha256=qWekQ6g2wOWp2ezINhkPXg_7qkRyjqxahic3dyb8Iok,15302
+chattolib/_pb/chatto/admin/v1/roles_connect.py,sha256=kmj95MgtGfYUnd0Zxi1zUUFtmgg_05lwDF2ukkWlZXY,21728
+chattolib/_pb/chatto/admin/v1/roles_pb2.py,sha256=Q7Y0Euck-9CsTxErrEoQUtsqam7ATda-Qh64lX5lB4c,7416
+chattolib/_pb/chatto/admin/v1/room_layout_connect.py,sha256=ULYsmKvrZccClkfosT7s4HVR_NsYzNqBJBt4PlU1y2c,42034
+chattolib/_pb/chatto/admin/v1/room_layout_pb2.py,sha256=3MIjZVS32tgaJyFzwkz73wPH7OcYy1sKNLk0aegBg2Q,15020
+chattolib/_pb/chatto/admin/v1/server_connect.py,sha256=NvvKG6r1aOEeGc9GcKssy7S4SCinZiTrRHQhupIOP1k,30415
+chattolib/_pb/chatto/admin/v1/server_pb2.py,sha256=2FfMJGWSFHL-AFC2C8nr7WTmHBN9VC5tZjA3ZHMlzOs,8432
+chattolib/_pb/chatto/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/api/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/api/v1/account_connect.py,sha256=wQEQRphN3r-jWfASbQTm3aRBjBVH_I-GPeE1tCx1xAg,48066
+chattolib/_pb/chatto/api/v1/account_pb2.py,sha256=wyH_E89OV7OTqF-jafMg6Y33TbCQjcIlLbY3r1ZNCNg,7846
+chattolib/_pb/chatto/api/v1/asset_uploads_connect.py,sha256=El2JJKuuqaVoTj7ZRe8CdclJUMq5Sp0ekmH13TPy_hw,19368
+chattolib/_pb/chatto/api/v1/asset_uploads_pb2.py,sha256=TL9zv5eEkINzBIHTrqMf76BLHi5ybns4ekyOrCerVCY,8033
+chattolib/_pb/chatto/api/v1/attachments_connect.py,sha256=SBVR8lJeSWovIoOPHQIJDCF0nmMo-1A5Wb9whwcuACA,8906
+chattolib/_pb/chatto/api/v1/attachments_pb2.py,sha256=6riNtl4UAtZrrXA-k-L_e70cz9gcvq3WxfdVOnkI6JQ,4938
+chattolib/_pb/chatto/api/v1/common_pb2.py,sha256=Qpd89qg4bJmdLrtnnky4kSlJsMA-ODwOMWjL6dT4NnY,3055
+chattolib/_pb/chatto/api/v1/external_identities_pb2.py,sha256=RvRs38xj0GTbmmn1yT8efFpTGFUaXTAMkJAfAAyM6iM,4262
+chattolib/_pb/chatto/api/v1/link_previews_pb2.py,sha256=DgVyJFBSWRhjEePliNS_xvhqjntZIad4Mwn3vx072EY,2713
+chattolib/_pb/chatto/api/v1/member_directory_connect.py,sha256=r70QgLxDUo7tRWH4Zdvweh-ZCmnwRPJEYWR-lbVwTFs,12363
+chattolib/_pb/chatto/api/v1/member_directory_pb2.py,sha256=zC0gZCKPw7DazhGekuU4X5cNgurMia4LNnV3J9QRadE,7853
+chattolib/_pb/chatto/api/v1/message_types_pb2.py,sha256=HRReFeH1XXga21SXBiA2Mw497S8AsS3DqudV9DD-qFs,5946
+chattolib/_pb/chatto/api/v1/messages_connect.py,sha256=q_Zp8VGDFtj9Iew0VMf0rah_h1IQJvHdixp_xq5E2zA,36040
+chattolib/_pb/chatto/api/v1/messages_pb2.py,sha256=W0xfZkYDV4SSoky9cOVq9h4eYx9F6c-NrWPGO8Nvpws,10878
+chattolib/_pb/chatto/api/v1/notification_preferences_connect.py,sha256=YDhA_Hlnl9915J81izTue3MtidFdZ7OigVI9okfuc9Q,19258
+chattolib/_pb/chatto/api/v1/notification_preferences_pb2.py,sha256=PFIngg53HQyy1hL9mIl-9k_vHbVBliPhLjx0TD5wgSA,5713
+chattolib/_pb/chatto/api/v1/notifications_connect.py,sha256=E3-nELCgTo36hdog4Ql35fPJcK4HEl7xr-5VKs0PRik,31342
+chattolib/_pb/chatto/api/v1/notifications_pb2.py,sha256=10osHCRK6me9HX88dN-HDvYiGgd9vSZWwFoQcH4KFSM,10352
+chattolib/_pb/chatto/api/v1/pagination_pb2.py,sha256=mk69lJ5YR2Ew5MgnPKVYEiXh1hhYPI9FoS4tpkFKvzc,2117
+chattolib/_pb/chatto/api/v1/permissions_pb2.py,sha256=omJLYEovPhmp0dkoeqWOpeVmLT9HmtZJ7SNq017B82A,1612
+chattolib/_pb/chatto/api/v1/presence_pb2.py,sha256=svAHzqOoTew7dhpXyPb55KRjIT__traXsd7A2j2gwf0,2393
+chattolib/_pb/chatto/api/v1/push_notifications_connect.py,sha256=H3cGLi9WlSIx6YhINVMMQ3Y4IQ-V83WMxcbPSNqtoNI,9502
+chattolib/_pb/chatto/api/v1/push_notifications_pb2.py,sha256=rA8qTQgaasR932JvTVUQHd1YFEfTcCpVucNrRY8emtw,3808
+chattolib/_pb/chatto/api/v1/reactions_pb2.py,sha256=vFxn7n4AMBWVCOdPfz3bHeAubcvyL9EDDBEx0TPPUlY,3856
+chattolib/_pb/chatto/api/v1/read_state_pb2.py,sha256=iiFDynSv484ohUGZbCndGW0rQ7DtwZIk3PK-zJoqH8g,3198
+chattolib/_pb/chatto/api/v1/roles_connect.py,sha256=rj5UB46KTbK3t27tF5CJjiKnuEvcqHtweX-CQMneijA,11753
+chattolib/_pb/chatto/api/v1/roles_pb2.py,sha256=maATiSHf9xc2fGehxJfgnncmWVtWnY2e0fkD3vYqRlg,3590
+chattolib/_pb/chatto/api/v1/room_directory_connect.py,sha256=JZuhxz-TblCUpASF-mwq-RyGzSL4kyjl0i3hx3B4Mvw,23084
+chattolib/_pb/chatto/api/v1/room_directory_pb2.py,sha256=0etcpI69xfvNr3r1cEIfs6il9wA59ZGZj_7ENz5DCJo,8501
+chattolib/_pb/chatto/api/v1/room_timeline_pb2.py,sha256=8g12SvOeZ8WqmeacKTx1Ku3kC1rqPG_MW1SvYvUwyqk,8449
+chattolib/_pb/chatto/api/v1/rooms_connect.py,sha256=qdUXcrwYHdr0XBq3dLqIH6PCT-ThcomFbWNuPjvg4KM,71369
+chattolib/_pb/chatto/api/v1/rooms_pb2.py,sha256=dAZXbPFSCm5O43D8zyS0UOggJBdLpwSFynHsbOotJaw,18248
+chattolib/_pb/chatto/api/v1/server_pb2.py,sha256=lnfGVI1gVH-gQm6kDHBoUW9TFvd8G0kb4bdhpqROE9A,2127
+chattolib/_pb/chatto/api/v1/server_state_connect.py,sha256=mHRna76ilc5VaNjaaPInuMcCi82eABOT2IwFaEjywJM,9026
+chattolib/_pb/chatto/api/v1/server_state_pb2.py,sha256=ds3uLiCZmBtBw1T7NuQcyi-WAp8EK74u4hrdTczvFwc,2884
+chattolib/_pb/chatto/api/v1/threads_connect.py,sha256=l2BPHjeD1Zy0kKU2nxHv-dO-Wu9ZBv02P-vgllMQMLg,23094
+chattolib/_pb/chatto/api/v1/threads_pb2.py,sha256=SIwdkgmXGzp0IUMDUIQUR0YeQwUwRFZTnULe_hDU2E0,6234
+chattolib/_pb/chatto/api/v1/user_status_pb2.py,sha256=EXqa7JCJ8PCFmrw6Ebv-7iOpN1CxHlKCWydAiq_M4mk,3093
+chattolib/_pb/chatto/api/v1/users_pb2.py,sha256=d0Z0z2OOhwsTUfhBmAMvlXIqpKp3GQadPgKGudXigxo,1918
+chattolib/_pb/chatto/api/v1/viewer_connect.py,sha256=Mk7rWShK5y8aNXQF7GueSPO17-0TylPgcxf1RR2KolI,5472
+chattolib/_pb/chatto/api/v1/viewer_pb2.py,sha256=IOcTUbZSxRDJN_C_CJkg-l11o3EQHjGqFkCmqeHCnSI,4996
+chattolib/_pb/chatto/api/v1/voice_calls_connect.py,sha256=oIdH8NqyONI6b-enGlHm4YAl1uhZYO0xlG2T8PZSqRY,26272
+chattolib/_pb/chatto/api/v1/voice_calls_pb2.py,sha256=4FB3slrXOxrnKDBn0Gfnk4hlU3bt9cbj-LrfEcRdFr4,7405
+chattolib/_pb/chatto/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/auth/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/auth/v1/external_identity_auth_connect.py,sha256=mvXXlae-E4bbVgRARpXv5dkAI6P0ewfiqbVhc1i5gKY,18830
+chattolib/_pb/chatto/auth/v1/external_identity_auth_pb2.py,sha256=pfHRfyfDAlKoTVcm62trX4Rq8guoMBILLkGWsDLovYk,6459
+chattolib/_pb/chatto/discovery/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/discovery/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/discovery/v1/server_connect.py,sha256=A_Cg-TPiIK8ga5scWMnIJ56vGxlu0aIKSrNCremCMxg,5796
+chattolib/_pb/chatto/discovery/v1/server_pb2.py,sha256=zWygBk0OSkNhiGDktzv7mD7zfRw5GB8qmTaT7ts55Rw,1983
+chattolib/_pb/chatto/realtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/realtime/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib/_pb/chatto/realtime/v1/realtime_pb2.py,sha256=TQA2Pal3BogpdrWSeYj6zguWGH6q1wCLEG_Gr0JQnUI,18261
+chattolib/_transport.py,sha256=kEIQNUFuFK0aYjtMUjvcQIrx8EGvZrw-1Hf84YprgBE,7379
+chattolib/client.py,sha256=mARYEEsxNbpWBTbXSvn9OHB9RD-XIo6pm3_SqNC71lk,78769
+chattolib/exceptions.py,sha256=1QIVUjfop1CUVIvS3yv-ZZlV6RvmiXpSrCb17vS2t_A,1044
+chattolib/realtime.py,sha256=h4QI95FmhixXPGm7JAiJ4AvIlRKo4AQCEioxBS4UThg,10240
+chattolib/types.py,sha256=TeP5pA3UZYGU_0gNnRt0GTAMfLKQnS744BIVO9I08Y4,34724

+ 0 - 0
vendor/chattolib-0.4.19.post1.dist-info/REQUESTED


+ 5 - 0
vendor/chattolib-0.4.19.post1.dist-info/WHEEL

@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: setuptools (83.0.0)
+Root-Is-Purelib: true
+Tag: py3-none-any
+

+ 373 - 0
vendor/chattolib-0.4.19.post1.dist-info/licenses/LICENSE

@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.

+ 202 - 0
vendor/chattolib-0.4.19.post1.dist-info/licenses/LICENSES/Apache-2.0.txt

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 373 - 0
vendor/chattolib-0.4.19.post1.dist-info/licenses/LICENSES/MPL-2.0.txt

@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.

+ 1 - 0
vendor/chattolib-0.4.19.post1.dist-info/top_level.txt

@@ -0,0 +1 @@
+chattolib

+ 1 - 0
vendor/chattolib/__init__.py

@@ -0,0 +1 @@
+# Vendored chattolib

+ 21 - 0
vendor/chattolib/_pb/__init__.py

@@ -0,0 +1,21 @@
+"""Vendored protobuf bindings for the Chatto realtime WebSocket protocol.
+
+Generated modules under this directory import each other via top-level package
+paths (``from chatto.api.v1 import ...``, ``from buf.validate import ...``)
+because that is how ``protoc`` emits Python bindings. To make them importable
+without polluting the top-level ``chatto`` / ``buf`` namespaces of dependent
+projects, this package inserts its own directory into ``sys.path`` on first
+import. Chatto is the only real project shipping under those names, so the
+collision risk is negligible.
+
+Regenerate with ``scripts/generate_pb.sh``.
+"""
+
+from __future__ import annotations
+
+import os
+import sys
+
+_here = os.path.dirname(os.path.abspath(__file__))
+if _here not in sys.path:
+    sys.path.insert(0, _here)

+ 0 - 0
vendor/chattolib/_pb/buf/__init__.py


+ 0 - 0
vendor/chattolib/_pb/buf/validate/__init__.py


ファイルの差分が大きいため隠しています
+ 30 - 0
vendor/chattolib/_pb/buf/validate/validate_pb2.py


+ 0 - 0
vendor/chattolib/_pb/chatto/__init__.py


+ 0 - 0
vendor/chattolib/_pb/chatto/admin/__init__.py


+ 0 - 0
vendor/chattolib/_pb/chatto/admin/v1/__init__.py


+ 123 - 0
vendor/chattolib/_pb/chatto/admin/v1/diagnostics_connect.py

@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/admin/v1/diagnostics.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.admin.v1.diagnostics_pb2 as chatto_dot_admin_dot_v1_dot_diagnostics__pb2
+
+
+class AdminDiagnosticsService(Protocol):
+    async def get_system_info(self, request: chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminDiagnosticsServiceASGIApplication(ConnectASGIApplication[AdminDiagnosticsService]):
+    def __init__(self, service: AdminDiagnosticsService | AsyncGenerator[AdminDiagnosticsService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.admin.v1.AdminDiagnosticsService/GetSystemInfo": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetSystemInfo",
+                        service_name="chatto.admin.v1.AdminDiagnosticsService",
+                        input=chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoRequest,
+                        output=chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_system_info,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminDiagnosticsService"
+
+
+class AdminDiagnosticsServiceClient(ConnectClient):
+    async def get_system_info(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetSystemInfo",
+                service_name="chatto.admin.v1.AdminDiagnosticsService",
+                input=chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoRequest,
+                output=chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class AdminDiagnosticsServiceSync(Protocol):
+    def get_system_info(self, request: chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminDiagnosticsServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: AdminDiagnosticsServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.admin.v1.AdminDiagnosticsService/GetSystemInfo": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetSystemInfo",
+                        service_name="chatto.admin.v1.AdminDiagnosticsService",
+                        input=chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoRequest,
+                        output=chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_system_info,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminDiagnosticsService"
+
+
+class AdminDiagnosticsServiceClientSync(ConnectClientSync):
+    def get_system_info(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetSystemInfo",
+                service_name="chatto.admin.v1.AdminDiagnosticsService",
+                input=chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoRequest,
+                output=chatto_dot_admin_dot_v1_dot_diagnostics__pb2.GetSystemInfoResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 26 - 0
vendor/chattolib/_pb/chatto/admin/v1/diagnostics_pb2.py


+ 253 - 0
vendor/chattolib/_pb/chatto/admin/v1/event_log_connect.py

@@ -0,0 +1,253 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/admin/v1/event_log.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.admin.v1.event_log_pb2 as chatto_dot_admin_dot_v1_dot_event__log__pb2
+
+
+class AdminEventLogService(Protocol):
+    async def list_events(self, request: chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_event_types(self, request: chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_event(self, request: chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminEventLogServiceASGIApplication(ConnectASGIApplication[AdminEventLogService]):
+    def __init__(self, service: AdminEventLogService | AsyncGenerator[AdminEventLogService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.admin.v1.AdminEventLogService/ListEvents": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListEvents",
+                        service_name="chatto.admin.v1.AdminEventLogService",
+                        input=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_events,
+                ),
+                "/chatto.admin.v1.AdminEventLogService/ListEventTypes": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListEventTypes",
+                        service_name="chatto.admin.v1.AdminEventLogService",
+                        input=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesRequest,
+                        output=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_event_types,
+                ),
+                "/chatto.admin.v1.AdminEventLogService/GetEvent": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetEvent",
+                        service_name="chatto.admin.v1.AdminEventLogService",
+                        input=chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventRequest,
+                        output=chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_event,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminEventLogService"
+
+
+class AdminEventLogServiceClient(ConnectClient):
+    async def list_events(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListEvents",
+                service_name="chatto.admin.v1.AdminEventLogService",
+                input=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsRequest,
+                output=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_event_types(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListEventTypes",
+                service_name="chatto.admin.v1.AdminEventLogService",
+                input=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesRequest,
+                output=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_event(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetEvent",
+                service_name="chatto.admin.v1.AdminEventLogService",
+                input=chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventRequest,
+                output=chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class AdminEventLogServiceSync(Protocol):
+    def list_events(self, request: chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_event_types(self, request: chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_event(self, request: chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminEventLogServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: AdminEventLogServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.admin.v1.AdminEventLogService/ListEvents": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListEvents",
+                        service_name="chatto.admin.v1.AdminEventLogService",
+                        input=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_events,
+                ),
+                "/chatto.admin.v1.AdminEventLogService/ListEventTypes": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListEventTypes",
+                        service_name="chatto.admin.v1.AdminEventLogService",
+                        input=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesRequest,
+                        output=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_event_types,
+                ),
+                "/chatto.admin.v1.AdminEventLogService/GetEvent": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetEvent",
+                        service_name="chatto.admin.v1.AdminEventLogService",
+                        input=chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventRequest,
+                        output=chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_event,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminEventLogService"
+
+
+class AdminEventLogServiceClientSync(ConnectClientSync):
+    def list_events(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListEvents",
+                service_name="chatto.admin.v1.AdminEventLogService",
+                input=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsRequest,
+                output=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_event_types(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListEventTypes",
+                service_name="chatto.admin.v1.AdminEventLogService",
+                input=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesRequest,
+                output=chatto_dot_admin_dot_v1_dot_event__log__pb2.ListEventTypesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_event(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetEvent",
+                service_name="chatto.admin.v1.AdminEventLogService",
+                input=chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventRequest,
+                output=chatto_dot_admin_dot_v1_dot_event__log__pb2.GetEventResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 28 - 0
vendor/chattolib/_pb/chatto/admin/v1/event_log_pb2.py


+ 643 - 0
vendor/chattolib/_pb/chatto/admin/v1/members_connect.py

@@ -0,0 +1,643 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/admin/v1/members.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.admin.v1.members_pb2 as chatto_dot_admin_dot_v1_dot_members__pb2
+
+
+class AdminUserService(Protocol):
+    async def list_members(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_member(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_members(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def assign_role(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def revoke_role(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_user(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_user_password(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def clear_username_cooldown(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_user(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminUserServiceASGIApplication(ConnectASGIApplication[AdminUserService]):
+    def __init__(self, service: AdminUserService | AsyncGenerator[AdminUserService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.admin.v1.AdminUserService/ListMembers": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListMembers",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_members,
+                ),
+                "/chatto.admin.v1.AdminUserService/GetMember": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetMember",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_member,
+                ),
+                "/chatto.admin.v1.AdminUserService/BatchGetMembers": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetMembers",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_members,
+                ),
+                "/chatto.admin.v1.AdminUserService/AssignRole": Endpoint.unary(
+                    method=MethodInfo(
+                        name="AssignRole",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.assign_role,
+                ),
+                "/chatto.admin.v1.AdminUserService/RevokeRole": Endpoint.unary(
+                    method=MethodInfo(
+                        name="RevokeRole",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.revoke_role,
+                ),
+                "/chatto.admin.v1.AdminUserService/UpdateUser": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateUser",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_user,
+                ),
+                "/chatto.admin.v1.AdminUserService/UpdateUserPassword": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateUserPassword",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_user_password,
+                ),
+                "/chatto.admin.v1.AdminUserService/ClearUsernameCooldown": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ClearUsernameCooldown",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.clear_username_cooldown,
+                ),
+                "/chatto.admin.v1.AdminUserService/DeleteUser": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteUser",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_user,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminUserService"
+
+
+class AdminUserServiceClient(ConnectClient):
+    async def list_members(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListMembers",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_member(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetMember",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_members(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetMembers",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def assign_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="AssignRole",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def revoke_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="RevokeRole",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_user(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateUser",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_user_password(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateUserPassword",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def clear_username_cooldown(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ClearUsernameCooldown",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_user(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteUser",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class AdminUserServiceSync(Protocol):
+    def list_members(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_member(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_members(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def assign_role(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def revoke_role(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_user(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_user_password(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def clear_username_cooldown(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_user(self, request: chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminUserServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: AdminUserServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.admin.v1.AdminUserService/ListMembers": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListMembers",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_members,
+                ),
+                "/chatto.admin.v1.AdminUserService/GetMember": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetMember",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_member,
+                ),
+                "/chatto.admin.v1.AdminUserService/BatchGetMembers": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetMembers",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_members,
+                ),
+                "/chatto.admin.v1.AdminUserService/AssignRole": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="AssignRole",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.assign_role,
+                ),
+                "/chatto.admin.v1.AdminUserService/RevokeRole": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="RevokeRole",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.revoke_role,
+                ),
+                "/chatto.admin.v1.AdminUserService/UpdateUser": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateUser",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_user,
+                ),
+                "/chatto.admin.v1.AdminUserService/UpdateUserPassword": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateUserPassword",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_user_password,
+                ),
+                "/chatto.admin.v1.AdminUserService/ClearUsernameCooldown": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ClearUsernameCooldown",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.clear_username_cooldown,
+                ),
+                "/chatto.admin.v1.AdminUserService/DeleteUser": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteUser",
+                        service_name="chatto.admin.v1.AdminUserService",
+                        input=chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserRequest,
+                        output=chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_user,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminUserService"
+
+
+class AdminUserServiceClientSync(ConnectClientSync):
+    def list_members(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListMembers",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.ListMembersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_member(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetMember",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.GetMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_members(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetMembers",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.BatchGetMembersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def assign_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="AssignRole",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.AssignRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def revoke_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="RevokeRole",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.RevokeRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_user(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateUser",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_user_password(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateUserPassword",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.UpdateUserPasswordResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def clear_username_cooldown(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ClearUsernameCooldown",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.ClearUsernameCooldownResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_user(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteUser",
+                service_name="chatto.admin.v1.AdminUserService",
+                input=chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserRequest,
+                output=chatto_dot_admin_dot_v1_dot_members__pb2.DeleteUserResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 32 - 0
vendor/chattolib/_pb/chatto/admin/v1/members_pb2.py


+ 578 - 0
vendor/chattolib/_pb/chatto/admin/v1/permissions_connect.py

@@ -0,0 +1,578 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/admin/v1/permissions.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.admin.v1.permissions_pb2 as chatto_dot_admin_dot_v1_dot_permissions__pb2
+
+
+class AdminPermissionService(Protocol):
+    async def get_role_permission_tier_matrix(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_role_permission_matrix(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_role_permission_decisions(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_user_permission_matrix(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_user_permission_decisions(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def explain_permissions(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def set_role_permission(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def set_user_permission(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminPermissionServiceASGIApplication(ConnectASGIApplication[AdminPermissionService]):
+    def __init__(self, service: AdminPermissionService | AsyncGenerator[AdminPermissionService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.admin.v1.AdminPermissionService/GetRolePermissionTierMatrix": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRolePermissionTierMatrix",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_role_permission_tier_matrix,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/GetRolePermissionMatrix": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRolePermissionMatrix",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_role_permission_matrix,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/ListRolePermissionDecisions": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListRolePermissionDecisions",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_role_permission_decisions,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/GetUserPermissionMatrix": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetUserPermissionMatrix",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_user_permission_matrix,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/ListUserPermissionDecisions": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListUserPermissionDecisions",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_user_permission_decisions,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/ExplainPermissions": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ExplainPermissions",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.explain_permissions,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/SetRolePermission": Endpoint.unary(
+                    method=MethodInfo(
+                        name="SetRolePermission",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.set_role_permission,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/SetUserPermission": Endpoint.unary(
+                    method=MethodInfo(
+                        name="SetUserPermission",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.set_user_permission,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminPermissionService"
+
+
+class AdminPermissionServiceClient(ConnectClient):
+    async def get_role_permission_tier_matrix(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRolePermissionTierMatrix",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_role_permission_matrix(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRolePermissionMatrix",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_role_permission_decisions(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRolePermissionDecisions",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_user_permission_matrix(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetUserPermissionMatrix",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_user_permission_decisions(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListUserPermissionDecisions",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def explain_permissions(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ExplainPermissions",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def set_role_permission(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="SetRolePermission",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def set_user_permission(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="SetUserPermission",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class AdminPermissionServiceSync(Protocol):
+    def get_role_permission_tier_matrix(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_role_permission_matrix(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_role_permission_decisions(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_user_permission_matrix(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_user_permission_decisions(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def explain_permissions(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def set_role_permission(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def set_user_permission(self, request: chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminPermissionServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: AdminPermissionServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.admin.v1.AdminPermissionService/GetRolePermissionTierMatrix": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRolePermissionTierMatrix",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_role_permission_tier_matrix,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/GetRolePermissionMatrix": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRolePermissionMatrix",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_role_permission_matrix,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/ListRolePermissionDecisions": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListRolePermissionDecisions",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_role_permission_decisions,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/GetUserPermissionMatrix": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetUserPermissionMatrix",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_user_permission_matrix,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/ListUserPermissionDecisions": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListUserPermissionDecisions",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_user_permission_decisions,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/ExplainPermissions": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ExplainPermissions",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.explain_permissions,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/SetRolePermission": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="SetRolePermission",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.set_role_permission,
+                ),
+                "/chatto.admin.v1.AdminPermissionService/SetUserPermission": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="SetUserPermission",
+                        service_name="chatto.admin.v1.AdminPermissionService",
+                        input=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionRequest,
+                        output=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.set_user_permission,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminPermissionService"
+
+
+class AdminPermissionServiceClientSync(ConnectClientSync):
+    def get_role_permission_tier_matrix(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRolePermissionTierMatrix",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionTierMatrixResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_role_permission_matrix(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRolePermissionMatrix",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetRolePermissionMatrixResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_role_permission_decisions(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRolePermissionDecisions",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListRolePermissionDecisionsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_user_permission_matrix(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetUserPermissionMatrix",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.GetUserPermissionMatrixResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_user_permission_decisions(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListUserPermissionDecisions",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ListUserPermissionDecisionsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def explain_permissions(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ExplainPermissions",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.ExplainPermissionsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def set_role_permission(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="SetRolePermission",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetRolePermissionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def set_user_permission(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="SetUserPermission",
+                service_name="chatto.admin.v1.AdminPermissionService",
+                input=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionRequest,
+                output=chatto_dot_admin_dot_v1_dot_permissions__pb2.SetUserPermissionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 28 - 0
vendor/chattolib/_pb/chatto/admin/v1/permissions_pb2.py


+ 448 - 0
vendor/chattolib/_pb/chatto/admin/v1/roles_connect.py

@@ -0,0 +1,448 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/admin/v1/roles.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.admin.v1.roles_pb2 as chatto_dot_admin_dot_v1_dot_roles__pb2
+
+
+class AdminRoleService(Protocol):
+    async def list_roles(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_role(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def create_role(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_role(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_role(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def reorder_roles(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminRoleServiceASGIApplication(ConnectASGIApplication[AdminRoleService]):
+    def __init__(self, service: AdminRoleService | AsyncGenerator[AdminRoleService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.admin.v1.AdminRoleService/ListRoles": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListRoles",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_roles,
+                ),
+                "/chatto.admin.v1.AdminRoleService/GetRole": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRole",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_role,
+                ),
+                "/chatto.admin.v1.AdminRoleService/CreateRole": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CreateRole",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.create_role,
+                ),
+                "/chatto.admin.v1.AdminRoleService/UpdateRole": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateRole",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_role,
+                ),
+                "/chatto.admin.v1.AdminRoleService/DeleteRole": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteRole",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_role,
+                ),
+                "/chatto.admin.v1.AdminRoleService/ReorderRoles": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ReorderRoles",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.reorder_roles,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminRoleService"
+
+
+class AdminRoleServiceClient(ConnectClient):
+    async def list_roles(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoles",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRole",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def create_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateRole",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateRole",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteRole",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def reorder_roles(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ReorderRoles",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class AdminRoleServiceSync(Protocol):
+    def list_roles(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_role(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def create_role(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_role(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_role(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def reorder_roles(self, request: chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminRoleServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: AdminRoleServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.admin.v1.AdminRoleService/ListRoles": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListRoles",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_roles,
+                ),
+                "/chatto.admin.v1.AdminRoleService/GetRole": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRole",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_role,
+                ),
+                "/chatto.admin.v1.AdminRoleService/CreateRole": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CreateRole",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.create_role,
+                ),
+                "/chatto.admin.v1.AdminRoleService/UpdateRole": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateRole",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_role,
+                ),
+                "/chatto.admin.v1.AdminRoleService/DeleteRole": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteRole",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_role,
+                ),
+                "/chatto.admin.v1.AdminRoleService/ReorderRoles": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ReorderRoles",
+                        service_name="chatto.admin.v1.AdminRoleService",
+                        input=chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesRequest,
+                        output=chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.reorder_roles,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminRoleService"
+
+
+class AdminRoleServiceClientSync(ConnectClientSync):
+    def list_roles(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoles",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.ListRolesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRole",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.GetRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def create_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateRole",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.CreateRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateRole",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.UpdateRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_role(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteRole",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.DeleteRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def reorder_roles(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ReorderRoles",
+                service_name="chatto.admin.v1.AdminRoleService",
+                input=chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesRequest,
+                output=chatto_dot_admin_dot_v1_dot_roles__pb2.ReorderRolesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 29 - 0
vendor/chattolib/_pb/chatto/admin/v1/roles_pb2.py


+ 773 - 0
vendor/chattolib/_pb/chatto/admin/v1/room_layout_connect.py

@@ -0,0 +1,773 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/admin/v1/room_layout.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.admin.v1.room_layout_pb2 as chatto_dot_admin_dot_v1_dot_room__layout__pb2
+
+
+class AdminRoomLayoutService(Protocol):
+    async def list_room_groups(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def create_room_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_room_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_room_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def reorder_room_groups(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def move_room_to_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def reorder_sidebar_items_in_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def create_sidebar_link(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_sidebar_link(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_sidebar_link(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def move_sidebar_link_to_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminRoomLayoutServiceASGIApplication(ConnectASGIApplication[AdminRoomLayoutService]):
+    def __init__(self, service: AdminRoomLayoutService | AsyncGenerator[AdminRoomLayoutService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.admin.v1.AdminRoomLayoutService/ListRoomGroups": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListRoomGroups",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_room_groups,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/CreateRoomGroup": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CreateRoomGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.create_room_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/UpdateRoomGroup": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateRoomGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_room_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/DeleteRoomGroup": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteRoomGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_room_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/ReorderRoomGroups": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ReorderRoomGroups",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.reorder_room_groups,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/MoveRoomToGroup": Endpoint.unary(
+                    method=MethodInfo(
+                        name="MoveRoomToGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.move_room_to_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/ReorderSidebarItemsInGroup": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ReorderSidebarItemsInGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.reorder_sidebar_items_in_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/CreateSidebarLink": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CreateSidebarLink",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.create_sidebar_link,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/UpdateSidebarLink": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateSidebarLink",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_sidebar_link,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/DeleteSidebarLink": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteSidebarLink",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_sidebar_link,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/MoveSidebarLinkToGroup": Endpoint.unary(
+                    method=MethodInfo(
+                        name="MoveSidebarLinkToGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.move_sidebar_link_to_group,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminRoomLayoutService"
+
+
+class AdminRoomLayoutServiceClient(ConnectClient):
+    async def list_room_groups(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomGroups",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def create_room_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateRoomGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_room_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateRoomGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_room_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteRoomGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def reorder_room_groups(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ReorderRoomGroups",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def move_room_to_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="MoveRoomToGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def reorder_sidebar_items_in_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ReorderSidebarItemsInGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def create_sidebar_link(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateSidebarLink",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_sidebar_link(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateSidebarLink",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_sidebar_link(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteSidebarLink",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def move_sidebar_link_to_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="MoveSidebarLinkToGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class AdminRoomLayoutServiceSync(Protocol):
+    def list_room_groups(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def create_room_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_room_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_room_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def reorder_room_groups(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def move_room_to_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def reorder_sidebar_items_in_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def create_sidebar_link(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_sidebar_link(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_sidebar_link(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def move_sidebar_link_to_group(self, request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminRoomLayoutServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: AdminRoomLayoutServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.admin.v1.AdminRoomLayoutService/ListRoomGroups": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListRoomGroups",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_room_groups,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/CreateRoomGroup": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CreateRoomGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.create_room_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/UpdateRoomGroup": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateRoomGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_room_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/DeleteRoomGroup": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteRoomGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_room_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/ReorderRoomGroups": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ReorderRoomGroups",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.reorder_room_groups,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/MoveRoomToGroup": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="MoveRoomToGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.move_room_to_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/ReorderSidebarItemsInGroup": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ReorderSidebarItemsInGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.reorder_sidebar_items_in_group,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/CreateSidebarLink": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CreateSidebarLink",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.create_sidebar_link,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/UpdateSidebarLink": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateSidebarLink",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_sidebar_link,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/DeleteSidebarLink": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteSidebarLink",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_sidebar_link,
+                ),
+                "/chatto.admin.v1.AdminRoomLayoutService/MoveSidebarLinkToGroup": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="MoveSidebarLinkToGroup",
+                        service_name="chatto.admin.v1.AdminRoomLayoutService",
+                        input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupRequest,
+                        output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.move_sidebar_link_to_group,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminRoomLayoutService"
+
+
+class AdminRoomLayoutServiceClientSync(ConnectClientSync):
+    def list_room_groups(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomGroups",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ListRoomGroupsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def create_room_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateRoomGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_room_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateRoomGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_room_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteRoomGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def reorder_room_groups(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ReorderRoomGroups",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderRoomGroupsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def move_room_to_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="MoveRoomToGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveRoomToGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def reorder_sidebar_items_in_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ReorderSidebarItemsInGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.ReorderSidebarItemsInGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def create_sidebar_link(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateSidebarLink",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.CreateSidebarLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_sidebar_link(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateSidebarLink",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.UpdateSidebarLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_sidebar_link(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteSidebarLink",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.DeleteSidebarLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def move_sidebar_link_to_group(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="MoveSidebarLinkToGroup",
+                service_name="chatto.admin.v1.AdminRoomLayoutService",
+                input=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupRequest,
+                output=chatto_dot_admin_dot_v1_dot_room__layout__pb2.MoveSidebarLinkToGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 29 - 0
vendor/chattolib/_pb/chatto/admin/v1/room_layout_pb2.py


+ 578 - 0
vendor/chattolib/_pb/chatto/admin/v1/server_connect.py

@@ -0,0 +1,578 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/admin/v1/server.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.admin.v1.server_pb2 as chatto_dot_admin_dot_v1_dot_server__pb2
+
+
+class AdminServerService(Protocol):
+    async def get_server_config(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_server_config(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def upload_server_logo(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_server_logo(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def upload_server_banner(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_server_banner(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_server_security_config(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_blocked_usernames(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminServerServiceASGIApplication(ConnectASGIApplication[AdminServerService]):
+    def __init__(self, service: AdminServerService | AsyncGenerator[AdminServerService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.admin.v1.AdminServerService/GetServerConfig": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetServerConfig",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_server_config,
+                ),
+                "/chatto.admin.v1.AdminServerService/UpdateServerConfig": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateServerConfig",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_server_config,
+                ),
+                "/chatto.admin.v1.AdminServerService/UploadServerLogo": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UploadServerLogo",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.upload_server_logo,
+                ),
+                "/chatto.admin.v1.AdminServerService/DeleteServerLogo": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteServerLogo",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_server_logo,
+                ),
+                "/chatto.admin.v1.AdminServerService/UploadServerBanner": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UploadServerBanner",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.upload_server_banner,
+                ),
+                "/chatto.admin.v1.AdminServerService/DeleteServerBanner": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteServerBanner",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_server_banner,
+                ),
+                "/chatto.admin.v1.AdminServerService/GetServerSecurityConfig": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetServerSecurityConfig",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_server_security_config,
+                ),
+                "/chatto.admin.v1.AdminServerService/UpdateBlockedUsernames": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateBlockedUsernames",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_blocked_usernames,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminServerService"
+
+
+class AdminServerServiceClient(ConnectClient):
+    async def get_server_config(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetServerConfig",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_server_config(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateServerConfig",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def upload_server_logo(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UploadServerLogo",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_server_logo(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteServerLogo",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def upload_server_banner(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UploadServerBanner",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_server_banner(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteServerBanner",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_server_security_config(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetServerSecurityConfig",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_blocked_usernames(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateBlockedUsernames",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class AdminServerServiceSync(Protocol):
+    def get_server_config(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_server_config(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def upload_server_logo(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_server_logo(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def upload_server_banner(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_server_banner(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_server_security_config(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_blocked_usernames(self, request: chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesRequest, ctx: RequestContext) -> chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AdminServerServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: AdminServerServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.admin.v1.AdminServerService/GetServerConfig": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetServerConfig",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_server_config,
+                ),
+                "/chatto.admin.v1.AdminServerService/UpdateServerConfig": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateServerConfig",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_server_config,
+                ),
+                "/chatto.admin.v1.AdminServerService/UploadServerLogo": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UploadServerLogo",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.upload_server_logo,
+                ),
+                "/chatto.admin.v1.AdminServerService/DeleteServerLogo": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteServerLogo",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_server_logo,
+                ),
+                "/chatto.admin.v1.AdminServerService/UploadServerBanner": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UploadServerBanner",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.upload_server_banner,
+                ),
+                "/chatto.admin.v1.AdminServerService/DeleteServerBanner": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteServerBanner",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_server_banner,
+                ),
+                "/chatto.admin.v1.AdminServerService/GetServerSecurityConfig": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetServerSecurityConfig",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_server_security_config,
+                ),
+                "/chatto.admin.v1.AdminServerService/UpdateBlockedUsernames": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateBlockedUsernames",
+                        service_name="chatto.admin.v1.AdminServerService",
+                        input=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesRequest,
+                        output=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_blocked_usernames,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.admin.v1.AdminServerService"
+
+
+class AdminServerServiceClientSync(ConnectClientSync):
+    def get_server_config(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetServerConfig",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerConfigResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_server_config(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateServerConfig",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateServerConfigResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def upload_server_logo(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UploadServerLogo",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerLogoResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_server_logo(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteServerLogo",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerLogoResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def upload_server_banner(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UploadServerBanner",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.UploadServerBannerResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_server_banner(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteServerBanner",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.DeleteServerBannerResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_server_security_config(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetServerSecurityConfig",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.GetServerSecurityConfigResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_blocked_usernames(
+        self,
+        request: chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateBlockedUsernames",
+                service_name="chatto.admin.v1.AdminServerService",
+                input=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesRequest,
+                output=chatto_dot_admin_dot_v1_dot_server__pb2.UpdateBlockedUsernamesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 29 - 0
vendor/chattolib/_pb/chatto/admin/v1/server_pb2.py


+ 0 - 0
vendor/chattolib/_pb/chatto/api/__init__.py


+ 0 - 0
vendor/chattolib/_pb/chatto/api/v1/__init__.py


+ 906 - 0
vendor/chattolib/_pb/chatto/api/v1/account_connect.py

@@ -0,0 +1,906 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/account.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.account_pb2 as chatto_dot_api_dot_v1_dot_account__pb2
+import chatto.api.v1.external_identities_pb2 as chatto_dot_api_dot_v1_dot_external__identities__pb2
+import chatto.api.v1.presence_pb2 as chatto_dot_api_dot_v1_dot_presence__pb2
+import chatto.api.v1.user_status_pb2 as chatto_dot_api_dot_v1_dot_user__status__pb2
+
+
+class MyAccountService(Protocol):
+    async def update_profile(self, request: chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def upload_avatar(self, request: chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_avatar(self, request: chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_password(self, request: chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_settings(self, request: chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_external_identities(self, request: chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def start_external_identity_link(self, request: chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def disconnect_external_identity(self, request: chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_presence(self, request: chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_custom_status(self, request: chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_custom_status(self, request: chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def request_account_deletion(self, request: chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_my_account(self, request: chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class MyAccountServiceASGIApplication(ConnectASGIApplication[MyAccountService]):
+    def __init__(self, service: MyAccountService | AsyncGenerator[MyAccountService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.MyAccountService/UpdateProfile": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateProfile",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_profile,
+                ),
+                "/chatto.api.v1.MyAccountService/UploadAvatar": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UploadAvatar",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.upload_avatar,
+                ),
+                "/chatto.api.v1.MyAccountService/DeleteAvatar": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteAvatar",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_avatar,
+                ),
+                "/chatto.api.v1.MyAccountService/UpdatePassword": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdatePassword",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_password,
+                ),
+                "/chatto.api.v1.MyAccountService/UpdateSettings": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateSettings",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_settings,
+                ),
+                "/chatto.api.v1.MyAccountService/ListExternalIdentities": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListExternalIdentities",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesRequest,
+                        output=chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_external_identities,
+                ),
+                "/chatto.api.v1.MyAccountService/StartExternalIdentityLink": Endpoint.unary(
+                    method=MethodInfo(
+                        name="StartExternalIdentityLink",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkRequest,
+                        output=chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.start_external_identity_link,
+                ),
+                "/chatto.api.v1.MyAccountService/DisconnectExternalIdentity": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DisconnectExternalIdentity",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityRequest,
+                        output=chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.disconnect_external_identity,
+                ),
+                "/chatto.api.v1.MyAccountService/UpdatePresence": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdatePresence",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_presence,
+                ),
+                "/chatto.api.v1.MyAccountService/UpdateCustomStatus": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateCustomStatus",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusRequest,
+                        output=chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_custom_status,
+                ),
+                "/chatto.api.v1.MyAccountService/DeleteCustomStatus": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteCustomStatus",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusRequest,
+                        output=chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_custom_status,
+                ),
+                "/chatto.api.v1.MyAccountService/RequestAccountDeletion": Endpoint.unary(
+                    method=MethodInfo(
+                        name="RequestAccountDeletion",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.request_account_deletion,
+                ),
+                "/chatto.api.v1.MyAccountService/DeleteMyAccount": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteMyAccount",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_my_account,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.MyAccountService"
+
+
+class MyAccountServiceClient(ConnectClient):
+    async def update_profile(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateProfile",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def upload_avatar(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UploadAvatar",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_avatar(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteAvatar",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_password(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdatePassword",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_settings(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateSettings",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_external_identities(
+        self,
+        request: chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListExternalIdentities",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesRequest,
+                output=chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def start_external_identity_link(
+        self,
+        request: chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="StartExternalIdentityLink",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkRequest,
+                output=chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def disconnect_external_identity(
+        self,
+        request: chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DisconnectExternalIdentity",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityRequest,
+                output=chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_presence(
+        self,
+        request: chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdatePresence",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceRequest,
+                output=chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_custom_status(
+        self,
+        request: chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateCustomStatus",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusRequest,
+                output=chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_custom_status(
+        self,
+        request: chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteCustomStatus",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusRequest,
+                output=chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def request_account_deletion(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="RequestAccountDeletion",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_my_account(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteMyAccount",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class MyAccountServiceSync(Protocol):
+    def update_profile(self, request: chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def upload_avatar(self, request: chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_avatar(self, request: chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_password(self, request: chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_settings(self, request: chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_external_identities(self, request: chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def start_external_identity_link(self, request: chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def disconnect_external_identity(self, request: chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_presence(self, request: chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_custom_status(self, request: chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_custom_status(self, request: chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def request_account_deletion(self, request: chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_my_account(self, request: chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class MyAccountServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: MyAccountServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.MyAccountService/UpdateProfile": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateProfile",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_profile,
+                ),
+                "/chatto.api.v1.MyAccountService/UploadAvatar": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UploadAvatar",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.upload_avatar,
+                ),
+                "/chatto.api.v1.MyAccountService/DeleteAvatar": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteAvatar",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_avatar,
+                ),
+                "/chatto.api.v1.MyAccountService/UpdatePassword": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdatePassword",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_password,
+                ),
+                "/chatto.api.v1.MyAccountService/UpdateSettings": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateSettings",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_settings,
+                ),
+                "/chatto.api.v1.MyAccountService/ListExternalIdentities": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListExternalIdentities",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesRequest,
+                        output=chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_external_identities,
+                ),
+                "/chatto.api.v1.MyAccountService/StartExternalIdentityLink": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="StartExternalIdentityLink",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkRequest,
+                        output=chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.start_external_identity_link,
+                ),
+                "/chatto.api.v1.MyAccountService/DisconnectExternalIdentity": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DisconnectExternalIdentity",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityRequest,
+                        output=chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.disconnect_external_identity,
+                ),
+                "/chatto.api.v1.MyAccountService/UpdatePresence": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdatePresence",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_presence,
+                ),
+                "/chatto.api.v1.MyAccountService/UpdateCustomStatus": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateCustomStatus",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusRequest,
+                        output=chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_custom_status,
+                ),
+                "/chatto.api.v1.MyAccountService/DeleteCustomStatus": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteCustomStatus",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusRequest,
+                        output=chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_custom_status,
+                ),
+                "/chatto.api.v1.MyAccountService/RequestAccountDeletion": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="RequestAccountDeletion",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.request_account_deletion,
+                ),
+                "/chatto.api.v1.MyAccountService/DeleteMyAccount": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteMyAccount",
+                        service_name="chatto.api.v1.MyAccountService",
+                        input=chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountRequest,
+                        output=chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_my_account,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.MyAccountService"
+
+
+class MyAccountServiceClientSync(ConnectClientSync):
+    def update_profile(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateProfile",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.UpdateProfileResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def upload_avatar(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UploadAvatar",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.UploadAvatarResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_avatar(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteAvatar",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.DeleteAvatarResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_password(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdatePassword",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.UpdatePasswordResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_settings(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateSettings",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.UpdateSettingsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_external_identities(
+        self,
+        request: chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListExternalIdentities",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesRequest,
+                output=chatto_dot_api_dot_v1_dot_external__identities__pb2.ListExternalIdentitiesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def start_external_identity_link(
+        self,
+        request: chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="StartExternalIdentityLink",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkRequest,
+                output=chatto_dot_api_dot_v1_dot_external__identities__pb2.StartExternalIdentityLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def disconnect_external_identity(
+        self,
+        request: chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DisconnectExternalIdentity",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityRequest,
+                output=chatto_dot_api_dot_v1_dot_external__identities__pb2.DisconnectExternalIdentityResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_presence(
+        self,
+        request: chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdatePresence",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceRequest,
+                output=chatto_dot_api_dot_v1_dot_presence__pb2.UpdatePresenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_custom_status(
+        self,
+        request: chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateCustomStatus",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusRequest,
+                output=chatto_dot_api_dot_v1_dot_user__status__pb2.UpdateCustomStatusResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_custom_status(
+        self,
+        request: chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteCustomStatus",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusRequest,
+                output=chatto_dot_api_dot_v1_dot_user__status__pb2.DeleteCustomStatusResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def request_account_deletion(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="RequestAccountDeletion",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.RequestAccountDeletionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_my_account(
+        self,
+        request: chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteMyAccount",
+                service_name="chatto.api.v1.MyAccountService",
+                input=chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountRequest,
+                output=chatto_dot_api_dot_v1_dot_account__pb2.DeleteMyAccountResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 33 - 0
vendor/chattolib/_pb/chatto/api/v1/account_pb2.py


+ 383 - 0
vendor/chattolib/_pb/chatto/api/v1/asset_uploads_connect.py

@@ -0,0 +1,383 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/asset_uploads.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.asset_uploads_pb2 as chatto_dot_api_dot_v1_dot_asset__uploads__pb2
+
+
+class AssetUploadService(Protocol):
+    async def create_upload(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def upload_chunk(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_upload(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def complete_upload(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def cancel_upload(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AssetUploadServiceASGIApplication(ConnectASGIApplication[AssetUploadService]):
+    def __init__(self, service: AssetUploadService | AsyncGenerator[AssetUploadService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.AssetUploadService/CreateUpload": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CreateUpload",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.create_upload,
+                ),
+                "/chatto.api.v1.AssetUploadService/UploadChunk": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UploadChunk",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.upload_chunk,
+                ),
+                "/chatto.api.v1.AssetUploadService/GetUpload": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetUpload",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_upload,
+                ),
+                "/chatto.api.v1.AssetUploadService/CompleteUpload": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CompleteUpload",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.complete_upload,
+                ),
+                "/chatto.api.v1.AssetUploadService/CancelUpload": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CancelUpload",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.cancel_upload,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.AssetUploadService"
+
+
+class AssetUploadServiceClient(ConnectClient):
+    async def create_upload(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateUpload",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def upload_chunk(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UploadChunk",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_upload(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetUpload",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def complete_upload(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CompleteUpload",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def cancel_upload(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CancelUpload",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class AssetUploadServiceSync(Protocol):
+    def create_upload(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def upload_chunk(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_upload(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def complete_upload(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def cancel_upload(self, request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AssetUploadServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: AssetUploadServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.AssetUploadService/CreateUpload": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CreateUpload",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.create_upload,
+                ),
+                "/chatto.api.v1.AssetUploadService/UploadChunk": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UploadChunk",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.upload_chunk,
+                ),
+                "/chatto.api.v1.AssetUploadService/GetUpload": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetUpload",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_upload,
+                ),
+                "/chatto.api.v1.AssetUploadService/CompleteUpload": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CompleteUpload",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.complete_upload,
+                ),
+                "/chatto.api.v1.AssetUploadService/CancelUpload": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CancelUpload",
+                        service_name="chatto.api.v1.AssetUploadService",
+                        input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadRequest,
+                        output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.cancel_upload,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.AssetUploadService"
+
+
+class AssetUploadServiceClientSync(ConnectClientSync):
+    def create_upload(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateUpload",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CreateUploadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def upload_chunk(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UploadChunk",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.UploadChunkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_upload(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetUpload",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.GetUploadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def complete_upload(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CompleteUpload",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CompleteUploadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def cancel_upload(
+        self,
+        request: chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CancelUpload",
+                service_name="chatto.api.v1.AssetUploadService",
+                input=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadRequest,
+                output=chatto_dot_api_dot_v1_dot_asset__uploads__pb2.CancelUploadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 29 - 0
vendor/chattolib/_pb/chatto/api/v1/asset_uploads_pb2.py


+ 188 - 0
vendor/chattolib/_pb/chatto/api/v1/attachments_connect.py

@@ -0,0 +1,188 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/attachments.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.attachments_pb2 as chatto_dot_api_dot_v1_dot_attachments__pb2
+
+
+class AssetService(Protocol):
+    async def get_asset(self, request: chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_assets(self, request: chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AssetServiceASGIApplication(ConnectASGIApplication[AssetService]):
+    def __init__(self, service: AssetService | AsyncGenerator[AssetService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.AssetService/GetAsset": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetAsset",
+                        service_name="chatto.api.v1.AssetService",
+                        input=chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetRequest,
+                        output=chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_asset,
+                ),
+                "/chatto.api.v1.AssetService/BatchGetAssets": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetAssets",
+                        service_name="chatto.api.v1.AssetService",
+                        input=chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsRequest,
+                        output=chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_assets,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.AssetService"
+
+
+class AssetServiceClient(ConnectClient):
+    async def get_asset(
+        self,
+        request: chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetAsset",
+                service_name="chatto.api.v1.AssetService",
+                input=chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetRequest,
+                output=chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_assets(
+        self,
+        request: chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetAssets",
+                service_name="chatto.api.v1.AssetService",
+                input=chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsRequest,
+                output=chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class AssetServiceSync(Protocol):
+    def get_asset(self, request: chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_assets(self, request: chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class AssetServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: AssetServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.AssetService/GetAsset": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetAsset",
+                        service_name="chatto.api.v1.AssetService",
+                        input=chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetRequest,
+                        output=chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_asset,
+                ),
+                "/chatto.api.v1.AssetService/BatchGetAssets": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetAssets",
+                        service_name="chatto.api.v1.AssetService",
+                        input=chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsRequest,
+                        output=chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_assets,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.AssetService"
+
+
+class AssetServiceClientSync(ConnectClientSync):
+    def get_asset(
+        self,
+        request: chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetAsset",
+                service_name="chatto.api.v1.AssetService",
+                input=chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetRequest,
+                output=chatto_dot_api_dot_v1_dot_attachments__pb2.GetAssetResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_assets(
+        self,
+        request: chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetAssets",
+                service_name="chatto.api.v1.AssetService",
+                input=chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsRequest,
+                output=chatto_dot_api_dot_v1_dot_attachments__pb2.BatchGetAssetsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 30 - 0
vendor/chattolib/_pb/chatto/api/v1/attachments_pb2.py


+ 49 - 0
vendor/chattolib/_pb/chatto/api/v1/common_pb2.py

@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/common.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/common.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1a\x63hatto/api/v1/common.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\"\x82\x01\n\x15ImageTransformOptions\x12\x19\n\x05width\x18\x01 \x01(\x05\x42\n\xbaH\x07\x1a\x05\x18\x80 (\x01\x12\x1a\n\x06height\x18\x02 \x01(\x05\x42\n\xbaH\x07\x1a\x05\x18\x80 (\x01\x12\x32\n\x03\x66it\x18\x03 \x01(\x0e\x32\x1b.chatto.api.v1.ImageFitModeB\x08\xbaH\x05\x82\x01\x02\x10\x01\"D\n\x0bImageUpload\x12\r\n\x05image\x18\x01 \x01(\x0c\x12\x10\n\x08\x66ilename\x18\x02 \x01(\t\x12\x14\n\x0c\x63ontent_type\x18\x03 \x01(\t\"N\n\x10ProviderMetadata\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\r\n\x05label\x18\x03 \x01(\t\x12\x11\n\tlogin_url\x18\x04 \x01(\t*d\n\x0cImageFitMode\x12\x1e\n\x1aIMAGE_FIT_MODE_UNSPECIFIED\x10\x00\x12\x1a\n\x16IMAGE_FIT_MODE_CONTAIN\x10\x01\x12\x18\n\x14IMAGE_FIT_MODE_COVER\x10\x02\x62\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.common_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_IMAGETRANSFORMOPTIONS'].fields_by_name['width']._loaded_options = None
+  _globals['_IMAGETRANSFORMOPTIONS'].fields_by_name['width']._serialized_options = b'\272H\007\032\005\030\200 (\001'
+  _globals['_IMAGETRANSFORMOPTIONS'].fields_by_name['height']._loaded_options = None
+  _globals['_IMAGETRANSFORMOPTIONS'].fields_by_name['height']._serialized_options = b'\272H\007\032\005\030\200 (\001'
+  _globals['_IMAGETRANSFORMOPTIONS'].fields_by_name['fit']._loaded_options = None
+  _globals['_IMAGETRANSFORMOPTIONS'].fields_by_name['fit']._serialized_options = b'\272H\005\202\001\002\020\001'
+  _globals['_IMAGEFITMODE']._serialized_start=357
+  _globals['_IMAGEFITMODE']._serialized_end=457
+  _globals['_IMAGETRANSFORMOPTIONS']._serialized_start=75
+  _globals['_IMAGETRANSFORMOPTIONS']._serialized_end=205
+  _globals['_IMAGEUPLOAD']._serialized_start=207
+  _globals['_IMAGEUPLOAD']._serialized_end=275
+  _globals['_PROVIDERMETADATA']._serialized_start=277
+  _globals['_PROVIDERMETADATA']._serialized_end=355
+# @@protoc_insertion_point(module_scope)

+ 56 - 0
vendor/chattolib/_pb/chatto/api/v1/external_identities_pb2.py

@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/external_identities.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/external_identities.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+from chatto.api.v1 import common_pb2 as chatto_dot_api_dot_v1_dot_common__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\'chatto/api/v1/external_identities.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\x1a\x1a\x63hatto/api/v1/common.proto\"\xb7\x01\n\x18\x45xternalIdentityProvider\x12\x10\n\x08link_url\x18\x05 \x01(\t\x12\x0e\n\x06linked\x18\x06 \x01(\x08\x12$\n\x1clinked_identity_subject_hash\x18\x07 \x01(\t\x12\x31\n\x08provider\x18\x08 \x01(\x0b\x32\x1f.chatto.api.v1.ProviderMetadataJ\x04\x08\x01\x10\x05R\x02idR\x04typeR\x05labelR\tlogin_url\"r\n\x16LinkedExternalIdentity\x12\x13\n\x0bprovider_id\x18\x01 \x01(\t\x12\x15\n\rprovider_type\x18\x02 \x01(\t\x12\x16\n\x0eprovider_label\x18\x03 \x01(\t\x12\x14\n\x0csubject_hash\x18\x04 \x01(\t\"\x1f\n\x1dListExternalIdentitiesRequest\"\x9e\x01\n\x1eListExternalIdentitiesResponse\x12:\n\tproviders\x18\x01 \x03(\x0b\x32\'.chatto.api.v1.ExternalIdentityProvider\x12@\n\x11linked_identities\x18\x02 \x03(\x0b\x32%.chatto.api.v1.LinkedExternalIdentity\"q\n StartExternalIdentityLinkRequest\x12\x1c\n\x0bprovider_id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\x12\x15\n\rredirect_path\x18\x02 \x01(\t\x12\x18\n\x10\x63urrent_password\x18\x03 \x01(\t\"6\n!StartExternalIdentityLinkResponse\x12\x11\n\tstart_url\x18\x01 \x01(\t\"\\\n!DisconnectExternalIdentityRequest\x12\x1d\n\x0csubject_hash\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\x12\x18\n\x10\x63urrent_password\x18\x02 \x01(\t\":\n\"DisconnectExternalIdentityResponse\x12\x14\n\x0c\x64isconnected\x18\x01 \x01(\x08\x62\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.external_identities_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_STARTEXTERNALIDENTITYLINKREQUEST'].fields_by_name['provider_id']._loaded_options = None
+  _globals['_STARTEXTERNALIDENTITYLINKREQUEST'].fields_by_name['provider_id']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_DISCONNECTEXTERNALIDENTITYREQUEST'].fields_by_name['subject_hash']._loaded_options = None
+  _globals['_DISCONNECTEXTERNALIDENTITYREQUEST'].fields_by_name['subject_hash']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_EXTERNALIDENTITYPROVIDER']._serialized_start=116
+  _globals['_EXTERNALIDENTITYPROVIDER']._serialized_end=299
+  _globals['_LINKEDEXTERNALIDENTITY']._serialized_start=301
+  _globals['_LINKEDEXTERNALIDENTITY']._serialized_end=415
+  _globals['_LISTEXTERNALIDENTITIESREQUEST']._serialized_start=417
+  _globals['_LISTEXTERNALIDENTITIESREQUEST']._serialized_end=448
+  _globals['_LISTEXTERNALIDENTITIESRESPONSE']._serialized_start=451
+  _globals['_LISTEXTERNALIDENTITIESRESPONSE']._serialized_end=609
+  _globals['_STARTEXTERNALIDENTITYLINKREQUEST']._serialized_start=611
+  _globals['_STARTEXTERNALIDENTITYLINKREQUEST']._serialized_end=724
+  _globals['_STARTEXTERNALIDENTITYLINKRESPONSE']._serialized_start=726
+  _globals['_STARTEXTERNALIDENTITYLINKRESPONSE']._serialized_end=780
+  _globals['_DISCONNECTEXTERNALIDENTITYREQUEST']._serialized_start=782
+  _globals['_DISCONNECTEXTERNALIDENTITYREQUEST']._serialized_end=874
+  _globals['_DISCONNECTEXTERNALIDENTITYRESPONSE']._serialized_start=876
+  _globals['_DISCONNECTEXTERNALIDENTITYRESPONSE']._serialized_end=934
+# @@protoc_insertion_point(module_scope)

+ 43 - 0
vendor/chattolib/_pb/chatto/api/v1/link_previews_pb2.py

@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/link_previews.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/link_previews.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!chatto/api/v1/link_previews.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\"2\n\x17\x46\x65tchLinkPreviewRequest\x12\x17\n\x03url\x18\x01 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80\x10\"\xaa\x02\n\x0bLinkPreview\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x12\n\x05title\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x16\n\timage_url\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1b\n\x0eimage_asset_id\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x16\n\tsite_name\x18\x06 \x01(\tH\x04\x88\x01\x01\x12\x17\n\nembed_type\x18\x07 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08\x65mbed_id\x18\x08 \x01(\tH\x06\x88\x01\x01\x42\x08\n\x06_titleB\x0e\n\x0c_descriptionB\x0c\n\n_image_urlB\x11\n\x0f_image_asset_idB\x0c\n\n_site_nameB\r\n\x0b_embed_typeB\x0b\n\t_embed_id\"^\n\x18\x46\x65tchLinkPreviewResponse\x12+\n\x07preview\x18\x01 \x01(\x0b\x32\x1a.chatto.api.v1.LinkPreview\x12\x15\n\rpreview_token\x18\x02 \x01(\tb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.link_previews_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_FETCHLINKPREVIEWREQUEST'].fields_by_name['url']._loaded_options = None
+  _globals['_FETCHLINKPREVIEWREQUEST'].fields_by_name['url']._serialized_options = b'\272H\007r\005\020\001\030\200\020'
+  _globals['_FETCHLINKPREVIEWREQUEST']._serialized_start=81
+  _globals['_FETCHLINKPREVIEWREQUEST']._serialized_end=131
+  _globals['_LINKPREVIEW']._serialized_start=134
+  _globals['_LINKPREVIEW']._serialized_end=432
+  _globals['_FETCHLINKPREVIEWRESPONSE']._serialized_start=434
+  _globals['_FETCHLINKPREVIEWRESPONSE']._serialized_end=528
+# @@protoc_insertion_point(module_scope)

+ 253 - 0
vendor/chattolib/_pb/chatto/api/v1/member_directory_connect.py

@@ -0,0 +1,253 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/member_directory.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.member_directory_pb2 as chatto_dot_api_dot_v1_dot_member__directory__pb2
+
+
+class UserService(Protocol):
+    async def list_users(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_user(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_users(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class UserServiceASGIApplication(ConnectASGIApplication[UserService]):
+    def __init__(self, service: UserService | AsyncGenerator[UserService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.UserService/ListUsers": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListUsers",
+                        service_name="chatto.api.v1.UserService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_users,
+                ),
+                "/chatto.api.v1.UserService/GetUser": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetUser",
+                        service_name="chatto.api.v1.UserService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_user,
+                ),
+                "/chatto.api.v1.UserService/BatchGetUsers": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetUsers",
+                        service_name="chatto.api.v1.UserService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_users,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.UserService"
+
+
+class UserServiceClient(ConnectClient):
+    async def list_users(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListUsers",
+                service_name="chatto.api.v1.UserService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_user(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetUser",
+                service_name="chatto.api.v1.UserService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_users(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetUsers",
+                service_name="chatto.api.v1.UserService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class UserServiceSync(Protocol):
+    def list_users(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_user(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_users(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class UserServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: UserServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.UserService/ListUsers": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListUsers",
+                        service_name="chatto.api.v1.UserService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_users,
+                ),
+                "/chatto.api.v1.UserService/GetUser": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetUser",
+                        service_name="chatto.api.v1.UserService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_user,
+                ),
+                "/chatto.api.v1.UserService/BatchGetUsers": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetUsers",
+                        service_name="chatto.api.v1.UserService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_users,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.UserService"
+
+
+class UserServiceClientSync(ConnectClientSync):
+    def list_users(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListUsers",
+                service_name="chatto.api.v1.UserService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListUsersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_user(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetUser",
+                service_name="chatto.api.v1.UserService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetUserResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_users(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetUsers",
+                service_name="chatto.api.v1.UserService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetUsersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 30 - 0
vendor/chattolib/_pb/chatto/api/v1/member_directory_pb2.py


ファイルの差分が大きいため隠しています
+ 28 - 0
vendor/chattolib/_pb/chatto/api/v1/message_types_pb2.py


+ 710 - 0
vendor/chattolib/_pb/chatto/api/v1/messages_connect.py

@@ -0,0 +1,710 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/messages.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.link_previews_pb2 as chatto_dot_api_dot_v1_dot_link__previews__pb2
+import chatto.api.v1.messages_pb2 as chatto_dot_api_dot_v1_dot_messages__pb2
+import chatto.api.v1.reactions_pb2 as chatto_dot_api_dot_v1_dot_reactions__pb2
+
+
+class MessageService(Protocol):
+    async def fetch_link_preview(self, request: chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def create_message(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_message(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_message(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_attachment(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def delete_link_preview(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_message(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_messages(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def add_reaction(self, request: chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def remove_reaction(self, request: chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class MessageServiceASGIApplication(ConnectASGIApplication[MessageService]):
+    def __init__(self, service: MessageService | AsyncGenerator[MessageService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.MessageService/FetchLinkPreview": Endpoint.unary(
+                    method=MethodInfo(
+                        name="FetchLinkPreview",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewRequest,
+                        output=chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.fetch_link_preview,
+                ),
+                "/chatto.api.v1.MessageService/CreateMessage": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CreateMessage",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.create_message,
+                ),
+                "/chatto.api.v1.MessageService/UpdateMessage": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateMessage",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_message,
+                ),
+                "/chatto.api.v1.MessageService/DeleteMessage": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteMessage",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_message,
+                ),
+                "/chatto.api.v1.MessageService/DeleteAttachment": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteAttachment",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_attachment,
+                ),
+                "/chatto.api.v1.MessageService/DeleteLinkPreview": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DeleteLinkPreview",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.delete_link_preview,
+                ),
+                "/chatto.api.v1.MessageService/GetMessage": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetMessage",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_message,
+                ),
+                "/chatto.api.v1.MessageService/BatchGetMessages": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetMessages",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_messages,
+                ),
+                "/chatto.api.v1.MessageService/AddReaction": Endpoint.unary(
+                    method=MethodInfo(
+                        name="AddReaction",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionRequest,
+                        output=chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.add_reaction,
+                ),
+                "/chatto.api.v1.MessageService/RemoveReaction": Endpoint.unary(
+                    method=MethodInfo(
+                        name="RemoveReaction",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionRequest,
+                        output=chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.remove_reaction,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.MessageService"
+
+
+class MessageServiceClient(ConnectClient):
+    async def fetch_link_preview(
+        self,
+        request: chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="FetchLinkPreview",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewRequest,
+                output=chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def create_message(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateMessage",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_message(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateMessage",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_message(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteMessage",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_attachment(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteAttachment",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def delete_link_preview(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteLinkPreview",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_message(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetMessage",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_messages(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetMessages",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def add_reaction(
+        self,
+        request: chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="AddReaction",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionRequest,
+                output=chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def remove_reaction(
+        self,
+        request: chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="RemoveReaction",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionRequest,
+                output=chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class MessageServiceSync(Protocol):
+    def fetch_link_preview(self, request: chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def create_message(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_message(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_message(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_attachment(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def delete_link_preview(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_message(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_messages(self, request: chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def add_reaction(self, request: chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def remove_reaction(self, request: chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class MessageServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: MessageServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.MessageService/FetchLinkPreview": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="FetchLinkPreview",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewRequest,
+                        output=chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.fetch_link_preview,
+                ),
+                "/chatto.api.v1.MessageService/CreateMessage": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CreateMessage",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.create_message,
+                ),
+                "/chatto.api.v1.MessageService/UpdateMessage": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateMessage",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_message,
+                ),
+                "/chatto.api.v1.MessageService/DeleteMessage": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteMessage",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_message,
+                ),
+                "/chatto.api.v1.MessageService/DeleteAttachment": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteAttachment",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_attachment,
+                ),
+                "/chatto.api.v1.MessageService/DeleteLinkPreview": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DeleteLinkPreview",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.delete_link_preview,
+                ),
+                "/chatto.api.v1.MessageService/GetMessage": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetMessage",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_message,
+                ),
+                "/chatto.api.v1.MessageService/BatchGetMessages": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetMessages",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesRequest,
+                        output=chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_messages,
+                ),
+                "/chatto.api.v1.MessageService/AddReaction": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="AddReaction",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionRequest,
+                        output=chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.add_reaction,
+                ),
+                "/chatto.api.v1.MessageService/RemoveReaction": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="RemoveReaction",
+                        service_name="chatto.api.v1.MessageService",
+                        input=chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionRequest,
+                        output=chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.remove_reaction,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.MessageService"
+
+
+class MessageServiceClientSync(ConnectClientSync):
+    def fetch_link_preview(
+        self,
+        request: chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="FetchLinkPreview",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewRequest,
+                output=chatto_dot_api_dot_v1_dot_link__previews__pb2.FetchLinkPreviewResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def create_message(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateMessage",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.CreateMessageResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_message(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateMessage",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.UpdateMessageResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_message(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteMessage",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteMessageResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_attachment(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteAttachment",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteAttachmentResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def delete_link_preview(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DeleteLinkPreview",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.DeleteLinkPreviewResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_message(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetMessage",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.GetMessageResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_messages(
+        self,
+        request: chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetMessages",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesRequest,
+                output=chatto_dot_api_dot_v1_dot_messages__pb2.BatchGetMessagesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def add_reaction(
+        self,
+        request: chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="AddReaction",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionRequest,
+                output=chatto_dot_api_dot_v1_dot_reactions__pb2.AddReactionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def remove_reaction(
+        self,
+        request: chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="RemoveReaction",
+                service_name="chatto.api.v1.MessageService",
+                input=chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionRequest,
+                output=chatto_dot_api_dot_v1_dot_reactions__pb2.RemoveReactionResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 30 - 0
vendor/chattolib/_pb/chatto/api/v1/messages_pb2.py


+ 318 - 0
vendor/chattolib/_pb/chatto/api/v1/notification_preferences_connect.py

@@ -0,0 +1,318 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/notification_preferences.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.notification_preferences_pb2 as chatto_dot_api_dot_v1_dot_notification__preferences__pb2
+
+
+class NotificationPreferencesService(Protocol):
+    async def get_server_notification_preference(self, request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetServerNotificationPreferenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_server_notification_preference(self, request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateServerNotificationPreferenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_room_notification_preference(self, request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetRoomNotificationPreferenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_room_notification_preference(self, request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateRoomNotificationPreferenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class NotificationPreferencesServiceASGIApplication(ConnectASGIApplication[NotificationPreferencesService]):
+    def __init__(self, service: NotificationPreferencesService | AsyncGenerator[NotificationPreferencesService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.NotificationPreferencesService/GetServerNotificationPreference": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetServerNotificationPreference",
+                        service_name="chatto.api.v1.NotificationPreferencesService",
+                        input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetServerNotificationPreferenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_server_notification_preference,
+                ),
+                "/chatto.api.v1.NotificationPreferencesService/UpdateServerNotificationPreference": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateServerNotificationPreference",
+                        service_name="chatto.api.v1.NotificationPreferencesService",
+                        input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateServerNotificationPreferenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_server_notification_preference,
+                ),
+                "/chatto.api.v1.NotificationPreferencesService/GetRoomNotificationPreference": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRoomNotificationPreference",
+                        service_name="chatto.api.v1.NotificationPreferencesService",
+                        input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetRoomNotificationPreferenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_room_notification_preference,
+                ),
+                "/chatto.api.v1.NotificationPreferencesService/UpdateRoomNotificationPreference": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateRoomNotificationPreference",
+                        service_name="chatto.api.v1.NotificationPreferencesService",
+                        input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateRoomNotificationPreferenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_room_notification_preference,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.NotificationPreferencesService"
+
+
+class NotificationPreferencesServiceClient(ConnectClient):
+    async def get_server_notification_preference(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetServerNotificationPreferenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetServerNotificationPreference",
+                service_name="chatto.api.v1.NotificationPreferencesService",
+                input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetServerNotificationPreferenceRequest,
+                output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_server_notification_preference(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateServerNotificationPreferenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateServerNotificationPreference",
+                service_name="chatto.api.v1.NotificationPreferencesService",
+                input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateServerNotificationPreferenceRequest,
+                output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_room_notification_preference(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetRoomNotificationPreferenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoomNotificationPreference",
+                service_name="chatto.api.v1.NotificationPreferencesService",
+                input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetRoomNotificationPreferenceRequest,
+                output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_room_notification_preference(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateRoomNotificationPreferenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateRoomNotificationPreference",
+                service_name="chatto.api.v1.NotificationPreferencesService",
+                input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateRoomNotificationPreferenceRequest,
+                output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class NotificationPreferencesServiceSync(Protocol):
+    def get_server_notification_preference(self, request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetServerNotificationPreferenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_server_notification_preference(self, request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateServerNotificationPreferenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_room_notification_preference(self, request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetRoomNotificationPreferenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_room_notification_preference(self, request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateRoomNotificationPreferenceRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class NotificationPreferencesServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: NotificationPreferencesServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.NotificationPreferencesService/GetServerNotificationPreference": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetServerNotificationPreference",
+                        service_name="chatto.api.v1.NotificationPreferencesService",
+                        input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetServerNotificationPreferenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_server_notification_preference,
+                ),
+                "/chatto.api.v1.NotificationPreferencesService/UpdateServerNotificationPreference": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateServerNotificationPreference",
+                        service_name="chatto.api.v1.NotificationPreferencesService",
+                        input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateServerNotificationPreferenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_server_notification_preference,
+                ),
+                "/chatto.api.v1.NotificationPreferencesService/GetRoomNotificationPreference": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRoomNotificationPreference",
+                        service_name="chatto.api.v1.NotificationPreferencesService",
+                        input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetRoomNotificationPreferenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_room_notification_preference,
+                ),
+                "/chatto.api.v1.NotificationPreferencesService/UpdateRoomNotificationPreference": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateRoomNotificationPreference",
+                        service_name="chatto.api.v1.NotificationPreferencesService",
+                        input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateRoomNotificationPreferenceRequest,
+                        output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_room_notification_preference,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.NotificationPreferencesService"
+
+
+class NotificationPreferencesServiceClientSync(ConnectClientSync):
+    def get_server_notification_preference(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetServerNotificationPreferenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetServerNotificationPreference",
+                service_name="chatto.api.v1.NotificationPreferencesService",
+                input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetServerNotificationPreferenceRequest,
+                output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_server_notification_preference(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateServerNotificationPreferenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateServerNotificationPreference",
+                service_name="chatto.api.v1.NotificationPreferencesService",
+                input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateServerNotificationPreferenceRequest,
+                output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_room_notification_preference(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetRoomNotificationPreferenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoomNotificationPreference",
+                service_name="chatto.api.v1.NotificationPreferencesService",
+                input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetRoomNotificationPreferenceRequest,
+                output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.GetNotificationPreferenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_room_notification_preference(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateRoomNotificationPreferenceRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateRoomNotificationPreference",
+                service_name="chatto.api.v1.NotificationPreferencesService",
+                input=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateRoomNotificationPreferenceRequest,
+                output=chatto_dot_api_dot_v1_dot_notification__preferences__pb2.UpdateNotificationPreferenceResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 27 - 0
vendor/chattolib/_pb/chatto/api/v1/notification_preferences_pb2.py


+ 578 - 0
vendor/chattolib/_pb/chatto/api/v1/notifications_connect.py

@@ -0,0 +1,578 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/notifications.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.notifications_pb2 as chatto_dot_api_dot_v1_dot_notifications__pb2
+
+
+class NotificationService(Protocol):
+    async def list_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_notification(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_room_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_room_notification_counts(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def has_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def dismiss_notification(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def dismiss_all_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class NotificationServiceASGIApplication(ConnectASGIApplication[NotificationService]):
+    def __init__(self, service: NotificationService | AsyncGenerator[NotificationService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.NotificationService/ListNotifications": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_notifications,
+                ),
+                "/chatto.api.v1.NotificationService/GetNotification": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetNotification",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_notification,
+                ),
+                "/chatto.api.v1.NotificationService/BatchGetNotifications": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_notifications,
+                ),
+                "/chatto.api.v1.NotificationService/ListRoomNotifications": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListRoomNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_room_notifications,
+                ),
+                "/chatto.api.v1.NotificationService/ListRoomNotificationCounts": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListRoomNotificationCounts",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_room_notification_counts,
+                ),
+                "/chatto.api.v1.NotificationService/HasNotifications": Endpoint.unary(
+                    method=MethodInfo(
+                        name="HasNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.has_notifications,
+                ),
+                "/chatto.api.v1.NotificationService/DismissNotification": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DismissNotification",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.dismiss_notification,
+                ),
+                "/chatto.api.v1.NotificationService/DismissAllNotifications": Endpoint.unary(
+                    method=MethodInfo(
+                        name="DismissAllNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.dismiss_all_notifications,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.NotificationService"
+
+
+class NotificationServiceClient(ConnectClient):
+    async def list_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_notification(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetNotification",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_room_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_room_notification_counts(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomNotificationCounts",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def has_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="HasNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def dismiss_notification(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DismissNotification",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def dismiss_all_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DismissAllNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class NotificationServiceSync(Protocol):
+    def list_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_notification(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_room_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_room_notification_counts(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def has_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def dismiss_notification(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def dismiss_all_notifications(self, request: chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class NotificationServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: NotificationServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.NotificationService/ListNotifications": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_notifications,
+                ),
+                "/chatto.api.v1.NotificationService/GetNotification": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetNotification",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_notification,
+                ),
+                "/chatto.api.v1.NotificationService/BatchGetNotifications": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_notifications,
+                ),
+                "/chatto.api.v1.NotificationService/ListRoomNotifications": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListRoomNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_room_notifications,
+                ),
+                "/chatto.api.v1.NotificationService/ListRoomNotificationCounts": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListRoomNotificationCounts",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_room_notification_counts,
+                ),
+                "/chatto.api.v1.NotificationService/HasNotifications": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="HasNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.has_notifications,
+                ),
+                "/chatto.api.v1.NotificationService/DismissNotification": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DismissNotification",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.dismiss_notification,
+                ),
+                "/chatto.api.v1.NotificationService/DismissAllNotifications": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="DismissAllNotifications",
+                        service_name="chatto.api.v1.NotificationService",
+                        input=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsRequest,
+                        output=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.dismiss_all_notifications,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.NotificationService"
+
+
+class NotificationServiceClientSync(ConnectClientSync):
+    def list_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_notification(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetNotification",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.GetNotificationResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.BatchGetNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_room_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_room_notification_counts(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomNotificationCounts",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.ListRoomNotificationCountsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def has_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="HasNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.HasNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def dismiss_notification(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DismissNotification",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissNotificationResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def dismiss_all_notifications(
+        self,
+        request: chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="DismissAllNotifications",
+                service_name="chatto.api.v1.NotificationService",
+                input=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsRequest,
+                output=chatto_dot_api_dot_v1_dot_notifications__pb2.DismissAllNotificationsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 31 - 0
vendor/chattolib/_pb/chatto/api/v1/notifications_pb2.py


+ 43 - 0
vendor/chattolib/_pb/chatto/api/v1/pagination_pb2.py

@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/pagination.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/pagination.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1e\x63hatto/api/v1/pagination.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\"A\n\x0bPageRequest\x12\x19\n\x05limit\x18\x01 \x01(\x05\x42\n\xbaH\x07\x1a\x05\x18\xf4\x03(\x00\x12\x17\n\x06offset\x18\x02 \x01(\x05\x42\x07\xbaH\x04\x1a\x02(\x00\"1\n\x08PageInfo\x12\x13\n\x0btotal_count\x18\x01 \x01(\x03\x12\x10\n\x08has_more\x18\x02 \x01(\x08\x62\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.pagination_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_PAGEREQUEST'].fields_by_name['limit']._loaded_options = None
+  _globals['_PAGEREQUEST'].fields_by_name['limit']._serialized_options = b'\272H\007\032\005\030\364\003(\000'
+  _globals['_PAGEREQUEST'].fields_by_name['offset']._loaded_options = None
+  _globals['_PAGEREQUEST'].fields_by_name['offset']._serialized_options = b'\272H\004\032\002(\000'
+  _globals['_PAGEREQUEST']._serialized_start=78
+  _globals['_PAGEREQUEST']._serialized_end=143
+  _globals['_PAGEINFO']._serialized_start=145
+  _globals['_PAGEINFO']._serialized_end=194
+# @@protoc_insertion_point(module_scope)

+ 38 - 0
vendor/chattolib/_pb/chatto/api/v1/permissions_pb2.py

@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/permissions.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/permissions.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63hatto/api/v1/permissions.proto\x12\rchatto.api.v1\"6\n\x0fPermissionGrant\x12\x12\n\npermission\x18\x01 \x01(\t\x12\x0f\n\x07granted\x18\x02 \x01(\x08\"6\n\x0f\x43\x61pabilityGrant\x12\x12\n\ncapability\x18\x01 \x01(\t\x12\x0f\n\x07granted\x18\x02 \x01(\x08\x62\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.permissions_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_PERMISSIONGRANT']._serialized_start=50
+  _globals['_PERMISSIONGRANT']._serialized_end=104
+  _globals['_CAPABILITYGRANT']._serialized_start=106
+  _globals['_CAPABILITYGRANT']._serialized_end=160
+# @@protoc_insertion_point(module_scope)

+ 43 - 0
vendor/chattolib/_pb/chatto/api/v1/presence_pb2.py

@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/presence.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/presence.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1c\x63hatto/api/v1/presence.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\"k\n\x15UpdatePresenceRequest\x12;\n\x06status\x18\x01 \x01(\x0e\x32\x1d.chatto.api.v1.PresenceStatusB\x0c\xbaH\t\x82\x01\x06\x10\x01 \x00 \x04\x12\x15\n\ruser_selected\x18\x02 \x01(\x08\"G\n\x16UpdatePresenceResponse\x12-\n\x06status\x18\x01 \x01(\x0e\x32\x1d.chatto.api.v1.PresenceStatus*\xa8\x01\n\x0ePresenceStatus\x12\x1f\n\x1bPRESENCE_STATUS_UNSPECIFIED\x10\x00\x12\x1a\n\x16PRESENCE_STATUS_ONLINE\x10\x01\x12\x18\n\x14PRESENCE_STATUS_AWAY\x10\x02\x12\"\n\x1ePRESENCE_STATUS_DO_NOT_DISTURB\x10\x03\x12\x1b\n\x17PRESENCE_STATUS_OFFLINE\x10\x04\x62\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.presence_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_UPDATEPRESENCEREQUEST'].fields_by_name['status']._loaded_options = None
+  _globals['_UPDATEPRESENCEREQUEST'].fields_by_name['status']._serialized_options = b'\272H\t\202\001\006\020\001 \000 \004'
+  _globals['_PRESENCESTATUS']._serialized_start=259
+  _globals['_PRESENCESTATUS']._serialized_end=427
+  _globals['_UPDATEPRESENCEREQUEST']._serialized_start=76
+  _globals['_UPDATEPRESENCEREQUEST']._serialized_end=183
+  _globals['_UPDATEPRESENCERESPONSE']._serialized_start=185
+  _globals['_UPDATEPRESENCERESPONSE']._serialized_end=256
+# @@protoc_insertion_point(module_scope)

+ 188 - 0
vendor/chattolib/_pb/chatto/api/v1/push_notifications_connect.py

@@ -0,0 +1,188 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/push_notifications.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.push_notifications_pb2 as chatto_dot_api_dot_v1_dot_push__notifications__pb2
+
+
+class PushNotificationService(Protocol):
+    async def subscribe(self, request: chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def unsubscribe(self, request: chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class PushNotificationServiceASGIApplication(ConnectASGIApplication[PushNotificationService]):
+    def __init__(self, service: PushNotificationService | AsyncGenerator[PushNotificationService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.PushNotificationService/Subscribe": Endpoint.unary(
+                    method=MethodInfo(
+                        name="Subscribe",
+                        service_name="chatto.api.v1.PushNotificationService",
+                        input=chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushRequest,
+                        output=chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.subscribe,
+                ),
+                "/chatto.api.v1.PushNotificationService/Unsubscribe": Endpoint.unary(
+                    method=MethodInfo(
+                        name="Unsubscribe",
+                        service_name="chatto.api.v1.PushNotificationService",
+                        input=chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushRequest,
+                        output=chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.unsubscribe,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.PushNotificationService"
+
+
+class PushNotificationServiceClient(ConnectClient):
+    async def subscribe(
+        self,
+        request: chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="Subscribe",
+                service_name="chatto.api.v1.PushNotificationService",
+                input=chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushRequest,
+                output=chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def unsubscribe(
+        self,
+        request: chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="Unsubscribe",
+                service_name="chatto.api.v1.PushNotificationService",
+                input=chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushRequest,
+                output=chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class PushNotificationServiceSync(Protocol):
+    def subscribe(self, request: chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def unsubscribe(self, request: chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class PushNotificationServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: PushNotificationServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.PushNotificationService/Subscribe": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="Subscribe",
+                        service_name="chatto.api.v1.PushNotificationService",
+                        input=chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushRequest,
+                        output=chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.subscribe,
+                ),
+                "/chatto.api.v1.PushNotificationService/Unsubscribe": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="Unsubscribe",
+                        service_name="chatto.api.v1.PushNotificationService",
+                        input=chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushRequest,
+                        output=chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.unsubscribe,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.PushNotificationService"
+
+
+class PushNotificationServiceClientSync(ConnectClientSync):
+    def subscribe(
+        self,
+        request: chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="Subscribe",
+                service_name="chatto.api.v1.PushNotificationService",
+                input=chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushRequest,
+                output=chatto_dot_api_dot_v1_dot_push__notifications__pb2.SubscribePushResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def unsubscribe(
+        self,
+        request: chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="Unsubscribe",
+                service_name="chatto.api.v1.PushNotificationService",
+                input=chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushRequest,
+                output=chatto_dot_api_dot_v1_dot_push__notifications__pb2.UnsubscribePushResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

+ 55 - 0
vendor/chattolib/_pb/chatto/api/v1/push_notifications_pb2.py

@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/push_notifications.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/push_notifications.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n&chatto/api/v1/push_notifications.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\"\x9c\x01\n\x14SubscribePushRequest\x12\x1c\n\x08\x65ndpoint\x18\x01 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80 \x12\x1a\n\x06p256dh\x18\x02 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80\x02\x12\x18\n\x04\x61uth\x18\x03 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80\x01\x12!\n\nuser_agent\x18\x04 \x01(\tB\x08\xbaH\x05r\x03\x18\x80\x04H\x00\x88\x01\x01\x42\r\n\x0b_user_agent\"+\n\x15SubscribePushResponse\x12\x12\n\nsubscribed\x18\x01 \x01(\x08\"6\n\x16UnsubscribePushRequest\x12\x1c\n\x08\x65ndpoint\x18\x01 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80 \"/\n\x17UnsubscribePushResponse\x12\x14\n\x0cunsubscribed\x18\x01 \x01(\x08\x32\xcf\x01\n\x17PushNotificationService\x12V\n\tSubscribe\x12#.chatto.api.v1.SubscribePushRequest\x1a$.chatto.api.v1.SubscribePushResponse\x12\\\n\x0bUnsubscribe\x12%.chatto.api.v1.UnsubscribePushRequest\x1a&.chatto.api.v1.UnsubscribePushResponseb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.push_notifications_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_SUBSCRIBEPUSHREQUEST'].fields_by_name['endpoint']._loaded_options = None
+  _globals['_SUBSCRIBEPUSHREQUEST'].fields_by_name['endpoint']._serialized_options = b'\272H\007r\005\020\001\030\200 '
+  _globals['_SUBSCRIBEPUSHREQUEST'].fields_by_name['p256dh']._loaded_options = None
+  _globals['_SUBSCRIBEPUSHREQUEST'].fields_by_name['p256dh']._serialized_options = b'\272H\007r\005\020\001\030\200\002'
+  _globals['_SUBSCRIBEPUSHREQUEST'].fields_by_name['auth']._loaded_options = None
+  _globals['_SUBSCRIBEPUSHREQUEST'].fields_by_name['auth']._serialized_options = b'\272H\007r\005\020\001\030\200\001'
+  _globals['_SUBSCRIBEPUSHREQUEST'].fields_by_name['user_agent']._loaded_options = None
+  _globals['_SUBSCRIBEPUSHREQUEST'].fields_by_name['user_agent']._serialized_options = b'\272H\005r\003\030\200\004'
+  _globals['_UNSUBSCRIBEPUSHREQUEST'].fields_by_name['endpoint']._loaded_options = None
+  _globals['_UNSUBSCRIBEPUSHREQUEST'].fields_by_name['endpoint']._serialized_options = b'\272H\007r\005\020\001\030\200 '
+  _globals['_SUBSCRIBEPUSHREQUEST']._serialized_start=87
+  _globals['_SUBSCRIBEPUSHREQUEST']._serialized_end=243
+  _globals['_SUBSCRIBEPUSHRESPONSE']._serialized_start=245
+  _globals['_SUBSCRIBEPUSHRESPONSE']._serialized_end=288
+  _globals['_UNSUBSCRIBEPUSHREQUEST']._serialized_start=290
+  _globals['_UNSUBSCRIBEPUSHREQUEST']._serialized_end=344
+  _globals['_UNSUBSCRIBEPUSHRESPONSE']._serialized_start=346
+  _globals['_UNSUBSCRIBEPUSHRESPONSE']._serialized_end=393
+  _globals['_PUSHNOTIFICATIONSERVICE']._serialized_start=396
+  _globals['_PUSHNOTIFICATIONSERVICE']._serialized_end=603
+# @@protoc_insertion_point(module_scope)

+ 56 - 0
vendor/chattolib/_pb/chatto/api/v1/reactions_pb2.py

@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/reactions.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/reactions.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+from chatto.api.v1 import message_types_pb2 as chatto_dot_api_dot_v1_dot_message__types__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1d\x63hatto/api/v1/reactions.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\x1a!chatto/api/v1/message_types.proto\"i\n\x12\x41\x64\x64ReactionRequest\x12\x18\n\x07room_id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\x12!\n\x10message_event_id\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\x12\x16\n\x05\x65moji\x18\x03 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\"V\n\x13\x41\x64\x64ReactionResponse\x12\r\n\x05\x61\x64\x64\x65\x64\x18\x01 \x01(\x08\x12\x30\n\x08reaction\x18\x02 \x01(\x0b\x32\x1e.chatto.api.v1.MessageReaction\"l\n\x15RemoveReactionRequest\x12\x18\n\x07room_id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\x12!\n\x10message_event_id\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\x12\x16\n\x05\x65moji\x18\x03 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\"[\n\x16RemoveReactionResponse\x12\x0f\n\x07removed\x18\x01 \x01(\x08\x12\x30\n\x08reaction\x18\x02 \x01(\x0b\x32\x1e.chatto.api.v1.MessageReactionb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.reactions_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_ADDREACTIONREQUEST'].fields_by_name['room_id']._loaded_options = None
+  _globals['_ADDREACTIONREQUEST'].fields_by_name['room_id']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_ADDREACTIONREQUEST'].fields_by_name['message_event_id']._loaded_options = None
+  _globals['_ADDREACTIONREQUEST'].fields_by_name['message_event_id']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_ADDREACTIONREQUEST'].fields_by_name['emoji']._loaded_options = None
+  _globals['_ADDREACTIONREQUEST'].fields_by_name['emoji']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_REMOVEREACTIONREQUEST'].fields_by_name['room_id']._loaded_options = None
+  _globals['_REMOVEREACTIONREQUEST'].fields_by_name['room_id']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_REMOVEREACTIONREQUEST'].fields_by_name['message_event_id']._loaded_options = None
+  _globals['_REMOVEREACTIONREQUEST'].fields_by_name['message_event_id']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_REMOVEREACTIONREQUEST'].fields_by_name['emoji']._loaded_options = None
+  _globals['_REMOVEREACTIONREQUEST'].fields_by_name['emoji']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_ADDREACTIONREQUEST']._serialized_start=112
+  _globals['_ADDREACTIONREQUEST']._serialized_end=217
+  _globals['_ADDREACTIONRESPONSE']._serialized_start=219
+  _globals['_ADDREACTIONRESPONSE']._serialized_end=305
+  _globals['_REMOVEREACTIONREQUEST']._serialized_start=307
+  _globals['_REMOVEREACTIONREQUEST']._serialized_end=415
+  _globals['_REMOVEREACTIONRESPONSE']._serialized_start=417
+  _globals['_REMOVEREACTIONRESPONSE']._serialized_end=508
+# @@protoc_insertion_point(module_scope)

+ 50 - 0
vendor/chattolib/_pb/chatto/api/v1/read_state_pb2.py

@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/read_state.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/read_state.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1e\x63hatto/api/v1/read_state.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"I\n\x15MarkRoomAsReadRequest\x12\x18\n\x07room_id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\x12\x16\n\x0eup_to_event_id\x18\x02 \x01(\t\"\x85\x01\n\x16MarkRoomAsReadResponse\x12\x30\n\x0clast_read_at\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x39\n\x15previous_last_read_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"r\n\x17MarkThreadAsReadRequest\x12\x18\n\x07room_id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\x12%\n\x14thread_root_event_id\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\x12\x16\n\x0eup_to_event_id\x18\x03 \x01(\t\"P\n\x18MarkThreadAsReadResponse\x12\x34\n\x10previous_read_at\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestampb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.read_state_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_MARKROOMASREADREQUEST'].fields_by_name['room_id']._loaded_options = None
+  _globals['_MARKROOMASREADREQUEST'].fields_by_name['room_id']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_MARKTHREADASREADREQUEST'].fields_by_name['room_id']._loaded_options = None
+  _globals['_MARKTHREADASREADREQUEST'].fields_by_name['room_id']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_MARKTHREADASREADREQUEST'].fields_by_name['thread_root_event_id']._loaded_options = None
+  _globals['_MARKTHREADASREADREQUEST'].fields_by_name['thread_root_event_id']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_MARKROOMASREADREQUEST']._serialized_start=111
+  _globals['_MARKROOMASREADREQUEST']._serialized_end=184
+  _globals['_MARKROOMASREADRESPONSE']._serialized_start=187
+  _globals['_MARKROOMASREADRESPONSE']._serialized_end=320
+  _globals['_MARKTHREADASREADREQUEST']._serialized_start=322
+  _globals['_MARKTHREADASREADREQUEST']._serialized_end=436
+  _globals['_MARKTHREADASREADRESPONSE']._serialized_start=438
+  _globals['_MARKTHREADASREADRESPONSE']._serialized_end=518
+# @@protoc_insertion_point(module_scope)

+ 253 - 0
vendor/chattolib/_pb/chatto/api/v1/roles_connect.py

@@ -0,0 +1,253 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/roles.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.roles_pb2 as chatto_dot_api_dot_v1_dot_roles__pb2
+
+
+class RoleService(Protocol):
+    async def list_roles(self, request: chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_role(self, request: chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_roles(self, request: chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class RoleServiceASGIApplication(ConnectASGIApplication[RoleService]):
+    def __init__(self, service: RoleService | AsyncGenerator[RoleService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.RoleService/ListRoles": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListRoles",
+                        service_name="chatto.api.v1.RoleService",
+                        input=chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesRequest,
+                        output=chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_roles,
+                ),
+                "/chatto.api.v1.RoleService/GetRole": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRole",
+                        service_name="chatto.api.v1.RoleService",
+                        input=chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleRequest,
+                        output=chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_role,
+                ),
+                "/chatto.api.v1.RoleService/BatchGetRoles": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetRoles",
+                        service_name="chatto.api.v1.RoleService",
+                        input=chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesRequest,
+                        output=chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_roles,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.RoleService"
+
+
+class RoleServiceClient(ConnectClient):
+    async def list_roles(
+        self,
+        request: chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoles",
+                service_name="chatto.api.v1.RoleService",
+                input=chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesRequest,
+                output=chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_role(
+        self,
+        request: chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRole",
+                service_name="chatto.api.v1.RoleService",
+                input=chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleRequest,
+                output=chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_roles(
+        self,
+        request: chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetRoles",
+                service_name="chatto.api.v1.RoleService",
+                input=chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesRequest,
+                output=chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class RoleServiceSync(Protocol):
+    def list_roles(self, request: chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_role(self, request: chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_roles(self, request: chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class RoleServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: RoleServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.RoleService/ListRoles": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListRoles",
+                        service_name="chatto.api.v1.RoleService",
+                        input=chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesRequest,
+                        output=chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_roles,
+                ),
+                "/chatto.api.v1.RoleService/GetRole": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRole",
+                        service_name="chatto.api.v1.RoleService",
+                        input=chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleRequest,
+                        output=chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_role,
+                ),
+                "/chatto.api.v1.RoleService/BatchGetRoles": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetRoles",
+                        service_name="chatto.api.v1.RoleService",
+                        input=chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesRequest,
+                        output=chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_roles,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.RoleService"
+
+
+class RoleServiceClientSync(ConnectClientSync):
+    def list_roles(
+        self,
+        request: chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoles",
+                service_name="chatto.api.v1.RoleService",
+                input=chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesRequest,
+                output=chatto_dot_api_dot_v1_dot_roles__pb2.ListRolesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_role(
+        self,
+        request: chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRole",
+                service_name="chatto.api.v1.RoleService",
+                input=chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleRequest,
+                output=chatto_dot_api_dot_v1_dot_roles__pb2.GetRoleResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_roles(
+        self,
+        request: chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetRoles",
+                service_name="chatto.api.v1.RoleService",
+                input=chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesRequest,
+                output=chatto_dot_api_dot_v1_dot_roles__pb2.BatchGetRolesResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

+ 55 - 0
vendor/chattolib/_pb/chatto/api/v1/roles_pb2.py

@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/roles.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/roles.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19\x63hatto/api/v1/roles.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\"v\n\x04Role\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x11\n\tis_system\x18\x04 \x01(\x08\x12\x10\n\x08position\x18\x05 \x01(\x05\x12\x10\n\x08pingable\x18\x06 \x01(\x08\"\x12\n\x10ListRolesRequest\"7\n\x11ListRolesResponse\x12\"\n\x05roles\x18\x01 \x03(\x0b\x32\x13.chatto.api.v1.Role\"\'\n\x0eGetRoleRequest\x12\x15\n\x04name\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01\"4\n\x0fGetRoleResponse\x12!\n\x04role\x18\x01 \x01(\x0b\x32\x13.chatto.api.v1.Role\"7\n\x14\x42\x61tchGetRolesRequest\x12\x1f\n\x05names\x18\x01 \x03(\tB\x10\xbaH\r\x92\x01\n\x08\x01\x10\x64\"\x04r\x02\x10\x01\";\n\x15\x42\x61tchGetRolesResponse\x12\"\n\x05roles\x18\x01 \x03(\x0b\x32\x13.chatto.api.v1.Role2\x83\x02\n\x0bRoleService\x12N\n\tListRoles\x12\x1f.chatto.api.v1.ListRolesRequest\x1a .chatto.api.v1.ListRolesResponse\x12H\n\x07GetRole\x12\x1d.chatto.api.v1.GetRoleRequest\x1a\x1e.chatto.api.v1.GetRoleResponse\x12Z\n\rBatchGetRoles\x12#.chatto.api.v1.BatchGetRolesRequest\x1a$.chatto.api.v1.BatchGetRolesResponseb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.roles_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_GETROLEREQUEST'].fields_by_name['name']._loaded_options = None
+  _globals['_GETROLEREQUEST'].fields_by_name['name']._serialized_options = b'\272H\004r\002\020\001'
+  _globals['_BATCHGETROLESREQUEST'].fields_by_name['names']._loaded_options = None
+  _globals['_BATCHGETROLESREQUEST'].fields_by_name['names']._serialized_options = b'\272H\r\222\001\n\010\001\020d\"\004r\002\020\001'
+  _globals['_ROLE']._serialized_start=73
+  _globals['_ROLE']._serialized_end=191
+  _globals['_LISTROLESREQUEST']._serialized_start=193
+  _globals['_LISTROLESREQUEST']._serialized_end=211
+  _globals['_LISTROLESRESPONSE']._serialized_start=213
+  _globals['_LISTROLESRESPONSE']._serialized_end=268
+  _globals['_GETROLEREQUEST']._serialized_start=270
+  _globals['_GETROLEREQUEST']._serialized_end=309
+  _globals['_GETROLERESPONSE']._serialized_start=311
+  _globals['_GETROLERESPONSE']._serialized_end=363
+  _globals['_BATCHGETROLESREQUEST']._serialized_start=365
+  _globals['_BATCHGETROLESREQUEST']._serialized_end=420
+  _globals['_BATCHGETROLESRESPONSE']._serialized_start=422
+  _globals['_BATCHGETROLESRESPONSE']._serialized_end=481
+  _globals['_ROLESERVICE']._serialized_start=484
+  _globals['_ROLESERVICE']._serialized_end=743
+# @@protoc_insertion_point(module_scope)

+ 448 - 0
vendor/chattolib/_pb/chatto/api/v1/room_directory_connect.py

@@ -0,0 +1,448 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/room_directory.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.room_directory_pb2 as chatto_dot_api_dot_v1_dot_room__directory__pb2
+
+
+class RoomDirectoryService(Protocol):
+    async def list_rooms(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_room_groups(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_room_group(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_room_groups(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_room(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_rooms(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class RoomDirectoryServiceASGIApplication(ConnectASGIApplication[RoomDirectoryService]):
+    def __init__(self, service: RoomDirectoryService | AsyncGenerator[RoomDirectoryService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.RoomDirectoryService/ListRooms": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListRooms",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_rooms,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/ListRoomGroups": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListRoomGroups",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_room_groups,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/GetRoomGroup": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRoomGroup",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_room_group,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/BatchGetRoomGroups": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetRoomGroups",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_room_groups,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/GetRoom": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRoom",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_room,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/BatchGetRooms": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetRooms",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_rooms,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.RoomDirectoryService"
+
+
+class RoomDirectoryServiceClient(ConnectClient):
+    async def list_rooms(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRooms",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_room_groups(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomGroups",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_room_group(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoomGroup",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_room_groups(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetRoomGroups",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoom",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_rooms(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetRooms",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class RoomDirectoryServiceSync(Protocol):
+    def list_rooms(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_room_groups(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_room_group(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_room_groups(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_room(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_rooms(self, request: chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class RoomDirectoryServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: RoomDirectoryServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.RoomDirectoryService/ListRooms": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListRooms",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_rooms,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/ListRoomGroups": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListRoomGroups",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_room_groups,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/GetRoomGroup": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRoomGroup",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_room_group,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/BatchGetRoomGroups": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetRoomGroups",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_room_groups,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/GetRoom": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRoom",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_room,
+                ),
+                "/chatto.api.v1.RoomDirectoryService/BatchGetRooms": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetRooms",
+                        service_name="chatto.api.v1.RoomDirectoryService",
+                        input=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_rooms,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.RoomDirectoryService"
+
+
+class RoomDirectoryServiceClientSync(ConnectClientSync):
+    def list_rooms(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRooms",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_room_groups(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomGroups",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.ListRoomGroupsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_room_group(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoomGroup",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_room_groups(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetRoomGroups",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomGroupsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoom",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.GetRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_rooms(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetRooms",
+                service_name="chatto.api.v1.RoomDirectoryService",
+                input=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__directory__pb2.BatchGetRoomsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 29 - 0
vendor/chattolib/_pb/chatto/api/v1/room_directory_pb2.py


ファイルの差分が大きいため隠しています
+ 30 - 0
vendor/chattolib/_pb/chatto/api/v1/room_timeline_pb2.py


+ 1426 - 0
vendor/chattolib/_pb/chatto/api/v1/rooms_connect.py

@@ -0,0 +1,1426 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/rooms.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.member_directory_pb2 as chatto_dot_api_dot_v1_dot_member__directory__pb2
+import chatto.api.v1.read_state_pb2 as chatto_dot_api_dot_v1_dot_read__state__pb2
+import chatto.api.v1.room_timeline_pb2 as chatto_dot_api_dot_v1_dot_room__timeline__pb2
+import chatto.api.v1.rooms_pb2 as chatto_dot_api_dot_v1_dot_rooms__pb2
+
+
+class RoomService(Protocol):
+    async def create_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def archive_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def unarchive_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def join_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def join_room_group(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def start_d_m(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def leave_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_members(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_member(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_members(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def add_member(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def remove_member(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_bans(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_room_attachments(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def update_typing_indicator(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_room_events(self, request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_room_events_around(self, request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def mark_room_as_read(self, request: chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def ban_member(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def unban_member(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class RoomServiceASGIApplication(ConnectASGIApplication[RoomService]):
+    def __init__(self, service: RoomService | AsyncGenerator[RoomService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.RoomService/CreateRoom": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CreateRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.create_room,
+                ),
+                "/chatto.api.v1.RoomService/UpdateRoom": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_room,
+                ),
+                "/chatto.api.v1.RoomService/ArchiveRoom": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ArchiveRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.archive_room,
+                ),
+                "/chatto.api.v1.RoomService/UnarchiveRoom": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UnarchiveRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.unarchive_room,
+                ),
+                "/chatto.api.v1.RoomService/JoinRoom": Endpoint.unary(
+                    method=MethodInfo(
+                        name="JoinRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.join_room,
+                ),
+                "/chatto.api.v1.RoomService/JoinRoomGroup": Endpoint.unary(
+                    method=MethodInfo(
+                        name="JoinRoomGroup",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.join_room_group,
+                ),
+                "/chatto.api.v1.RoomService/StartDM": Endpoint.unary(
+                    method=MethodInfo(
+                        name="StartDM",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.start_d_m,
+                ),
+                "/chatto.api.v1.RoomService/LeaveRoom": Endpoint.unary(
+                    method=MethodInfo(
+                        name="LeaveRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.leave_room,
+                ),
+                "/chatto.api.v1.RoomService/ListMembers": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListMembers",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_members,
+                ),
+                "/chatto.api.v1.RoomService/GetMember": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_member,
+                ),
+                "/chatto.api.v1.RoomService/BatchGetMembers": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetMembers",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_members,
+                ),
+                "/chatto.api.v1.RoomService/AddMember": Endpoint.unary(
+                    method=MethodInfo(
+                        name="AddMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.add_member,
+                ),
+                "/chatto.api.v1.RoomService/RemoveMember": Endpoint.unary(
+                    method=MethodInfo(
+                        name="RemoveMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.remove_member,
+                ),
+                "/chatto.api.v1.RoomService/ListBans": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListBans",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_bans,
+                ),
+                "/chatto.api.v1.RoomService/ListRoomAttachments": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListRoomAttachments",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_room_attachments,
+                ),
+                "/chatto.api.v1.RoomService/UpdateTypingIndicator": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UpdateTypingIndicator",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.update_typing_indicator,
+                ),
+                "/chatto.api.v1.RoomService/GetRoomEvents": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRoomEvents",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_room_events,
+                ),
+                "/chatto.api.v1.RoomService/GetRoomEventsAround": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRoomEventsAround",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_room_events_around,
+                ),
+                "/chatto.api.v1.RoomService/MarkRoomAsRead": Endpoint.unary(
+                    method=MethodInfo(
+                        name="MarkRoomAsRead",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadRequest,
+                        output=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.mark_room_as_read,
+                ),
+                "/chatto.api.v1.RoomService/BanMember": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BanMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.ban_member,
+                ),
+                "/chatto.api.v1.RoomService/UnbanMember": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UnbanMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.unban_member,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.RoomService"
+
+
+class RoomServiceClient(ConnectClient):
+    async def create_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def archive_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ArchiveRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def unarchive_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UnarchiveRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def join_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="JoinRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def join_room_group(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="JoinRoomGroup",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def start_d_m(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="StartDM",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def leave_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="LeaveRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_members(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListMembers",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_members(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetMembers",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def add_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="AddMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def remove_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="RemoveMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_bans(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListBans",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_room_attachments(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomAttachments",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def update_typing_indicator(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateTypingIndicator",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_room_events(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoomEvents",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_room_events_around(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoomEventsAround",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundRequest,
+                output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def mark_room_as_read(
+        self,
+        request: chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="MarkRoomAsRead",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadRequest,
+                output=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def ban_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BanMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def unban_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UnbanMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class RoomServiceSync(Protocol):
+    def create_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def archive_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def unarchive_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def join_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def join_room_group(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def start_d_m(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def leave_room(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_members(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_member(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_members(self, request: chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def add_member(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def remove_member(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_bans(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_room_attachments(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def update_typing_indicator(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_room_events(self, request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_room_events_around(self, request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def mark_room_as_read(self, request: chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def ban_member(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def unban_member(self, request: chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class RoomServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: RoomServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.RoomService/CreateRoom": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CreateRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.create_room,
+                ),
+                "/chatto.api.v1.RoomService/UpdateRoom": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_room,
+                ),
+                "/chatto.api.v1.RoomService/ArchiveRoom": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ArchiveRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.archive_room,
+                ),
+                "/chatto.api.v1.RoomService/UnarchiveRoom": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UnarchiveRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.unarchive_room,
+                ),
+                "/chatto.api.v1.RoomService/JoinRoom": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="JoinRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.join_room,
+                ),
+                "/chatto.api.v1.RoomService/JoinRoomGroup": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="JoinRoomGroup",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.join_room_group,
+                ),
+                "/chatto.api.v1.RoomService/StartDM": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="StartDM",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.start_d_m,
+                ),
+                "/chatto.api.v1.RoomService/LeaveRoom": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="LeaveRoom",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.leave_room,
+                ),
+                "/chatto.api.v1.RoomService/ListMembers": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListMembers",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_members,
+                ),
+                "/chatto.api.v1.RoomService/GetMember": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_member,
+                ),
+                "/chatto.api.v1.RoomService/BatchGetMembers": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetMembers",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersRequest,
+                        output=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_members,
+                ),
+                "/chatto.api.v1.RoomService/AddMember": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="AddMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.add_member,
+                ),
+                "/chatto.api.v1.RoomService/RemoveMember": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="RemoveMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.remove_member,
+                ),
+                "/chatto.api.v1.RoomService/ListBans": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListBans",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_bans,
+                ),
+                "/chatto.api.v1.RoomService/ListRoomAttachments": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListRoomAttachments",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_room_attachments,
+                ),
+                "/chatto.api.v1.RoomService/UpdateTypingIndicator": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UpdateTypingIndicator",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.update_typing_indicator,
+                ),
+                "/chatto.api.v1.RoomService/GetRoomEvents": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRoomEvents",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_room_events,
+                ),
+                "/chatto.api.v1.RoomService/GetRoomEventsAround": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRoomEventsAround",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_room_events_around,
+                ),
+                "/chatto.api.v1.RoomService/MarkRoomAsRead": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="MarkRoomAsRead",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadRequest,
+                        output=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.mark_room_as_read,
+                ),
+                "/chatto.api.v1.RoomService/BanMember": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BanMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.ban_member,
+                ),
+                "/chatto.api.v1.RoomService/UnbanMember": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UnbanMember",
+                        service_name="chatto.api.v1.RoomService",
+                        input=chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberRequest,
+                        output=chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.unban_member,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.RoomService"
+
+
+class RoomServiceClientSync(ConnectClientSync):
+    def create_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.CreateRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def archive_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ArchiveRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.ArchiveRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def unarchive_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UnarchiveRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.UnarchiveRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def join_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="JoinRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def join_room_group(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="JoinRoomGroup",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.JoinRoomGroupResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def start_d_m(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="StartDM",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.StartDMResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def leave_room(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="LeaveRoom",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.LeaveRoomResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_members(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListMembers",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.ListRoomMembersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.GetRoomMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_members(
+        self,
+        request: chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetMembers",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersRequest,
+                output=chatto_dot_api_dot_v1_dot_member__directory__pb2.BatchGetRoomMembersResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def add_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="AddMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.AddMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def remove_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="RemoveMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.RemoveMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_bans(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListBans",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.ListBansResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_room_attachments(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListRoomAttachments",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.ListRoomAttachmentsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def update_typing_indicator(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UpdateTypingIndicator",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.UpdateTypingIndicatorResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_room_events(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoomEvents",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_room_events_around(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRoomEventsAround",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundRequest,
+                output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetRoomEventsAroundResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def mark_room_as_read(
+        self,
+        request: chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="MarkRoomAsRead",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadRequest,
+                output=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkRoomAsReadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def ban_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BanMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.BanMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def unban_member(
+        self,
+        request: chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UnbanMember",
+                service_name="chatto.api.v1.RoomService",
+                input=chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberRequest,
+                output=chatto_dot_api_dot_v1_dot_rooms__pb2.UnbanMemberResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 34 - 0
vendor/chattolib/_pb/chatto/api/v1/rooms_pb2.py


+ 39 - 0
vendor/chattolib/_pb/chatto/api/v1/server_pb2.py

@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/server.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/server.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chatto.api.v1 import common_pb2 as chatto_dot_api_dot_v1_dot_common__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1a\x63hatto/api/v1/server.proto\x12\rchatto.api.v1\x1a\x1a\x63hatto/api/v1/common.proto\"\xdc\x01\n\x13ServerPublicProfile\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x15\n\x08logo_url\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x17\n\nbanner_url\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x1c\n\x0fwelcome_message\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x06 \x01(\tH\x03\x88\x01\x01\x42\x0b\n\t_logo_urlB\r\n\x0b_banner_urlB\x12\n\x10_welcome_messageB\x0e\n\x0c_description\"}\n\x0bServerLogin\x12#\n\x1b\x64irect_registration_enabled\x18\x01 \x01(\x08\x12\x32\n\tproviders\x18\x02 \x03(\x0b\x32\x1f.chatto.api.v1.ProviderMetadata\x12\x15\n\rauthorize_url\x18\x03 \x01(\tb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.server_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_SERVERPUBLICPROFILE']._serialized_start=74
+  _globals['_SERVERPUBLICPROFILE']._serialized_end=294
+  _globals['_SERVERLOGIN']._serialized_start=296
+  _globals['_SERVERLOGIN']._serialized_end=421
+# @@protoc_insertion_point(module_scope)

+ 188 - 0
vendor/chattolib/_pb/chatto/api/v1/server_state_connect.py

@@ -0,0 +1,188 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/server_state.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.server_state_pb2 as chatto_dot_api_dot_v1_dot_server__state__pb2
+
+
+class ServerService(Protocol):
+    async def get_motd(self, request: chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_runtime_config(self, request: chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ServerServiceASGIApplication(ConnectASGIApplication[ServerService]):
+    def __init__(self, service: ServerService | AsyncGenerator[ServerService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.ServerService/GetMotd": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetMotd",
+                        service_name="chatto.api.v1.ServerService",
+                        input=chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdRequest,
+                        output=chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_motd,
+                ),
+                "/chatto.api.v1.ServerService/GetRuntimeConfig": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetRuntimeConfig",
+                        service_name="chatto.api.v1.ServerService",
+                        input=chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigRequest,
+                        output=chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_runtime_config,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.ServerService"
+
+
+class ServerServiceClient(ConnectClient):
+    async def get_motd(
+        self,
+        request: chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetMotd",
+                service_name="chatto.api.v1.ServerService",
+                input=chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdRequest,
+                output=chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_runtime_config(
+        self,
+        request: chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRuntimeConfig",
+                service_name="chatto.api.v1.ServerService",
+                input=chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigRequest,
+                output=chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class ServerServiceSync(Protocol):
+    def get_motd(self, request: chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_runtime_config(self, request: chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ServerServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: ServerServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.ServerService/GetMotd": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetMotd",
+                        service_name="chatto.api.v1.ServerService",
+                        input=chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdRequest,
+                        output=chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_motd,
+                ),
+                "/chatto.api.v1.ServerService/GetRuntimeConfig": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetRuntimeConfig",
+                        service_name="chatto.api.v1.ServerService",
+                        input=chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigRequest,
+                        output=chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_runtime_config,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.ServerService"
+
+
+class ServerServiceClientSync(ConnectClientSync):
+    def get_motd(
+        self,
+        request: chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetMotd",
+                service_name="chatto.api.v1.ServerService",
+                input=chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdRequest,
+                output=chatto_dot_api_dot_v1_dot_server__state__pb2.GetMotdResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_runtime_config(
+        self,
+        request: chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetRuntimeConfig",
+                service_name="chatto.api.v1.ServerService",
+                input=chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigRequest,
+                output=chatto_dot_api_dot_v1_dot_server__state__pb2.GetRuntimeConfigResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

+ 46 - 0
vendor/chattolib/_pb/chatto/api/v1/server_state_pb2.py

@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/server_state.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/server_state.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n chatto/api/v1/server_state.proto\x12\rchatto.api.v1\"\x10\n\x0eGetMotdRequest\"-\n\x0fGetMotdResponse\x12\x11\n\x04motd\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x07\n\x05_motd\"\xb9\x02\n\x13ServerRuntimeConfig\x12\"\n\x1apush_notifications_enabled\x18\x01 \x01(\x08\x12\x1d\n\x10vapid_public_key\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0blivekit_url\x18\x03 \x01(\tH\x01\x88\x01\x01\x12 \n\x18video_processing_enabled\x18\x05 \x01(\x08\x12\x17\n\x0fmax_upload_size\x18\x06 \x01(\x03\x12\x1d\n\x15max_video_upload_size\x18\x07 \x01(\x03\x12#\n\x1bmessage_edit_window_seconds\x18\x08 \x01(\x05\x42\x13\n\x11_vapid_public_keyB\x0e\n\x0c_livekit_urlJ\x04\x08\x04\x10\x05R\x1b\x64irect_registration_enabled\"\x19\n\x17GetRuntimeConfigRequest\"O\n\x18GetRuntimeConfigResponse\x12\x33\n\x07runtime\x18\x01 \x01(\x0b\x32\".chatto.api.v1.ServerRuntimeConfig2\xbe\x01\n\rServerService\x12H\n\x07GetMotd\x12\x1d.chatto.api.v1.GetMotdRequest\x1a\x1e.chatto.api.v1.GetMotdResponse\x12\x63\n\x10GetRuntimeConfig\x12&.chatto.api.v1.GetRuntimeConfigRequest\x1a\'.chatto.api.v1.GetRuntimeConfigResponseb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.server_state_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_GETMOTDREQUEST']._serialized_start=51
+  _globals['_GETMOTDREQUEST']._serialized_end=67
+  _globals['_GETMOTDRESPONSE']._serialized_start=69
+  _globals['_GETMOTDRESPONSE']._serialized_end=114
+  _globals['_SERVERRUNTIMECONFIG']._serialized_start=117
+  _globals['_SERVERRUNTIMECONFIG']._serialized_end=430
+  _globals['_GETRUNTIMECONFIGREQUEST']._serialized_start=432
+  _globals['_GETRUNTIMECONFIGREQUEST']._serialized_end=457
+  _globals['_GETRUNTIMECONFIGRESPONSE']._serialized_start=459
+  _globals['_GETRUNTIMECONFIGRESPONSE']._serialized_end=538
+  _globals['_SERVERSERVICE']._serialized_start=541
+  _globals['_SERVERSERVICE']._serialized_end=731
+# @@protoc_insertion_point(module_scope)

+ 450 - 0
vendor/chattolib/_pb/chatto/api/v1/threads_connect.py

@@ -0,0 +1,450 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/threads.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.read_state_pb2 as chatto_dot_api_dot_v1_dot_read__state__pb2
+import chatto.api.v1.room_timeline_pb2 as chatto_dot_api_dot_v1_dot_room__timeline__pb2
+import chatto.api.v1.threads_pb2 as chatto_dot_api_dot_v1_dot_threads__pb2
+
+
+class ThreadService(Protocol):
+    async def list_followed_threads(self, request: chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def follow_thread(self, request: chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def unfollow_thread(self, request: chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_thread_events(self, request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_thread_events_around(self, request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def mark_thread_as_read(self, request: chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ThreadServiceASGIApplication(ConnectASGIApplication[ThreadService]):
+    def __init__(self, service: ThreadService | AsyncGenerator[ThreadService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.ThreadService/ListFollowedThreads": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListFollowedThreads",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsRequest,
+                        output=chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_followed_threads,
+                ),
+                "/chatto.api.v1.ThreadService/FollowThread": Endpoint.unary(
+                    method=MethodInfo(
+                        name="FollowThread",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadRequest,
+                        output=chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.follow_thread,
+                ),
+                "/chatto.api.v1.ThreadService/UnfollowThread": Endpoint.unary(
+                    method=MethodInfo(
+                        name="UnfollowThread",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadRequest,
+                        output=chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.unfollow_thread,
+                ),
+                "/chatto.api.v1.ThreadService/GetThreadEvents": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetThreadEvents",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_thread_events,
+                ),
+                "/chatto.api.v1.ThreadService/GetThreadEventsAround": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetThreadEventsAround",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_thread_events_around,
+                ),
+                "/chatto.api.v1.ThreadService/MarkThreadAsRead": Endpoint.unary(
+                    method=MethodInfo(
+                        name="MarkThreadAsRead",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadRequest,
+                        output=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.mark_thread_as_read,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.ThreadService"
+
+
+class ThreadServiceClient(ConnectClient):
+    async def list_followed_threads(
+        self,
+        request: chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListFollowedThreads",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsRequest,
+                output=chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def follow_thread(
+        self,
+        request: chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="FollowThread",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadRequest,
+                output=chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def unfollow_thread(
+        self,
+        request: chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UnfollowThread",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadRequest,
+                output=chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_thread_events(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetThreadEvents",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_thread_events_around(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetThreadEventsAround",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundRequest,
+                output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def mark_thread_as_read(
+        self,
+        request: chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="MarkThreadAsRead",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadRequest,
+                output=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class ThreadServiceSync(Protocol):
+    def list_followed_threads(self, request: chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def follow_thread(self, request: chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def unfollow_thread(self, request: chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_thread_events(self, request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_thread_events_around(self, request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def mark_thread_as_read(self, request: chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ThreadServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: ThreadServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.ThreadService/ListFollowedThreads": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListFollowedThreads",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsRequest,
+                        output=chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_followed_threads,
+                ),
+                "/chatto.api.v1.ThreadService/FollowThread": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="FollowThread",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadRequest,
+                        output=chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.follow_thread,
+                ),
+                "/chatto.api.v1.ThreadService/UnfollowThread": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="UnfollowThread",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadRequest,
+                        output=chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.unfollow_thread,
+                ),
+                "/chatto.api.v1.ThreadService/GetThreadEvents": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetThreadEvents",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_thread_events,
+                ),
+                "/chatto.api.v1.ThreadService/GetThreadEventsAround": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetThreadEventsAround",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundRequest,
+                        output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_thread_events_around,
+                ),
+                "/chatto.api.v1.ThreadService/MarkThreadAsRead": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="MarkThreadAsRead",
+                        service_name="chatto.api.v1.ThreadService",
+                        input=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadRequest,
+                        output=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.mark_thread_as_read,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.ThreadService"
+
+
+class ThreadServiceClientSync(ConnectClientSync):
+    def list_followed_threads(
+        self,
+        request: chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListFollowedThreads",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsRequest,
+                output=chatto_dot_api_dot_v1_dot_threads__pb2.ListFollowedThreadsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def follow_thread(
+        self,
+        request: chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="FollowThread",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadRequest,
+                output=chatto_dot_api_dot_v1_dot_threads__pb2.FollowThreadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def unfollow_thread(
+        self,
+        request: chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="UnfollowThread",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadRequest,
+                output=chatto_dot_api_dot_v1_dot_threads__pb2.UnfollowThreadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_thread_events(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetThreadEvents",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsRequest,
+                output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_thread_events_around(
+        self,
+        request: chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetThreadEventsAround",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundRequest,
+                output=chatto_dot_api_dot_v1_dot_room__timeline__pb2.GetThreadEventsAroundResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def mark_thread_as_read(
+        self,
+        request: chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="MarkThreadAsRead",
+                service_name="chatto.api.v1.ThreadService",
+                input=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadRequest,
+                output=chatto_dot_api_dot_v1_dot_read__state__pb2.MarkThreadAsReadResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 32 - 0
vendor/chattolib/_pb/chatto/api/v1/threads_pb2.py


+ 50 - 0
vendor/chattolib/_pb/chatto/api/v1/user_status_pb2.py

@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/user_status.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/user_status.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2
+from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63hatto/api/v1/user_status.proto\x12\rchatto.api.v1\x1a\x1b\x62uf/validate/validate.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"u\n\x10\x43ustomUserStatus\x12\x18\n\x05\x65moji\x18\x01 \x01(\tB\t\xbaH\x06r\x04\x10\x01\x18\x10\x12\x17\n\x04text\x18\x02 \x01(\tB\t\xbaH\x06r\x04\x10\x01\x18\x64\x12.\n\nexpires_at\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"h\n\x19UpdateCustomStatusRequest\x12\r\n\x05\x65moji\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t\x12.\n\nexpires_at\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"M\n\x1aUpdateCustomStatusResponse\x12/\n\x06status\x18\x01 \x01(\x0b\x32\x1f.chatto.api.v1.CustomUserStatus\"\x1b\n\x19\x44\x65leteCustomStatusRequest\"M\n\x1a\x44\x65leteCustomStatusResponse\x12/\n\x06status\x18\x01 \x01(\x0b\x32\x1f.chatto.api.v1.CustomUserStatusb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.user_status_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_CUSTOMUSERSTATUS'].fields_by_name['emoji']._loaded_options = None
+  _globals['_CUSTOMUSERSTATUS'].fields_by_name['emoji']._serialized_options = b'\272H\006r\004\020\001\030\020'
+  _globals['_CUSTOMUSERSTATUS'].fields_by_name['text']._loaded_options = None
+  _globals['_CUSTOMUSERSTATUS'].fields_by_name['text']._serialized_options = b'\272H\006r\004\020\001\030d'
+  _globals['_CUSTOMUSERSTATUS']._serialized_start=112
+  _globals['_CUSTOMUSERSTATUS']._serialized_end=229
+  _globals['_UPDATECUSTOMSTATUSREQUEST']._serialized_start=231
+  _globals['_UPDATECUSTOMSTATUSREQUEST']._serialized_end=335
+  _globals['_UPDATECUSTOMSTATUSRESPONSE']._serialized_start=337
+  _globals['_UPDATECUSTOMSTATUSRESPONSE']._serialized_end=414
+  _globals['_DELETECUSTOMSTATUSREQUEST']._serialized_start=416
+  _globals['_DELETECUSTOMSTATUSREQUEST']._serialized_end=443
+  _globals['_DELETECUSTOMSTATUSRESPONSE']._serialized_start=445
+  _globals['_DELETECUSTOMSTATUSRESPONSE']._serialized_end=522
+# @@protoc_insertion_point(module_scope)

+ 38 - 0
vendor/chattolib/_pb/chatto/api/v1/users_pb2.py

@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/api/v1/users.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/api/v1/users.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chatto.api.v1 import presence_pb2 as chatto_dot_api_dot_v1_dot_presence__pb2
+from chatto.api.v1 import user_status_pb2 as chatto_dot_api_dot_v1_dot_user__status__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19\x63hatto/api/v1/users.proto\x12\rchatto.api.v1\x1a\x1c\x63hatto/api/v1/presence.proto\x1a\x1f\x63hatto/api/v1/user_status.proto\"\xe0\x01\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\r\n\x05login\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12\x0f\n\x07\x64\x65leted\x18\x04 \x01(\x08\x12\x17\n\navatar_url\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\x36\n\x0fpresence_status\x18\x06 \x01(\x0e\x32\x1d.chatto.api.v1.PresenceStatus\x12\x36\n\rcustom_status\x18\x07 \x01(\x0b\x32\x1f.chatto.api.v1.CustomUserStatusB\r\n\x0b_avatar_urlb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.users_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_USER']._serialized_start=108
+  _globals['_USER']._serialized_end=332
+# @@protoc_insertion_point(module_scope)

+ 123 - 0
vendor/chattolib/_pb/chatto/api/v1/viewer_connect.py

@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/viewer.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.viewer_pb2 as chatto_dot_api_dot_v1_dot_viewer__pb2
+
+
+class ViewerService(Protocol):
+    async def get_viewer(self, request: chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ViewerServiceASGIApplication(ConnectASGIApplication[ViewerService]):
+    def __init__(self, service: ViewerService | AsyncGenerator[ViewerService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.ViewerService/GetViewer": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetViewer",
+                        service_name="chatto.api.v1.ViewerService",
+                        input=chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerRequest,
+                        output=chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_viewer,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.ViewerService"
+
+
+class ViewerServiceClient(ConnectClient):
+    async def get_viewer(
+        self,
+        request: chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetViewer",
+                service_name="chatto.api.v1.ViewerService",
+                input=chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerRequest,
+                output=chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class ViewerServiceSync(Protocol):
+    def get_viewer(self, request: chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ViewerServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: ViewerServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.ViewerService/GetViewer": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetViewer",
+                        service_name="chatto.api.v1.ViewerService",
+                        input=chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerRequest,
+                        output=chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_viewer,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.ViewerService"
+
+
+class ViewerServiceClientSync(ConnectClientSync):
+    def get_viewer(
+        self,
+        request: chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetViewer",
+                service_name="chatto.api.v1.ViewerService",
+                input=chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerRequest,
+                output=chatto_dot_api_dot_v1_dot_viewer__pb2.GetViewerResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 30 - 0
vendor/chattolib/_pb/chatto/api/v1/viewer_pb2.py


+ 513 - 0
vendor/chattolib/_pb/chatto/api/v1/voice_calls_connect.py

@@ -0,0 +1,513 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/api/v1/voice_calls.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.api.v1.voice_calls_pb2 as chatto_dot_api_dot_v1_dot_voice__calls__pb2
+
+
+class VoiceCallService(Protocol):
+    async def list_active_calls(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_active_call(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def batch_get_active_calls(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def list_call_participants(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def join_call(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def get_call_token(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def leave_call(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class VoiceCallServiceASGIApplication(ConnectASGIApplication[VoiceCallService]):
+    def __init__(self, service: VoiceCallService | AsyncGenerator[VoiceCallService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.api.v1.VoiceCallService/ListActiveCalls": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListActiveCalls",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_active_calls,
+                ),
+                "/chatto.api.v1.VoiceCallService/GetActiveCall": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetActiveCall",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_active_call,
+                ),
+                "/chatto.api.v1.VoiceCallService/BatchGetActiveCalls": Endpoint.unary(
+                    method=MethodInfo(
+                        name="BatchGetActiveCalls",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.batch_get_active_calls,
+                ),
+                "/chatto.api.v1.VoiceCallService/ListCallParticipants": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ListCallParticipants",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.list_call_participants,
+                ),
+                "/chatto.api.v1.VoiceCallService/JoinCall": Endpoint.unary(
+                    method=MethodInfo(
+                        name="JoinCall",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.join_call,
+                ),
+                "/chatto.api.v1.VoiceCallService/GetCallToken": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetCallToken",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_call_token,
+                ),
+                "/chatto.api.v1.VoiceCallService/LeaveCall": Endpoint.unary(
+                    method=MethodInfo(
+                        name="LeaveCall",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.leave_call,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.VoiceCallService"
+
+
+class VoiceCallServiceClient(ConnectClient):
+    async def list_active_calls(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListActiveCalls",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_active_call(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetActiveCall",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def batch_get_active_calls(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetActiveCalls",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def list_call_participants(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListCallParticipants",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def join_call(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="JoinCall",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def get_call_token(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetCallToken",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def leave_call(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="LeaveCall",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class VoiceCallServiceSync(Protocol):
+    def list_active_calls(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_active_call(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def batch_get_active_calls(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def list_call_participants(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def join_call(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def get_call_token(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def leave_call(self, request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallRequest, ctx: RequestContext) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class VoiceCallServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: VoiceCallServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.api.v1.VoiceCallService/ListActiveCalls": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListActiveCalls",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_active_calls,
+                ),
+                "/chatto.api.v1.VoiceCallService/GetActiveCall": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetActiveCall",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_active_call,
+                ),
+                "/chatto.api.v1.VoiceCallService/BatchGetActiveCalls": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="BatchGetActiveCalls",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.batch_get_active_calls,
+                ),
+                "/chatto.api.v1.VoiceCallService/ListCallParticipants": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ListCallParticipants",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.list_call_participants,
+                ),
+                "/chatto.api.v1.VoiceCallService/JoinCall": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="JoinCall",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.join_call,
+                ),
+                "/chatto.api.v1.VoiceCallService/GetCallToken": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetCallToken",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_call_token,
+                ),
+                "/chatto.api.v1.VoiceCallService/LeaveCall": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="LeaveCall",
+                        service_name="chatto.api.v1.VoiceCallService",
+                        input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallRequest,
+                        output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.leave_call,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.api.v1.VoiceCallService"
+
+
+class VoiceCallServiceClientSync(ConnectClientSync):
+    def list_active_calls(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListActiveCalls",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListActiveCallsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_active_call(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetActiveCall",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetActiveCallResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def batch_get_active_calls(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="BatchGetActiveCalls",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.BatchGetActiveCallsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def list_call_participants(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ListCallParticipants",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.ListCallParticipantsResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def join_call(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="JoinCall",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.JoinCallResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def get_call_token(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetCallToken",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.GetCallTokenResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def leave_call(
+        self,
+        request: chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="LeaveCall",
+                service_name="chatto.api.v1.VoiceCallService",
+                input=chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallRequest,
+                output=chatto_dot_api_dot_v1_dot_voice__calls__pb2.LeaveCallResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 30 - 0
vendor/chattolib/_pb/chatto/api/v1/voice_calls_pb2.py


+ 0 - 0
vendor/chattolib/_pb/chatto/auth/__init__.py


+ 0 - 0
vendor/chattolib/_pb/chatto/auth/v1/__init__.py


+ 318 - 0
vendor/chattolib/_pb/chatto/auth/v1/external_identity_auth_connect.py

@@ -0,0 +1,318 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/auth/v1/external_identity_auth.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.auth.v1.external_identity_auth_pb2 as chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2
+
+
+class ExternalIdentityAuthService(Protocol):
+    async def get_pending_external_identity(self, request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityRequest, ctx: RequestContext) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def create_external_identity_account(self, request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountRequest, ctx: RequestContext) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def confirm_external_identity_link(self, request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkRequest, ctx: RequestContext) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+    async def cancel_external_identity_flow(self, request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowRequest, ctx: RequestContext) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ExternalIdentityAuthServiceASGIApplication(ConnectASGIApplication[ExternalIdentityAuthService]):
+    def __init__(self, service: ExternalIdentityAuthService | AsyncGenerator[ExternalIdentityAuthService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.auth.v1.ExternalIdentityAuthService/GetPendingExternalIdentity": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetPendingExternalIdentity",
+                        service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                        input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityRequest,
+                        output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_pending_external_identity,
+                ),
+                "/chatto.auth.v1.ExternalIdentityAuthService/CreateExternalIdentityAccount": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CreateExternalIdentityAccount",
+                        service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                        input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountRequest,
+                        output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.create_external_identity_account,
+                ),
+                "/chatto.auth.v1.ExternalIdentityAuthService/ConfirmExternalIdentityLink": Endpoint.unary(
+                    method=MethodInfo(
+                        name="ConfirmExternalIdentityLink",
+                        service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                        input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkRequest,
+                        output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.confirm_external_identity_link,
+                ),
+                "/chatto.auth.v1.ExternalIdentityAuthService/CancelExternalIdentityFlow": Endpoint.unary(
+                    method=MethodInfo(
+                        name="CancelExternalIdentityFlow",
+                        service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                        input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowRequest,
+                        output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.cancel_external_identity_flow,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.auth.v1.ExternalIdentityAuthService"
+
+
+class ExternalIdentityAuthServiceClient(ConnectClient):
+    async def get_pending_external_identity(
+        self,
+        request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetPendingExternalIdentity",
+                service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityRequest,
+                output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def create_external_identity_account(
+        self,
+        request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateExternalIdentityAccount",
+                service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountRequest,
+                output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def confirm_external_identity_link(
+        self,
+        request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ConfirmExternalIdentityLink",
+                service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkRequest,
+                output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    async def cancel_external_identity_flow(
+        self,
+        request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CancelExternalIdentityFlow",
+                service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowRequest,
+                output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class ExternalIdentityAuthServiceSync(Protocol):
+    def get_pending_external_identity(self, request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityRequest, ctx: RequestContext) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def create_external_identity_account(self, request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountRequest, ctx: RequestContext) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def confirm_external_identity_link(self, request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkRequest, ctx: RequestContext) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+    def cancel_external_identity_flow(self, request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowRequest, ctx: RequestContext) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ExternalIdentityAuthServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: ExternalIdentityAuthServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.auth.v1.ExternalIdentityAuthService/GetPendingExternalIdentity": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetPendingExternalIdentity",
+                        service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                        input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityRequest,
+                        output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_pending_external_identity,
+                ),
+                "/chatto.auth.v1.ExternalIdentityAuthService/CreateExternalIdentityAccount": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CreateExternalIdentityAccount",
+                        service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                        input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountRequest,
+                        output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.create_external_identity_account,
+                ),
+                "/chatto.auth.v1.ExternalIdentityAuthService/ConfirmExternalIdentityLink": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="ConfirmExternalIdentityLink",
+                        service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                        input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkRequest,
+                        output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.confirm_external_identity_link,
+                ),
+                "/chatto.auth.v1.ExternalIdentityAuthService/CancelExternalIdentityFlow": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="CancelExternalIdentityFlow",
+                        service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                        input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowRequest,
+                        output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.cancel_external_identity_flow,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.auth.v1.ExternalIdentityAuthService"
+
+
+class ExternalIdentityAuthServiceClientSync(ConnectClientSync):
+    def get_pending_external_identity(
+        self,
+        request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetPendingExternalIdentity",
+                service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityRequest,
+                output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.GetPendingExternalIdentityResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def create_external_identity_account(
+        self,
+        request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CreateExternalIdentityAccount",
+                service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountRequest,
+                output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CreateExternalIdentityAccountResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def confirm_external_identity_link(
+        self,
+        request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="ConfirmExternalIdentityLink",
+                service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkRequest,
+                output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.ConfirmExternalIdentityLinkResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+    def cancel_external_identity_flow(
+        self,
+        request: chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="CancelExternalIdentityFlow",
+                service_name="chatto.auth.v1.ExternalIdentityAuthService",
+                input=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowRequest,
+                output=chatto_dot_auth_dot_v1_dot_external__identity__auth__pb2.CancelExternalIdentityFlowResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

ファイルの差分が大きいため隠しています
+ 28 - 0
vendor/chattolib/_pb/chatto/auth/v1/external_identity_auth_pb2.py


+ 0 - 0
vendor/chattolib/_pb/chatto/discovery/__init__.py


+ 0 - 0
vendor/chattolib/_pb/chatto/discovery/v1/__init__.py


+ 123 - 0
vendor/chattolib/_pb/chatto/discovery/v1/server_connect.py

@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# Generated by https://github.com/connectrpc/connect-python.  DO NOT EDIT!
+# source: chatto/discovery/v1/server.proto
+
+from collections.abc import AsyncGenerator, AsyncIterator, Iterable, Iterator, Mapping
+from typing import Protocol
+
+from connectrpc.client import ConnectClient, ConnectClientSync
+from connectrpc.code import Code
+from connectrpc.compression import Compression
+from connectrpc.errors import ConnectError
+from connectrpc.interceptor import Interceptor, InterceptorSync
+from connectrpc.method import IdempotencyLevel, MethodInfo
+from connectrpc.request import Headers, RequestContext
+from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync
+import chatto.discovery.v1.server_pb2 as chatto_dot_discovery_dot_v1_dot_server__pb2
+
+
+class ServerDiscoveryService(Protocol):
+    async def get_server(self, request: chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerRequest, ctx: RequestContext) -> chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ServerDiscoveryServiceASGIApplication(ConnectASGIApplication[ServerDiscoveryService]):
+    def __init__(self, service: ServerDiscoveryService | AsyncGenerator[ServerDiscoveryService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            service=service,
+            endpoints=lambda svc: {
+                "/chatto.discovery.v1.ServerDiscoveryService/GetServer": Endpoint.unary(
+                    method=MethodInfo(
+                        name="GetServer",
+                        service_name="chatto.discovery.v1.ServerDiscoveryService",
+                        input=chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerRequest,
+                        output=chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=svc.get_server,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.discovery.v1.ServerDiscoveryService"
+
+
+class ServerDiscoveryServiceClient(ConnectClient):
+    async def get_server(
+        self,
+        request: chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerResponse:
+        return await self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetServer",
+                service_name="chatto.discovery.v1.ServerDiscoveryService",
+                input=chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerRequest,
+                output=chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )
+
+
+class ServerDiscoveryServiceSync(Protocol):
+    def get_server(self, request: chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerRequest, ctx: RequestContext) -> chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerResponse:
+        raise ConnectError(Code.UNIMPLEMENTED, "Not implemented")
+
+
+class ServerDiscoveryServiceWSGIApplication(ConnectWSGIApplication):
+    def __init__(self, service: ServerDiscoveryServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None:
+        super().__init__(
+            endpoints={
+                "/chatto.discovery.v1.ServerDiscoveryService/GetServer": EndpointSync.unary(
+                    method=MethodInfo(
+                        name="GetServer",
+                        service_name="chatto.discovery.v1.ServerDiscoveryService",
+                        input=chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerRequest,
+                        output=chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerResponse,
+                        idempotency_level=IdempotencyLevel.UNKNOWN,
+                    ),
+                    function=service.get_server,
+                ),
+            },
+            interceptors=interceptors,
+            read_max_bytes=read_max_bytes,
+            compressions=compressions,
+        )
+
+    @property
+    def path(self) -> str:
+        """Returns the URL path to mount the application to when serving multiple applications."""
+        return "/chatto.discovery.v1.ServerDiscoveryService"
+
+
+class ServerDiscoveryServiceClientSync(ConnectClientSync):
+    def get_server(
+        self,
+        request: chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerRequest,
+        *,
+        headers: Headers | Mapping[str, str] | None = None,
+        timeout_ms: int | None = None,
+    ) -> chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerResponse:
+        return self.execute_unary(
+            request=request,
+            method=MethodInfo(
+                name="GetServer",
+                service_name="chatto.discovery.v1.ServerDiscoveryService",
+                input=chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerRequest,
+                output=chatto_dot_discovery_dot_v1_dot_server__pb2.GetServerResponse,
+                idempotency_level=IdempotencyLevel.UNKNOWN,
+            ),
+            headers=headers,
+            timeout_ms=timeout_ms,
+        )

+ 41 - 0
vendor/chattolib/_pb/chatto/discovery/v1/server_pb2.py

@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: chatto/discovery/v1/server.proto
+# Protobuf Python Version: 7.34.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+    _runtime_version.Domain.PUBLIC,
+    7,
+    34,
+    1,
+    '',
+    'chatto/discovery/v1/server.proto'
+)
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chatto.api.v1 import server_pb2 as chatto_dot_api_dot_v1_dot_server__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n chatto/discovery/v1/server.proto\x12\x13\x63hatto.discovery.v1\x1a\x1a\x63hatto/api/v1/server.proto\"\x12\n\x10GetServerRequest\"s\n\x11GetServerResponse\x12\x33\n\x07profile\x18\x01 \x01(\x0b\x32\".chatto.api.v1.ServerPublicProfile\x12)\n\x05login\x18\x02 \x01(\x0b\x32\x1a.chatto.api.v1.ServerLogin2t\n\x16ServerDiscoveryService\x12Z\n\tGetServer\x12%.chatto.discovery.v1.GetServerRequest\x1a&.chatto.discovery.v1.GetServerResponseb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.discovery.v1.server_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+  DESCRIPTOR._loaded_options = None
+  _globals['_GETSERVERREQUEST']._serialized_start=85
+  _globals['_GETSERVERREQUEST']._serialized_end=103
+  _globals['_GETSERVERRESPONSE']._serialized_start=105
+  _globals['_GETSERVERRESPONSE']._serialized_end=220
+  _globals['_SERVERDISCOVERYSERVICE']._serialized_start=222
+  _globals['_SERVERDISCOVERYSERVICE']._serialized_end=338
+# @@protoc_insertion_point(module_scope)

+ 0 - 0
vendor/chattolib/_pb/chatto/realtime/__init__.py


+ 0 - 0
vendor/chattolib/_pb/chatto/realtime/v1/__init__.py


ファイルの差分が大きいため隠しています
+ 30 - 0
vendor/chattolib/_pb/chatto/realtime/v1/realtime_pb2.py


+ 179 - 0
vendor/chattolib/_transport.py

@@ -0,0 +1,179 @@
+# mypy: disable-error-code="no-any-return"
+"""Shared plumbing for the ConnectRPC-based transport.
+
+Chatto's public API is a ConnectRPC service surface. ``chattolib.client``
+speaks to it through generated service stubs (see ``chattolib._pb``) driven
+by the official ``connectrpc`` Python package.
+
+This module exposes:
+
+* :func:`build_service_clients` — one call, one ``base_url`` argument,
+  returns a ``ServiceClients`` object with a typed field per Chatto service.
+* :func:`translate_connect_error` — translates a
+  ``connectrpc.errors.ConnectError`` into the library's public exception
+  hierarchy (:class:`chattolib.exceptions.ChattoAuthError` /
+  :class:`chattolib.exceptions.ChattoConnectError`).
+* :func:`pb_to_dict` — turns a protobuf response into the camelCase JSON
+  shape that the existing ``types.py`` dataclass parsers already accept.
+
+Keeping the parsers dict-driven means the migration from Connect-JSON to
+Connect-binary transport doesn't ripple through the entire public API.
+"""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import Any
+
+from connectrpc.code import Code
+from connectrpc.compat import google_protobuf_binary_codec
+from connectrpc.errors import ConnectError
+from google.protobuf.json_format import MessageToDict
+from google.protobuf.message import Message
+
+from chattolib._pb.chatto.admin.v1.diagnostics_connect import (
+    AdminDiagnosticsServiceClient,
+)
+from chattolib._pb.chatto.admin.v1.event_log_connect import AdminEventLogServiceClient
+from chattolib._pb.chatto.admin.v1.members_connect import AdminUserServiceClient
+from chattolib._pb.chatto.admin.v1.permissions_connect import (
+    AdminPermissionServiceClient,
+)
+from chattolib._pb.chatto.admin.v1.roles_connect import AdminRoleServiceClient
+from chattolib._pb.chatto.admin.v1.room_layout_connect import (
+    AdminRoomLayoutServiceClient,
+)
+from chattolib._pb.chatto.admin.v1.server_connect import AdminServerServiceClient
+from chattolib._pb.chatto.api.v1.account_connect import MyAccountServiceClient
+from chattolib._pb.chatto.api.v1.asset_uploads_connect import AssetUploadServiceClient
+from chattolib._pb.chatto.api.v1.attachments_connect import AssetServiceClient
+from chattolib._pb.chatto.api.v1.member_directory_connect import UserServiceClient
+from chattolib._pb.chatto.api.v1.messages_connect import MessageServiceClient
+from chattolib._pb.chatto.api.v1.notification_preferences_connect import (
+    NotificationPreferencesServiceClient,
+)
+from chattolib._pb.chatto.api.v1.notifications_connect import (
+    NotificationServiceClient,
+)
+from chattolib._pb.chatto.api.v1.push_notifications_connect import (
+    PushNotificationServiceClient,
+)
+from chattolib._pb.chatto.api.v1.roles_connect import RoleServiceClient
+from chattolib._pb.chatto.api.v1.room_directory_connect import (
+    RoomDirectoryServiceClient,
+)
+from chattolib._pb.chatto.api.v1.rooms_connect import RoomServiceClient
+from chattolib._pb.chatto.api.v1.server_state_connect import ServerServiceClient
+from chattolib._pb.chatto.api.v1.threads_connect import ThreadServiceClient
+from chattolib._pb.chatto.api.v1.viewer_connect import ViewerServiceClient
+from chattolib._pb.chatto.api.v1.voice_calls_connect import VoiceCallServiceClient
+from chattolib._pb.chatto.auth.v1.external_identity_auth_connect import (
+    ExternalIdentityAuthServiceClient,
+)
+from chattolib._pb.chatto.discovery.v1.server_connect import (
+    ServerDiscoveryServiceClient,
+)
+from chattolib.exceptions import ChattoAuthError, ChattoConnectError
+
+CONNECT_PREFIX = "/api/connect"
+
+
+@dataclass
+class ServiceClients:
+    """Typed bundle of ConnectRPC service clients used by ``ChattoClient``."""
+
+    server_discovery: ServerDiscoveryServiceClient
+    server: ServerServiceClient
+    viewer: ViewerServiceClient
+    account: MyAccountServiceClient
+    users: UserServiceClient
+    roles: RoleServiceClient
+    room_directory: RoomDirectoryServiceClient
+    rooms: RoomServiceClient
+    messages: MessageServiceClient
+    threads: ThreadServiceClient
+    notifications: NotificationServiceClient
+    notification_prefs: NotificationPreferencesServiceClient
+    push: PushNotificationServiceClient
+    assets: AssetServiceClient
+    asset_uploads: AssetUploadServiceClient
+    voice_calls: VoiceCallServiceClient
+    external_auth: ExternalIdentityAuthServiceClient
+    admin_server: AdminServerServiceClient
+    admin_room_layout: AdminRoomLayoutServiceClient
+    admin_users: AdminUserServiceClient
+    admin_roles: AdminRoleServiceClient
+    admin_event_log: AdminEventLogServiceClient
+    admin_diagnostics: AdminDiagnosticsServiceClient
+    admin_permissions: AdminPermissionServiceClient
+
+    async def close(self) -> None:
+        for name in self.__dataclass_fields__:
+            client = getattr(self, name)
+            await client.close()
+
+
+def build_service_clients(base_url: str) -> ServiceClients:
+    """Instantiate one service client per Chatto Connect service.
+
+    ``base_url`` is the server root (e.g. ``https://chat.chatto.run``); the
+    ConnectRPC prefix is appended by this function.
+    """
+    address = f"{base_url.rstrip('/')}{CONNECT_PREFIX}"
+    codec = google_protobuf_binary_codec()
+
+    def make(cls: Any) -> Any:
+        return cls(address, codec=codec)
+
+    return ServiceClients(
+        server_discovery=make(ServerDiscoveryServiceClient),
+        server=make(ServerServiceClient),
+        viewer=make(ViewerServiceClient),
+        account=make(MyAccountServiceClient),
+        users=make(UserServiceClient),
+        roles=make(RoleServiceClient),
+        room_directory=make(RoomDirectoryServiceClient),
+        rooms=make(RoomServiceClient),
+        messages=make(MessageServiceClient),
+        threads=make(ThreadServiceClient),
+        notifications=make(NotificationServiceClient),
+        notification_prefs=make(NotificationPreferencesServiceClient),
+        push=make(PushNotificationServiceClient),
+        assets=make(AssetServiceClient),
+        asset_uploads=make(AssetUploadServiceClient),
+        voice_calls=make(VoiceCallServiceClient),
+        external_auth=make(ExternalIdentityAuthServiceClient),
+        admin_server=make(AdminServerServiceClient),
+        admin_room_layout=make(AdminRoomLayoutServiceClient),
+        admin_users=make(AdminUserServiceClient),
+        admin_roles=make(AdminRoleServiceClient),
+        admin_event_log=make(AdminEventLogServiceClient),
+        admin_diagnostics=make(AdminDiagnosticsServiceClient),
+        admin_permissions=make(AdminPermissionServiceClient),
+    )
+
+
+def translate_connect_error(exc: ConnectError) -> Exception:
+    """Convert a ``connectrpc`` error into chattolib's exception hierarchy."""
+    if exc.code == Code.UNAUTHENTICATED:
+        return ChattoAuthError(str(exc))
+    return ChattoConnectError(
+        code=exc.code.name.lower(),
+        message=str(exc),
+    )
+
+
+def pb_to_dict(message: Message | None) -> dict[str, Any]:
+    """Convert a protobuf message to the camelCase dict shape the parsers accept.
+
+    ``preserving_proto_field_name=False`` gives us JSON-mapping camelCase
+    keys (e.g. ``created_at`` → ``createdAt``), matching what the
+    ``types.py`` dataclass parsers already consume.
+    """
+    if message is None:
+        return {}
+    return MessageToDict(
+        message,
+        preserving_proto_field_name=False,
+        use_integers_for_enums=False,
+    )

+ 2306 - 0
vendor/chattolib/client.py

@@ -0,0 +1,2306 @@
+"""Main async client for the Chatto Connect API.
+
+Chatto migrated from GraphQL to a protobuf-first Connect API in v0.4.x
+(see ADR-042). The client speaks Connect binary protobuf via the official
+``connectrpc`` Python package and the generated service stubs under
+``chattolib._pb`` for all request/response operations. Realtime events
+live in ``chattolib.realtime``.
+"""
+
+# mypy: disable-error-code="no-any-return"
+# Rationale: attribute access on generated protobuf messages is Any-typed
+# from mypy's perspective (the generated modules skip type checking via
+# follow_imports=skip). The runtime types are exactly what the return-type
+# annotations claim.
+
+from __future__ import annotations
+
+import hashlib
+from collections.abc import Awaitable
+from datetime import datetime
+from pathlib import Path
+from typing import Any, TypeVar
+
+import httpx
+
+# ConnectError isn't re-exported publicly by connectrpc.__init__; import from
+# its submodule so the top-level import path stays clean for callers.
+from connectrpc.errors import ConnectError  # noqa: E402
+
+from chattolib._pb.chatto.admin.v1 import (
+    event_log_pb2,
+    room_layout_pb2,
+)
+from chattolib._pb.chatto.admin.v1 import (
+    members_pb2 as admin_members_pb2,
+)
+from chattolib._pb.chatto.admin.v1 import (
+    permissions_pb2 as admin_permissions_pb2,
+)
+from chattolib._pb.chatto.admin.v1 import (
+    roles_pb2 as admin_roles_pb2,
+)
+from chattolib._pb.chatto.admin.v1 import (
+    server_pb2 as admin_server_pb2,
+)
+from chattolib._pb.chatto.api.v1 import (
+    account_pb2,
+    asset_uploads_pb2,
+    attachments_pb2,
+    common_pb2,
+    external_identities_pb2,
+    link_previews_pb2,
+    member_directory_pb2,
+    messages_pb2,
+    notification_preferences_pb2,
+    notifications_pb2,
+    pagination_pb2,
+    presence_pb2,
+    push_notifications_pb2,
+    reactions_pb2,
+    read_state_pb2,
+    roles_pb2,
+    room_directory_pb2,
+    room_timeline_pb2,
+    rooms_pb2,
+    server_state_pb2,
+    threads_pb2,
+    user_status_pb2,
+    viewer_pb2,
+    voice_calls_pb2,
+)
+from chattolib._pb.chatto.auth.v1 import external_identity_auth_pb2
+from chattolib._pb.chatto.discovery.v1 import server_pb2 as discovery_server_pb2
+from chattolib._transport import (
+    ServiceClients,
+    build_service_clients,
+    pb_to_dict,
+    translate_connect_error,
+)
+from chattolib.exceptions import ChattoAuthError, ChattoError
+from chattolib.types import (
+    ActiveCall,
+    AdminMember,
+    AdminRole,
+    AdminRoomLayoutGroup,
+    AdminRoomLayoutItemKind,
+    Asset,
+    AssetUpload,
+    DirectoryMember,
+    ExternalIdentityProvider,
+    FollowedThread,
+    FollowedThreadsPage,
+    ImageTransformOptions,
+    LinkedExternalIdentity,
+    LinkPreview,
+    Message,
+    Notification,
+    NotificationLevel,
+    NotificationPreference,
+    NotificationsPage,
+    Page,
+    PresenceStatus,
+    Role,
+    Room,
+    RoomBan,
+    RoomDirectoryScope,
+    RoomGroup,
+    RoomWithViewerState,
+    ServerConfig,
+    ServerLogin,
+    ServerProfile,
+    ServerRuntimeConfig,
+    TimeFormat,
+    TimelinePage,
+    User,
+    UserSettings,
+    ViewerUser,
+    format_datetime,
+    parse_datetime,
+)
+
+RES = TypeVar("RES")
+
+
+def _page_pb(
+    limit: int | None, offset: int | None
+) -> pagination_pb2.PageRequest | None:
+    if limit is None and offset is None:
+        return None
+    return pagination_pb2.PageRequest(limit=limit or 0, offset=offset or 0)
+
+
+def _thumbnail_pb(
+    opts: ImageTransformOptions | None,
+) -> common_pb2.ImageTransformOptions | None:
+    if opts is None:
+        return None
+    return common_pb2.ImageTransformOptions(
+        width=opts.width, height=opts.height, fit=opts.fit.value
+    )
+
+
+def _timestamp_pb(value: datetime | None) -> Any:
+    from google.protobuf import timestamp_pb2
+
+    if value is None:
+        return None
+    ts = timestamp_pb2.Timestamp()
+    ts.FromJsonString(format_datetime(value))
+    return ts
+
+
+class ChattoClient:
+    """Async client for the Chatto Connect API.
+
+    Usage::
+
+        async with await ChattoClient.login("user", "pass") as client:
+            viewer = await client.get_viewer()
+            rooms = await client.list_rooms()
+
+        # Or with an existing token:
+        async with ChattoClient(token="cht_...") as client:
+            ...
+    """
+
+    DEFAULT_BASE_URL = "https://chat.chatto.run"
+
+    def __init__(
+        self,
+        token: str | None = None,
+        *,
+        base_url: str = DEFAULT_BASE_URL,
+        session_cookie: str | None = None,
+        service_clients: ServiceClients | None = None,
+    ) -> None:
+        self._base_url = base_url.rstrip("/")
+        self._token = token
+        self._session_cookie = session_cookie
+        self._svc = service_clients or build_service_clients(self._base_url)
+        self._owns_clients = service_clients is None
+
+    @classmethod
+    async def login(
+        cls,
+        login: str,
+        password: str,
+        *,
+        base_url: str = DEFAULT_BASE_URL,
+    ) -> ChattoClient:
+        """Authenticate with username and password, returning a connected client.
+
+        Uses Chatto's ``/auth/login`` HTTP endpoint (which is still exposed
+        alongside the Connect API) and captures both the returned bearer token
+        and any ``chatto_session`` cookie.
+        """
+        base = base_url.rstrip("/")
+        async with httpx.AsyncClient() as http:
+            resp = await http.post(
+                f"{base}/auth/login",
+                json={"login": login, "password": password},
+            )
+            if resp.status_code == 401:
+                raise ChattoAuthError("Invalid credentials")
+            resp.raise_for_status()
+            body = resp.json()
+
+        token = body.get("token")
+        session_cookie = None
+        if "set-cookie" in resp.headers:
+            for cookie_header in resp.headers.get_list("set-cookie"):
+                if cookie_header.startswith("chatto_session="):
+                    session_cookie = cookie_header.split(";")[0].split("=", 1)[1]
+                    break
+
+        return cls(token=token, base_url=base_url, session_cookie=session_cookie)
+
+    async def __aenter__(self) -> ChattoClient:
+        return self
+
+    async def __aexit__(self, *exc: Any) -> None:
+        await self.close()
+
+    async def close(self) -> None:
+        if self._owns_clients:
+            await self._svc.close()
+
+    # --- Transport ------------------------------------------------------
+
+    @property
+    def base_url(self) -> str:
+        return self._base_url
+
+    @property
+    def token(self) -> str | None:
+        return self._token
+
+    @property
+    def session_cookie(self) -> str | None:
+        return self._session_cookie
+
+    @property
+    def services(self) -> ServiceClients:
+        """Direct access to the underlying ConnectRPC service clients.
+
+        Useful when a caller wants to reach an RPC that this class doesn't
+        expose yet, or wants full protobuf messages instead of the
+        dataclass views returned by the high-level helpers.
+        """
+        return self._svc
+
+    def _headers(self) -> dict[str, str]:
+        headers: dict[str, str] = {}
+        if self._token:
+            headers["Authorization"] = f"Bearer {self._token}"
+        if self._session_cookie:
+            headers["Cookie"] = f"chatto_session={self._session_cookie}"
+        return headers
+
+    async def _rpc(self, coro: Awaitable[RES]) -> RES:
+        """Await a ConnectRPC coroutine, translating errors."""
+        try:
+            return await coro
+        except ConnectError as exc:
+            raise translate_connect_error(exc) from exc
+
+    # --- Server discovery ----------------------------------------------
+
+    async def get_server(self) -> tuple[ServerProfile, ServerLogin]:
+        """Public server profile and login options. Does not require auth."""
+        resp = await self._rpc(
+            self._svc.server_discovery.get_server(
+                discovery_server_pb2.GetServerRequest(),
+                headers=self._headers(),
+            )
+        )
+        return (
+            ServerProfile.parse(pb_to_dict(resp.profile)),
+            ServerLogin.parse(pb_to_dict(resp.login)),
+        )
+
+    async def get_motd(self) -> str | None:
+        resp = await self._rpc(
+            self._svc.server.get_motd(
+                server_state_pb2.GetMotdRequest(), headers=self._headers()
+            )
+        )
+        if not resp.HasField("motd"):
+            return None
+        return resp.motd
+
+    async def get_runtime_config(self) -> ServerRuntimeConfig:
+        resp = await self._rpc(
+            self._svc.server.get_runtime_config(
+                server_state_pb2.GetRuntimeConfigRequest(),
+                headers=self._headers(),
+            )
+        )
+        return ServerRuntimeConfig.parse(pb_to_dict(resp.runtime))
+
+    # --- Viewer ---------------------------------------------------------
+
+    async def get_viewer(self) -> dict[str, Any]:
+        """Full authenticated viewer snapshot (camelCase JSON dict).
+
+        The response contains ``user``, ``capabilities``, notification
+        preferences, permissions and viewer state. Callers that only need the
+        current user's public profile should use ``me()`` for a typed result.
+        """
+        resp = await self._rpc(
+            self._svc.viewer.get_viewer(
+                viewer_pb2.GetViewerRequest(), headers=self._headers()
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def viewer_user(self) -> ViewerUser | None:
+        data = await self.get_viewer()
+        return ViewerUser.parse(data.get("user"))
+
+    async def me(self) -> User:
+        """Return the authenticated user's public profile."""
+        viewer = await self.viewer_user()
+        if viewer is None or viewer.profile is None:
+            raise ChattoAuthError("No authenticated viewer")
+        return viewer.profile
+
+    # --- MyAccount -----------------------------------------------------
+
+    async def update_profile(
+        self,
+        *,
+        display_name: str | None = None,
+        login: str | None = None,
+    ) -> User:
+        req = account_pb2.UpdateProfileRequest()
+        if display_name is not None:
+            req.display_name = display_name
+        if login is not None:
+            req.login = login
+        resp = await self._rpc(
+            self._svc.account.update_profile(req, headers=self._headers())
+        )
+        user = User.parse(pb_to_dict(resp.user))
+        assert user is not None
+        return user
+
+    async def upload_avatar(
+        self,
+        file_path: str | Path,
+        *,
+        content_type: str = "image/png",
+    ) -> User:
+        p = Path(file_path)
+        req = account_pb2.UploadAvatarRequest(
+            image=common_pb2.ImageUpload(
+                image=p.read_bytes(),
+                filename=p.name,
+                content_type=content_type,
+            )
+        )
+        resp = await self._rpc(
+            self._svc.account.upload_avatar(req, headers=self._headers())
+        )
+        user = User.parse(pb_to_dict(resp.user))
+        assert user is not None
+        return user
+
+    async def delete_avatar(self) -> User:
+        resp = await self._rpc(
+            self._svc.account.delete_avatar(
+                account_pb2.DeleteAvatarRequest(), headers=self._headers()
+            )
+        )
+        user = User.parse(pb_to_dict(resp.user))
+        assert user is not None
+        return user
+
+    async def update_password(self, new_password: str, current_password: str = "") -> User:
+        resp = await self._rpc(
+            self._svc.account.update_password(
+                account_pb2.UpdatePasswordRequest(
+                    password=new_password, current_password=current_password
+                ),
+                headers=self._headers(),
+            )
+        )
+        user = User.parse(pb_to_dict(resp.user))
+        assert user is not None
+        return user
+
+    async def update_settings(
+        self,
+        *,
+        timezone: str | None = None,
+        time_format: TimeFormat | None = None,
+    ) -> UserSettings:
+        req = account_pb2.UpdateSettingsRequest()
+        if timezone is not None:
+            req.timezone = timezone
+        if time_format is not None:
+            req.time_format = time_format.value
+        resp = await self._rpc(
+            self._svc.account.update_settings(req, headers=self._headers())
+        )
+        return UserSettings.parse(pb_to_dict(resp.settings))
+
+    async def update_presence(
+        self,
+        status: PresenceStatus,
+        *,
+        user_selected: bool = True,
+    ) -> PresenceStatus:
+        if status in (PresenceStatus.UNSPECIFIED, PresenceStatus.OFFLINE):
+            raise ValueError(
+                "UNSPECIFIED and OFFLINE cannot be set as presence status; "
+                "stop refreshing to go offline"
+            )
+        req = presence_pb2.UpdatePresenceRequest(
+            status=status.value, user_selected=user_selected
+        )
+        resp = await self._rpc(
+            self._svc.account.update_presence(req, headers=self._headers())
+        )
+        name = presence_pb2.PresenceStatus.Name(resp.status)
+        return PresenceStatus(name)
+
+    async def update_custom_status(
+        self,
+        emoji: str,
+        text: str,
+        *,
+        expires_at: datetime | None = None,
+    ) -> dict[str, Any]:
+        req = user_status_pb2.UpdateCustomStatusRequest(emoji=emoji, text=text)
+        if expires_at is not None:
+            req.expires_at.CopyFrom(_timestamp_pb(expires_at))
+        resp = await self._rpc(
+            self._svc.account.update_custom_status(req, headers=self._headers())
+        )
+        return pb_to_dict(resp)
+
+    async def delete_custom_status(self) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.account.delete_custom_status(
+                user_status_pb2.DeleteCustomStatusRequest(), headers=self._headers()
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def request_account_deletion(self) -> str:
+        resp = await self._rpc(
+            self._svc.account.request_account_deletion(
+                account_pb2.RequestAccountDeletionRequest(),
+                headers=self._headers(),
+            )
+        )
+        return resp.confirmation_token
+
+    async def delete_my_account(self, confirmation_token: str) -> bool:
+        resp = await self._rpc(
+            self._svc.account.delete_my_account(
+                account_pb2.DeleteMyAccountRequest(
+                    confirmation_token=confirmation_token
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.deleted
+
+    # --- Users ----------------------------------------------------------
+
+    async def list_users(
+        self,
+        *,
+        search: str = "",
+        limit: int | None = None,
+        offset: int | None = None,
+    ) -> tuple[list[DirectoryMember], Page]:
+        req = member_directory_pb2.ListUsersRequest(search=search)
+        page = _page_pb(limit, offset)
+        if page is not None:
+            req.page.CopyFrom(page)
+        resp = await self._rpc(
+            self._svc.users.list_users(req, headers=self._headers())
+        )
+        data = pb_to_dict(resp)
+        users = [
+            u
+            for u in (DirectoryMember.parse(row) for row in data.get("users") or [])
+            if u is not None
+        ]
+        return users, Page.parse(data.get("page"))
+
+    async def get_user(
+        self, *, user_id: str | None = None, login: str | None = None
+    ) -> DirectoryMember | None:
+        if bool(user_id) == bool(login):
+            raise ValueError("get_user requires exactly one of user_id or login")
+        req = member_directory_pb2.GetUserRequest()
+        if user_id:
+            req.user_id = user_id
+        else:
+            assert login is not None
+            req.login = login
+        resp = await self._rpc(
+            self._svc.users.get_user(req, headers=self._headers())
+        )
+        return DirectoryMember.parse(pb_to_dict(resp.user))
+
+    async def batch_get_users(self, user_ids: list[str]) -> list[DirectoryMember]:
+        resp = await self._rpc(
+            self._svc.users.batch_get_users(
+                member_directory_pb2.BatchGetUsersRequest(user_ids=user_ids),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            u
+            for u in (DirectoryMember.parse(row) for row in data.get("users") or [])
+            if u is not None
+        ]
+
+    # --- Roles (public) -----------------------------------------------
+
+    async def list_roles(self) -> list[Role]:
+        resp = await self._rpc(
+            self._svc.roles.list_roles(
+                roles_pb2.ListRolesRequest(), headers=self._headers()
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            r for r in (Role.parse(row) for row in data.get("roles") or []) if r is not None
+        ]
+
+    async def get_role(self, name: str) -> Role | None:
+        resp = await self._rpc(
+            self._svc.roles.get_role(
+                roles_pb2.GetRoleRequest(name=name), headers=self._headers()
+            )
+        )
+        return Role.parse(pb_to_dict(resp.role))
+
+    async def batch_get_roles(self, names: list[str]) -> list[Role]:
+        resp = await self._rpc(
+            self._svc.roles.batch_get_roles(
+                roles_pb2.BatchGetRolesRequest(names=names), headers=self._headers()
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            r for r in (Role.parse(row) for row in data.get("roles") or []) if r is not None
+        ]
+
+    # --- Room directory ------------------------------------------------
+
+    async def list_rooms(
+        self, scope: RoomDirectoryScope = RoomDirectoryScope.ALL
+    ) -> list[RoomWithViewerState]:
+        resp = await self._rpc(
+            self._svc.room_directory.list_rooms(
+                room_directory_pb2.ListRoomsRequest(scope=scope.value),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            r
+            for r in (RoomWithViewerState.parse(row) for row in data.get("rooms") or [])
+            if r is not None
+        ]
+
+    async def list_room_groups(self) -> list[RoomGroup]:
+        resp = await self._rpc(
+            self._svc.room_directory.list_room_groups(
+                room_directory_pb2.ListRoomGroupsRequest(),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            g
+            for g in (RoomGroup.parse(row) for row in data.get("groups") or [])
+            if g is not None
+        ]
+
+    async def get_room_group(self, group_id: str) -> RoomGroup | None:
+        resp = await self._rpc(
+            self._svc.room_directory.get_room_group(
+                room_directory_pb2.GetRoomGroupRequest(group_id=group_id),
+                headers=self._headers(),
+            )
+        )
+        return RoomGroup.parse(pb_to_dict(resp.group))
+
+    async def batch_get_room_groups(self, group_ids: list[str]) -> list[RoomGroup]:
+        resp = await self._rpc(
+            self._svc.room_directory.batch_get_room_groups(
+                room_directory_pb2.BatchGetRoomGroupsRequest(group_ids=group_ids),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            g
+            for g in (RoomGroup.parse(row) for row in data.get("groups") or [])
+            if g is not None
+        ]
+
+    async def get_room(self, room_id: str) -> RoomWithViewerState | None:
+        resp = await self._rpc(
+            self._svc.room_directory.get_room(
+                room_directory_pb2.GetRoomRequest(room_id=room_id),
+                headers=self._headers(),
+            )
+        )
+        return RoomWithViewerState.parse(pb_to_dict(resp.room))
+
+    async def batch_get_rooms(self, room_ids: list[str]) -> list[RoomWithViewerState]:
+        resp = await self._rpc(
+            self._svc.room_directory.batch_get_rooms(
+                room_directory_pb2.BatchGetRoomsRequest(room_ids=room_ids),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            r
+            for r in (RoomWithViewerState.parse(row) for row in data.get("rooms") or [])
+            if r is not None
+        ]
+
+    # --- Room lifecycle & membership -----------------------------------
+
+    async def create_room(
+        self,
+        name: str,
+        group_id: str,
+        *,
+        description: str = "",
+        universal: bool = False,
+    ) -> Room:
+        resp = await self._rpc(
+            self._svc.rooms.create_room(
+                rooms_pb2.CreateRoomRequest(
+                    name=name,
+                    group_id=group_id,
+                    description=description,
+                    universal=universal,
+                ),
+                headers=self._headers(),
+            )
+        )
+        room = Room.parse(pb_to_dict(resp.room))
+        assert room is not None
+        return room
+
+    async def update_room(
+        self,
+        room_id: str,
+        *,
+        name: str | None = None,
+        description: str | None = None,
+        universal: bool | None = None,
+    ) -> Room:
+        req = rooms_pb2.UpdateRoomRequest(room_id=room_id)
+        if name is not None:
+            req.name = name
+        if description is not None:
+            req.description = description
+        if universal is not None:
+            req.universal = universal
+        resp = await self._rpc(
+            self._svc.rooms.update_room(req, headers=self._headers())
+        )
+        room = Room.parse(pb_to_dict(resp.room))
+        assert room is not None
+        return room
+
+    async def archive_room(self, room_id: str) -> Room:
+        resp = await self._rpc(
+            self._svc.rooms.archive_room(
+                rooms_pb2.ArchiveRoomRequest(room_id=room_id),
+                headers=self._headers(),
+            )
+        )
+        room = Room.parse(pb_to_dict(resp.room))
+        assert room is not None
+        return room
+
+    async def unarchive_room(self, room_id: str) -> Room:
+        resp = await self._rpc(
+            self._svc.rooms.unarchive_room(
+                rooms_pb2.UnarchiveRoomRequest(room_id=room_id),
+                headers=self._headers(),
+            )
+        )
+        room = Room.parse(pb_to_dict(resp.room))
+        assert room is not None
+        return room
+
+    async def join_room(self, room_id: str) -> Room:
+        resp = await self._rpc(
+            self._svc.rooms.join_room(
+                rooms_pb2.JoinRoomRequest(room_id=room_id),
+                headers=self._headers(),
+            )
+        )
+        room = Room.parse(pb_to_dict(resp.room))
+        assert room is not None
+        return room
+
+    async def join_room_group(self, group_id: str) -> list[str]:
+        resp = await self._rpc(
+            self._svc.rooms.join_room_group(
+                rooms_pb2.JoinRoomGroupRequest(group_id=group_id),
+                headers=self._headers(),
+            )
+        )
+        return list(resp.joined_room_ids)
+
+    async def start_dm(self, participant_ids: list[str]) -> Room:
+        resp = await self._rpc(
+            self._svc.rooms.start_dm(
+                rooms_pb2.StartDMRequest(participant_ids=participant_ids),
+                headers=self._headers(),
+            )
+        )
+        room = Room.parse(pb_to_dict(resp.room))
+        assert room is not None
+        return room
+
+    async def leave_room(self, room_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.rooms.leave_room(
+                rooms_pb2.LeaveRoomRequest(room_id=room_id),
+                headers=self._headers(),
+            )
+        )
+        return resp.left
+
+    async def add_member(self, room_id: str, user_id: str) -> DirectoryMember | None:
+        resp = await self._rpc(
+            self._svc.rooms.add_member(
+                rooms_pb2.AddMemberRequest(room_id=room_id, user_id=user_id),
+                headers=self._headers(),
+            )
+        )
+        return DirectoryMember.parse(pb_to_dict(resp.member))
+
+    async def remove_member(self, room_id: str, user_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.rooms.remove_member(
+                rooms_pb2.RemoveMemberRequest(room_id=room_id, user_id=user_id),
+                headers=self._headers(),
+            )
+        )
+        return resp.removed
+
+    async def list_room_members(
+        self,
+        room_id: str,
+        *,
+        search: str = "",
+        limit: int | None = None,
+        offset: int | None = None,
+    ) -> tuple[list[DirectoryMember], Page]:
+        req = member_directory_pb2.ListRoomMembersRequest(room_id=room_id, search=search)
+        page = _page_pb(limit, offset)
+        if page is not None:
+            req.page.CopyFrom(page)
+        resp = await self._rpc(
+            self._svc.rooms.list_members(req, headers=self._headers())
+        )
+        data = pb_to_dict(resp)
+        members = [
+            m
+            for m in (DirectoryMember.parse(row) for row in data.get("members") or [])
+            if m is not None
+        ]
+        return members, Page.parse(data.get("page"))
+
+    async def get_room_member(self, room_id: str, user_id: str) -> DirectoryMember | None:
+        resp = await self._rpc(
+            self._svc.rooms.get_member(
+                member_directory_pb2.GetRoomMemberRequest(
+                    room_id=room_id, user_id=user_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        return DirectoryMember.parse(pb_to_dict(resp.member))
+
+    async def batch_get_room_members(
+        self, room_id: str, user_ids: list[str]
+    ) -> list[DirectoryMember]:
+        resp = await self._rpc(
+            self._svc.rooms.batch_get_members(
+                member_directory_pb2.BatchGetRoomMembersRequest(
+                    room_id=room_id, user_ids=user_ids
+                ),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            m
+            for m in (DirectoryMember.parse(row) for row in data.get("members") or [])
+            if m is not None
+        ]
+
+    async def ban_member(
+        self,
+        room_id: str,
+        user_id: str,
+        reason: str,
+        *,
+        expires_at: datetime | None = None,
+    ) -> bool:
+        req = rooms_pb2.BanMemberRequest(
+            room_id=room_id, user_id=user_id, reason=reason
+        )
+        if expires_at is not None:
+            req.expires_at.CopyFrom(_timestamp_pb(expires_at))
+        resp = await self._rpc(
+            self._svc.rooms.ban_member(req, headers=self._headers())
+        )
+        return resp.banned
+
+    async def unban_member(self, room_id: str, user_id: str, reason: str) -> bool:
+        resp = await self._rpc(
+            self._svc.rooms.unban_member(
+                rooms_pb2.UnbanMemberRequest(
+                    room_id=room_id, user_id=user_id, reason=reason
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.unbanned
+
+    async def list_bans(
+        self,
+        *,
+        room_id: str = "",
+        limit: int | None = None,
+        offset: int | None = None,
+    ) -> tuple[list[RoomBan], Page]:
+        req = rooms_pb2.ListBansRequest(room_id=room_id)
+        page = _page_pb(limit, offset)
+        if page is not None:
+            req.page.CopyFrom(page)
+        resp = await self._rpc(
+            self._svc.rooms.list_bans(req, headers=self._headers())
+        )
+        data = pb_to_dict(resp)
+        bans = [
+            b
+            for b in (RoomBan.parse(row) for row in data.get("bans") or [])
+            if b is not None
+        ]
+        return bans, Page.parse(data.get("page"))
+
+    async def update_typing_indicator(
+        self, room_id: str, *, thread_root_event_id: str = ""
+    ) -> bool:
+        resp = await self._rpc(
+            self._svc.rooms.update_typing_indicator(
+                rooms_pb2.UpdateTypingIndicatorRequest(
+                    room_id=room_id, thread_root_event_id=thread_root_event_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.updated
+
+    # --- Room timeline / read state -----------------------------------
+
+    async def get_room_events(
+        self,
+        room_id: str,
+        *,
+        limit: int | None = None,
+        before: str | None = None,
+        after: str | None = None,
+    ) -> TimelinePage:
+        req = room_timeline_pb2.GetRoomEventsRequest(room_id=room_id)
+        if limit is not None:
+            req.limit = limit
+        if before is not None:
+            req.before = before
+        elif after is not None:
+            req.after = after
+        resp = await self._rpc(
+            self._svc.rooms.get_room_events(req, headers=self._headers())
+        )
+        return TimelinePage.parse(pb_to_dict(resp.page))
+
+    async def get_room_events_around(
+        self,
+        room_id: str,
+        event_id: str,
+        *,
+        limit: int | None = None,
+    ) -> tuple[TimelinePage, int]:
+        req = room_timeline_pb2.GetRoomEventsAroundRequest(
+            room_id=room_id, event_id=event_id
+        )
+        if limit is not None:
+            req.limit = limit
+        resp = await self._rpc(
+            self._svc.rooms.get_room_events_around(req, headers=self._headers())
+        )
+        return TimelinePage.parse(pb_to_dict(resp.page)), resp.target_index
+
+    async def mark_room_as_read(
+        self, room_id: str, up_to_event_id: str = ""
+    ) -> tuple[datetime | None, datetime | None]:
+        resp = await self._rpc(
+            self._svc.rooms.mark_room_as_read(
+                read_state_pb2.MarkRoomAsReadRequest(
+                    room_id=room_id, up_to_event_id=up_to_event_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        d = pb_to_dict(resp)
+        return (
+            parse_datetime(d.get("lastReadAt")),
+            parse_datetime(d.get("previousLastReadAt")),
+        )
+
+    async def list_room_attachments(
+        self,
+        room_id: str,
+        *,
+        thumbnail: ImageTransformOptions | None = None,
+        limit: int | None = None,
+        offset: int | None = None,
+    ) -> tuple[list[dict[str, Any]], Page]:
+        req = rooms_pb2.ListRoomAttachmentsRequest(room_id=room_id)
+        thumb = _thumbnail_pb(thumbnail)
+        if thumb is not None:
+            req.thumbnail.CopyFrom(thumb)
+        page = _page_pb(limit, offset)
+        if page is not None:
+            req.page.CopyFrom(page)
+        resp = await self._rpc(
+            self._svc.rooms.list_room_attachments(req, headers=self._headers())
+        )
+        data = pb_to_dict(resp)
+        return list(data.get("attachments") or []), Page.parse(data.get("page"))
+
+    # --- Messages -------------------------------------------------------
+
+    async def fetch_link_preview(self, url: str) -> tuple[LinkPreview | None, str]:
+        resp = await self._rpc(
+            self._svc.messages.fetch_link_preview(
+                link_previews_pb2.FetchLinkPreviewRequest(url=url),
+                headers=self._headers(),
+            )
+        )
+        return LinkPreview.parse(pb_to_dict(resp.preview)), resp.preview_token
+
+    async def post_message(
+        self,
+        room_id: str,
+        body: str = "",
+        *,
+        attachment_asset_ids: list[str] | None = None,
+        thread_root_event_id: str = "",
+        in_reply_to: str = "",
+        also_send_to_channel: bool = False,
+        link_preview_token: str = "",
+    ) -> Message:
+        req = messages_pb2.CreateMessageRequest(
+            room_id=room_id,
+            body=body,
+            thread_root_event_id=thread_root_event_id,
+            in_reply_to=in_reply_to,
+            also_send_to_channel=also_send_to_channel,
+            link_preview_token=link_preview_token,
+        )
+        if attachment_asset_ids:
+            req.attachment_asset_ids.extend(attachment_asset_ids)
+        resp = await self._rpc(
+            self._svc.messages.create_message(req, headers=self._headers())
+        )
+        message = Message.parse(pb_to_dict(resp.message))
+        assert message is not None
+        return message
+
+    async def update_message(
+        self,
+        room_id: str,
+        event_id: str,
+        *,
+        body: str | None = None,
+        also_send_to_channel: bool | None = None,
+    ) -> Message:
+        req = messages_pb2.UpdateMessageRequest(room_id=room_id, event_id=event_id)
+        if body is not None:
+            req.body = body
+        if also_send_to_channel is not None:
+            req.also_send_to_channel = also_send_to_channel
+        resp = await self._rpc(
+            self._svc.messages.update_message(req, headers=self._headers())
+        )
+        message = Message.parse(pb_to_dict(resp.message))
+        assert message is not None
+        return message
+
+    async def delete_message(self, room_id: str, event_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.messages.delete_message(
+                messages_pb2.DeleteMessageRequest(room_id=room_id, event_id=event_id),
+                headers=self._headers(),
+            )
+        )
+        return resp.deleted
+
+    async def delete_attachment(
+        self, room_id: str, event_id: str, attachment_id: str
+    ) -> bool:
+        resp = await self._rpc(
+            self._svc.messages.delete_attachment(
+                messages_pb2.DeleteAttachmentRequest(
+                    room_id=room_id, event_id=event_id, attachment_id=attachment_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.deleted
+
+    async def delete_link_preview(self, room_id: str, event_id: str, url: str) -> bool:
+        resp = await self._rpc(
+            self._svc.messages.delete_link_preview(
+                messages_pb2.DeleteLinkPreviewRequest(
+                    room_id=room_id, event_id=event_id, url=url
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.deleted
+
+    async def get_message(self, room_id: str, event_id: str) -> Message | None:
+        resp = await self._rpc(
+            self._svc.messages.get_message(
+                messages_pb2.GetMessageRequest(room_id=room_id, event_id=event_id),
+                headers=self._headers(),
+            )
+        )
+        return Message.parse(pb_to_dict(resp.message))
+
+    async def batch_get_messages(
+        self, room_id: str, event_ids: list[str]
+    ) -> list[Message]:
+        resp = await self._rpc(
+            self._svc.messages.batch_get_messages(
+                messages_pb2.BatchGetMessagesRequest(
+                    room_id=room_id, event_ids=event_ids
+                ),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            m
+            for m in (Message.parse(row) for row in data.get("messages") or [])
+            if m is not None
+        ]
+
+    async def add_reaction(
+        self, room_id: str, message_event_id: str, emoji: str
+    ) -> bool:
+        resp = await self._rpc(
+            self._svc.messages.add_reaction(
+                reactions_pb2.AddReactionRequest(
+                    room_id=room_id, message_event_id=message_event_id, emoji=emoji
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.added
+
+    async def remove_reaction(
+        self, room_id: str, message_event_id: str, emoji: str
+    ) -> bool:
+        resp = await self._rpc(
+            self._svc.messages.remove_reaction(
+                reactions_pb2.RemoveReactionRequest(
+                    room_id=room_id, message_event_id=message_event_id, emoji=emoji
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.removed
+
+    # --- Threads --------------------------------------------------------
+
+    async def follow_thread(self, room_id: str, thread_root_event_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.threads.follow_thread(
+                threads_pb2.FollowThreadRequest(
+                    room_id=room_id, thread_root_event_id=thread_root_event_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.following
+
+    async def unfollow_thread(self, room_id: str, thread_root_event_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.threads.unfollow_thread(
+                threads_pb2.UnfollowThreadRequest(
+                    room_id=room_id, thread_root_event_id=thread_root_event_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.following
+
+    async def list_followed_threads(
+        self, *, limit: int | None = None, offset: int | None = None
+    ) -> FollowedThreadsPage:
+        req = threads_pb2.ListFollowedThreadsRequest()
+        page = _page_pb(limit, offset)
+        if page is not None:
+            req.page.CopyFrom(page)
+        resp = await self._rpc(
+            self._svc.threads.list_followed_threads(req, headers=self._headers())
+        )
+        data = pb_to_dict(resp)
+        threads = [FollowedThread.parse(t) for t in data.get("threads") or []]
+        users: dict[str, User] = {}
+        includes = data.get("includes") or {}
+        for uid, user_data in (includes.get("users") or {}).items():
+            parsed = User.parse(user_data)
+            if parsed is not None:
+                users[uid] = parsed
+        return FollowedThreadsPage(
+            threads=threads, page=Page.parse(data.get("page")), users_by_id=users
+        )
+
+    async def get_thread_events(
+        self,
+        room_id: str,
+        thread_root_event_id: str,
+        *,
+        limit: int | None = None,
+        before: str | None = None,
+        after: str | None = None,
+    ) -> TimelinePage:
+        req = room_timeline_pb2.GetThreadEventsRequest(
+            room_id=room_id, thread_root_event_id=thread_root_event_id
+        )
+        if limit is not None:
+            req.limit = limit
+        if before is not None:
+            req.before = before
+        elif after is not None:
+            req.after = after
+        resp = await self._rpc(
+            self._svc.threads.get_thread_events(req, headers=self._headers())
+        )
+        return TimelinePage.parse(pb_to_dict(resp.page))
+
+    async def get_thread_events_around(
+        self,
+        room_id: str,
+        thread_root_event_id: str,
+        event_id: str,
+        *,
+        limit: int | None = None,
+    ) -> tuple[TimelinePage, int]:
+        req = room_timeline_pb2.GetThreadEventsAroundRequest(
+            room_id=room_id,
+            thread_root_event_id=thread_root_event_id,
+            event_id=event_id,
+        )
+        if limit is not None:
+            req.limit = limit
+        resp = await self._rpc(
+            self._svc.threads.get_thread_events_around(req, headers=self._headers())
+        )
+        return TimelinePage.parse(pb_to_dict(resp.page)), resp.target_index
+
+    async def mark_thread_as_read(
+        self,
+        room_id: str,
+        thread_root_event_id: str,
+        up_to_event_id: str = "",
+    ) -> datetime | None:
+        resp = await self._rpc(
+            self._svc.threads.mark_thread_as_read(
+                read_state_pb2.MarkThreadAsReadRequest(
+                    room_id=room_id,
+                    thread_root_event_id=thread_root_event_id,
+                    up_to_event_id=up_to_event_id,
+                ),
+                headers=self._headers(),
+            )
+        )
+        d = pb_to_dict(resp)
+        return parse_datetime(d.get("previousReadAt"))
+
+    # --- Notifications --------------------------------------------------
+
+    async def list_notifications(
+        self, *, limit: int | None = None, offset: int | None = None
+    ) -> NotificationsPage:
+        req = notifications_pb2.ListNotificationsRequest()
+        page = _page_pb(limit, offset)
+        if page is not None:
+            req.page.CopyFrom(page)
+        resp = await self._rpc(
+            self._svc.notifications.list_notifications(req, headers=self._headers())
+        )
+        data = pb_to_dict(resp)
+        notifications = [Notification.parse(n) for n in data.get("notifications") or []]
+        return NotificationsPage(
+            notifications=notifications, page=Page.parse(data.get("page"))
+        )
+
+    async def has_notifications(self) -> bool:
+        resp = await self._rpc(
+            self._svc.notifications.has_notifications(
+                notifications_pb2.HasNotificationsRequest(),
+                headers=self._headers(),
+            )
+        )
+        return resp.has_notifications
+
+    async def get_notification(self, notification_id: str) -> Notification | None:
+        resp = await self._rpc(
+            self._svc.notifications.get_notification(
+                notifications_pb2.GetNotificationRequest(notification_id=notification_id),
+                headers=self._headers(),
+            )
+        )
+        raw = pb_to_dict(resp).get("notification")
+        return Notification.parse(raw) if raw else None
+
+    async def batch_get_notifications(
+        self, notification_ids: list[str]
+    ) -> list[Notification]:
+        resp = await self._rpc(
+            self._svc.notifications.batch_get_notifications(
+                notifications_pb2.BatchGetNotificationsRequest(
+                    notification_ids=notification_ids
+                ),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [Notification.parse(n) for n in data.get("notifications") or []]
+
+    async def list_room_notifications(
+        self,
+        room_id: str,
+        *,
+        limit: int | None = None,
+        offset: int | None = None,
+    ) -> NotificationsPage:
+        req = notifications_pb2.ListRoomNotificationsRequest(room_id=room_id)
+        page = _page_pb(limit, offset)
+        if page is not None:
+            req.page.CopyFrom(page)
+        resp = await self._rpc(
+            self._svc.notifications.list_room_notifications(
+                req, headers=self._headers()
+            )
+        )
+        data = pb_to_dict(resp)
+        return NotificationsPage(
+            notifications=[Notification.parse(n) for n in data.get("notifications") or []],
+            page=Page.parse(data.get("page")),
+        )
+
+    async def list_room_notification_counts(self) -> dict[str, int]:
+        resp = await self._rpc(
+            self._svc.notifications.list_room_notification_counts(
+                notifications_pb2.ListRoomNotificationCountsRequest(),
+                headers=self._headers(),
+            )
+        )
+        return {row.room_id: row.total_count for row in resp.room_counts}
+
+    async def dismiss_notification(self, notification_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.notifications.dismiss_notification(
+                notifications_pb2.DismissNotificationRequest(
+                    notification_id=notification_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.dismissed
+
+    async def dismiss_all_notifications(self) -> int:
+        resp = await self._rpc(
+            self._svc.notifications.dismiss_all_notifications(
+                notifications_pb2.DismissAllNotificationsRequest(),
+                headers=self._headers(),
+            )
+        )
+        return resp.dismissed_count
+
+    # --- Notification preferences --------------------------------------
+
+    async def get_server_notification_preference(self) -> NotificationPreference:
+        resp = await self._rpc(
+            self._svc.notification_prefs.get_server_notification_preference(
+                notification_preferences_pb2.GetServerNotificationPreferenceRequest(),
+                headers=self._headers(),
+            )
+        )
+        return NotificationPreference.parse(pb_to_dict(resp.preference))
+
+    async def update_server_notification_preference(
+        self, level: NotificationLevel
+    ) -> NotificationPreference:
+        resp = await self._rpc(
+            self._svc.notification_prefs.update_server_notification_preference(
+                notification_preferences_pb2.UpdateServerNotificationPreferenceRequest(
+                    level=level.value
+                ),
+                headers=self._headers(),
+            )
+        )
+        return NotificationPreference.parse(pb_to_dict(resp.preference))
+
+    async def get_room_notification_preference(
+        self, room_id: str
+    ) -> NotificationPreference:
+        resp = await self._rpc(
+            self._svc.notification_prefs.get_room_notification_preference(
+                notification_preferences_pb2.GetRoomNotificationPreferenceRequest(
+                    room_id=room_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        return NotificationPreference.parse(pb_to_dict(resp.preference))
+
+    async def update_room_notification_preference(
+        self, room_id: str, level: NotificationLevel
+    ) -> NotificationPreference:
+        resp = await self._rpc(
+            self._svc.notification_prefs.update_room_notification_preference(
+                notification_preferences_pb2.UpdateRoomNotificationPreferenceRequest(
+                    room_id=room_id, level=level.value
+                ),
+                headers=self._headers(),
+            )
+        )
+        return NotificationPreference.parse(pb_to_dict(resp.preference))
+
+    # --- Push notifications --------------------------------------------
+
+    async def subscribe_push(
+        self,
+        endpoint: str,
+        p256dh: str,
+        auth: str,
+        *,
+        user_agent: str | None = None,
+    ) -> bool:
+        req = push_notifications_pb2.SubscribePushRequest(
+            endpoint=endpoint, p256dh=p256dh, auth=auth
+        )
+        if user_agent is not None:
+            req.user_agent = user_agent
+        resp = await self._rpc(
+            self._svc.push.subscribe(req, headers=self._headers())
+        )
+        return resp.subscribed
+
+    async def unsubscribe_push(self, endpoint: str) -> bool:
+        resp = await self._rpc(
+            self._svc.push.unsubscribe(
+                push_notifications_pb2.UnsubscribePushRequest(endpoint=endpoint),
+                headers=self._headers(),
+            )
+        )
+        return resp.unsubscribed
+
+    # --- Assets ---------------------------------------------------------
+
+    async def get_asset(
+        self,
+        room_id: str,
+        asset_id: str,
+        *,
+        thumbnail: ImageTransformOptions | None = None,
+    ) -> Asset | None:
+        req = attachments_pb2.GetAssetRequest(room_id=room_id, asset_id=asset_id)
+        thumb = _thumbnail_pb(thumbnail)
+        if thumb is not None:
+            req.thumbnail.CopyFrom(thumb)
+        resp = await self._rpc(
+            self._svc.assets.get_asset(req, headers=self._headers())
+        )
+        return Asset.parse(pb_to_dict(resp.asset))
+
+    async def batch_get_assets(
+        self,
+        room_id: str,
+        asset_ids: list[str],
+        *,
+        thumbnail: ImageTransformOptions | None = None,
+    ) -> list[Asset]:
+        req = attachments_pb2.BatchGetAssetsRequest(
+            room_id=room_id, asset_ids=asset_ids
+        )
+        thumb = _thumbnail_pb(thumbnail)
+        if thumb is not None:
+            req.thumbnail.CopyFrom(thumb)
+        resp = await self._rpc(
+            self._svc.assets.batch_get_assets(req, headers=self._headers())
+        )
+        data = pb_to_dict(resp)
+        return [
+            a
+            for a in (Asset.parse(row) for row in data.get("assets") or [])
+            if a is not None
+        ]
+
+    # --- Asset uploads ------------------------------------------------
+
+    async def create_upload(
+        self,
+        room_id: str,
+        filename: str,
+        size: int,
+        sha256: str,
+        *,
+        content_type: str = "",
+    ) -> AssetUpload:
+        resp = await self._rpc(
+            self._svc.asset_uploads.create_upload(
+                asset_uploads_pb2.CreateUploadRequest(
+                    room_id=room_id,
+                    filename=filename,
+                    content_type=content_type,
+                    size=size,
+                    sha256=sha256,
+                ),
+                headers=self._headers(),
+            )
+        )
+        upload = AssetUpload.parse(pb_to_dict(resp.upload))
+        assert upload is not None
+        return upload
+
+    async def upload_chunk(
+        self, upload_id: str, offset: int, content: bytes, chunk_sha256: str
+    ) -> AssetUpload:
+        resp = await self._rpc(
+            self._svc.asset_uploads.upload_chunk(
+                asset_uploads_pb2.UploadChunkRequest(
+                    upload_id=upload_id,
+                    offset=offset,
+                    content=content,
+                    chunk_sha256=chunk_sha256,
+                ),
+                headers=self._headers(),
+            )
+        )
+        upload = AssetUpload.parse(pb_to_dict(resp.upload))
+        assert upload is not None
+        return upload
+
+    async def get_upload(self, upload_id: str) -> AssetUpload:
+        resp = await self._rpc(
+            self._svc.asset_uploads.get_upload(
+                asset_uploads_pb2.GetUploadRequest(upload_id=upload_id),
+                headers=self._headers(),
+            )
+        )
+        upload = AssetUpload.parse(pb_to_dict(resp.upload))
+        assert upload is not None
+        return upload
+
+    async def complete_upload(
+        self, upload_id: str
+    ) -> tuple[AssetUpload, Asset | None]:
+        resp = await self._rpc(
+            self._svc.asset_uploads.complete_upload(
+                asset_uploads_pb2.CompleteUploadRequest(upload_id=upload_id),
+                headers=self._headers(),
+            )
+        )
+        upload = AssetUpload.parse(pb_to_dict(resp.upload))
+        assert upload is not None
+        return upload, Asset.parse(pb_to_dict(resp.asset))
+
+    async def cancel_upload(self, upload_id: str) -> AssetUpload:
+        resp = await self._rpc(
+            self._svc.asset_uploads.cancel_upload(
+                asset_uploads_pb2.CancelUploadRequest(upload_id=upload_id),
+                headers=self._headers(),
+            )
+        )
+        upload = AssetUpload.parse(pb_to_dict(resp.upload))
+        assert upload is not None
+        return upload
+
+    async def upload_attachment(
+        self,
+        room_id: str,
+        file_path: str | Path,
+        *,
+        content_type: str = "",
+        filename: str | None = None,
+    ) -> Asset:
+        """Upload a file as a room attachment and return the resulting Asset."""
+        path = Path(file_path)
+        data = path.read_bytes()
+        size = len(data)
+        sha = hashlib.sha256(data).hexdigest()
+        upload = await self.create_upload(
+            room_id, filename or path.name, size, sha, content_type=content_type
+        )
+        chunk_size = upload.max_chunk_size or 512 * 1024
+        offset = upload.committed_offset
+        while offset < size:
+            end = min(offset + chunk_size, size)
+            chunk = data[offset:end]
+            chunk_sha = hashlib.sha256(chunk).hexdigest()
+            upload = await self.upload_chunk(upload.upload_id, offset, chunk, chunk_sha)
+            if upload.committed_offset <= offset:
+                raise ChattoError(
+                    f"upload stalled at offset {offset} (server reported "
+                    f"committed_offset={upload.committed_offset})"
+                )
+            offset = upload.committed_offset
+        upload, asset = await self.complete_upload(upload.upload_id)
+        if asset is None:
+            raise ChattoError("upload completed but server returned no asset")
+        return asset
+
+    # --- MyAccount external identities --------------------------------
+
+    async def list_external_identities(
+        self,
+    ) -> tuple[list[ExternalIdentityProvider], list[LinkedExternalIdentity]]:
+        resp = await self._rpc(
+            self._svc.account.list_external_identities(
+                external_identities_pb2.ListExternalIdentitiesRequest(),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        providers = [
+            ExternalIdentityProvider.parse(p) for p in data.get("providers") or []
+        ]
+        linked = [
+            LinkedExternalIdentity.parse(li)
+            for li in data.get("linkedIdentities") or []
+        ]
+        return providers, linked
+
+    async def start_external_identity_link(
+        self,
+        provider_id: str,
+        *,
+        redirect_path: str = "",
+        current_password: str = "",
+    ) -> str:
+        resp = await self._rpc(
+            self._svc.account.start_external_identity_link(
+                external_identities_pb2.StartExternalIdentityLinkRequest(
+                    provider_id=provider_id,
+                    redirect_path=redirect_path,
+                    current_password=current_password,
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.start_url
+
+    async def disconnect_external_identity(
+        self, subject_hash: str, *, current_password: str = ""
+    ) -> bool:
+        resp = await self._rpc(
+            self._svc.account.disconnect_external_identity(
+                external_identities_pb2.DisconnectExternalIdentityRequest(
+                    subject_hash=subject_hash, current_password=current_password
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.disconnected
+
+    # --- ExternalIdentityAuthService (public OAuth handoff) -----------
+
+    async def get_pending_external_identity(self, token: str) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.external_auth.get_pending_external_identity(
+                external_identity_auth_pb2.GetPendingExternalIdentityRequest(
+                    token=token
+                ),
+                headers=self._headers(),
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def create_external_identity_account(
+        self, token: str, login: str
+    ) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.external_auth.create_external_identity_account(
+                external_identity_auth_pb2.CreateExternalIdentityAccountRequest(
+                    token=token, login=login
+                ),
+                headers=self._headers(),
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def confirm_external_identity_link(
+        self, token: str
+    ) -> LinkedExternalIdentity | None:
+        resp = await self._rpc(
+            self._svc.external_auth.confirm_external_identity_link(
+                external_identity_auth_pb2.ConfirmExternalIdentityLinkRequest(
+                    token=token
+                ),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp).get("linkedIdentity")
+        return LinkedExternalIdentity.parse(data) if data else None
+
+    async def cancel_external_identity_flow(self, token: str) -> bool:
+        resp = await self._rpc(
+            self._svc.external_auth.cancel_external_identity_flow(
+                external_identity_auth_pb2.CancelExternalIdentityFlowRequest(
+                    token=token
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.cancelled
+
+    # --- Voice calls ----------------------------------------------------
+
+    async def list_active_calls(self) -> list[ActiveCall]:
+        resp = await self._rpc(
+            self._svc.voice_calls.list_active_calls(
+                voice_calls_pb2.ListActiveCallsRequest(), headers=self._headers()
+            )
+        )
+        data = pb_to_dict(resp)
+        return [ActiveCall.parse(c) for c in data.get("calls") or []]
+
+    async def get_active_call(self, room_id: str) -> ActiveCall | None:
+        resp = await self._rpc(
+            self._svc.voice_calls.get_active_call(
+                voice_calls_pb2.GetActiveCallRequest(room_id=room_id),
+                headers=self._headers(),
+            )
+        )
+        raw = pb_to_dict(resp).get("call")
+        return ActiveCall.parse(raw) if raw else None
+
+    async def batch_get_active_calls(self, room_ids: list[str]) -> list[ActiveCall]:
+        resp = await self._rpc(
+            self._svc.voice_calls.batch_get_active_calls(
+                voice_calls_pb2.BatchGetActiveCallsRequest(room_ids=room_ids),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [ActiveCall.parse(c) for c in data.get("calls") or []]
+
+    async def join_call(self, room_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.voice_calls.join_call(
+                voice_calls_pb2.JoinCallRequest(room_id=room_id),
+                headers=self._headers(),
+            )
+        )
+        return resp.joined
+
+    async def leave_call(self, room_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.voice_calls.leave_call(
+                voice_calls_pb2.LeaveCallRequest(room_id=room_id),
+                headers=self._headers(),
+            )
+        )
+        return resp.left
+
+    async def get_call_token(self, room_id: str) -> str:
+        resp = await self._rpc(
+            self._svc.voice_calls.get_call_token(
+                voice_calls_pb2.GetCallTokenRequest(room_id=room_id),
+                headers=self._headers(),
+            )
+        )
+        return resp.token
+
+    # --- Admin: server --------------------------------------------------
+
+    async def admin_get_server_config(self) -> tuple[ServerConfig, ServerProfile]:
+        resp = await self._rpc(
+            self._svc.admin_server.get_server_config(
+                admin_server_pb2.GetServerConfigRequest(),
+                headers=self._headers(),
+            )
+        )
+        return (
+            ServerConfig.parse(pb_to_dict(resp.config)),
+            ServerProfile.parse(pb_to_dict(resp.public_profile)),
+        )
+
+    async def admin_update_server_config(
+        self,
+        *,
+        server_name: str | None = None,
+        description: str | None = None,
+        motd: str | None = None,
+        welcome_message: str | None = None,
+    ) -> tuple[ServerConfig, ServerProfile]:
+        req = admin_server_pb2.UpdateServerConfigRequest()
+        if server_name is not None:
+            req.server_name = server_name
+        if description is not None:
+            req.description = description
+        if motd is not None:
+            req.motd = motd
+        if welcome_message is not None:
+            req.welcome_message = welcome_message
+        resp = await self._rpc(
+            self._svc.admin_server.update_server_config(req, headers=self._headers())
+        )
+        return (
+            ServerConfig.parse(pb_to_dict(resp.config)),
+            ServerProfile.parse(pb_to_dict(resp.public_profile)),
+        )
+
+    async def admin_upload_server_logo(
+        self,
+        file_path: str | Path,
+        *,
+        content_type: str = "image/png",
+    ) -> ServerProfile:
+        p = Path(file_path)
+        req = admin_server_pb2.UploadServerLogoRequest(
+            image=common_pb2.ImageUpload(
+                image=p.read_bytes(), filename=p.name, content_type=content_type
+            )
+        )
+        resp = await self._rpc(
+            self._svc.admin_server.upload_server_logo(req, headers=self._headers())
+        )
+        return ServerProfile.parse(pb_to_dict(resp.public_profile))
+
+    async def admin_delete_server_logo(self) -> ServerProfile:
+        resp = await self._rpc(
+            self._svc.admin_server.delete_server_logo(
+                admin_server_pb2.DeleteServerLogoRequest(),
+                headers=self._headers(),
+            )
+        )
+        return ServerProfile.parse(pb_to_dict(resp.public_profile))
+
+    async def admin_upload_server_banner(
+        self,
+        file_path: str | Path,
+        *,
+        content_type: str = "image/png",
+    ) -> ServerProfile:
+        p = Path(file_path)
+        req = admin_server_pb2.UploadServerBannerRequest(
+            image=common_pb2.ImageUpload(
+                image=p.read_bytes(), filename=p.name, content_type=content_type
+            )
+        )
+        resp = await self._rpc(
+            self._svc.admin_server.upload_server_banner(req, headers=self._headers())
+        )
+        return ServerProfile.parse(pb_to_dict(resp.public_profile))
+
+    async def admin_delete_server_banner(self) -> ServerProfile:
+        resp = await self._rpc(
+            self._svc.admin_server.delete_server_banner(
+                admin_server_pb2.DeleteServerBannerRequest(),
+                headers=self._headers(),
+            )
+        )
+        return ServerProfile.parse(pb_to_dict(resp.public_profile))
+
+    async def admin_get_server_security_config(self) -> list[str]:
+        resp = await self._rpc(
+            self._svc.admin_server.get_server_security_config(
+                admin_server_pb2.GetServerSecurityConfigRequest(),
+                headers=self._headers(),
+            )
+        )
+        return list(resp.blocked_usernames)
+
+    async def admin_update_blocked_usernames(self, usernames: list[str]) -> list[str]:
+        resp = await self._rpc(
+            self._svc.admin_server.update_blocked_usernames(
+                admin_server_pb2.UpdateBlockedUsernamesRequest(
+                    blocked_usernames=usernames
+                ),
+                headers=self._headers(),
+            )
+        )
+        return list(resp.blocked_usernames)
+
+    # --- Admin: room layout & sidebar links ---------------------------
+
+    async def admin_list_room_groups(self) -> list[AdminRoomLayoutGroup]:
+        resp = await self._rpc(
+            self._svc.admin_room_layout.list_room_groups(
+                room_layout_pb2.ListRoomGroupsRequest(),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            g
+            for g in (
+                AdminRoomLayoutGroup.parse(row) for row in data.get("groups") or []
+            )
+            if g is not None
+        ]
+
+    async def admin_create_room_group(
+        self, name: str, description: str = ""
+    ) -> AdminRoomLayoutGroup:
+        resp = await self._rpc(
+            self._svc.admin_room_layout.create_room_group(
+                room_layout_pb2.CreateRoomGroupRequest(
+                    name=name, description=description
+                ),
+                headers=self._headers(),
+            )
+        )
+        group = AdminRoomLayoutGroup.parse(pb_to_dict(resp.group))
+        assert group is not None
+        return group
+
+    async def admin_update_room_group(
+        self,
+        group_id: str,
+        *,
+        name: str | None = None,
+        description: str | None = None,
+    ) -> AdminRoomLayoutGroup:
+        req = room_layout_pb2.UpdateRoomGroupRequest(group_id=group_id)
+        if name is not None:
+            req.name = name
+        if description is not None:
+            req.description = description
+        resp = await self._rpc(
+            self._svc.admin_room_layout.update_room_group(
+                req, headers=self._headers()
+            )
+        )
+        group = AdminRoomLayoutGroup.parse(pb_to_dict(resp.group))
+        assert group is not None
+        return group
+
+    async def admin_delete_room_group(self, group_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.admin_room_layout.delete_room_group(
+                room_layout_pb2.DeleteRoomGroupRequest(group_id=group_id),
+                headers=self._headers(),
+            )
+        )
+        return resp.deleted
+
+    async def admin_reorder_room_groups(
+        self, ordered_group_ids: list[str]
+    ) -> list[AdminRoomLayoutGroup]:
+        resp = await self._rpc(
+            self._svc.admin_room_layout.reorder_room_groups(
+                room_layout_pb2.ReorderRoomGroupsRequest(
+                    ordered_group_ids=ordered_group_ids
+                ),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            g
+            for g in (
+                AdminRoomLayoutGroup.parse(row) for row in data.get("groups") or []
+            )
+            if g is not None
+        ]
+
+    async def admin_move_room_to_group(self, room_id: str, group_id: str) -> Room:
+        resp = await self._rpc(
+            self._svc.admin_room_layout.move_room_to_group(
+                room_layout_pb2.MoveRoomToGroupRequest(
+                    room_id=room_id, group_id=group_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        room = Room.parse(pb_to_dict(resp.room))
+        assert room is not None
+        return room
+
+    async def admin_reorder_sidebar_items_in_group(
+        self,
+        group_id: str,
+        items: list[tuple[AdminRoomLayoutItemKind, str]],
+    ) -> AdminRoomLayoutGroup:
+        req = room_layout_pb2.ReorderSidebarItemsInGroupRequest(group_id=group_id)
+        for kind, item_id in items:
+            item = req.items.add()
+            item.kind = kind.value
+            item.id = item_id
+        resp = await self._rpc(
+            self._svc.admin_room_layout.reorder_sidebar_items_in_group(
+                req, headers=self._headers()
+            )
+        )
+        group = AdminRoomLayoutGroup.parse(pb_to_dict(resp.group))
+        assert group is not None
+        return group
+
+    async def admin_create_sidebar_link(
+        self, group_id: str, label: str, url: str
+    ) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.admin_room_layout.create_sidebar_link(
+                room_layout_pb2.CreateSidebarLinkRequest(
+                    group_id=group_id, label=label, url=url
+                ),
+                headers=self._headers(),
+            )
+        )
+        sl = resp.sidebar_link
+        return {"id": sl.id, "label": sl.label, "url": sl.url}
+
+    async def admin_update_sidebar_link(
+        self,
+        link_id: str,
+        *,
+        label: str | None = None,
+        url: str | None = None,
+    ) -> dict[str, Any]:
+        req = room_layout_pb2.UpdateSidebarLinkRequest(link_id=link_id)
+        if label is not None:
+            req.label = label
+        if url is not None:
+            req.url = url
+        resp = await self._rpc(
+            self._svc.admin_room_layout.update_sidebar_link(
+                req, headers=self._headers()
+            )
+        )
+        sl = resp.sidebar_link
+        return {"id": sl.id, "label": sl.label, "url": sl.url}
+
+    async def admin_delete_sidebar_link(self, link_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.admin_room_layout.delete_sidebar_link(
+                room_layout_pb2.DeleteSidebarLinkRequest(link_id=link_id),
+                headers=self._headers(),
+            )
+        )
+        return resp.deleted
+
+    async def admin_move_sidebar_link_to_group(
+        self, link_id: str, group_id: str
+    ) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.admin_room_layout.move_sidebar_link_to_group(
+                room_layout_pb2.MoveSidebarLinkToGroupRequest(
+                    link_id=link_id, group_id=group_id
+                ),
+                headers=self._headers(),
+            )
+        )
+        sl = resp.sidebar_link
+        return {"id": sl.id, "label": sl.label, "url": sl.url}
+
+    # --- Admin: users --------------------------------------------------
+
+    async def admin_list_members(
+        self,
+        *,
+        search: str = "",
+        limit: int | None = None,
+        offset: int | None = None,
+    ) -> tuple[list[AdminMember], list[Role], Page]:
+        req = admin_members_pb2.ListMembersRequest(search=search)
+        page = _page_pb(limit, offset)
+        if page is not None:
+            req.page.CopyFrom(page)
+        resp = await self._rpc(
+            self._svc.admin_users.list_members(req, headers=self._headers())
+        )
+        data = pb_to_dict(resp)
+        members = [
+            m
+            for m in (AdminMember.parse(row) for row in data.get("members") or [])
+            if m is not None
+        ]
+        roles = [
+            r for r in (Role.parse(row) for row in data.get("roles") or []) if r is not None
+        ]
+        return members, roles, Page.parse(data.get("page"))
+
+    async def admin_get_member(
+        self,
+        *,
+        user_id: str | None = None,
+        login: str | None = None,
+    ) -> dict[str, Any]:
+        if bool(user_id) == bool(login):
+            raise ValueError("admin_get_member requires exactly one of user_id or login")
+        req = admin_members_pb2.GetMemberRequest()
+        if user_id:
+            req.user_id = user_id
+        else:
+            assert login is not None
+            req.login = login
+        resp = await self._rpc(
+            self._svc.admin_users.get_member(req, headers=self._headers())
+        )
+        return pb_to_dict(resp)
+
+    async def admin_batch_get_members(self, user_ids: list[str]) -> list[AdminMember]:
+        resp = await self._rpc(
+            self._svc.admin_users.batch_get_members(
+                admin_members_pb2.BatchGetMembersRequest(user_ids=user_ids),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            m
+            for m in (AdminMember.parse(row) for row in data.get("members") or [])
+            if m is not None
+        ]
+
+    async def admin_assign_role(
+        self, user_id: str, role_name: str
+    ) -> AdminMember | None:
+        resp = await self._rpc(
+            self._svc.admin_users.assign_role(
+                admin_members_pb2.AssignRoleRequest(
+                    user_id=user_id, role_name=role_name
+                ),
+                headers=self._headers(),
+            )
+        )
+        return AdminMember.parse(pb_to_dict(resp.member))
+
+    async def admin_revoke_role(
+        self, user_id: str, role_name: str
+    ) -> AdminMember | None:
+        resp = await self._rpc(
+            self._svc.admin_users.revoke_role(
+                admin_members_pb2.RevokeRoleRequest(
+                    user_id=user_id, role_name=role_name
+                ),
+                headers=self._headers(),
+            )
+        )
+        return AdminMember.parse(pb_to_dict(resp.member))
+
+    async def admin_update_user(
+        self,
+        user_id: str,
+        *,
+        display_name: str | None = None,
+        login: str | None = None,
+    ) -> tuple[User | None, AdminMember | None]:
+        req = admin_members_pb2.UpdateUserRequest(user_id=user_id)
+        if display_name is not None:
+            req.display_name = display_name
+        if login is not None:
+            req.login = login
+        resp = await self._rpc(
+            self._svc.admin_users.update_user(req, headers=self._headers())
+        )
+        return (
+            User.parse(pb_to_dict(resp.user)),
+            AdminMember.parse(pb_to_dict(resp.member)),
+        )
+
+    async def admin_update_user_password(
+        self, user_id: str, password: str
+    ) -> AdminMember | None:
+        resp = await self._rpc(
+            self._svc.admin_users.update_user_password(
+                admin_members_pb2.UpdateUserPasswordRequest(
+                    user_id=user_id, password=password
+                ),
+                headers=self._headers(),
+            )
+        )
+        return AdminMember.parse(pb_to_dict(resp.member))
+
+    async def admin_clear_username_cooldown(self, user_id: str) -> bool:
+        resp = await self._rpc(
+            self._svc.admin_users.clear_username_cooldown(
+                admin_members_pb2.ClearUsernameCooldownRequest(user_id=user_id),
+                headers=self._headers(),
+            )
+        )
+        return resp.cleared
+
+    async def admin_delete_user(
+        self, user_id: str, *, current_password: str = ""
+    ) -> bool:
+        resp = await self._rpc(
+            self._svc.admin_users.delete_user(
+                admin_members_pb2.DeleteUserRequest(
+                    user_id=user_id, current_password=current_password
+                ),
+                headers=self._headers(),
+            )
+        )
+        return resp.deleted
+
+    # --- Admin: roles --------------------------------------------------
+
+    async def admin_list_roles(self) -> list[AdminRole]:
+        resp = await self._rpc(
+            self._svc.admin_roles.list_roles(
+                admin_roles_pb2.ListRolesRequest(), headers=self._headers()
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            r
+            for r in (AdminRole.parse(row) for row in data.get("roles") or [])
+            if r is not None
+        ]
+
+    async def admin_get_role(self, name: str) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.admin_roles.get_role(
+                admin_roles_pb2.GetRoleRequest(name=name), headers=self._headers()
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def admin_create_role(
+        self,
+        name: str,
+        *,
+        display_name: str = "",
+        description: str = "",
+        pingable: bool = False,
+    ) -> AdminRole | None:
+        resp = await self._rpc(
+            self._svc.admin_roles.create_role(
+                admin_roles_pb2.CreateRoleRequest(
+                    name=name,
+                    display_name=display_name,
+                    description=description,
+                    pingable=pingable,
+                ),
+                headers=self._headers(),
+            )
+        )
+        return AdminRole.parse(pb_to_dict(resp.role))
+
+    async def admin_update_role(
+        self,
+        name: str,
+        *,
+        display_name: str | None = None,
+        description: str | None = None,
+        pingable: bool | None = None,
+    ) -> AdminRole | None:
+        req = admin_roles_pb2.UpdateRoleRequest(name=name)
+        if display_name is not None:
+            req.display_name = display_name
+        if description is not None:
+            req.description = description
+        if pingable is not None:
+            req.pingable = pingable
+        resp = await self._rpc(
+            self._svc.admin_roles.update_role(req, headers=self._headers())
+        )
+        return AdminRole.parse(pb_to_dict(resp.role))
+
+    async def admin_delete_role(self, name: str) -> bool:
+        resp = await self._rpc(
+            self._svc.admin_roles.delete_role(
+                admin_roles_pb2.DeleteRoleRequest(name=name),
+                headers=self._headers(),
+            )
+        )
+        return resp.deleted
+
+    async def admin_reorder_roles(self, role_names: list[str]) -> list[AdminRole]:
+        resp = await self._rpc(
+            self._svc.admin_roles.reorder_roles(
+                admin_roles_pb2.ReorderRolesRequest(role_names=role_names),
+                headers=self._headers(),
+            )
+        )
+        data = pb_to_dict(resp)
+        return [
+            r
+            for r in (AdminRole.parse(row) for row in data.get("roles") or [])
+            if r is not None
+        ]
+
+    # --- Admin: event log / diagnostics / permissions ----------------
+
+    async def admin_list_events(
+        self,
+        *,
+        event_types: list[str] | None = None,
+        limit: int | None = None,
+        offset: int | None = None,
+    ) -> dict[str, Any]:
+        req = event_log_pb2.ListEventsRequest()
+        if event_types:
+            req.event_types.extend(event_types)
+        page = _page_pb(limit, offset)
+        if page is not None:
+            req.page.CopyFrom(page)
+        resp = await self._rpc(
+            self._svc.admin_event_log.list_events(req, headers=self._headers())
+        )
+        return pb_to_dict(resp)
+
+    async def admin_list_event_types(self) -> list[str]:
+        resp = await self._rpc(
+            self._svc.admin_event_log.list_event_types(
+                event_log_pb2.ListEventTypesRequest(),
+                headers=self._headers(),
+            )
+        )
+        return list(resp.event_types)
+
+    async def admin_get_event(self, event_id: str) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.admin_event_log.get_event(
+                event_log_pb2.GetEventRequest(event_id=event_id),
+                headers=self._headers(),
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def admin_get_system_info(self) -> dict[str, Any]:
+        from chattolib._pb.chatto.admin.v1 import diagnostics_pb2
+
+        resp = await self._rpc(
+            self._svc.admin_diagnostics.get_system_info(
+                diagnostics_pb2.GetSystemInfoRequest(),
+                headers=self._headers(),
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def admin_get_role_permission_matrix(self) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.admin_permissions.get_role_permission_matrix(
+                admin_permissions_pb2.GetRolePermissionMatrixRequest(),
+                headers=self._headers(),
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def admin_list_role_permission_decisions(
+        self, role_name: str
+    ) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.admin_permissions.list_role_permission_decisions(
+                admin_permissions_pb2.ListRolePermissionDecisionsRequest(
+                    role_name=role_name
+                ),
+                headers=self._headers(),
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def admin_get_user_permission_matrix(self, user_id: str) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.admin_permissions.get_user_permission_matrix(
+                admin_permissions_pb2.GetUserPermissionMatrixRequest(user_id=user_id),
+                headers=self._headers(),
+            )
+        )
+        return pb_to_dict(resp)
+
+    async def admin_list_user_permission_decisions(
+        self, user_id: str
+    ) -> dict[str, Any]:
+        resp = await self._rpc(
+            self._svc.admin_permissions.list_user_permission_decisions(
+                admin_permissions_pb2.ListUserPermissionDecisionsRequest(user_id=user_id),
+                headers=self._headers(),
+            )
+        )
+        return pb_to_dict(resp)

+ 37 - 0
vendor/chattolib/exceptions.py

@@ -0,0 +1,37 @@
+"""Exception hierarchy for chattolib."""
+
+from __future__ import annotations
+
+from typing import Any
+
+
+class ChattoError(Exception):
+    """Base exception for all chattolib errors."""
+
+
+class ChattoConnectError(ChattoError):
+    """A ConnectRPC call returned a protocol error.
+
+    The Chatto Connect API returns errors as JSON bodies of the shape
+    ``{"code": "<code>", "message": "<message>", "details": [...]}`` alongside a
+    non-2xx HTTP status. See https://connectrpc.com/docs/protocol#error-codes for
+    the canonical code list.
+    """
+
+    def __init__(
+        self,
+        code: str,
+        message: str,
+        *,
+        status_code: int | None = None,
+        details: list[dict[str, Any]] | None = None,
+    ) -> None:
+        self.code = code
+        self.message = message
+        self.status_code = status_code
+        self.details = details or []
+        super().__init__(f"{code}: {message}")
+
+
+class ChattoAuthError(ChattoError):
+    """Authentication failed (missing token, expired session, or bad credentials)."""

+ 306 - 0
vendor/chattolib/realtime.py

@@ -0,0 +1,306 @@
+"""Chatto realtime WebSocket client.
+
+Chatto exposes a binary-protobuf realtime channel at ``/api/realtime`` (see
+``proto/chatto/realtime/v1/realtime.proto``). This module speaks that
+protocol: it opens the WebSocket, exchanges ``hello`` frames, subscribes to
+the caller's authorized live-event stream, and yields decoded events.
+
+Usage::
+
+    async with await ChattoClient.login(...) as client:
+        async for event in stream_events(client):
+            print(event.kind, event.payload)
+
+Requires the ``chattolib[realtime]`` extra (which pulls in ``websockets`` and
+``protobuf``).
+"""
+
+from __future__ import annotations
+
+from collections.abc import AsyncIterator
+from dataclasses import dataclass
+from datetime import datetime
+from typing import TYPE_CHECKING, Any
+
+from chattolib import _pb  # noqa: F401 — installs pb import path
+from chattolib.exceptions import ChattoError
+from chattolib.types import parse_datetime
+
+if TYPE_CHECKING:
+    from chattolib.client import ChattoClient
+
+REALTIME_PATH = "/api/realtime"
+REALTIME_PROTOCOL_VERSION = 1
+
+
+class ChattoRealtimeError(ChattoError):
+    """Server returned a protocol error over the realtime WebSocket."""
+
+    def __init__(self, code: str, message: str, *, fatal: bool = False) -> None:
+        self.code = code
+        self.message = message
+        self.fatal = fatal
+        super().__init__(f"{code}: {message}")
+
+
+class ChattoRealtimeCloseError(ChattoError):
+    """Server sent a close frame."""
+
+    def __init__(
+        self,
+        code: str,
+        message: str,
+        *,
+        reconnect: bool = False,
+        retry_after_ms: int = 0,
+    ) -> None:
+        self.code = code
+        self.message = message
+        self.reconnect = reconnect
+        self.retry_after_ms = retry_after_ms
+        super().__init__(f"{code}: {message}")
+
+
+def realtime_url(base_url: str) -> str:
+    """Convert an HTTP(S) base URL to the realtime WebSocket URL."""
+    base = base_url.rstrip("/")
+    if base.startswith("https://"):
+        return "wss://" + base[len("https://") :] + REALTIME_PATH
+    if base.startswith("http://"):
+        return "ws://" + base[len("http://") :] + REALTIME_PATH
+    return "wss://" + base + REALTIME_PATH
+
+
+@dataclass
+class ServerHello:
+    """Server's response to the initial hello frame."""
+
+    protocol_version: int
+    server_version: str
+    heartbeat_interval_seconds: int
+    capabilities: list[str]
+
+
+@dataclass
+class RealtimeEvent:
+    """One live event delivered over the realtime WebSocket.
+
+    ``kind`` names the ``oneof event`` case set on the envelope
+    (``message_posted``, ``reaction_added``, ``presence_changed``, …).
+    ``payload`` is the concrete protobuf sub-message; access its fields
+    directly (e.g. ``event.payload.room_id``). Callers that want to hydrate
+    the referenced resource should follow the hydration hints documented on
+    each event message in ``realtime.proto``.
+    """
+
+    id: str
+    created_at: datetime | None
+    actor_id: str | None
+    kind: str
+    payload: Any
+    raw: Any  # the full RealtimeEventEnvelope
+
+
+class RealtimeConnection:
+    """Live realtime WebSocket session.
+
+    Prefer :func:`stream_events` for the common case; use this class directly
+    when you also need to send client pings, close cleanly, or inspect the
+    negotiated :class:`ServerHello`.
+    """
+
+    def __init__(
+        self,
+        client: ChattoClient,
+        *,
+        protocol_version: int = REALTIME_PROTOCOL_VERSION,
+    ) -> None:
+        self._client = client
+        self._protocol_version = protocol_version
+        self._ws: Any = None
+        self._server_hello: ServerHello | None = None
+
+    @property
+    def server_hello(self) -> ServerHello | None:
+        return self._server_hello
+
+    async def __aenter__(self) -> RealtimeConnection:
+        await self.connect()
+        return self
+
+    async def __aexit__(self, *exc: Any) -> None:
+        await self.close()
+
+    async def connect(self) -> None:
+        try:
+            import websockets
+        except ImportError as exc:  # pragma: no cover
+            raise ChattoError(
+                "The realtime channel requires the 'websockets' package. "
+                "Install with `pip install chattolib[realtime]`."
+            ) from exc
+
+        from chattolib._pb.chatto.realtime.v1 import realtime_pb2
+
+        url = realtime_url(self._client.base_url)
+        headers: dict[str, str] = {}
+        if self._client.session_cookie:
+            headers["Cookie"] = f"chatto_session={self._client.session_cookie}"
+
+        self._ws = await websockets.connect(url, additional_headers=headers)
+
+        client_hello = realtime_pb2.RealtimeClientFrame()
+        client_hello.hello.protocol_version = self._protocol_version
+        if self._client.token:
+            client_hello.hello.bearer_token = self._client.token
+        await self._ws.send(client_hello.SerializeToString())
+
+        first = await self._ws.recv()
+        first_frame = realtime_pb2.RealtimeServerFrame()
+        first_frame.ParseFromString(first)
+        if first_frame.WhichOneof("frame") != "hello":
+            _raise_for_control(first_frame)
+            raise ChattoRealtimeError(
+                "unexpected_frame",
+                f"expected server hello, got {first_frame.WhichOneof('frame')!r}",
+            )
+        hello = first_frame.hello
+        self._server_hello = ServerHello(
+            protocol_version=hello.protocol_version,
+            server_version=hello.server_version,
+            heartbeat_interval_seconds=hello.heartbeat_interval_seconds,
+            capabilities=list(hello.capabilities),
+        )
+
+        subscribe = realtime_pb2.RealtimeClientFrame()
+        subscribe.subscribe_events.SetInParent()
+        await self._ws.send(subscribe.SerializeToString())
+
+    async def close(self) -> None:
+        if self._ws is None:
+            return
+        try:
+            await self._ws.close()
+        finally:
+            self._ws = None
+
+    async def ping(self, nonce: str = "") -> None:
+        """Send a client ping. The server replies with a matching pong."""
+        if self._ws is None:
+            raise ChattoError("realtime connection is closed")
+        from chattolib._pb.chatto.realtime.v1 import realtime_pb2
+
+        frame = realtime_pb2.RealtimeClientFrame()
+        frame.ping.nonce = nonce
+        await self._ws.send(frame.SerializeToString())
+
+    async def events(self) -> AsyncIterator[RealtimeEvent]:
+        """Yield decoded live events until the connection closes."""
+        if self._ws is None:
+            raise ChattoError("realtime connection is not open")
+        from chattolib._pb.chatto.realtime.v1 import realtime_pb2
+
+        async for raw in self._ws:
+            if isinstance(raw, str):
+                # The protocol is binary; a text frame indicates a protocol violation.
+                raise ChattoRealtimeError(
+                    "unexpected_text_frame",
+                    "server sent a text frame; realtime protocol expects binary",
+                )
+            frame = realtime_pb2.RealtimeServerFrame()
+            frame.ParseFromString(raw)
+            case = frame.WhichOneof("frame")
+            if case == "event":
+                yield _wrap_event(frame.event)
+            elif case in ("heartbeat", "pong", "subscribed"):
+                continue
+            elif case == "error":
+                err = frame.error
+                exc = ChattoRealtimeError(err.code, err.message, fatal=err.fatal)
+                if err.fatal:
+                    raise exc
+                # Non-fatal errors are surfaced but the stream continues.
+                # Callers can still receive them if desired; for now we log
+                # by re-raising on fatal only.
+                continue
+            elif case == "close":
+                close = frame.close
+                raise ChattoRealtimeCloseError(
+                    close.code,
+                    close.message,
+                    reconnect=close.reconnect,
+                    retry_after_ms=close.retry_after_ms,
+                )
+            else:
+                raise ChattoRealtimeError(
+                    "unexpected_frame",
+                    f"unknown server frame: {case!r}",
+                )
+
+
+def _raise_for_control(frame: Any) -> None:
+    """If ``frame`` is an error or close frame, translate it and raise."""
+    case = frame.WhichOneof("frame")
+    if case == "error":
+        err = frame.error
+        raise ChattoRealtimeError(err.code, err.message, fatal=err.fatal)
+    if case == "close":
+        close = frame.close
+        raise ChattoRealtimeCloseError(
+            close.code,
+            close.message,
+            reconnect=close.reconnect,
+            retry_after_ms=close.retry_after_ms,
+        )
+
+
+def _wrap_event(envelope: Any) -> RealtimeEvent:
+    kind = envelope.WhichOneof("event") or ""
+    payload = getattr(envelope, kind, None) if kind else None
+    created_at = None
+    if envelope.HasField("created_at"):
+        created_at = parse_datetime(envelope.created_at.ToJsonString())
+    actor_id: str | None = None
+    if envelope.HasField("actor_id"):
+        actor_id = envelope.actor_id
+    return RealtimeEvent(
+        id=envelope.id,
+        created_at=created_at,
+        actor_id=actor_id,
+        kind=kind,
+        payload=payload,
+        raw=envelope,
+    )
+
+
+async def stream_events(
+    client: ChattoClient,
+    *,
+    protocol_version: int = REALTIME_PROTOCOL_VERSION,
+) -> AsyncIterator[RealtimeEvent]:
+    """Open a realtime connection and yield events until the server closes.
+
+    Raises :class:`ChattoRealtimeCloseError` when the server sends a close frame,
+    :class:`ChattoRealtimeError` on fatal protocol errors, or
+    :class:`ChattoConnectError` if the initial HTTP handshake fails.
+    """
+    conn = RealtimeConnection(client, protocol_version=protocol_version)
+    try:
+        await conn.connect()
+        async for event in conn.events():
+            yield event
+    finally:
+        await conn.close()
+
+
+__all__ = [
+    "REALTIME_PATH",
+    "REALTIME_PROTOCOL_VERSION",
+    "ChattoRealtimeCloseError",
+    "ChattoRealtimeError",
+    "RealtimeConnection",
+    "RealtimeEvent",
+    "ServerHello",
+    "realtime_url",
+    "stream_events",
+]

+ 1121 - 0
vendor/chattolib/types.py

@@ -0,0 +1,1121 @@
+"""Dataclasses and enums mirroring Chatto's Connect API messages.
+
+Enum ``value`` strings match the proto JSON encoding used on the wire
+(e.g. ``PRESENCE_STATUS_ONLINE``). Parsers below accept both the fully-qualified
+form and the short/legacy tail (``ONLINE``) for robustness against older
+snapshots or clients that construct short enum strings by hand.
+"""
+
+from __future__ import annotations
+
+from dataclasses import dataclass, field
+from datetime import UTC, datetime
+from enum import Enum, StrEnum
+from typing import Any
+
+# --- Enums ---------------------------------------------------------------
+
+
+def _parse_enum(cls: type[Enum], raw: Any, default: Enum) -> Enum:
+    """Accept either the full ``FOO_BAR_BAZ`` form or its tail (``BAZ``)."""
+    if raw is None or raw == "":
+        return default
+    if isinstance(raw, cls):
+        return raw
+    try:
+        return cls(raw)
+    except ValueError:
+        pass
+    # Tolerate integer values from proto JSON alternate encoding.
+    if isinstance(raw, int):
+        for member in cls:
+            if getattr(member, "_proto_index", None) == raw:
+                return member
+    text = str(raw)
+    for member in cls:
+        value = member.value if isinstance(member.value, str) else ""
+        if value.endswith("_" + text) or value == text:
+            return member
+    return default
+
+
+class PresenceStatus(StrEnum):
+    UNSPECIFIED = "PRESENCE_STATUS_UNSPECIFIED"
+    ONLINE = "PRESENCE_STATUS_ONLINE"
+    AWAY = "PRESENCE_STATUS_AWAY"
+    DO_NOT_DISTURB = "PRESENCE_STATUS_DO_NOT_DISTURB"
+    OFFLINE = "PRESENCE_STATUS_OFFLINE"
+
+
+class TimeFormat(StrEnum):
+    UNSPECIFIED = "TIME_FORMAT_UNSPECIFIED"
+    AUTO = "TIME_FORMAT_AUTO"
+    HOUR_12 = "TIME_FORMAT_12_HOUR"
+    HOUR_24 = "TIME_FORMAT_24_HOUR"
+
+
+class RoomKind(StrEnum):
+    UNSPECIFIED = "ROOM_KIND_UNSPECIFIED"
+    CHANNEL = "ROOM_KIND_CHANNEL"
+    DM = "ROOM_KIND_DM"
+
+
+class RoomDirectoryScope(StrEnum):
+    UNSPECIFIED = "ROOM_DIRECTORY_SCOPE_UNSPECIFIED"
+    ALL = "ROOM_DIRECTORY_SCOPE_ALL"
+    CHANNELS = "ROOM_DIRECTORY_SCOPE_CHANNELS"
+    DMS = "ROOM_DIRECTORY_SCOPE_DMS"
+
+
+class NotificationLevel(StrEnum):
+    UNSPECIFIED = "NOTIFICATION_LEVEL_UNSPECIFIED"
+    DEFAULT = "NOTIFICATION_LEVEL_DEFAULT"
+    MUTED = "NOTIFICATION_LEVEL_MUTED"
+    NORMAL = "NOTIFICATION_LEVEL_NORMAL"
+    ALL_MESSAGES = "NOTIFICATION_LEVEL_ALL_MESSAGES"
+
+
+class ImageFitMode(StrEnum):
+    UNSPECIFIED = "IMAGE_FIT_MODE_UNSPECIFIED"
+    CONTAIN = "IMAGE_FIT_MODE_CONTAIN"
+    COVER = "IMAGE_FIT_MODE_COVER"
+
+
+class VideoProcessingStatus(StrEnum):
+    UNSPECIFIED = "MESSAGE_VIDEO_PROCESSING_STATUS_UNSPECIFIED"
+    PROCESSING = "MESSAGE_VIDEO_PROCESSING_STATUS_PROCESSING"
+    COMPLETED = "MESSAGE_VIDEO_PROCESSING_STATUS_COMPLETED"
+    FAILED = "MESSAGE_VIDEO_PROCESSING_STATUS_FAILED"
+
+
+class AssetUploadStatus(StrEnum):
+    UNSPECIFIED = "ASSET_UPLOAD_STATUS_UNSPECIFIED"
+    OPEN = "ASSET_UPLOAD_STATUS_OPEN"
+    COMPLETED = "ASSET_UPLOAD_STATUS_COMPLETED"
+    CANCELLED = "ASSET_UPLOAD_STATUS_CANCELLED"
+
+
+class AdminRoomLayoutItemKind(StrEnum):
+    UNSPECIFIED = "ADMIN_ROOM_LAYOUT_ITEM_KIND_UNSPECIFIED"
+    ROOM = "ADMIN_ROOM_LAYOUT_ITEM_KIND_ROOM"
+    SIDEBAR_LINK = "ADMIN_ROOM_LAYOUT_ITEM_KIND_SIDEBAR_LINK"
+
+
+# --- Time helpers --------------------------------------------------------
+
+
+def parse_datetime(value: Any) -> datetime | None:
+    """Parse an RFC 3339 timestamp string (proto JSON encoding for Timestamp)."""
+    if not value:
+        return None
+    if isinstance(value, datetime):
+        return value
+    text = str(value)
+    if text.endswith("Z"):
+        text = text[:-1] + "+00:00"
+    try:
+        return datetime.fromisoformat(text)
+    except ValueError:
+        return None
+
+
+def format_datetime(value: datetime) -> str:
+    """Format a ``datetime`` as an RFC 3339 UTC timestamp (``...Z``)."""
+    if value.tzinfo is None:
+        value = value.replace(tzinfo=UTC)
+    return value.astimezone(UTC).isoformat().replace("+00:00", "Z")
+
+
+# --- Core resource dataclasses ------------------------------------------
+
+
+@dataclass
+class CustomUserStatus:
+    emoji: str
+    text: str
+    expires_at: datetime | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> CustomUserStatus | None:
+        if not data:
+            return None
+        return cls(
+            emoji=data.get("emoji", ""),
+            text=data.get("text", ""),
+            expires_at=parse_datetime(data.get("expiresAt")),
+        )
+
+
+@dataclass
+class User:
+    id: str
+    login: str
+    display_name: str
+    presence_status: PresenceStatus = PresenceStatus.UNSPECIFIED
+    avatar_url: str | None = None
+    deleted: bool = False
+    custom_status: CustomUserStatus | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> User | None:
+        if not data:
+            return None
+        return cls(
+            id=data.get("id", ""),
+            login=data.get("login", ""),
+            display_name=data.get("displayName", ""),
+            presence_status=_parse_enum(
+                PresenceStatus, data.get("presenceStatus"), PresenceStatus.UNSPECIFIED
+            ),  # type: ignore[arg-type]
+            avatar_url=data.get("avatarUrl"),
+            deleted=bool(data.get("deleted", False)),
+            custom_status=CustomUserStatus.parse(data.get("customStatus")),
+        )
+
+
+@dataclass
+class UserSettings:
+    timezone: str | None = None
+    time_format: TimeFormat = TimeFormat.UNSPECIFIED
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> UserSettings:
+        data = data or {}
+        return cls(
+            timezone=data.get("timezone"),
+            time_format=_parse_enum(
+                TimeFormat, data.get("timeFormat"), TimeFormat.UNSPECIFIED
+            ),  # type: ignore[arg-type]
+        )
+
+
+@dataclass
+class ViewerUser:
+    profile: User | None
+    settings: UserSettings
+    has_verified_email: bool = False
+    viewer_can_delete_account: bool = False
+    last_login_change: datetime | None = None
+    has_password: bool = False
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> ViewerUser | None:
+        if not data:
+            return None
+        return cls(
+            profile=User.parse(data.get("profile")),
+            settings=UserSettings.parse(data.get("settings")),
+            has_verified_email=bool(data.get("hasVerifiedEmail", False)),
+            viewer_can_delete_account=bool(data.get("viewerCanDeleteAccount", False)),
+            last_login_change=parse_datetime(data.get("lastLoginChange")),
+            has_password=bool(data.get("hasPassword", False)),
+        )
+
+
+@dataclass
+class DirectoryMember:
+    user: User | None
+    roles: list[str] = field(default_factory=list)
+    created_at: datetime | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> DirectoryMember | None:
+        if not data:
+            return None
+        return cls(
+            user=User.parse(data.get("user")),
+            roles=list(data.get("roles") or []),
+            created_at=parse_datetime(data.get("createdAt")),
+        )
+
+
+@dataclass
+class Page:
+    total_count: int = 0
+    has_more: bool = False
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> Page:
+        data = data or {}
+        return cls(
+            total_count=int(data.get("totalCount", 0)),
+            has_more=bool(data.get("hasMore", False)),
+        )
+
+
+@dataclass
+class ServerProfile:
+    name: str
+    version: str = ""
+    logo_url: str | None = None
+    banner_url: str | None = None
+    welcome_message: str | None = None
+    description: str | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> ServerProfile:
+        data = data or {}
+        return cls(
+            name=data.get("name", ""),
+            version=data.get("version", ""),
+            logo_url=data.get("logoUrl"),
+            banner_url=data.get("bannerUrl"),
+            welcome_message=data.get("welcomeMessage"),
+            description=data.get("description"),
+        )
+
+
+@dataclass
+class ProviderMetadata:
+    id: str
+    type: str
+    label: str
+    login_url: str = ""
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> ProviderMetadata:
+        return cls(
+            id=data.get("id", ""),
+            type=data.get("type", ""),
+            label=data.get("label", ""),
+            login_url=data.get("loginUrl", ""),
+        )
+
+
+@dataclass
+class ServerLogin:
+    direct_registration_enabled: bool = False
+    providers: list[ProviderMetadata] = field(default_factory=list)
+    authorize_url: str = ""
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> ServerLogin:
+        data = data or {}
+        return cls(
+            direct_registration_enabled=bool(data.get("directRegistrationEnabled", False)),
+            providers=[ProviderMetadata.parse(p) for p in data.get("providers") or []],
+            authorize_url=data.get("authorizeUrl", ""),
+        )
+
+
+@dataclass
+class ServerRuntimeConfig:
+    push_notifications_enabled: bool = False
+    vapid_public_key: str | None = None
+    livekit_url: str | None = None
+    video_processing_enabled: bool = False
+    max_upload_size: int = 0
+    max_video_upload_size: int = 0
+    message_edit_window_seconds: int = 0
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> ServerRuntimeConfig:
+        data = data or {}
+        return cls(
+            push_notifications_enabled=bool(data.get("pushNotificationsEnabled", False)),
+            vapid_public_key=data.get("vapidPublicKey"),
+            livekit_url=data.get("livekitUrl"),
+            video_processing_enabled=bool(data.get("videoProcessingEnabled", False)),
+            max_upload_size=int(data.get("maxUploadSize", 0)),
+            max_video_upload_size=int(data.get("maxVideoUploadSize", 0)),
+            message_edit_window_seconds=int(data.get("messageEditWindowSeconds", 0)),
+        )
+
+
+@dataclass
+class Room:
+    id: str
+    kind: RoomKind = RoomKind.UNSPECIFIED
+    name: str = ""
+    description: str = ""
+    archived: bool = False
+    group_id: str = ""
+    universal: bool = False
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> Room | None:
+        if not data:
+            return None
+        return cls(
+            id=data.get("id", ""),
+            kind=_parse_enum(RoomKind, data.get("kind"), RoomKind.UNSPECIFIED),  # type: ignore[arg-type]
+            name=data.get("name", ""),
+            description=data.get("description", ""),
+            archived=bool(data.get("archived", False)),
+            group_id=data.get("groupId", ""),
+            universal=bool(data.get("universal", False)),
+        )
+
+
+@dataclass
+class RoomSummary:
+    id: str
+    kind: RoomKind = RoomKind.UNSPECIFIED
+    name: str = ""
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> RoomSummary | None:
+        if not data:
+            return None
+        return cls(
+            id=data.get("id", ""),
+            kind=_parse_enum(RoomKind, data.get("kind"), RoomKind.UNSPECIFIED),  # type: ignore[arg-type]
+            name=data.get("name", ""),
+        )
+
+
+@dataclass
+class RoomViewerState:
+    is_member: bool = False
+    has_unread: bool = False
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> RoomViewerState:
+        data = data or {}
+        return cls(
+            is_member=bool(data.get("isMember", False)),
+            has_unread=bool(data.get("hasUnread", False)),
+        )
+
+
+@dataclass
+class RoomWithViewerState:
+    room: Room | None
+    viewer_state: RoomViewerState
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> RoomWithViewerState | None:
+        if not data:
+            return None
+        return cls(
+            room=Room.parse(data.get("room")),
+            viewer_state=RoomViewerState.parse(data.get("viewerState")),
+        )
+
+
+@dataclass
+class SidebarLink:
+    id: str
+    label: str
+    url: str
+
+
+@dataclass
+class RoomGroup:
+    id: str
+    name: str
+    description: str = ""
+    rooms: list[RoomWithViewerState] = field(default_factory=list)
+    sidebar_links: list[SidebarLink] = field(default_factory=list)
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> RoomGroup | None:
+        if not data:
+            return None
+        rooms: list[RoomWithViewerState] = []
+        links: list[SidebarLink] = []
+        for item in data.get("items") or []:
+            room = RoomWithViewerState.parse(item.get("room"))
+            if room:
+                rooms.append(room)
+            sl = item.get("sidebarLink")
+            if sl:
+                links.append(
+                    SidebarLink(
+                        id=sl.get("id", ""),
+                        label=sl.get("label", ""),
+                        url=sl.get("url", ""),
+                    )
+                )
+        return cls(
+            id=data.get("id", ""),
+            name=data.get("name", ""),
+            description=data.get("description", ""),
+            rooms=rooms,
+            sidebar_links=links,
+        )
+
+
+@dataclass
+class RoomBan:
+    id: str
+    room_id: str
+    user_id: str
+    moderator_id: str = ""
+    reason: str = ""
+    created_at: datetime | None = None
+    expires_at: datetime | None = None
+    room: Room | None = None
+    user: DirectoryMember | None = None
+    moderator: DirectoryMember | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> RoomBan | None:
+        if not data:
+            return None
+        return cls(
+            id=data.get("id", ""),
+            room_id=data.get("roomId", ""),
+            user_id=data.get("userId", ""),
+            moderator_id=data.get("moderatorId", ""),
+            reason=data.get("reason", ""),
+            created_at=parse_datetime(data.get("createdAt")),
+            expires_at=parse_datetime(data.get("expiresAt")),
+            room=Room.parse(data.get("room")),
+            user=DirectoryMember.parse(data.get("user")),
+            moderator=DirectoryMember.parse(data.get("moderator")),
+        )
+
+
+@dataclass
+class AssetUrl:
+    url: str
+    expires_at: datetime | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> AssetUrl | None:
+        if not data:
+            return None
+        return cls(
+            url=data.get("url", ""),
+            expires_at=parse_datetime(data.get("expiresAt")),
+        )
+
+
+@dataclass
+class VideoVariant:
+    quality: str
+    width: int
+    height: int
+    size: int
+    asset_url: AssetUrl | None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> VideoVariant:
+        return cls(
+            quality=data.get("quality", ""),
+            width=int(data.get("width", 0)),
+            height=int(data.get("height", 0)),
+            size=int(data.get("size", 0)),
+            asset_url=AssetUrl.parse(data.get("assetUrl")),
+        )
+
+
+@dataclass
+class VideoProcessing:
+    status: VideoProcessingStatus = VideoProcessingStatus.UNSPECIFIED
+    duration_ms: int = 0
+    width: int = 0
+    height: int = 0
+    source_available: bool = False
+    reason_code: str = ""
+    thumbnail_asset_url: AssetUrl | None = None
+    variants: list[VideoVariant] = field(default_factory=list)
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> VideoProcessing | None:
+        if not data:
+            return None
+        return cls(
+            status=_parse_enum(
+                VideoProcessingStatus,
+                data.get("status"),
+                VideoProcessingStatus.UNSPECIFIED,
+            ),  # type: ignore[arg-type]
+            duration_ms=int(data.get("durationMs", 0)),
+            width=int(data.get("width", 0)),
+            height=int(data.get("height", 0)),
+            source_available=bool(data.get("sourceAvailable", False)),
+            reason_code=data.get("reasonCode", ""),
+            thumbnail_asset_url=AssetUrl.parse(data.get("thumbnailAssetUrl")),
+            variants=[VideoVariant.parse(v) for v in data.get("variants") or []],
+        )
+
+
+@dataclass
+class MessageAttachment:
+    id: str
+    filename: str
+    content_type: str
+    width: int = 0
+    height: int = 0
+    asset_url: AssetUrl | None = None
+    thumbnail_asset_url: AssetUrl | None = None
+    video_processing: VideoProcessing | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> MessageAttachment:
+        return cls(
+            id=data.get("id", ""),
+            filename=data.get("filename", ""),
+            content_type=data.get("contentType", ""),
+            width=int(data.get("width", 0)),
+            height=int(data.get("height", 0)),
+            asset_url=AssetUrl.parse(data.get("assetUrl")),
+            thumbnail_asset_url=AssetUrl.parse(data.get("thumbnailAssetUrl")),
+            video_processing=VideoProcessing.parse(data.get("videoProcessing")),
+        )
+
+
+@dataclass
+class LinkPreview:
+    url: str
+    title: str | None = None
+    description: str | None = None
+    image_url: str | None = None
+    image_asset_id: str | None = None
+    site_name: str | None = None
+    embed_type: str | None = None
+    embed_id: str | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> LinkPreview | None:
+        if not data:
+            return None
+        return cls(
+            url=data.get("url", ""),
+            title=data.get("title"),
+            description=data.get("description"),
+            image_url=data.get("imageUrl"),
+            image_asset_id=data.get("imageAssetId"),
+            site_name=data.get("siteName"),
+            embed_type=data.get("embedType"),
+            embed_id=data.get("embedId"),
+        )
+
+
+@dataclass
+class MessageReaction:
+    emoji: str
+    count: int = 0
+    has_reacted: bool = False
+    preview_user_ids: list[str] = field(default_factory=list)
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> MessageReaction:
+        return cls(
+            emoji=data.get("emoji", ""),
+            count=int(data.get("count", 0)),
+            has_reacted=bool(data.get("hasReacted", False)),
+            preview_user_ids=list(data.get("previewUserIds") or []),
+        )
+
+
+@dataclass
+class ThreadSummary:
+    thread_root_event_id: str
+    reply_count: int = 0
+    last_reply_at: datetime | None = None
+    participant_preview_user_ids: list[str] = field(default_factory=list)
+    participant_count: int = 0
+    is_following: bool | None = None
+    has_unread: bool | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> ThreadSummary | None:
+        if not data:
+            return None
+        viewer = data.get("viewerState") or {}
+        return cls(
+            thread_root_event_id=data.get("threadRootEventId", ""),
+            reply_count=int(data.get("replyCount", 0)),
+            last_reply_at=parse_datetime(data.get("lastReplyAt")),
+            participant_preview_user_ids=list(
+                data.get("participantPreviewUserIds") or []
+            ),
+            participant_count=int(data.get("participantCount", 0)),
+            is_following=viewer.get("isFollowing") if "isFollowing" in viewer else None,
+            has_unread=viewer.get("hasUnread") if "hasUnread" in viewer else None,
+        )
+
+
+@dataclass
+class Message:
+    id: str
+    room_id: str
+    created_at: datetime | None
+    actor_id: str
+    body: str | None = None
+    attachments: list[MessageAttachment] = field(default_factory=list)
+    link_preview: LinkPreview | None = None
+    updated_at: datetime | None = None
+    in_reply_to: str = ""
+    thread_root_event_id: str = ""
+    echo_of_event_id: str = ""
+    echo_from_thread_root_event_id: str = ""
+    channel_echo_event_id: str = ""
+    reactions: list[MessageReaction] = field(default_factory=list)
+    thread: ThreadSummary | None = None
+    deleted_at: datetime | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> Message | None:
+        if not data:
+            return None
+        return cls(
+            id=data.get("id", ""),
+            room_id=data.get("roomId", ""),
+            created_at=parse_datetime(data.get("createdAt")),
+            actor_id=data.get("actorId", ""),
+            body=data.get("body"),
+            attachments=[MessageAttachment.parse(a) for a in data.get("attachments") or []],
+            link_preview=LinkPreview.parse(data.get("linkPreview")),
+            updated_at=parse_datetime(data.get("updatedAt")),
+            in_reply_to=data.get("inReplyTo", ""),
+            thread_root_event_id=data.get("threadRootEventId", ""),
+            echo_of_event_id=data.get("echoOfEventId", ""),
+            echo_from_thread_root_event_id=data.get("echoFromThreadRootEventId", ""),
+            channel_echo_event_id=data.get("channelEchoEventId", ""),
+            reactions=[MessageReaction.parse(r) for r in data.get("reactions") or []],
+            thread=ThreadSummary.parse(data.get("thread")),
+            deleted_at=parse_datetime(data.get("deletedAt")),
+        )
+
+
+@dataclass
+class TimelineEvent:
+    id: str
+    created_at: datetime | None
+    actor_id: str = ""
+    kind: str = ""  # "message_posted", "room_created", "user_joined_room", ...
+    message: Message | None = None
+    room_id: str = ""
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> TimelineEvent:
+        kind = ""
+        message: Message | None = None
+        room_id = ""
+        for candidate in (
+            "messagePosted",
+            "roomCreated",
+            "roomUpdated",
+            "roomDeleted",
+            "roomArchived",
+            "roomUnarchived",
+            "userJoinedRoom",
+            "userLeftRoom",
+        ):
+            payload = data.get(candidate)
+            if payload is None:
+                continue
+            kind = _snake_case(candidate)
+            if candidate == "messagePosted":
+                message = Message.parse(payload.get("message"))
+            else:
+                room_id = payload.get("roomId", "")
+            break
+        return cls(
+            id=data.get("id", ""),
+            created_at=parse_datetime(data.get("createdAt")),
+            actor_id=data.get("actorId", ""),
+            kind=kind,
+            message=message,
+            room_id=room_id,
+        )
+
+
+def _snake_case(name: str) -> str:
+    out: list[str] = []
+    for ch in name:
+        if ch.isupper() and out:
+            out.append("_")
+        out.append(ch.lower())
+    return "".join(out)
+
+
+@dataclass
+class TimelinePage:
+    events: list[TimelineEvent] = field(default_factory=list)
+    start_cursor: str = ""
+    end_cursor: str = ""
+    has_older: bool = False
+    has_newer: bool = False
+    users_by_id: dict[str, User] = field(default_factory=dict)
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> TimelinePage:
+        data = data or {}
+        includes = data.get("includes") or {}
+        users_raw = includes.get("users") or {}
+        users: dict[str, User] = {}
+        for uid, user_data in users_raw.items():
+            parsed_user = User.parse(user_data)
+            if parsed_user is not None:
+                users[uid] = parsed_user
+        return cls(
+            events=[TimelineEvent.parse(e) for e in data.get("events") or []],
+            start_cursor=data.get("startCursor", ""),
+            end_cursor=data.get("endCursor", ""),
+            has_older=bool(data.get("hasOlder", False)),
+            has_newer=bool(data.get("hasNewer", False)),
+            users_by_id=users,
+        )
+
+
+@dataclass
+class FollowedThread:
+    room: RoomSummary | None
+    root_message: Message | None
+    thread: ThreadSummary | None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> FollowedThread:
+        return cls(
+            room=RoomSummary.parse(data.get("room")),
+            root_message=Message.parse(data.get("rootMessage")),
+            thread=ThreadSummary.parse(data.get("thread")),
+        )
+
+
+@dataclass
+class FollowedThreadsPage:
+    threads: list[FollowedThread] = field(default_factory=list)
+    page: Page = field(default_factory=Page)
+    users_by_id: dict[str, User] = field(default_factory=dict)
+
+
+@dataclass
+class Notification:
+    id: str
+    created_at: datetime | None
+    actor: User | None
+    kind: str  # "direct_message" | "mention" | "reply" | "room_message"
+    room: RoomSummary | None = None
+    event_id: str = ""
+    in_reply_to_id: str = ""
+    thread_root_event_id: str | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> Notification:
+        kind = ""
+        room: RoomSummary | None = None
+        event_id = ""
+        in_reply_to_id = ""
+        thread_root: str | None = None
+        for candidate in ("directMessage", "mention", "reply", "roomMessage"):
+            payload = data.get(candidate)
+            if payload is None:
+                continue
+            kind = _snake_case(candidate)
+            room = RoomSummary.parse(payload.get("room"))
+            event_id = payload.get("eventId", "")
+            in_reply_to_id = payload.get("inReplyToId", "") if candidate == "reply" else ""
+            thread_root = payload.get("threadRootEventId")
+            break
+        return cls(
+            id=data.get("id", ""),
+            created_at=parse_datetime(data.get("createdAt")),
+            actor=User.parse(data.get("actor")),
+            kind=kind,
+            room=room,
+            event_id=event_id,
+            in_reply_to_id=in_reply_to_id,
+            thread_root_event_id=thread_root,
+        )
+
+
+@dataclass
+class NotificationsPage:
+    notifications: list[Notification] = field(default_factory=list)
+    page: Page = field(default_factory=Page)
+
+
+@dataclass
+class NotificationPreference:
+    level: NotificationLevel = NotificationLevel.UNSPECIFIED
+    effective_level: NotificationLevel = NotificationLevel.UNSPECIFIED
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> NotificationPreference:
+        data = data or {}
+        return cls(
+            level=_parse_enum(
+                NotificationLevel, data.get("level"), NotificationLevel.UNSPECIFIED
+            ),  # type: ignore[arg-type]
+            effective_level=_parse_enum(
+                NotificationLevel,
+                data.get("effectiveLevel"),
+                NotificationLevel.UNSPECIFIED,
+            ),  # type: ignore[arg-type]
+        )
+
+
+@dataclass
+class Asset:
+    id: str
+    filename: str
+    content_type: str
+    size: int
+    width: int = 0
+    height: int = 0
+    asset_url: AssetUrl | None = None
+    thumbnail_asset_url: AssetUrl | None = None
+    video_processing: VideoProcessing | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> Asset | None:
+        if not data:
+            return None
+        return cls(
+            id=data.get("id", ""),
+            filename=data.get("filename", ""),
+            content_type=data.get("contentType", ""),
+            size=int(data.get("size", 0)),
+            width=int(data.get("width", 0)),
+            height=int(data.get("height", 0)),
+            asset_url=AssetUrl.parse(data.get("assetUrl")),
+            thumbnail_asset_url=AssetUrl.parse(data.get("thumbnailAssetUrl")),
+            video_processing=VideoProcessing.parse(data.get("videoProcessing")),
+        )
+
+
+@dataclass
+class ImageTransformOptions:
+    width: int
+    height: int
+    fit: ImageFitMode = ImageFitMode.UNSPECIFIED
+
+    def to_wire(self) -> dict[str, Any]:
+        return {
+            "width": self.width,
+            "height": self.height,
+            "fit": self.fit.value,
+        }
+
+
+@dataclass
+class ActiveCallParticipant:
+    user: User | None = None
+    joined_at: datetime | None = None
+    call_id: str = ""
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> ActiveCallParticipant:
+        return cls(
+            user=User.parse(data.get("user")),
+            joined_at=parse_datetime(data.get("joinedAt")),
+            call_id=data.get("callId", ""),
+        )
+
+
+@dataclass
+class ActiveCall:
+    call_id: str
+    room: RoomSummary | None
+    participants: list[ActiveCallParticipant] = field(default_factory=list)
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> ActiveCall:
+        return cls(
+            call_id=data.get("callId", ""),
+            room=RoomSummary.parse(data.get("room")),
+            participants=[
+                ActiveCallParticipant.parse(p) for p in data.get("participants") or []
+            ],
+        )
+
+
+# --- Roles ----------------------------------------------------------------
+
+
+@dataclass
+class Role:
+    name: str
+    display_name: str = ""
+    description: str = ""
+    is_system: bool = False
+    position: int = 0
+    pingable: bool = False
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> Role | None:
+        if not data:
+            return None
+        return cls(
+            name=data.get("name", ""),
+            display_name=data.get("displayName", ""),
+            description=data.get("description", ""),
+            is_system=bool(data.get("isSystem", False)),
+            position=int(data.get("position", 0)),
+            pingable=bool(data.get("pingable", False)),
+        )
+
+
+@dataclass
+class AdminRole:
+    role: Role | None
+    permissions: list[str] = field(default_factory=list)
+    permission_denials: list[str] = field(default_factory=list)
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> AdminRole | None:
+        if not data:
+            return None
+        return cls(
+            role=Role.parse(data.get("role")),
+            permissions=list(data.get("permissions") or []),
+            permission_denials=list(data.get("permissionDenials") or []),
+        )
+
+
+# --- Asset uploads --------------------------------------------------------
+
+
+@dataclass
+class AssetUpload:
+    upload_id: str
+    room_id: str
+    status: AssetUploadStatus = AssetUploadStatus.UNSPECIFIED
+    committed_offset: int = 0
+    size: int = 0
+    max_chunk_size: int = 0
+    sha256: str = ""
+    expires_at: datetime | None = None
+    asset_id: str = ""
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> AssetUpload | None:
+        if not data:
+            return None
+        return cls(
+            upload_id=data.get("uploadId", ""),
+            room_id=data.get("roomId", ""),
+            status=_parse_enum(
+                AssetUploadStatus,
+                data.get("status"),
+                AssetUploadStatus.UNSPECIFIED,
+            ),  # type: ignore[arg-type]
+            committed_offset=int(data.get("committedOffset", 0)),
+            size=int(data.get("size", 0)),
+            max_chunk_size=int(data.get("maxChunkSize", 0)),
+            sha256=data.get("sha256", ""),
+            expires_at=parse_datetime(data.get("expiresAt")),
+            asset_id=data.get("assetId", ""),
+        )
+
+
+# --- External identity ----------------------------------------------------
+
+
+@dataclass
+class ExternalIdentityProvider:
+    provider: ProviderMetadata | None
+    link_url: str = ""
+    linked: bool = False
+    linked_identity_subject_hash: str = ""
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> ExternalIdentityProvider:
+        provider_data = data.get("provider")
+        provider = ProviderMetadata.parse(provider_data) if provider_data else None
+        return cls(
+            provider=provider,
+            link_url=data.get("linkUrl", ""),
+            linked=bool(data.get("linked", False)),
+            linked_identity_subject_hash=data.get("linkedIdentitySubjectHash", ""),
+        )
+
+
+@dataclass
+class LinkedExternalIdentity:
+    provider_id: str
+    provider_type: str = ""
+    provider_label: str = ""
+    subject_hash: str = ""
+
+    @classmethod
+    def parse(cls, data: dict[str, Any]) -> LinkedExternalIdentity:
+        return cls(
+            provider_id=data.get("providerId", ""),
+            provider_type=data.get("providerType", ""),
+            provider_label=data.get("providerLabel", ""),
+            subject_hash=data.get("subjectHash", ""),
+        )
+
+
+# --- Admin: server / members ---------------------------------------------
+
+
+@dataclass
+class ServerConfig:
+    server_name: str = ""
+    description: str = ""
+    motd: str = ""
+    welcome_message: str = ""
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> ServerConfig:
+        data = data or {}
+        return cls(
+            server_name=data.get("serverName", ""),
+            description=data.get("description", ""),
+            motd=data.get("motd", ""),
+            welcome_message=data.get("welcomeMessage", ""),
+        )
+
+
+@dataclass
+class AdminMember:
+    user: User | None
+    roles: list[str] = field(default_factory=list)
+    created_at: datetime | None = None
+    has_verified_email: bool = False
+    verified_emails: list[str] = field(default_factory=list)
+    viewer_can_delete_account: bool = False
+    last_login_change: datetime | None = None
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> AdminMember | None:
+        if not data:
+            return None
+        return cls(
+            user=User.parse(data.get("user")),
+            roles=list(data.get("roles") or []),
+            created_at=parse_datetime(data.get("createdAt")),
+            has_verified_email=bool(data.get("hasVerifiedEmail", False)),
+            verified_emails=list(data.get("verifiedEmails") or []),
+            viewer_can_delete_account=bool(data.get("viewerCanDeleteAccount", False)),
+            last_login_change=parse_datetime(data.get("lastLoginChange")),
+        )
+
+
+# --- Admin: room layout --------------------------------------------------
+
+
+@dataclass
+class AdminRoomLayoutGroup:
+    id: str
+    name: str
+    description: str = ""
+    rooms: list[Room] = field(default_factory=list)
+    sidebar_links: list[SidebarLink] = field(default_factory=list)
+    can_create_room: bool = False
+
+    @classmethod
+    def parse(cls, data: dict[str, Any] | None) -> AdminRoomLayoutGroup | None:
+        if not data:
+            return None
+        rooms: list[Room] = []
+        links: list[SidebarLink] = []
+        for item in data.get("items") or []:
+            room = Room.parse(item.get("room"))
+            if room is not None:
+                rooms.append(room)
+            sl = item.get("sidebarLink")
+            if sl:
+                links.append(
+                    SidebarLink(
+                        id=sl.get("id", ""),
+                        label=sl.get("label", ""),
+                        url=sl.get("url", ""),
+                    )
+                )
+        return cls(
+            id=data.get("id", ""),
+            name=data.get("name", ""),
+            description=data.get("description", ""),
+            rooms=rooms,
+            sidebar_links=links,
+            can_create_room=bool(data.get("canCreateRoom", False)),
+        )

+ 38 - 0
vendor_chattolib.sh

@@ -0,0 +1,38 @@
+#!/bin/bash
+# Vendoring script for hermes-chatto-plugin
+# Downloads dependencies from pyproject.toml using uv and vendors them into chattolib_vendor/
+# Usage: ./vendor_chattolib.sh
+
+set -euo pipefail
+
+PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+echo "Vendoring dependencies from pyproject.toml using uv..."
+
+# Clean up any existing vendored dependencies
+rm -rf "${PLUGIN_DIR}/vendor"
+
+# Create target directory
+mkdir -p "${PLUGIN_DIR}/vendor"
+
+# Create a temporary virtual environment
+uv venv .venv --clear
+
+# Set environment variables for the venv
+# shellcheck disable=SC1091
+source .venv/bin/activate
+cd "${PLUGIN_DIR}"
+
+uv pip install chattolib --target vendor-tmp
+
+cp -r vendor-tmp/chattolib* "${PLUGIN_DIR}/vendor/"
+
+# Create __init__.py to make it importable
+cat > "${PLUGIN_DIR}/vendor/chattolib/__init__.py" << 'EOF'
+# Vendored chattolib
+EOF
+
+rm -rf vendor-tmp/
+
+echo "✓ Dependencies vendored successfully to ${PLUGIN_DIR}/vendor/chattolib/"
+echo "do 'git add vendor/' now or later"

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません