diff --git a/shared/static/scripts/sx-browser.js b/shared/static/scripts/sx-browser.js index 9ab4a7d..8db1fde 100644 --- a/shared/static/scripts/sx-browser.js +++ b/shared/static/scripts/sx-browser.js @@ -14,7 +14,7 @@ // ========================================================================= var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } }); - var SX_VERSION = "2026-03-07T09:03:03Z"; + var SX_VERSION = "2026-03-07T09:23:03Z"; function isNil(x) { return x === NIL || x === null || x === undefined; } function isSxTruthy(x) { return x !== false && !isNil(x); } @@ -3336,7 +3336,7 @@ callExpr.push(dictGet(kwargs, k)); } } result.then(function(rendered) { callback(rendered); }).catch(function(e) { - logInfo("sx:async eval miss: " + (e && e.message ? e.message : e)); + logWarn("sx:async eval miss: " + (e && e.message ? e.message : e)); callback(null); }); } else { @@ -4329,6 +4329,7 @@ callExpr.push(dictGet(kwargs, k)); } } } // Register a server-proxied IO primitive: fetches from /sx/io/ + // Uses GET for short args, POST for long payloads (URL length safety). function registerProxiedIo(name) { registerIoPrimitive(name, function(args, kwargs) { var url = "/sx/io/" + encodeURIComponent(name); @@ -4341,8 +4342,29 @@ callExpr.push(dictGet(kwargs, k)); } } qs.push(encodeURIComponent(k) + "=" + encodeURIComponent(String(kwargs[k]))); } } - if (qs.length) url += "?" + qs.join("&"); - return fetch(url, { headers: { "SX-Request": "true" } }) + var queryStr = qs.join("&"); + var fetchOpts; + if (queryStr.length > 1500) { + // POST with JSON body for long payloads + var sArgs = []; + for (var j = 0; j < args.length; j++) sArgs.push(String(args[j])); + var sKwargs = {}; + for (var kk in kwargs) { + if (kwargs.hasOwnProperty(kk)) sKwargs[kk] = String(kwargs[kk]); + } + var postHeaders = { "SX-Request": "true", "Content-Type": "application/json" }; + var csrf = csrfToken(); + if (csrf && csrf !== NIL) postHeaders["X-CSRFToken"] = csrf; + fetchOpts = { + method: "POST", + headers: postHeaders, + body: JSON.stringify({ args: sArgs, kwargs: sKwargs }) + }; + } else { + if (queryStr) url += "?" + queryStr; + fetchOpts = { headers: { "SX-Request": "true" } }; + } + return fetch(url, fetchOpts) .then(function(resp) { if (!resp.ok) { logWarn("sx:io " + name + " failed " + resp.status); @@ -4359,6 +4381,10 @@ callExpr.push(dictGet(kwargs, k)); } } logWarn("sx:io " + name + " parse error: " + (e && e.message ? e.message : e)); return NIL; } + }) + .catch(function(e) { + logWarn("sx:io " + name + " network error: " + (e && e.message ? e.message : e)); + return NIL; }); }); } diff --git a/shared/sx/ref/bootstrap_js.py b/shared/sx/ref/bootstrap_js.py index a0ef7a1..657b127 100644 --- a/shared/sx/ref/bootstrap_js.py +++ b/shared/sx/ref/bootstrap_js.py @@ -1699,6 +1699,7 @@ ASYNC_IO_JS = ''' } // Register a server-proxied IO primitive: fetches from /sx/io/ + // Uses GET for short args, POST for long payloads (URL length safety). function registerProxiedIo(name) { registerIoPrimitive(name, function(args, kwargs) { var url = "/sx/io/" + encodeURIComponent(name); @@ -1711,8 +1712,29 @@ ASYNC_IO_JS = ''' qs.push(encodeURIComponent(k) + "=" + encodeURIComponent(String(kwargs[k]))); } } - if (qs.length) url += "?" + qs.join("&"); - return fetch(url, { headers: { "SX-Request": "true" } }) + var queryStr = qs.join("&"); + var fetchOpts; + if (queryStr.length > 1500) { + // POST with JSON body for long payloads + var sArgs = []; + for (var j = 0; j < args.length; j++) sArgs.push(String(args[j])); + var sKwargs = {}; + for (var kk in kwargs) { + if (kwargs.hasOwnProperty(kk)) sKwargs[kk] = String(kwargs[kk]); + } + var postHeaders = { "SX-Request": "true", "Content-Type": "application/json" }; + var csrf = csrfToken(); + if (csrf && csrf !== NIL) postHeaders["X-CSRFToken"] = csrf; + fetchOpts = { + method: "POST", + headers: postHeaders, + body: JSON.stringify({ args: sArgs, kwargs: sKwargs }) + }; + } else { + if (queryStr) url += "?" + queryStr; + fetchOpts = { headers: { "SX-Request": "true" } }; + } + return fetch(url, fetchOpts) .then(function(resp) { if (!resp.ok) { logWarn("sx:io " + name + " failed " + resp.status); @@ -1729,6 +1751,10 @@ ASYNC_IO_JS = ''' logWarn("sx:io " + name + " parse error: " + (e && e.message ? e.message : e)); return NIL; } + }) + .catch(function(e) { + logWarn("sx:io " + name + " network error: " + (e && e.message ? e.message : e)); + return NIL; }); }); } @@ -3406,7 +3432,7 @@ PLATFORM_ORCHESTRATION_JS = """ result.then(function(rendered) { callback(rendered); }).catch(function(e) { - logInfo("sx:async eval miss: " + (e && e.message ? e.message : e)); + logWarn("sx:async eval miss: " + (e && e.message ? e.message : e)); callback(null); }); } else {