use serde_json::Value;
pub const TRIGGER_SOURCES: [&str; 9] = ["webhook", "manual", "schedule", "function", "mcp", "error", "room", "socket", "topic"];
pub const REQUEST_ONLY_KEYS: [&str; 3] = ["headers", "cookies", "auth"];
const REQUEST_ONLY_ROOT_KEYS: [&str; 2] = ["headers", "cookies"];
pub fn browser_state(state: &Value) -> Value {
let mut state = state.clone();
if let Some(map) = state.as_object_mut() {
for key in REQUEST_ONLY_ROOT_KEYS {
map.remove(key);
}
for source in TRIGGER_SOURCES {
if let Some(Value::Object(envelope)) = map.get_mut(source) {
for key in REQUEST_ONLY_KEYS {
envelope.remove(key);
}
}
}
}
state
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::browser_state;
#[test]
fn the_request_never_reaches_the_browser_and_the_page_data_does() {
let state = json!({
"headers": { "x-forwarded-for": "203.0.113.7, 10.1.2.3", "host": "site-a.example" },
"cookies": { "session": "s1" },
"auth": { "sub": "user-1" },
"route": "/book",
"webhook": { "body": { "title": "Demo" }, "query": { "q": "1" }, "headers": { "x-real-ip": "10.1.2.3" }, "cookies": { "s": "x" }, "auth": { "sub": "user-1", "email": "a@example.com" } },
"room": { "message": "hi", "auth": { "sub": "user-2" } },
"query": { "rows": [{ "headers": "a column, not a request" }] },
});
let browser = browser_state(&state);
assert!(browser.get("headers").is_none() && browser.get("cookies").is_none(), "{browser}");
assert_eq!(browser["webhook"], json!({ "body": { "title": "Demo" }, "query": { "q": "1" } }));
assert_eq!(browser["room"], json!({ "message": "hi" }));
assert_eq!(browser["query"], state["query"], "a node's answer is the author's to render");
assert_eq!(browser["auth"], json!({ "sub": "user-1" }), "the root auth is already cut to its public claims");
assert_eq!(browser["route"], "/book");
assert_eq!(state["headers"]["host"], "site-a.example", "the server's copy is untouched");
}
}