code wiki / _hdl_build / nx_js_hydrate_index_gate.nx
nx_js_hydrate_index_gate.nx source
↩ module page · 97 lines · 5649 B
1// nx_js_hydrate_index_gate.nx -- CLOSES THE LOOP: a page whose INLINE JS builds content -> hydrate
2// (js_render_page, async-drained) -> extract text -> INDEX into a seg_store shard -> the JS-built token
3// is SEARCHABLE (ss_term finds it), whereas indexing the RAW static HTML does NOT. Proves hydration makes
4// JS content indexable/searchable -- the payoff of the whole JS-execution arc, end-to-end, HERMETIC.
5// license_tier: ORIGINAL
6import "nx_syscalls.nx"
7import "nx_js_eval.nx" // js_render_page
8import "nx_html_to_text.nx" // hydrated/raw HTML -> text
9import "nx_seg_store.nx" // ss_begin/add/commit/open/term/manifest_cap
10
11func r_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
12func r_pn(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 }
13func r_clen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
14
15func next_segid(prefix: *u8) -> i64 {
16 let segs: *i64 = sys_mmap(4096 * 8) as *i64
17 let nseg: i64 = ss_manifest_cap(prefix, segs, 4096)
18 var segid: i64 = 1; var si: i64 = 0
19 // ROOT FIX seq1730 (id 1785450987): segs[] holds POINTERS to seg-<id> name strings
20 // (nx_seg_store.nx:1234 stores segs[cnt] = name as i64), NOT ids -- so segs[si] + 1 produced
21 // MMAP_ADDRESS+1 (~1.4e14), the pointer-shaped poison that PINS a plane forever: every later
22 // epoch id sorts BELOW it in supersede order and its rows are silently shadowed while rc=0.
23 // Parse the DIGITS, as nx_web_shard_compact.nx:55-58 already does on this SAME array.
24 while si < nseg {
25 let sg_nm: *u8 = segs[si] as *u8
26 var sg_v: i64 = 0
27 var sg_ci: i64 = 0
28 while sg_nm[sg_ci] != (0 as u8) { let sg_c: i64 = sg_nm[sg_ci] as i64; if sg_c >= 48 { if sg_c <= 57 { sg_v = sg_v * 10 + (sg_c - 48) } } sg_ci = sg_ci + 1 }
29 if sg_v >= segid { segid = sg_v + 1 }
30 si = si + 1
31 }
32 return segid
33}
34// index `text` as one doc into the shard at `prefix` (fresh segment; re-run-safe).
35func index_doc(prefix: *u8, key: *u8, text: *u8, tlen: i64) -> i64 {
36 let segid: i64 = next_segid(prefix)
37 let w: *i64 = ss_begin()
38 ss_add(w, 1, key, text, tlen)
39 ss_commit(prefix, w, segid)
40 return 0
41}
42// how many docs in the shard contain `term` (0 = not indexed / not searchable).
43func term_count(prefix: *u8, term: *u8) -> i64 {
44 let h: *i64 = ss_open(prefix)
45 if (h as i64) == 0 { return 0 }
46 let kp: *i64 = sys_mmap(64 * 8) as *i64
47 let kl: *i64 = sys_mmap(64 * 8) as *i64
48 return ss_term(h, term, kp, kl, 64)
49}
50func chk(cond: i64, name: *u8, pp: *i64, tp: *i64) -> i64 {
51 tp[0] = tp[0] + 1; r_p(" "); r_p(name)
52 if cond == 1 { pp[0] = pp[0] + 1; r_p(": ok\n\x00" as *u8) } else { r_p(": FAIL\n\x00" as *u8) }
53 return 0
54}
55
56func main() -> i64 {
57 r_p("=== nx_js_hydrate_index_gate: JS-built content -> hydrate -> index -> SEARCHABLE ===\n\x00" as *u8)
58 let pp: *i64 = sys_mmap(8) as *i64; pp[0] = 0
59 let tp: *i64 = sys_mmap(8) as *i64; tp[0] = 0
60
61 // A page whose INLINE SCRIPT replaces "LOADING" with a distinctive token only JS produces.
62 let html: *u8 = "<html><body><div id=\"app\">LOADING</div><script>document.getElementById('app').innerHTML='<p>jshydratedtoken99 kyokahydrated</p>';</script></body></html>\x00" as *u8
63 let hlen: i64 = r_clen(html)
64
65 // STATIC path = what a non-JS crawler indexes (raw HTML -> text). Contains "loading", NOT the token.
66 let stat: *u8 = sys_mmap(65536)
67 let statlen: i64 = nx_html_to_text(html, hlen, stat, 65536)
68 // HYDRATED path = run the JS, serialize, then text. Contains the token, NOT "loading".
69 let hydr: *u8 = sys_mmap(262144)
70 let hyl: i64 = js_render_page(html, hlen, hydr, 262144)
71 let hydtext: *u8 = sys_mmap(65536)
72 let hydtlen: i64 = nx_html_to_text(hydr, hyl, hydtext, 65536)
73
74 index_doc("/tmp/hydidx-static-\x00" as *u8, "doc:s\x00" as *u8, stat, statlen)
75 index_doc("/tmp/hydidx-hydr-\x00" as *u8, "doc:h\x00" as *u8, hydtext, hydtlen)
76
77 let ch: i64 = term_count("/tmp/hydidx-hydr-\x00" as *u8, "jshydratedtoken99\x00" as *u8)
78 let cs: i64 = term_count("/tmp/hydidx-static-\x00" as *u8, "jshydratedtoken99\x00" as *u8)
79 let sl: i64 = term_count("/tmp/hydidx-static-\x00" as *u8, "loading\x00" as *u8)
80 let hl2: i64 = term_count("/tmp/hydidx-hydr-\x00" as *u8, "loading\x00" as *u8)
81
82 r_p(" [static text=\x00" as *u8); r_pn(statlen); r_p("B hydrated text=\x00" as *u8); r_pn(hydtlen); r_p("B]\n\x00" as *u8)
83 // T1 THE PAYOFF: the JS-built token is searchable after hydration.
84 chk(ch >= 1, "T1 hydrated: JS token SEARCHABLE\x00" as *u8, pp, tp)
85 // T2 a static crawler MISSES it (the whole reason this arc exists).
86 chk(cs == 0, "T2 static: JS token ABSENT\x00" as *u8, pp, tp)
87 // T3 control: the static shard works (its own content is searchable).
88 chk(sl >= 1, "T3 static shard works (finds 'loading')\x00" as *u8, pp, tp)
89 // T4 hydration REPLACED (not appended): 'loading' is gone from the hydrated doc.
90 chk(hl2 == 0, "T4 hydration replaced 'loading'\x00" as *u8, pp, tp)
91
92 r_p("=== \x00" as *u8)
93 if pp[0] == tp[0] { r_p("GREEN\x00" as *u8) } else { r_p("RED\x00" as *u8) }
94 r_p(" (\x00" as *u8); r_pn(pp[0]); r_p("/\x00" as *u8); r_pn(tp[0]); r_p(") ===\n\x00" as *u8)
95 if pp[0] == tp[0] { return 0 }
96 return 1
97}