code wiki / _hdl_build / nx_js_headless_render.nx

nx_js_headless_render.nx source

↩ module page · 121 lines · 6629 B

1// nx_js_headless_render.nx -- RUNG 5 CONSUMER + API-CAPTURE: fetch a REAL site over sovereign TLS, fetch its 2// same-origin external <script> BUNDLES, run everything (inline+bundles) in ONE shared genv, and -- the SPA 3// unlock -- CAPTURE the runtime fetch()/XHR calls the app makes (js_pending_*), service them over TLS, and 4// print the captured API endpoint + its JSON. That reaches SPA *data* without rendering the framework. 5// usage: nx_js_headless_render <url> 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_js_eval.nx" 9import "nx_html_to_text.nx" 10import "nx_x509_trust_store.nx" 11import "nx_trust_store_load_from_certdata.nx" 12import "nx_https_fetch_follow.nx" 13const HR_MAGIC_4194304: i64 = 4194304 14const HR_MAGIC_65536: i64 = 65536 15const HR_MAGIC_4096: i64 = 4096 16const HR_MAGIC_4094: i64 = 4094 17const HR_MAGIC_1048576: i64 = 1048576 18 19func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 20func hn(v: i64) -> i64 { if v==0 { sys_write(1,"0" as *u8,1); return 0 } var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m } let t: *u8=sys_mmap(24); var k: i64=0; while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } let o: *u8=sys_mmap(24); var q: i64=k-1; var x: i64=0; while q>=0 { o[x]=t[q]; x=x+1; q=q-1 } sys_write(1,o,x); return 0 } 21func hsl(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 22// origin ("scheme://host") of url -> out; returns length. 23func origin_of(url: *u8, out: *u8) -> i64 { 24 let n: i64 = hsl(url) 25 var i: i64 = 0; var sp: i64 = 0 - 1 26 while i < (n - 2) { if (url[i] & 0xff) == 58 { if (url[i+1] & 0xff) == 47 { if (url[i+2] & 0xff) == 47 { sp = i } } } if sp >= 0 { i = n } else { i = i + 1 } } 27 var stop: i64 = n 28 if sp >= 0 { 29 var j: i64 = sp + 3; var f: i64 = 0 30 while f == 0 { if j >= n { f = 1 } else { if (url[j] & 0xff) == 47 { stop = j; f = 1 } else { j = j + 1 } } } 31 } 32 var k: i64 = 0; while k < stop { out[k] = url[k]; k = k + 1 } out[stop] = 0 as u8 33 return stop 34} 35 36const HR_MAXROUNDS: i64 = 10 37 38func main(argc: i64, argv: *i64) -> i64 { 39 if argc < 2 { hw("usage: nx_js_headless_render <url>\n" as *u8); return 1 } 40 let url: *u8 = argv[1] as *u8 41 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, HR_MAGIC_4194304) 42 if r <= 0 { hw("trust store load failed\n" as *u8); return 2 } 43 let store: *TrustStore = r as *TrustStore 44 let cap: i64 = HR_MAGIC_4194304 45 let out: *u8 = sys_mmap(cap) 46 let st: *i64 = sys_mmap(16) as *i64 47 hw("fetch (sovereign TLS): "); hw(url); hw("\n" as *u8) 48 let n: i64 = nx_https_fetch_follow_best(url, store, out, cap, 6, st) 49 hw(" status="); hn(st[0]); hw(" html_bytes="); hn(n); hw("\n" as *u8) 50 if st[0] != 200 { return 3 } 51 52 let origin: *u8 = sys_mmap(512); origin_of(url, origin) 53 hw(" origin="); hw(origin); hw("\n" as *u8) 54 55 // fetch same-origin external bundles -> extrascripts (run in the SAME ctx+genv as inline scripts) 56 let srcbuf: *u8 = sys_mmap(HR_MAGIC_65536) 57 let nsrc: i64 = js_extract_script_srcs(out, n, srcbuf, HR_MAGIC_65536) 58 hw(" external scripts referenced="); hn(nsrc); hw("\n" as *u8) 59 let extra: *u8 = sys_mmap(cap); var extralen: i64 = 0 60 let fbuf: *u8 = sys_mmap(cap); let fst: *i64 = sys_mmap(16) as *i64 61 let absb: *u8 = sys_mmap(HR_MAGIC_4096) 62 var p: i64 = 0; var got: i64 = 0 63 while srcbuf[p] != (0 as u8) { 64 var le: i64 = p 65 while srcbuf[le] != (0 as u8) { if srcbuf[le] == (10 as u8) { srcbuf[le] = 0 as u8 } else { le = le + 1 } } 66 // srcbuf[p..] is now a C-string (this line). same-origin if starts '/' and not '//' 67 if (srcbuf[p] & 0xff) == 47 { if (srcbuf[p+1] & 0xff) != 47 { 68 // build absolute = origin + line 69 var a: i64 = 0; var oc: i64 = 0 70 while origin[oc] != (0 as u8) { absb[a] = origin[oc]; a = a + 1; oc = oc + 1 } 71 var lc: i64 = p 72 while srcbuf[lc] != (0 as u8) { if a < HR_MAGIC_4094 { absb[a] = srcbuf[lc]; a = a + 1 } lc = lc + 1 } 73 absb[a] = 0 as u8 74 let fn: i64 = nx_https_fetch_follow_best(absb, store, fbuf, cap, 6, fst) 75 if fst[0] == 200 { if (extralen + fn + 2) < cap { var e: i64 = 0; while e < fn { extra[extralen] = fbuf[e]; extralen = extralen + 1; e = e + 1 } extra[extralen] = 59 as u8; extralen = extralen + 1; extra[extralen] = 10 as u8; extralen = extralen + 1; got = got + 1 } } 76 } } 77 p = le + 1 78 } 79 hw(" same-origin bundles fetched="); hn(got); hw(" ("); hn(extralen); hw(" bytes of JS)\n" as *u8) 80 81 // run inline + bundles in one shared genv; capture their runtime fetches 82 let obox: *i64 = sys_mmap(32) as *i64 83 js_render_page_pending_begin(out, n, extra, extralen, obox) 84 let ctx: *i64 = (obox[0]) as *i64 85 let genv: *i64 = (obox[1]) as *i64 86 let tree: i64 = obox[2] 87 88 hw("=== CAPTURED runtime requests (the app's private API) ===\n" as *u8) 89 let urlbuf: *u8 = sys_mmap(HR_MAGIC_4096) 90 var round: i64 = 0; var captured: i64 = 0; var going: i64 = 1 91 while going == 1 { 92 if round >= HR_MAXROUNDS { going = 0 } else { if js_pending_count(genv) == 0 { going = 0 } else { 93 let total: i64 = js_pending_total(genv) 94 var i: i64 = 0 95 while i < total { 96 if js_pending_serviced(genv, i) == 0 { 97 let ul: i64 = js_pending_url(genv, i, urlbuf, HR_MAGIC_4096) 98 if ul > 0 { 99 hw(" API: "); hw(urlbuf); hw("\n" as *u8) 100 let afn: i64 = nx_https_fetch_follow_best(urlbuf, store, fbuf, cap, 6, fst) 101 hw(" -> status="); hn(fst[0]); hw(" bytes="); hn(afn); hw(" first160: " as *u8) 102 var lim: i64 = afn; if lim > 160 { lim = 160 } 103 sys_write(1, fbuf, lim); hw("\n" as *u8) 104 js_pending_service(ctx, genv, i, fst[0], fbuf, afn) 105 captured = captured + 1 106 } else { js_pending_service(ctx, genv, i, 0, fbuf, 0) } 107 } 108 i = i + 1 109 } 110 el_drain(ctx, genv); round = round + 1 111 } } 112 } 113 hw("=== captured "); hn(captured); hw(" API call(s) in "); hn(round); hw(" round(s) ===\n" as *u8) 114 115 let hydr: *u8 = sys_mmap(cap) 116 let hlen: i64 = js_render_page_serialize(tree, hydr, cap) 117 let hydtext: *u8 = sys_mmap(HR_MAGIC_1048576) 118 let hydlen: i64 = nx_html_to_text(hydr, hlen, hydtext, HR_MAGIC_1048576) 119 hw("HYDRATED DOM text="); hn(hydlen); hw(" bytes\n" as *u8) 120 return 0 121}