codex-mobile-bridge 0.2.6

Remote bridge and service manager for codex-mobile.
Documentation
use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::directory::{DirectoryBookmarkRecord, DirectoryHistoryRecord};
use super::runtime::{ApiError, RuntimeStatusSnapshot, RuntimeSummary};
use super::thread::PendingServerRequestRecord;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PersistedEvent {
    pub seq: i64,
    pub event_type: String,
    pub runtime_id: Option<String>,
    pub thread_id: Option<String>,
    pub payload: Value,
    pub created_at_ms: i64,
}

#[derive(Debug, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ClientEnvelope {
    Hello {
        device_id: String,
        last_ack_seq: Option<i64>,
    },
    Request {
        request_id: String,
        action: String,
        #[serde(default)]
        payload: Value,
    },
    AckEvents {
        last_seq: i64,
    },
    Ping,
}

#[derive(Debug, Serialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ServerEnvelope {
    Hello {
        bridge_version: String,
        protocol_version: u32,
        runtime: RuntimeStatusSnapshot,
        runtimes: Vec<RuntimeSummary>,
        directory_bookmarks: Vec<DirectoryBookmarkRecord>,
        directory_history: Vec<DirectoryHistoryRecord>,
        pending_requests: Vec<PendingServerRequestRecord>,
    },
    Response {
        request_id: String,
        success: bool,
        #[serde(skip_serializing_if = "Option::is_none")]
        data: Option<Value>,
        #[serde(skip_serializing_if = "Option::is_none")]
        error: Option<ApiError>,
    },
    Event {
        seq: i64,
        event_type: String,
        #[serde(skip_serializing_if = "Option::is_none")]
        runtime_id: Option<String>,
        #[serde(skip_serializing_if = "Option::is_none")]
        thread_id: Option<String>,
        payload: Value,
    },
    Pong {
        server_time_ms: i64,
    },
}

pub fn ok_response(request_id: String, data: Value) -> ServerEnvelope {
    ServerEnvelope::Response {
        request_id,
        success: true,
        data: Some(data),
        error: None,
    }
}

pub fn event_envelope(event: PersistedEvent) -> ServerEnvelope {
    ServerEnvelope::Event {
        seq: event.seq,
        event_type: event.event_type,
        runtime_id: event.runtime_id,
        thread_id: event.thread_id,
        payload: event.payload,
    }
}