/<repo>.git/<path> in a browser: the code, browsed. A directory lists
its entries and shows its README; a file is shown with numbered lines, or
rendered if it is markdown; ?raw serves it as it is.
Everything comes from GitHub's contents API with the clone proxy's read-only token, at most once a minute per isolate for a given path. jevcrates is browsed on its own and where each project pins it: a path under a project's jevcrates submodule is read from jevcrates at the pinned commit.
11use std::cell::RefCell;
How long an isolate keeps what GitHub said about a path.
24const KEPT_MS: f64 = 60_000.0;
How many paths an isolate keeps at once; the oldest goes first.
26const KEPT: usize = 64;
28thread_local! {
What GitHub said, by (repository, ref, path), and when.
30 static READ: RefCell<Vec<((Repo, String, String), f64, Read)>> = const { RefCell::new(Vec::new()) };
Each repository's whole tree at main, submodules mounted, and when.
The whole tree of repo at main for the explorer, each submodule's tree
mounted where it is pinned: two calls to GitHub at most, kept a minute.
Empty if GitHub cannot be read; the pages still work without it.
38pub async fn explorer(env: &worker::Env, repo: Repo) -> tree::Tree { 39 let now = js_sys::Date::now(); 40 let kept = TREES.with(|trees| trees.borrow().iter().find(|(seen, at, _)| *seen == repo && now - at < KEPT_MS).map(|(_, _, tree)| tree.clone())); 41 if let Some(tree) = kept { 42 return tree; 43 } 44 let Some(mut whole) = git_tree(env, repo, repo.branch()).await else { return tree::Tree::default() }; 45 for (mount, inner) in repo.submodules() { 46 let pin = whole.pins.iter().find(|(path, _)| path == mount).map(|(_, sha)| sha.clone()); 47 if let Some(inner_tree) = match pin { Some(sha) => git_tree(env, *inner, &sha).await, None => None } { 48 whole.mount(mount, inner_tree); 49 } 50 } 51 TREES.with(|trees| { 52 let mut trees = trees.borrow_mut(); 53 trees.retain(|(seen, _, _)| *seen != repo); 54 trees.push((repo, now, whole.clone())); 55 }); 56 whole 57}
59async fn git_tree(env: &worker::Env, repo: Repo, reference: &str) -> Option<tree::Tree> { 60 let url = format!("https://api.github.com/repos/{}/git/trees/{}?recursive=1", repo.github(), tree::encoded(&[reference])); 61 match clone::github(env, &url).await? { 62 (200, body, _) => tree::parse_tree(&body), 63 _ => None, 64 } 65}
GitHub said there is nothing there.
72 Missing,
?raw serves a file as it is; ?view=agents shows a directory's
CLAUDE.md in place of its README.
GET /<repo>/<path>.
87#[worker::send] 88pub async fn path( 89 State(app): State<App>, 90 Path((segment, path)): Path<(String, String)>, 91 Query(asked): Query<Asked>, 92 headers: HeaderMap, 93) -> Response<Body> { 94 let origin = super::origin(&headers); 95 let Some(repo) = Repo::named(&segment) else { return clone::refused(StatusCode::NOT_FOUND, "No such page.") }; 96 let Some(segments) = tree::segments(&path) else { return clone::refused(StatusCode::NOT_FOUND, "No such page.") }; 97 let served = segments.join("/"); 98 let read = resolve(&app.env, repo, &segments).await; 99 if asked.raw.is_some() 100 && let Read::Found(Contents::File { path, body, .. }) = &read 101 { 102 return raw_file(path, body); 103 } 104 let view = View::asked(asked.view.as_deref()); 105 let (status, shown) = match &read { 106 Read::Found(Contents::Dir(entries)) => { 107 let entries = mounted(repo, &served, entries); 108 let docs = docs(&app.env, repo, &segments, &entries, view).await; 109 (StatusCode::OK, Shown::Dir { docs }) 110 } 111 Read::Found(Contents::File { size, body, .. }) => (StatusCode::OK, Shown::File { size: *size, body, view }), 112 // A submodule's own path resolves to its root, so this is not seen. 113 Read::Found(Contents::Submodule { .. }) | Read::Missing => (StatusCode::NOT_FOUND, Shown::Missing), 114 Read::Unreachable => (StatusCode::BAD_GATEWAY, Shown::Unreachable), 115 }; 116 let whole = explorer(&app.env, repo).await; 117 let latest = clone::latest(&app.env, repo).await; 118 let frame = frame(&origin, repo, &served, &whole, latest.as_ref()); 119 let page = code::page(&frame, shown); 120 Response::builder() 121 .status(status) 122 .header(header::CONTENT_TYPE, "text/html; charset=utf-8") 123 .header(header::CACHE_CONTROL, "no-cache") 124 .body(Body::from(page.into_string())) 125 .expect("static headers are valid") 126}
Everything around a code page's main pane, for repo.
129pub fn frame<'a>(origin: &'a str, repo: Repo, path: &'a str, tree: &'a tree::Tree, latest: Option<&'a card::Commit>) -> code::Frame<'a> { 130 code::Frame { 131 origin, 132 project: repo.project(), 133 path, 134 tree, 135 latest, 136 clone: repo.command(origin), 137 projects: Repo::ALL.iter().map(|repo| repo.project()).collect(), 138 } 139}
The root of a repository's documents, for the front page.
What is at a served path: in the repository itself, or under one of its submodules, in the submodule at the commit it is pinned at.
151async fn resolve(env: &worker::Env, repo: Repo, segments: &[&str]) -> Read { 152 for (mount, inner) in repo.submodules() { 153 let mount_segments: Vec<&str> = mount.split('/').collect(); 154 if segments.starts_with(&mount_segments) { 155 let pin = match read(env, repo, repo.branch(), &mount_segments).await { 156 Read::Found(Contents::Submodule { sha, .. }) => sha, 157 Read::Found(_) | Read::Missing => return Read::Missing, 158 Read::Unreachable => return Read::Unreachable, 159 }; 160 return read(env, *inner, &pin, &segments[mount_segments.len()..]).await; 161 } 162 } 163 read(env, repo, repo.branch(), segments).await 164}
A directory's entries with their paths as served: a submodule's entries are under its mount.
168fn mounted(repo: Repo, served: &str, entries: &[tree::Entry]) -> Vec<tree::Entry> { 169 let mount = repo.submodules().iter().map(|(mount, _)| *mount).find(|mount| served == *mount || served.starts_with(&format!("{mount}/"))); 170 entries 171 .iter() 172 .map(|entry| tree::Entry { 173 path: match mount { 174 Some(mount) => format!("{mount}/{}", entry.path), 175 None => entry.path.clone(), 176 }, 177 ..entry.clone() 178 }) 179 .collect() 180}
The directory's README and CLAUDE.md, rendered.
191async fn doc(env: &worker::Env, repo: Repo, segments: &[&str], entries: &[tree::Entry], name: &str) -> Option<Doc> { 192 let found = entries.iter().find(|entry| entry.kind == Kind::File && entry.name.eq_ignore_ascii_case(name))?; 193 let mut path = segments.to_vec(); 194 path.push(&found.name); 195 match resolve(env, repo, &path).await { 196 Read::Found(Contents::File { body: tree::Body::Text(text), .. }) => Some(Doc::new(&path.join("/"), &text, &repo.project().base())), 197 _ => None, 198 } 199}
One path of one repository at one ref, from this isolate's memory or from GitHub.
203async fn read(env: &worker::Env, repo: Repo, reference: &str, segments: &[&str]) -> Read { 204 let key = (repo, reference.to_owned(), segments.join("/")); 205 let now = js_sys::Date::now(); 206 let kept = READ.with(|read| { 207 read.borrow().iter().find(|(seen, at, _)| *seen == key && now - at < KEPT_MS).map(|(_, _, read)| read.clone()) 208 }); 209 if let Some(read) = kept { 210 return read; 211 } 212 let url = format!("https://api.github.com/repos/{}/contents/{}?ref={}", repo.github(), tree::encoded(segments), tree::encoded(&[reference])); 213 let read = match clone::github(env, &url).await { 214 Some((200, body, _)) => tree::parse(&body).map_or(Read::Unreachable, Read::Found), 215 Some((404, _, _)) => Read::Missing, 216 _ => Read::Unreachable, 217 }; 218 // Only answers are kept: an outage is asked about again next time. 219 if !matches!(read, Read::Unreachable) { 220 READ.with(|kept| { 221 let mut kept = kept.borrow_mut(); 222 kept.retain(|(seen, at, _)| *seen != key && now - at < KEPT_MS); 223 if kept.len() >= KEPT { 224 kept.remove(0); 225 } 226 kept.push((key, now, read.clone())); 227 }); 228 } 229 read 230}
A file as it is. A sandbox keeps anything in it from running as this site.
234fn raw_file(path: &str, body: &tree::Body) -> Response<Body> { 235 let bytes = match body { 236 tree::Body::Text(text) => text.clone().into_bytes(), 237 tree::Body::Binary(bytes) => bytes.clone(), 238 tree::Body::TooLarge => return clone::refused(StatusCode::PAYLOAD_TOO_LARGE, "Too large to show here. Clone it."), 239 }; 240 Response::builder() 241 .header(header::CONTENT_TYPE, tree::media_type(path, body)) 242 .header(header::CACHE_CONTROL, "public, max-age=60") 243 .header("content-security-policy", "sandbox") 244 .header("x-content-type-options", "nosniff") 245 .body(Body::from(bytes)) 246 .expect("static headers are valid") 247}