|
@@ -70,7 +70,7 @@ generated protobuf bindings.
|
|
|
- Enums on the wire are the **full enum value name** as a string, e.g. `"PRESENCE_STATUS_ONLINE"`. `types._parse_enum` also accepts the short tail (`"ONLINE"`) for robustness.
|
|
- Enums on the wire are the **full enum value name** as a string, e.g. `"PRESENCE_STATUS_ONLINE"`. `types._parse_enum` also accepts the short tail (`"ONLINE"`) for robustness.
|
|
|
- Timestamps are RFC 3339 strings (usually `Z`-suffixed). Use `types.parse_datetime` / `types.format_datetime` helpers.
|
|
- Timestamps are RFC 3339 strings (usually `Z`-suffixed). Use `types.parse_datetime` / `types.format_datetime` helpers.
|
|
|
- `optional` scalars: absent from JSON when unset. A present empty string is distinct.
|
|
- `optional` scalars: absent from JSON when unset. A present empty string is distinct.
|
|
|
-- `bytes`: base64-encoded strings (used by `MyAccountService.UploadAvatar` via the `ImageUpload` message).
|
|
|
|
|
|
|
+- `bytes`: base64-encoded strings (used by `UserService.UploadAvatar` via the `ImageUpload` message).
|
|
|
- Errors: non-2xx HTTP status with a JSON body of `{"code": "...", "message": "...", "details": [...]}`. `ChattoConnectError` surfaces `code`, `message`, `status_code`, `details`.
|
|
- Errors: non-2xx HTTP status with a JSON body of `{"code": "...", "message": "...", "details": [...]}`. `ChattoConnectError` surfaces `code`, `message`, `status_code`, `details`.
|
|
|
|
|
|
|
|
### Auth
|
|
### Auth
|
|
@@ -91,7 +91,8 @@ to its grants.
|
|
|
| Discovery | `chatto.discovery.v1.ServerDiscoveryService` | `GetServer` (public), `ListNeighbors` (public), `ListNeighborhoodServers` (public — the Neighborhood the server discovered in the background; `NeighborhoodServer { origin, profile, direct_neighbor, recommended_by_origins }` + `refreshed_at`) |
|
|
| Discovery | `chatto.discovery.v1.ServerDiscoveryService` | `GetServer` (public), `ListNeighbors` (public), `ListNeighborhoodServers` (public — the Neighborhood the server discovered in the background; `NeighborhoodServer { origin, profile, direct_neighbor, recommended_by_origins }` + `refreshed_at`) |
|
|
|
| Server | `ServerService` | `GetMotd`, `GetRuntimeConfig` |
|
|
| Server | `ServerService` | `GetMotd`, `GetRuntimeConfig` |
|
|
|
| Viewer | `ViewerService` | `GetViewer` |
|
|
| Viewer | `ViewerService` | `GetViewer` |
|
|
|
-| My account | `MyAccountService` | `UpdateProfile`, `UpdateSettings`, `SetPresence` (legacy live report), `GetPresencePreference`, `SetPresencePreference`, `RefreshPresence`, `SetCustomStatus`, `DeleteCustomStatus`, `ChangePassword`, `DeleteMyAccount` (avatar upload was removed in 0.5.0b4) |
|
|
|
|
|
|
|
+| My account | `MyAccountService` | `UpdateSettings`, `SetPresence` (legacy live report), `GetPresencePreference`, `SetPresencePreference`, `RefreshPresence`, `SetCustomStatus`, `DeleteCustomStatus`, `ChangePassword`, `DeleteMyAccount` (avatar upload was removed in 0.5.0b4; `UpdateProfile` moved to `UserService` in 0.5.0b9) |
|
|
|
|
|
+| User profiles | `UserService` | `UpdateUserProfile` (self or privileged — the single profile-edit RPC since 0.5.0b9; `display_name`/`login`/`bio` + inferred `update_mask`), `ListUsers`/`GetUser`/`BatchGetUsers` (directory), `UploadAvatar`/`DeleteAvatar` |
|
|
|
| Roles | `RoleService` | `ListRoles`, `GetRole`, `BatchGetRoles` |
|
|
| Roles | `RoleService` | `ListRoles`, `GetRole`, `BatchGetRoles` |
|
|
|
| Room directory | `RoomDirectoryService` | `ListRooms`, `ListRoomGroups`, `GetRoomGroup`, `BatchGetRoomGroups`, `GetRoom`, `BatchGetRooms` |
|
|
| Room directory | `RoomDirectoryService` | `ListRooms`, `ListRoomGroups`, `GetRoomGroup`, `BatchGetRoomGroups`, `GetRoom`, `BatchGetRooms` |
|
|
|
| Rooms | `RoomService` | `CreateRoom`, `UpdateRoom`, `ArchiveRoom`, `UnarchiveRoom`, `JoinRoom`, `JoinRoomGroup`, `StartDM`, `LeaveRoom`, `AddMember`, `RemoveMember`, `ListMembers`, `GetMember`, `BatchGetMembers`, `RemoveUser`, `LiftSuspension`, `ListSuspensions`, `RefreshTypingIndicator`, `GetRoomEvents`, `GetRoomEventsAround`, `MarkRoomAsRead`, `ListRoomAttachments` |
|
|
| Rooms | `RoomService` | `CreateRoom`, `UpdateRoom`, `ArchiveRoom`, `UnarchiveRoom`, `JoinRoom`, `JoinRoomGroup`, `StartDM`, `LeaveRoom`, `AddMember`, `RemoveMember`, `ListMembers`, `GetMember`, `BatchGetMembers`, `RemoveUser`, `LiftSuspension`, `ListSuspensions`, `RefreshTypingIndicator`, `GetRoomEvents`, `GetRoomEventsAround`, `MarkRoomAsRead`, `ListRoomAttachments` |
|
|
@@ -106,7 +107,7 @@ to its grants.
|
|
|
| Asset uploads | `AssetUploadService` | `CreateUpload`, `UploadChunk`, `GetUpload`, `CompleteUpload`, `CancelUpload`. `upload_attachment(room, path)` helper computes SHA-256, chunks, and completes in one call. |
|
|
| Asset uploads | `AssetUploadService` | `CreateUpload`, `UploadChunk`, `GetUpload`, `CompleteUpload`, `CancelUpload`. `upload_attachment(room, path)` helper computes SHA-256, chunks, and completes in one call. |
|
|
|
| Admin: server | `chatto.admin.v1.AdminServerService` | `GetServerConfig`, `UpdateServerConfig`, `UploadServerLogo`, `DeleteServerLogo`, `UploadServerBanner`, `DeleteServerBanner`, `GetServerSecurityConfig`, `UpdateBlockedUsernames` |
|
|
| Admin: server | `chatto.admin.v1.AdminServerService` | `GetServerConfig`, `UpdateServerConfig`, `UploadServerLogo`, `DeleteServerLogo`, `UploadServerBanner`, `DeleteServerBanner`, `GetServerSecurityConfig`, `UpdateBlockedUsernames` |
|
|
|
| Admin: room layout | `chatto.admin.v1.AdminRoomLayoutService` | `ListRoomGroups`, `Create/Update/Delete/ReorderRoomGroup(s)`, `MoveRoomGroup`, `MoveRoomToGroup`, `ReorderSidebarItemsInGroup`, `MoveSidebarItem`, `Create/Update/Delete/MoveSidebarLink(ToGroup)` |
|
|
| Admin: room layout | `chatto.admin.v1.AdminRoomLayoutService` | `ListRoomGroups`, `Create/Update/Delete/ReorderRoomGroup(s)`, `MoveRoomGroup`, `MoveRoomToGroup`, `ReorderSidebarItemsInGroup`, `MoveSidebarItem`, `Create/Update/Delete/MoveSidebarLink(ToGroup)` |
|
|
|
-| Admin: users | `chatto.admin.v1.AdminUserService` | `ListMembers`, `GetMember`, `BatchGetMembers`, `AssignRole`, `RevokeRole`, `UpdateUser`, `UpdateUserPassword`, `ClearUsernameCooldown`, `DeleteUser` |
|
|
|
|
|
|
|
+| Admin: users | `chatto.admin.v1.AdminUserService` | `ListMembers`, `GetMember`, `BatchGetMembers`, `AssignRole`, `RevokeRole`, `UpdateUserPassword`, `ClearUsernameCooldown`, `DeleteUser` (the old `UpdateUser` admin RPC was removed in 0.5.0b9 — privileged profile edits go through `UserService.UpdateUserProfile`) |
|
|
|
| Admin: roles | `chatto.admin.v1.AdminRoleService` | `ListRoles`, `GetRole`, `CreateRole`, `UpdateRole`, `DeleteRole`, `ReorderRoles` |
|
|
| Admin: roles | `chatto.admin.v1.AdminRoleService` | `ListRoles`, `GetRole`, `CreateRole`, `UpdateRole`, `DeleteRole`, `ReorderRoles` |
|
|
|
| Admin: event log | `chatto.admin.v1.AdminEventLogService` | `ListEvents`, `ListEventTypes`, `GetEvent` (raw response) |
|
|
| Admin: event log | `chatto.admin.v1.AdminEventLogService` | `ListEvents`, `ListEventTypes`, `GetEvent` (raw response) |
|
|
|
| Admin: diagnostics | `chatto.admin.v1.AdminDiagnosticsService` | `GetSystemInfo` (raw response) |
|
|
| Admin: diagnostics | `chatto.admin.v1.AdminDiagnosticsService` | `GetSystemInfo` (raw response) |
|
|
@@ -137,6 +138,7 @@ to its grants.
|
|
|
- **0.5.0b6 split presence into a *saved preference* and a *live report*.** `SetPresence` is now the legacy, transient live report (still rejects `OFFLINE`/`UNSPECIFIED`); a saved choice takes precedence over it, even a `user_selected` one. The new pair is `GetPresencePreference`/`SetPresencePreference` (choice for every device on the server; `OFFLINE` = "Appear Offline" and *is* allowed there; a stale `expected_revision` returns `ABORTED`) plus `RefreshPresence` for 30-second liveness. `Message` also gained `viewer_state` (`MessageViewerState.can_reply_in_thread`), resolved per viewer even before a thread exists.
|
|
- **0.5.0b6 split presence into a *saved preference* and a *live report*.** `SetPresence` is now the legacy, transient live report (still rejects `OFFLINE`/`UNSPECIFIED`); a saved choice takes precedence over it, even a `user_selected` one. The new pair is `GetPresencePreference`/`SetPresencePreference` (choice for every device on the server; `OFFLINE` = "Appear Offline" and *is* allowed there; a stale `expected_revision` returns `ABORTED`) plus `RefreshPresence` for 30-second liveness. `Message` also gained `viewer_state` (`MessageViewerState.can_reply_in_thread`), resolved per viewer even before a thread exists.
|
|
|
- **0.5.0b7 replaced the room ban triad with a *suspension* triad (breaking).** `BanMember`/`UnbanMember`/`ListBans` and the `RoomBan` message are gone; they are now `RemoveUser` (remove a member with a required reason; the optional `oneof suspension` is either `suspension_expires_at` or `suspend_indefinitely` — at most one, and Universal rooms require one; DM rooms are excluded), `LiftSuspension` (no-op success when no active suspension), and `ListSuspensions` (returns `repeated RoomSuspension suspensions`, page newest-first). The client methods are `remove_user(...)` / `lift_suspension(...)` / `list_suspensions(...)` and the dataclass is `RoomSuspension` (the ban's `expires_at` field name is kept). Both `RemoveUser` and `LiftSuspension` require `room.remove-member` at server scope.
|
|
- **0.5.0b7 replaced the room ban triad with a *suspension* triad (breaking).** `BanMember`/`UnbanMember`/`ListBans` and the `RoomBan` message are gone; they are now `RemoveUser` (remove a member with a required reason; the optional `oneof suspension` is either `suspension_expires_at` or `suspend_indefinitely` — at most one, and Universal rooms require one; DM rooms are excluded), `LiftSuspension` (no-op success when no active suspension), and `ListSuspensions` (returns `repeated RoomSuspension suspensions`, page newest-first). The client methods are `remove_user(...)` / `lift_suspension(...)` / `list_suspensions(...)` and the dataclass is `RoomSuspension` (the ban's `expires_at` field name is kept). Both `RemoveUser` and `LiftSuspension` require `room.remove-member` at server scope.
|
|
|
- **0.5.0b8 added the public `ServerDiscoveryService.ListNeighborhoodServers` RPC** (no session needed; the server caches background discovery, refreshed at least hourly). `NeighborhoodServer.profile` is a `ServerPublicProfile` **without** the welcome message, and its logo/banner URLs are server-relative paths of copies on the *called* server — resolve them against that server's origin, not the neighbor's. `ListFollowedThreadsRequest.unread_only` filters to followed threads with unread replies (older servers ignore the field and return everything; the page total then counts only the filtered set).
|
|
- **0.5.0b8 added the public `ServerDiscoveryService.ListNeighborhoodServers` RPC** (no session needed; the server caches background discovery, refreshed at least hourly). `NeighborhoodServer.profile` is a `ServerPublicProfile` **without** the welcome message, and its logo/banner URLs are server-relative paths of copies on the *called* server — resolve them against that server's origin, not the neighbor's. `ListFollowedThreadsRequest.unread_only` filters to followed threads with unread replies (older servers ignore the field and return everything; the page total then counts only the filtered set).
|
|
|
|
|
+- **0.5.0b9 consolidated all public-profile edits into a new `chatto.api.v1.UserService.UpdateUserProfile` RPC (breaking for both edit paths).** `MyAccountService.UpdateProfile` was removed and `chatto.admin.v1.AdminUserService.UpdateUser` was removed; the new RPC takes a required `user_id` plus `display_name`/`login`/`bio` (an inferred `update_mask`) and returns just the updated `User` — no admin member row. Self-updates need no extra authority; editing another human requires `user.manage-accounts` (and, for a bot target, ownership of the bot, `user.manage-accounts`, or `bot.manage`), and a `user.manage-accounts` caller bypasses the username-change cooldown without starting one. Client: new `update_user_profile(user_id, ...)` plus a self-service `update_profile(...)` that resolves the caller's id via the viewer snapshot and delegates (same public signature as before, plus `bio`); `admin_update_user(...)` keeps its name/shape but now delegates to the same RPC and its second return value is always `None` (the removed response no longer carries an `AdminMember`) — re-fetch with `admin_get_member()` when the row is needed. `User.bio` is now documented as Markdown. The vendored `user_service.proto` also newly carries `ListUsers`/`GetUser`/`BatchGetUsers` (directory) and `UploadAvatar`/`DeleteAvatar`, for which chattolib still ships no wrappers.
|
|
|
- **Never regenerate protos from `chattocorp/chatto@main`.** `scripts/generate_pb.sh` defaults to a tag derived from `pyproject.toml`: `v<base>` for finals, and `v<base>-<kind>.<n>` for PEP 440 pre-releases (`0.5.0b6` → `v0.5.0-beta.6`), probing candidates with `git ls-remote` (exact ref match; the REST `/tags/{name}` endpoint 404s on lightweight tags). Override with `CHATTO_REF=<tag>` only when you know the deployed server has caught up. chattolib 0.4.19 shipped once from `main` and broke realtime for every downstream client because Chatto's main had a protocol-v2 rewrite that the deployed 0.4.19 server did not speak.
|
|
- **Never regenerate protos from `chattocorp/chatto@main`.** `scripts/generate_pb.sh` defaults to a tag derived from `pyproject.toml`: `v<base>` for finals, and `v<base>-<kind>.<n>` for PEP 440 pre-releases (`0.5.0b6` → `v0.5.0-beta.6`), probing candidates with `git ls-remote` (exact ref match; the REST `/tags/{name}` endpoint 404s on lightweight tags). Override with `CHATTO_REF=<tag>` only when you know the deployed server has caught up. chattolib 0.4.19 shipped once from `main` and broke realtime for every downstream client because Chatto's main had a protocol-v2 rewrite that the deployed 0.4.19 server did not speak.
|
|
|
|
|
|
|
|
### Known bugs
|
|
### Known bugs
|