code wiki / _hdl_build / nx_cms_api.nx
nx_cms_api.nx source
↩ module page · 66 lines · 3164 B
1// nx_cms_api.nx -- CMS REST + GraphQL-style content API (the rest-graphql-api class). Serves the real
2// nx_cms_store content as RFC 8259 JSON via nx_json_emit, with FIELD SELECTION (the GraphQL essence:
3// the caller asks for exactly the fields it wants; REST = ask for all, GraphQL = ask for a subset) and
4// correct string escaping (the security axis -- a value containing a quote or newline can never break
5// out of the JSON, unlike naive string concatenation). Read side; composes cst_get + json_emit.
6// module: nishi-core.cms.api
7// depends: nishi-core.cms.store + nishi-core.data.json_emit + nishi-core.io.syscalls
8// capability: CMS
9// license_tier: ORIGINAL
10import "nx_cms_store.nx"
11// ⚠SWAPPED 2026-08-07: this imported nx_json_emit.nx, which shares the je_ prefix but is a COMPLETELY
12// DIFFERENT LIBRARY -- je_puts/je_key/je_str write straight to fd 1, while everything this file calls
13// (json_writer_init / json_begin_object / json_emit_string / JsonWriter) is the BUFFER serializer in
14// json_emit.nx. So the type and every function were undefined and nx_cms_api_exceed_gate has NEVER had
15// a binary: absent from the serving root, from staging and from _offc.
16// ★★★★★TWO LIBRARIES THAT SHARE A PREFIX BUT NOT AN API ARE A MISIMPORT WAITING TO HAPPEN, AND THE
17// NAME THAT LOOKS CANONICAL (nx_) WAS THE WRONG ONE.
18import "json_emit.nx"
19
20import "nx_syscalls.nx"
21
22func capi_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
23
24// emit a JSON object into an existing writer, projecting only the named fields that are
25// PRESENT in the store (absent fields are skipped gracefully -- a GraphQL/REST must not 500
26// on a field that doesn't exist). names is an array of *u8 (one per requested field).
27func cms_api_emit_obj(w: *JsonWriter, store: *u8, n: i64, names: *i64, nf: i64) -> i64 {
28 let valbuf: *u8 = sys_mmap(2048)
29 json_begin_object(w)
30 var i: i64 = 0
31 while i < nf {
32 let name: *u8 = (names[i]) as *u8
33 let vl: i64 = cst_get(store, n, name, valbuf, 2048)
34 if vl >= 0 {
35 json_emit_key(w, name, capi_slen(name))
36 json_emit_string(w, valbuf, vl)
37 }
38 i = i + 1
39 }
40 json_end_object(w)
41 return 0
42}
43
44// REST/GraphQL single-record endpoint: project the named fields of one store into a JSON object.
45// Returns the JSON byte length written to out.
46func cms_api_render_obj(store: *u8, n: i64, names: *i64, nf: i64, out: *u8, cap: i64) -> i64 {
47 let w: *JsonWriter = sys_mmap(128) as *JsonWriter
48 json_writer_init(w, out, cap)
49 cms_api_emit_obj(w, store, n, names, nf)
50 return w.pos
51}
52
53// REST/GraphQL list endpoint: a JSON array of projected objects, one per store.
54// stores[i] = *u8 store ptr, counts[i] = its byte length.
55func cms_api_render_list(stores: *i64, counts: *i64, ns: i64, names: *i64, nf: i64, out: *u8, cap: i64) -> i64 {
56 let w: *JsonWriter = sys_mmap(128) as *JsonWriter
57 json_writer_init(w, out, cap)
58 json_begin_array(w)
59 var i: i64 = 0
60 while i < ns {
61 cms_api_emit_obj(w, (stores[i]) as *u8, counts[i], names, nf)
62 i = i + 1
63 }
64 json_end_array(w)
65 return w.pos
66}