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}