Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151// Thin HTTP client for the kidlisp Datomic sidecar.// Used by system/netlify/functions/store-kidlisp.mjs behind the// KIDLISP_DATOMIC feature flag (default off — see that file).//// The sidecar exposes a clean Datomic-native API; this module does not// reshape responses. The caller is responsible for mapping sidecar// shapes to the external Mongo-era response shape that existing clients// depend on.//// Env:// DATOMIC_SIDECAR_URL default http://127.0.0.1:8891// DATOMIC_SIDECAR_CLIENT_SECRET required when KIDLISP_DATOMIC=on
const URL_BASE = () => process.env.DATOMIC_SIDECAR_URL || "http://127.0.0.1:8891";
function headers() { const s = process.env.DATOMIC_SIDECAR_CLIENT_SECRET; if (!s) throw new Error("DATOMIC_SIDECAR_CLIENT_SECRET not set"); return { "content-type": "application/json", "x-sidecar-secret": s };}
async function req(method, path, body) { const res = await fetch(`${URL_BASE()}${path}`, { method, headers: headers(), body: body != null ? JSON.stringify(body) : undefined, }); const text = await res.text(); let json = null; try { json = text ? JSON.parse(text) : null; } catch { /* not JSON */ } return { ok: res.ok, status: res.status, body: json ?? text };}
export const sidecar = { // ── public API surface used by store-kidlisp.mjs ──
async lookupByHash(hash) { const r = await req("GET", `/kidlisp/hash/${encodeURIComponent(hash)}`); if (r.status === 404) return null; if (!r.ok) throw new Error(`sidecar lookupByHash failed: ${r.status}`); return r.body; },
async lookupByCode(code) { const r = await req("GET", `/kidlisp/${encodeURIComponent(code)}`); if (r.status === 404) return null; if (!r.ok) throw new Error(`sidecar lookupByCode failed: ${r.status}`); return r.body; },
async batchLookup(codes) { const r = await req("POST", `/kidlisp/lookup`, { codes }); if (!r.ok) throw new Error(`sidecar batchLookup failed: ${r.status}`); return r.body; },
async listCodes({ limit, sort, since } = {}) { const qs = new URLSearchParams(); if (limit) qs.set("limit", String(limit)); if (sort) qs.set("sort", sort); if (since) qs.set("since", since); const r = await req("GET", `/kidlisp?${qs.toString()}`); if (!r.ok) throw new Error(`sidecar listCodes failed: ${r.status}`); return r.body; },
async statsFunctions({ limit } = {}) { const qs = new URLSearchParams(); if (limit) qs.set("limit", String(limit)); const r = await req("GET", `/kidlisp/stats/functions?${qs.toString()}`); if (!r.ok) throw new Error(`sidecar statsFunctions failed: ${r.status}`); return r.body; },
// Create-or-find. Body fields: // source, hash, code, user_sub?, forked_from?, when?, hits? // Returns { code, cached }. async create(piece) { const r = await req("POST", "/kidlisp", piece); if (!r.ok) throw new Error(`sidecar create failed: ${r.status} ${r.body}`); return r.body; },
async recordMint(code, keep) { const r = await req("POST", `/kidlisp/${encodeURIComponent(code)}/mint`, keep); if (!r.ok) throw new Error(`sidecar recordMint failed: ${r.status}`); return r.body; },
async setTezosState(code, state) { const r = await req("POST", `/kidlisp/${encodeURIComponent(code)}/tezos-state`, state); if (!r.ok) throw new Error(`sidecar setTezosState failed: ${r.status}`); return r.body; },
async setPendingRebake(code, rebake) { const r = await req("POST", `/kidlisp/${encodeURIComponent(code)}/pending-rebake`, rebake); if (!r.ok) throw new Error(`sidecar setPendingRebake failed: ${r.status}`); return r.body; },
async setIpfsMedia(code, media) { const r = await req("POST", `/kidlisp/${encodeURIComponent(code)}/ipfs-media`, media); if (!r.ok) throw new Error(`sidecar setIpfsMedia failed: ${r.status}`); return r.body; },
async setAtprotoRkey(code, rkey) { const r = await req("POST", `/kidlisp/${encodeURIComponent(code)}/atproto-rkey`, { rkey }); if (!r.ok) throw new Error(`sidecar setAtprotoRkey failed: ${r.status}`); return r.body; },
async lineage(code) { const r = await req("GET", `/kidlisp/${encodeURIComponent(code)}/lineage`); if (r.status === 404) return null; if (!r.ok) throw new Error(`sidecar lineage failed: ${r.status}`); return r.body; },
// AST (v2): replace-all. `nodes` is the flat list from // system/backend/kidlisp-ast.mjs extractAst(). Atomic retract + assert // on the sidecar side. async setAst(code, nodes) { const r = await req("POST", `/kidlisp/${encodeURIComponent(code)}/ast`, { nodes }); if (!r.ok) throw new Error(`sidecar setAst failed: ${r.status}`); return r.body; },
async getAst(code) { const r = await req("GET", `/kidlisp/${encodeURIComponent(code)}/ast`); if (r.status === 404) return null; if (!r.ok) throw new Error(`sidecar getAst failed: ${r.status}`); return r.body; },
async piecesUsingOp(op, limit = 50) { const qs = new URLSearchParams({ op, limit: String(limit) }); const r = await req("GET", `/kidlisp/structural/pieces-using?${qs.toString()}`); if (!r.ok) throw new Error(`sidecar piecesUsingOp failed: ${r.status}`); return r.body; },};
// Feature flag helper — read once per request since Netlify functions// reuse the module across invocations.export function kidlispDatomicEnabled() { return process.env.KIDLISP_DATOMIC === "on";}