| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- syntax = "proto3";
- package chatto.realtime.v1;
- import "chatto/api/v1/member_directory.proto";
- import "chatto/api/v1/room_directory.proto";
- import "chatto/api/v1/server.proto";
- import "chatto/api/v1/voice_calls.proto";
- import "chatto/realtime/v1/events.proto";
- import "google/protobuf/duration.proto";
- import "google/protobuf/timestamp.proto";
- // Starts one authorized public realtime subscription.
- //
- // The client sends this message as the first binary WebSocket message. The
- // client does not send more application messages on the socket.
- message RealtimeSubscribe {
- // Behavioral protocol version requested by the client. The only supported
- // version is 4.
- uint32 protocol_version = 1;
- // Optional bearer token. When present, it takes precedence over cookie auth.
- optional string bearer_token = 2;
- // Opaque cursor from a previously received replayable event or `caught_up`
- // frame. A usable cursor receives bounded authorized events after
- // that position. Cursors expire 15 minutes after issue.
- optional string resume_cursor = 3;
- // Required fallback when the cursor is absent or cannot resume safely.
- RealtimeInitialState initial_state = 4;
- }
- // Server-to-client frame for Chatto's protobuf WebSocket realtime protocol.
- message RealtimeServerFrame {
- oneof frame {
- // One authorized public event copy.
- RealtimeEvent event = 1;
- // Application-level heartbeat used for liveness checks.
- RealtimeHeartbeat heartbeat = 2;
- // Server-requested close with reconnect guidance.
- RealtimeClose close = 3;
- // Confirms that recovery reached the live-stream boundary.
- RealtimeCaughtUp caught_up = 4;
- // One exact authorized server-content snapshot.
- RealtimeSnapshot snapshot = 5;
- }
- }
- // Startup behavior when a subscription cannot resume from its cursor.
- enum RealtimeInitialState {
- // Invalid value. The server rejects subscriptions that use it.
- REALTIME_INITIAL_STATE_UNSPECIFIED = 0;
- // Start at the current event boundary without sending current resources.
- REALTIME_INITIAL_STATE_LIVE_ONLY = 1;
- // Send an exact authorized snapshot before later public events.
- REALTIME_INITIAL_STATE_SNAPSHOT = 2;
- }
- // One authorized snapshot of the current bounded server content.
- //
- // The server sends at most one snapshot before `caught_up`. The client must
- // discard the snapshot if the socket closes before `caught_up`. List values
- // replace the complete local family.
- // Large and paginated resources, such as message history, are not part of the
- // snapshot and remain available through ConnectRPC.
- message RealtimeSnapshot {
- // Current public server profile.
- chatto.api.v1.ServerPublicProfile server = 1;
- // All rooms visible to the caller at the snapshot boundary.
- repeated chatto.api.v1.RoomWithViewerState rooms = 2;
- // All room groups visible to the caller at the snapshot boundary.
- repeated chatto.api.v1.RoomGroup room_groups = 3;
- // The viewer and public users referenced by another snapshot family.
- repeated chatto.api.v1.DirectoryMember users = 4;
- // All active calls visible to the caller at the snapshot boundary.
- repeated chatto.api.v1.ActiveCall active_calls = 5;
- }
- // Confirms that recovery is complete and live delivery has begun.
- //
- // Clients can retain `cursor` after they apply every preceding event.
- message RealtimeCaughtUp {
- // Opaque cursor at the recovery-to-live handoff boundary.
- string cursor = 1;
- // Actual recovery result, including a successful replay with no events.
- RealtimeRecovery recovery = 2;
- }
- // How the server reached the live-delivery boundary.
- enum RealtimeRecovery {
- // Invalid value. The server always supplies a recovery result.
- REALTIME_RECOVERY_UNSPECIFIED = 0;
- // The requested cursor was accepted and all available authorized events followed it.
- REALTIME_RECOVERY_RESUMED = 1;
- // The server sent a replacement snapshot.
- REALTIME_RECOVERY_SNAPSHOT = 2;
- // The server started at the current boundary without past events or resources.
- REALTIME_RECOVERY_LIVE_ONLY = 3;
- }
- // One authorized public event with its optional cursor.
- //
- // Each payload uses a realtime-owned public message. The union is the public
- // event catalogue. An internal event that is absent from this union is not
- // part of the realtime API. The server creates a fresh caller-specific value
- // after authorization. An event has a resume cursor when it can be replayed.
- // An event without a cursor is safe to miss, or its state can be restored from
- // a snapshot or a ConnectRPC resource.
- message RealtimeEvent {
- // Universal event identifier (NanoID).
- string id = 1;
- // Time when the source event was created.
- google.protobuf.Timestamp created_at = 2;
- // ID of the user that caused the event. Absence means no user actor.
- optional string actor_id = 3;
- // Opaque cursor safe to retain after this complete event is accepted.
- optional string cursor = 4;
- reserved 35 to 45;
- reserved "room_group_created", "room_group_updated", "room_group_deleted", "room_added_to_group", "room_removed_from_group", "rooms_in_group_reordered", "sidebar_link_added_to_group", "sidebar_link_updated", "sidebar_link_removed_from_group", "sidebar_group_entries_reordered", "room_groups_reordered";
- // Authorized semantic payload.
- oneof event {
- RoomCreatedEvent room_created = 10;
- RoomUpdatedEvent room_updated = 11;
- RoomDeletedEvent room_deleted = 12;
- RoomArchivedEvent room_archived = 13;
- RoomUnarchivedEvent room_unarchived = 14;
- RoomUniversalChangedEvent room_universal_changed = 15;
- RoomSlowModeChangedEvent room_slow_mode_changed = 16;
- RoomThreadingModeChangedEvent room_threading_mode_changed = 17;
- UserJoinedRoomEvent user_joined_room = 18;
- UserLeftRoomEvent user_left_room = 19;
- VoiceCallParticipantJoinedEvent voice_call_participant_joined = 20;
- VoiceCallParticipantLeftEvent voice_call_participant_left = 21;
- VoiceCallStartedEvent voice_call_started = 22;
- VoiceCallEndedEvent voice_call_ended = 23;
- MessagePostedEvent message_posted = 24;
- MessageEditedEvent message_edited = 25;
- MessageRetractedEvent message_retracted = 26;
- MessagePinnedEvent message_pinned = 27;
- MessageUnpinnedEvent message_unpinned = 28;
- ThreadCreatedEvent thread_created = 29;
- AssetProcessingStartedEvent asset_processing_started = 30;
- AssetProcessingSucceededEvent asset_processing_succeeded = 31;
- AssetProcessingFailedEvent asset_processing_failed = 32;
- AssetDeletedEvent asset_deleted = 33;
- ServerMotdChangedEvent server_motd_changed = 34;
- UserAccountCreatedEvent user_account_created = 46;
- UserProfileChangedEvent user_profile_changed = 47;
- UserAccountDeletedEvent user_account_deleted = 48;
- ReactionAddedEvent reaction_added = 49;
- ReactionRemovedEvent reaction_removed = 50;
- ViewerPreferencesChangedEvent viewer_preferences_changed = 51;
- ThreadViewerStateChangedEvent thread_viewer_state_changed = 52;
- ServerProfileChangedEvent server_profile_changed = 53;
- UserTypingEvent user_typing = 54;
- PresenceChangedEvent presence_changed = 55;
- NotificationOccurrencesChangedEvent notification_occurrences_changed = 56;
- NotificationUnreadStateChangedEvent notification_unread_state_changed = 57;
- RoomReadStateChangedEvent room_read_state_changed = 58;
- RoomLayoutChangedEvent room_layout_changed = 59;
- RoleCreatedEvent role_created = 60;
- RoleUpdatedEvent role_updated = 61;
- RoleDeletedEvent role_deleted = 62;
- RolesReorderedEvent roles_reordered = 63;
- RoleAssignedEvent role_assigned = 64;
- RoleRevokedEvent role_revoked = 65;
- RolePermissionsChangedEvent role_permissions_changed = 66;
- ViewerPermissionsChangedEvent viewer_permissions_changed = 67;
- ViewerPresencePreferenceChangedEvent viewer_presence_preference_changed = 68;
- }
- }
- // Application-level heartbeat.
- message RealtimeHeartbeat {
- // Fresh resume cursor for the latest replay boundary delivered on this
- // socket. A client can retain it only after all earlier frames have been
- // applied.
- optional string cursor = 1;
- }
- // Stable server-requested close category.
- enum RealtimeCloseCode {
- // Invalid or unknown close code.
- REALTIME_CLOSE_CODE_UNSPECIFIED = 0;
- // The subscription message is malformed or contains an invalid value.
- REALTIME_CLOSE_CODE_INVALID_REQUEST = 1;
- // The requested behavioral protocol version is not supported.
- REALTIME_CLOSE_CODE_UNSUPPORTED_PROTOCOL = 2;
- // The server cannot accept or continue a realtime session at present.
- REALTIME_CLOSE_CODE_TEMPORARILY_UNAVAILABLE = 3;
- // The caller is no longer authenticated.
- REALTIME_CLOSE_CODE_AUTHENTICATION_REQUIRED = 4;
- // The caller must renew its session before reconnecting.
- REALTIME_CLOSE_CODE_SESSION_RENEWAL_REQUIRED = 5;
- // The client must discard its cursor and synchronize current state again.
- REALTIME_CLOSE_CODE_RESYNC_REQUIRED = 6;
- // The user's session ended and the client must return to sign-in.
- REALTIME_CLOSE_CODE_SESSION_TERMINATED = 7;
- // Privileged mode expired. Reconnect and refresh effective viewer and room permissions.
- REALTIME_CLOSE_CODE_PRIVILEGED_MODE_EXPIRED = 8;
- }
- // Close instruction sent before the socket closes when possible.
- message RealtimeClose {
- // Stable machine-readable close code.
- RealtimeCloseCode code = 1;
- // Safe human-readable close message.
- string message = 2;
- // Whether the client should reconnect automatically.
- bool reconnect = 3;
- // Suggested delay before reconnect.
- google.protobuf.Duration retry_after = 4;
- }
|