What happened on the site, kept whole: one Event per request worth
keeping, with everything the request said about itself and everything
Cloudflare said about where it came from. The archive writes each one as
a row of events (the owner, 2026-10-03: "anywhere in the app where we
are dropping data we should plug", and of visitors, "Everything, linked").
Nothing here is shown on the site. It is for the owner's admin backend, which reads the archive's tables.
COLUMNS and values are the table's shape: the archive's migration
spells the same columns out, and a test there holds the two together.
The cookie that says when this browser was last counted as a visit, in Unix milliseconds.
18pub const VISIT: &str = "lmjtfy_visit";
A visit ends after this long with no page viewed.
What Cloudflare says of where a request came from (request.cf), and
the address it came from. All of it may be missing: a dev server has
none.
The region's code within its country (ISO 3166-2 without the
country: CA for California), which a map's outlines are found by;
the name alone is spelled differently from one source to the next.
The continent's two letters, and the metro area's code where Cloudflare has one (the United States).
What kind of bot Cloudflare has verified the request as from ("Search Engine Crawler", "AI Crawler"), if any.
The network's number, and whose it is: the visitor's ISP.
The Cloudflare data centre that took the request.
One thing that happened.
view, answer, gate, vote, more, card, fetch, moved,
live, left, and from the page itself read (how long a page was
looked at, and how far down) and out (a link followed off the site).
The query as it came, the question in a shared link included.
74 pub query: String,
The question typed, asked or voted on, cleaned.
76 pub input: String,
What came of it: how an ask ended, which way a vote went, clone or
pull, shared for a page opened with a question in its link.
79 pub detail: String,
The response's status, or 0 when the event is not a response.
81 pub status: f64,
Requests sent to Jev or the LLM for it, and requests answered from what was kept.
Whether an LLM was needed, 1 or 0.
87 pub llm: f64,
How long it took or lasted, in milliseconds.
89 pub took_ms: f64,
1 on the first page this browser was ever given, its first of the UTC day, and its first in half an hour.
The page that linked here, whole.
96 pub referrer: String,
A campaign the link named (utm_source or ref).
98 pub source: String,
browser, git, bot or other, and for a browser its family,
operating system and mobile or desktop: read from agent, for
grouping.
The browser's id (the lmjtfy_browser cookie), which ties one
browser's events together.
The screen and the window, 1920x1080, as the page says them.
A value of one column.
132impl Event {
The columns of events, after id and at_ms, in the order of
values.
135 pub const COLUMNS: [&str; 45] = [ 136 "what", "method", "host", "path", "query", "input", "detail", "status", "sent", "kept", "llm", "took_ms", "first", "daily", "session", "referrer", 137 "source", "client", "family", "os", "device", "language", "agent", "browser", "ip", "country", "region", "city", "postcode", "timezone", "latitude", 138 "longitude", "asn", "network", "colo", "protocol", "medium", "campaign", "screen", "viewport", "scroll", "region_code", "continent", "metro", "bot", 139 ];
141 pub fn values(&self) -> Vec<Cell> { 142 let text = |value: &str| Cell::Text(value.to_owned()); 143 let number = |value: Option<f64>| value.map_or(Cell::Null, Cell::Number); 144 let origin = &self.origin; 145 vec![ 146 text(&self.what), 147 text(&self.method), 148 text(&self.host), 149 text(&self.path), 150 text(&self.query), 151 text(&self.input), 152 text(&self.detail), 153 Cell::Number(self.status), 154 Cell::Number(self.sent), 155 Cell::Number(self.kept), 156 Cell::Number(self.llm), 157 Cell::Number(self.took_ms), 158 Cell::Number(self.first), 159 Cell::Number(self.daily), 160 Cell::Number(self.session), 161 text(&self.referrer), 162 text(&self.source), 163 text(&self.client), 164 text(&self.family), 165 text(&self.os), 166 text(&self.device), 167 text(&self.language), 168 text(&self.agent), 169 text(&self.browser), 170 text(&origin.ip), 171 text(&origin.country), 172 text(&origin.region), 173 text(&origin.city), 174 text(&origin.postcode), 175 text(&origin.timezone), 176 number(origin.latitude), 177 number(origin.longitude), 178 number(origin.asn.map(f64::from)), 179 text(&origin.network), 180 text(&origin.colo), 181 text(&format!("{} {}", origin.protocol, origin.tls).trim().to_owned()), 182 text(&self.medium), 183 text(&self.campaign), 184 text(&self.screen), 185 text(&self.viewport), 186 Cell::Number(self.scroll), 187 text(&origin.region_code), 188 text(&origin.continent), 189 text(&origin.metro), 190 text(&origin.bot), 191 ] 192 }
What a request says of itself, before it is known what came of it.
browser is the id in its cookie, if it has one.
196 pub fn from(method: &Method, uri: &Uri, headers: &HeaderMap, browser: Option<String>, origin: Origin) -> Event { 197 let agent = text(headers, header::USER_AGENT.as_str()); 198 let lower = agent.to_ascii_lowercase(); 199 let client = client(&lower, headers); 200 let person = client == "browser"; 201 let query = uri.query().unwrap_or_default(); 202 Event { 203 method: method.as_str().to_owned(), 204 host: cut(text(headers, header::HOST.as_str()), 200), 205 path: cut(uri.path(), 500), 206 query: cut(query, 2000), 207 referrer: cut(text(headers, header::REFERER.as_str()), 1000), 208 source: tag(query, "utm_source").or_else(|| tag(query, "ref")).unwrap_or_default(), 209 medium: tag(query, "utm_medium").unwrap_or_default(), 210 campaign: tag(query, "utm_campaign").unwrap_or_default(), 211 client: client.to_owned(), 212 family: if person { family(&lower) } else { "" }.to_owned(), 213 os: if person { os(&lower) } else { "" }.to_owned(), 214 device: if person { device(&lower, headers) } else { "" }.to_owned(), 215 language: cut(text(headers, header::ACCEPT_LANGUAGE.as_str()), 200), 216 agent: cut(agent, 500), 217 browser: browser.unwrap_or_default(), 218 origin, 219 ..Event::default() 220 } 221 }
What a GET is, if it is worth keeping: not the site's own scripts
and fonts, or git's first request. A POST is named by the handler
that knows what came of it.
226 pub fn got(mut self) -> Option<Event> { 227 if self.method != "GET" { 228 return None; 229 } 230 self.what = match self.path.as_str() { 231 "/datastar.js" | "/emoji.woff2" | "/live.js" | "/rules.svg" | "/favicon.ico" => return None, 232 // The socket's own event is written by the archive, which keeps 233 // it to say how long the page stayed. 234 "/live" => return None, 235 path if path.ends_with("/info/refs") || path.starts_with("/icons/") => return None, 236 "/feed" => "more", 237 "/card.png" => "card", 238 _ => "view", 239 } 240 .to_owned(); 241 if self.what == "view" && self.query.split('&').any(|pair| pair.starts_with("q=") && pair.len() > 2) { 242 self.detail = "shared".into(); 243 } 244 Some(self) 245 }
The question it was about.
Counts a browser's page view as a visit: whether it is the browser's first page ever (it came with no cookie of the site's), its first today, and its first in half an hour. Returns the cookie that says it was counted now. Only a browser's page is a visit.
267 pub fn visit(&mut self, headers: &HeaderMap, now_ms: f64) -> Option<String> { 268 if self.what != "view" || self.client != "browser" { 269 return None; 270 } 271 let cookies = text(headers, header::COOKIE.as_str()); 272 let last = cookies.split(';').filter_map(|pair| pair.trim().strip_prefix(VISIT)?.strip_prefix('=')?.parse::<f64>().ok()).find(|last| last.is_finite() && *last <= now_ms); 273 let flag = |is: bool| if is { 1.0 } else { 0.0 }; 274 self.first = flag(cookies.trim().is_empty()); 275 self.daily = flag(last.is_none_or(|last| (last / DAY_MS).floor() < (now_ms / DAY_MS).floor())); 276 self.session = flag(last.is_none_or(|last| now_ms - last >= SESSION_MS)); 277 Some(format!("{VISIT}={now_ms:.0}; Path=/; Max-Age=31536000; Secure; HttpOnly; SameSite=Lax")) 278 } 279}
What kind of client asked, from what it says of itself.
290fn client(agent: &str, headers: &HeaderMap) -> &'static str { 291 const BOTS: [&str; 10] = ["bot", "crawler", "spider", "preview", "facebookexternalhit", "slurp", "curl/", "python", "wget", "headless"]; 292 if agent.starts_with("git/") || agent.starts_with("cargo") { 293 "git" 294 } else if BOTS.iter().any(|mark| agent.contains(mark)) { 295 "bot" 296 } else if headers.contains_key("sec-fetch-mode") || agent.starts_with("mozilla/") { 297 "browser" 298 } else { 299 "other" 300 } 301}
The browser's family. The order matters: Edge and Opera say Chrome too, and Chrome says Safari.
The operating system. iPhones say "like Mac OS X" and Android says Linux, so they are looked for first.
One of a link's campaign tags (utm_source, utm_medium, ...), if it
has it.
What the page says of itself when it is left or a link off the site is
followed (page.js, posted to /seen). Every part is the page's word
and is checked before it is kept.
Milliseconds it was in view since it last said.
354impl Event {
The event of a page's report: read, or out when it names a link.
The request is the report's own (POST /seen); the page it is about
is in the report.
358 pub fn seen(mut self, seen: &Seen) -> Event { 359 // A size is two numbers and an `x`, and nothing else. 360 let size = |text: &str| { 361 let fits = text.len() <= 11 && text.split_once('x').is_some_and(|(wide, high)| [wide, high].iter().all(|n| !n.is_empty() && n.bytes().all(|b| b.is_ascii_digit()))); 362 if fits { text.to_owned() } else { String::new() } 363 }; 364 let within = |n: f64, most: f64| if n.is_finite() { n.clamp(0.0, most) } else { 0.0 }; 365 self.what = if seen.out.is_empty() { "read" } else { "out" }.to_owned(); 366 self.detail = cut(&seen.out, 500); 367 if seen.path.starts_with('/') { 368 self.path = cut(&seen.path, 500); 369 self.query = cut(seen.query.trim_start_matches('?'), 2000); 370 } 371 // A page cannot have been looked at for longer than a day. 372 self.took_ms = within(seen.ms, 86_400_000.0); 373 self.scroll = within(seen.scroll, 1.0); 374 self.screen = size(&seen.screen); 375 self.viewport = size(&seen.viewport); 376 self 377 } 378}
380#[cfg(test)] 381mod tests { 382 use super::*; 383 384 fn headers(pairs: &[(&str, &str)]) -> HeaderMap { 385 let mut headers = HeaderMap::new(); 386 for (name, value) in pairs { 387 headers.insert(http::HeaderName::from_bytes(name.as_bytes()).unwrap(), value.parse().unwrap()); 388 } 389 headers 390 } 391 392 const CHROME: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36"; 393 394 fn event(method: Method, uri: &str, from: &[(&str, &str)]) -> Event { 395 Event::from(&method, &uri.parse().unwrap(), &headers(from), None, Origin::default()) 396 } 397 398 #[test] 399 fn a_get_is_named_for_what_it_is() { 400 let what = |uri: &str| event(Method::GET, uri, &[]).got().map(|event| event.what); 401 assert_eq!(what("/").as_deref(), Some("view")); 402 assert_eq!(what("/lmjtfy.git/packages/rules/").as_deref(), Some("view")); 403 assert_eq!(what("/feed?ms=1&q=x").as_deref(), Some("more")); 404 assert_eq!(what("/card.png?q=x").as_deref(), Some("card")); 405 // The site's own parts, the socket and git's first request are not 406 // named here. 407 assert_eq!(what("/live"), None); 408 assert_eq!(what("/emoji.woff2"), None); 409 assert_eq!(what("/icons/file-rust.png"), None); 410 assert_eq!(what("/lmjtfy.git/info/refs?service=git-upload-pack"), None); 411 // A POST is its handler's to name. 412 assert_eq!(event(Method::POST, "/ask", &[]).got(), None); 413 } 414 415 #[test] 416 fn nothing_the_request_said_is_dropped() { 417 let from = [ 418 ("referer", "https://discord.com/channels/1/2?x=y"), 419 ("host", "lmjtfy.fun"), 420 ("user-agent", CHROME), 421 ("accept-language", "en-GB,en;q=0.9"), 422 ]; 423 let uri: Uri = "/?q=Is+my+boss+a+lizard%3F&utm_source=discord&utm_medium=chat&utm_campaign=launch".parse().unwrap(); 424 let origin = Origin { ip: "203.0.113.7".into(), country: "GB".into(), asn: Some(2856), network: "British Telecommunications PLC".into(), ..Origin::default() }; 425 let event = Event::from(&Method::GET, &uri, &headers(&from), Some("0b5f2a1e".into()), origin).got().unwrap(); 426 assert_eq!((event.what.as_str(), event.detail.as_str(), event.path.as_str()), ("view", "shared", "/")); 427 assert_eq!(event.query, "q=Is+my+boss+a+lizard%3F&utm_source=discord&utm_medium=chat&utm_campaign=launch"); 428 assert_eq!(event.referrer, "https://discord.com/channels/1/2?x=y"); 429 assert_eq!((event.source.as_str(), event.language.as_str(), event.agent.as_str()), ("discord", "en-GB,en;q=0.9", CHROME)); 430 assert_eq!((event.medium.as_str(), event.campaign.as_str()), ("chat", "launch")); 431 assert_eq!((event.client.as_str(), event.family.as_str(), event.os.as_str(), event.device.as_str()), ("browser", "Chrome", "Windows", "desktop")); 432 assert_eq!((event.browser.as_str(), event.origin.ip.as_str(), event.origin.asn), ("0b5f2a1e", "203.0.113.7", Some(2856))); 433 } 434 435 #[test] 436 fn every_column_has_its_value_and_an_event_survives_the_wire() { 437 let event = Event { what: "answer".into(), origin: Origin { asn: Some(7), latitude: Some(1.5), ..Origin::default() }, ..Event::default() }; 438 let values = event.values(); 439 assert_eq!(values.len(), Event::COLUMNS.len()); 440 let at = |name: &str| values[Event::COLUMNS.iter().position(|column| *column == name).unwrap()].clone(); 441 assert_eq!(at("what"), Cell::Text("answer".into())); 442 assert_eq!(at("asn"), Cell::Number(7.0)); 443 assert_eq!(at("latitude"), Cell::Number(1.5)); 444 assert_eq!(at("longitude"), Cell::Null); 445 let wire = serde_json::to_string(&event).unwrap(); 446 assert_eq!(serde_json::from_str::<Event>(&wire).unwrap(), event); 447 } 448 449 #[test] 450 fn a_pages_report_is_checked_before_it_is_kept() { 451 let report = event(Method::POST, "/seen", &[("user-agent", CHROME)]); 452 let read = report.clone().seen(&Seen { path: "/rules".into(), query: "?answerable=no".into(), ms: 4200.0, scroll: 0.5, screen: "1920x1080".into(), viewport: "1200x800".into(), out: String::new() }); 453 assert_eq!((read.what.as_str(), read.path.as_str(), read.query.as_str()), ("read", "/rules", "answerable=no")); 454 assert_eq!((read.took_ms, read.scroll, read.screen.as_str(), read.viewport.as_str()), (4200.0, 0.5, "1920x1080", "1200x800")); 455 // A link followed off the site. 456 let out = report.clone().seen(&Seen { path: "/".into(), out: "https://docs.typesafe.ai/".into(), ..Seen::default() }); 457 assert_eq!((out.what.as_str(), out.detail.as_str()), ("out", "https://docs.typesafe.ai/")); 458 // What a page makes up is cut down to what it could be. 459 let odd = report.seen(&Seen { path: "elsewhere".into(), ms: f64::INFINITY, scroll: 7.0, screen: "<b>".into(), viewport: "9999999x9999999".into(), ..Seen::default() }); 460 assert_eq!((odd.path.as_str(), odd.took_ms, odd.scroll, odd.screen.as_str(), odd.viewport.as_str()), ("/seen", 0.0, 1.0, "", "")); 461 assert_eq!(serde_json::from_str::<Seen>("{\"ms\": 5}").unwrap().ms, 5.0); 462 } 463 464 #[test] 465 fn clients_are_classed() { 466 let class = |agent: &str| { 467 let event = event(Method::GET, "/", &[("user-agent", agent)]); 468 (event.client, event.family, event.os, event.device) 469 }; 470 let is = |client: &str, family: &str, os: &str, device: &str| (client.to_owned(), family.to_owned(), os.to_owned(), device.to_owned()); 471 assert_eq!(class("git/2.55.0"), is("git", "", "", "")); 472 assert_eq!(class("Mozilla/5.0 (compatible; Discordbot/2.0; +https://discordapp.com)"), is("bot", "", "", "")); 473 assert_eq!(class("curl/8.22.0"), is("bot", "", "", "")); 474 assert_eq!(class(""), is("other", "", "", "")); 475 assert_eq!(class(CHROME), is("browser", "Chrome", "Windows", "desktop")); 476 assert_eq!(class("Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 Chrome/140.0 Safari/537.36 Edg/140.0"), is("browser", "Edge", "Windows", "desktop")); 477 assert_eq!(class("Mozilla/5.0 (iPhone; CPU iPhone OS 19_0 like Mac OS X) AppleWebKit/605.1.15 Version/19.0 Mobile/15E148 Safari/604.1"), is("browser", "Safari", "iOS", "mobile")); 478 assert_eq!(class("Mozilla/5.0 (Android 16; Mobile; rv:143.0) Gecko/143.0 Firefox/143.0"), is("browser", "Firefox", "Android", "mobile")); 479 assert_eq!(class("Mozilla/5.0 (X11; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0"), is("browser", "Firefox", "Linux", "desktop")); 480 } 481 482 #[test] 483 fn a_visit_is_counted_from_when_the_browser_was_last_counted() { 484 let noon = 20_000.0 * DAY_MS + DAY_MS / 2.0; 485 let visit = |cookie: Option<String>, now: f64| { 486 let mut pairs = vec![("user-agent", CHROME.to_owned())]; 487 pairs.extend(cookie.map(|cookie| ("cookie", cookie))); 488 let pairs: Vec<(&str, &str)> = pairs.iter().map(|(name, value)| (*name, value.as_str())).collect(); 489 let mut event = event(Method::GET, "/", &pairs).named("view"); 490 let cookie = event.visit(&headers(&pairs), now); 491 ((event.first, event.daily, event.session), cookie) 492 }; 493 // No cookie at all: a new browser, today's first page, a new visit. 494 let (flags, cookie) = visit(None, noon); 495 assert_eq!(flags, (1.0, 1.0, 1.0)); 496 let cookie = cookie.unwrap(); 497 assert!(cookie.starts_with(&format!("lmjtfy_visit={noon:.0}; ")), "{cookie}"); 498 let last = |ms: f64| Some(format!("lmjtfy_browser=x; lmjtfy_visit={ms:.0}")); 499 // A minute on: none of them. An hour on: a new visit, the same day. 500 assert_eq!(visit(last(noon), noon + 60_000.0).0, (0.0, 0.0, 0.0)); 501 assert_eq!(visit(last(noon), noon + 3_600_000.0).0, (0.0, 0.0, 1.0)); 502 // Past midnight UTC: a new day too. 503 assert_eq!(visit(last(noon), noon + DAY_MS).0, (0.0, 1.0, 1.0)); 504 // A cookie from before this one existed: known, not yet counted. 505 assert_eq!(visit(Some("lmjtfy_browser=x".into()), noon).0, (0.0, 1.0, 1.0)); 506 // A time the page made up, or one from the future, is no time. 507 assert_eq!(visit(Some("lmjtfy_visit=soon".into()), noon).0, (0.0, 1.0, 1.0)); 508 assert_eq!(visit(last(noon + DAY_MS), noon).0, (0.0, 1.0, 1.0)); 509 // Only a browser's page view is a visit. 510 let mut bot = event(Method::GET, "/", &[("user-agent", "curl/8")]).named("view"); 511 assert_eq!(bot.visit(&HeaderMap::new(), noon), None); 512 let mut vote = event(Method::POST, "/rate", &[("user-agent", CHROME)]).named("vote"); 513 assert_eq!(vote.visit(&HeaderMap::new(), noon), None); 514 } 515}