From bdb54d5919e4a5a570fae71c0369ef26b204a345 Mon Sep 17 00:00:00 2001 From: giles Date: Wed, 1 Apr 2026 14:42:02 +0000 Subject: [PATCH] Handler dispatch in OCaml: look up handler dict, aser body directly Skip the SX api function entirely. The OCaml handler interception looks up handler:ex-{slug} in the env, extracts the body, and calls aser directly with the full global env. This avoids the double-eval problem where eval-expr evaluates HTML tags as function calls and then tries to call the result. Co-Authored-By: Claude Opus 4.6 (1M context) --- hosts/ocaml/bin/sx_server.ml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/hosts/ocaml/bin/sx_server.ml b/hosts/ocaml/bin/sx_server.ml index b3010d19..552f3f0a 100644 --- a/hosts/ocaml/bin/sx_server.ml +++ b/hosts/ocaml/bin/sx_server.ml @@ -2650,11 +2650,9 @@ let http_mode port = let is_sx = path = "/sx/" || path = "/sx" || (String.length path > 4 && String.sub path 0 4 = "/sx/") in if is_sx && is_handler_path then begin - (* Handler dispatch — evaluate handler, return raw fragment *) + (* Handler dispatch — look up handler dict, evaluate body, aser result *) let response = try - let api_fn = env_get env "api" in - (* Extract handler slug from path: ...api.SLUG)... *) let slug = let rec find_api s i = if i + 5 > String.length s then "" @@ -2664,17 +2662,19 @@ let http_mode port = String.sub s start (end_ - start) else find_api s (i + 1) in find_api path 0 in - let result = Sx_ref.cek_call api_fn (List [String slug]) in - (* Render to SX wire format or HTML depending on content type *) - let body_str = match result with - | String s | SxExpr s -> s - | Nil -> "" - | _ -> - let call = List [Symbol "aser"; List [Symbol "quote"; result]; Env env] in - (match Sx_ref.eval_expr call (Env env) with - | String s | SxExpr s -> s - | v -> Sx_types.inspect v) in - http_response ~content_type:"text/sx; charset=utf-8" body_str + let handler_key = "handler:ex-" ^ slug in + let hdef = try env_get env handler_key with _ -> Nil in + if hdef = Nil then + http_response ~status:404 ~content_type:"text/sx; charset=utf-8" + (Printf.sprintf "(div :class \"p-4 text-rose-600\" \"Handler not found: %s\")" handler_key) + else + let body = match hdef with Dict d -> (match Hashtbl.find_opt d "body" with Some v -> v | None -> Nil) | _ -> Nil in + (* Evaluate the body in the global env — aser renders HTML tags to wire format *) + let aser_call = List [Symbol "aser"; List [Symbol "quote"; body]; Env env] in + let body_str = match Sx_ref.eval_expr aser_call (Env env) with + | String s | SxExpr s -> s + | v -> Sx_types.inspect v in + http_response ~content_type:"text/sx; charset=utf-8" body_str with e -> Printf.eprintf "[handler] Error for %s: %s\n%!" path (Printexc.to_string e); http_response ~status:500 ~content_type:"text/sx; charset=utf-8"