@xuda.io/runtime-bundle 1.0.1438 → 1.0.1440

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10611,6 +10611,60 @@ func.runtime.ui.set_style = function (target, prop, value) {
10611
10611
  target_node.style[prop] = value;
10612
10612
  return target_node;
10613
10613
  };
10614
+ func.runtime.ui.normalize_external_asset_url = function (value) {
10615
+ if (typeof value !== 'string' || !value.trim()) {
10616
+ return value;
10617
+ }
10618
+
10619
+ const trimmed_value = value.trim();
10620
+ try {
10621
+ const url = new URL(trimmed_value, typeof document !== 'undefined' ? document.baseURI : 'https://xuda.ai');
10622
+ if (url.hostname === 'via.placeholder.com') {
10623
+ url.hostname = 'placehold.co';
10624
+ return url.toString();
10625
+ }
10626
+ } catch (_) {
10627
+ if (trimmed_value.startsWith('https://via.placeholder.com/') || trimmed_value.startsWith('http://via.placeholder.com/')) {
10628
+ return trimmed_value.replace('via.placeholder.com', 'placehold.co');
10629
+ }
10630
+ }
10631
+
10632
+ return value;
10633
+ };
10634
+ func.runtime.ui.normalize_svg_path_value = function (value) {
10635
+ if (typeof value !== 'string' || !value.trim()) {
10636
+ return value;
10637
+ }
10638
+
10639
+ let normalized_value = value.trim();
10640
+
10641
+ // Common AI-generated typo: path data ends with a dangling command after closepath, e.g. "...zzm".
10642
+ normalized_value = normalized_value.replace(/([zZ])+\s*[mMlLhHvVcCsSqQtTaA]\s*$/g, '$1');
10643
+
10644
+ return normalized_value;
10645
+ };
10646
+ func.runtime.ui.normalize_attr_value = function (target_or_tag, key, value) {
10647
+ if (typeof value !== 'string') {
10648
+ return value;
10649
+ }
10650
+
10651
+ const target_tag_name =
10652
+ typeof target_or_tag === 'string'
10653
+ ? target_or_tag
10654
+ : func.runtime.ui.get_first_node(target_or_tag)?.tagName || '';
10655
+ const tag_name = `${target_tag_name || ''}`.trim().toLowerCase();
10656
+ const attr_name = `${key || ''}`.trim().toLowerCase();
10657
+
10658
+ if ((tag_name === 'img' || tag_name === 'image') && ['src', 'href', 'xlink:href'].includes(attr_name)) {
10659
+ return func.runtime.ui.normalize_external_asset_url(value);
10660
+ }
10661
+
10662
+ if (tag_name === 'path' && attr_name === 'd') {
10663
+ return func.runtime.ui.normalize_svg_path_value(value);
10664
+ }
10665
+
10666
+ return value;
10667
+ };
10614
10668
  func.runtime.ui.get_attr = function (target, key) {
10615
10669
  const target_node = func.runtime.ui.get_first_node(target);
10616
10670
  return target_node?.getAttribute?.(key) ?? undefined;
@@ -10618,7 +10672,12 @@ func.runtime.ui.get_attr = function (target, key) {
10618
10672
  func.runtime.ui.set_attr = function (target, key, value) {
10619
10673
  const target_node = func.runtime.ui.get_first_node(target);
10620
10674
  if (target_node?.setAttribute) {
10621
- target_node.setAttribute(key, value);
10675
+ const normalized_value = func.runtime.ui.normalize_attr_value(target_node, key, value);
10676
+ try {
10677
+ target_node.setAttribute(key, normalized_value);
10678
+ } catch (error) {
10679
+ console.warn(`Failed to set attribute "${key}" on <${target_node.tagName?.toLowerCase?.() || 'unknown'}>`, error);
10680
+ }
10622
10681
  }
10623
10682
  return target_node || target;
10624
10683
  };
@@ -10925,7 +10984,12 @@ func.runtime.ui.create_element = function (tag_name, attr_str) {
10925
10984
  while ((match = attr_regex.exec(attr_str)) !== null) {
10926
10985
  const key = match[1];
10927
10986
  const value = match[2] !== undefined ? match[2] : (match[3] !== undefined ? match[3] : (match[4] !== undefined ? match[4] : ''));
10928
- el.setAttribute(key, value);
10987
+ const normalized_value = func.runtime.ui.normalize_attr_value(tag_name, key, value);
10988
+ try {
10989
+ el.setAttribute(key, normalized_value);
10990
+ } catch (error) {
10991
+ console.warn(`Failed to set attribute "${key}" on <${tag_name}>`, error);
10992
+ }
10929
10993
  }
10930
10994
  }
10931
10995
  return el;
@@ -10935,7 +10999,8 @@ func.runtime.ui.create_svg_element = function (element, prop, nodeP, $appendTo)
10935
10999
  let attr_str = '';
10936
11000
  for (const [key, value] of Object.entries(prop)) {
10937
11001
  if (key.substr(0, 2) !== 'xu') {
10938
- attr_str += ` ${key}="${value}" `;
11002
+ const normalized_value = func.runtime.ui.normalize_attr_value(element, key, value);
11003
+ attr_str += ` ${key}="${normalized_value}" `;
10939
11004
  }
10940
11005
  }
10941
11006
  if (element === 'svg') {
@@ -17916,66 +17981,39 @@ const create_runtime_head_element = function (doc, tag_name, attributes, asset_k
17916
17981
  return node;
17917
17982
  };
17918
17983
 
17919
- const queue_runtime_html_script_task = function (task) {
17920
- const queue =
17984
+ const get_runtime_html_script_queue = function () {
17985
+ return (
17921
17986
  func.runtime.render._html_script_queue ||
17922
17987
  (func.runtime.render._html_script_queue = {
17923
17988
  items: [],
17924
- scheduled: false,
17925
17989
  running: false,
17926
- });
17990
+ })
17991
+ );
17992
+ };
17927
17993
 
17994
+ const queue_runtime_html_script_task = function (task) {
17995
+ const queue = get_runtime_html_script_queue();
17928
17996
  queue.items.push(task);
17997
+ };
17929
17998
 
17930
- if (queue.scheduled || queue.running) {
17999
+ func.runtime.render.flush_html_script_queue = async function () {
18000
+ const queue = get_runtime_html_script_queue();
18001
+ if (queue.running || !queue.items.length) {
17931
18002
  return;
17932
18003
  }
17933
18004
 
17934
- queue.scheduled = true;
17935
-
17936
- const drain_queue = async function () {
17937
- if (queue.running) {
17938
- return;
17939
- }
17940
-
17941
- queue.running = true;
17942
- queue.scheduled = false;
18005
+ queue.running = true;
17943
18006
 
17944
- try {
17945
- while (queue.items.length) {
17946
- const next_task = queue.items.shift();
17947
- await next_task();
17948
- }
17949
- } catch (error) {
17950
- console.error(error);
17951
- } finally {
17952
- queue.running = false;
17953
- if (queue.items.length && !queue.scheduled) {
17954
- queue.scheduled = true;
17955
- schedule_runtime_html_script_queue();
17956
- }
17957
- }
17958
- };
17959
-
17960
- const schedule_runtime_html_script_queue = function () {
17961
- const win = func.runtime.platform.get_window?.();
17962
- const run_later = function () {
17963
- setTimeout(function () {
17964
- drain_queue();
17965
- }, 0);
17966
- };
17967
-
17968
- if (win?.requestAnimationFrame) {
17969
- win.requestAnimationFrame(function () {
17970
- win.requestAnimationFrame(run_later);
17971
- });
17972
- return;
18007
+ try {
18008
+ while (queue.items.length) {
18009
+ const next_task = queue.items.shift();
18010
+ await next_task();
17973
18011
  }
17974
-
17975
- run_later();
17976
- };
17977
-
17978
- schedule_runtime_html_script_queue();
18012
+ } catch (error) {
18013
+ console.error(error);
18014
+ } finally {
18015
+ queue.running = false;
18016
+ }
17979
18017
  };
17980
18018
 
17981
18019
  const upsert_runtime_head_element = async function (options) {
@@ -18515,20 +18553,30 @@ func.runtime.render.render_ui_tree = async function (SESSION_ID, $container, nod
18515
18553
  keyP,
18516
18554
  parent_nodeP,
18517
18555
  });
18556
+ const render_depth = func.runtime.render._html_script_render_depth || (func.runtime.render._html_script_render_depth = {});
18557
+ render_depth[SESSION_ID] = (render_depth[SESSION_ID] || 0) + 1;
18518
18558
 
18519
- return await func.runtime.render.render_tree(treeP, {
18520
- SESSION_ID,
18521
- $container,
18522
- parent_infoP,
18523
- paramsP,
18524
- jobNoP,
18525
- is_skeleton,
18526
- keyP,
18527
- refreshed_ds,
18528
- parent_nodeP,
18529
- check_existP,
18530
- $root_container,
18531
- });
18559
+ try {
18560
+ return await func.runtime.render.render_tree(treeP, {
18561
+ SESSION_ID,
18562
+ $container,
18563
+ parent_infoP,
18564
+ paramsP,
18565
+ jobNoP,
18566
+ is_skeleton,
18567
+ keyP,
18568
+ refreshed_ds,
18569
+ parent_nodeP,
18570
+ check_existP,
18571
+ $root_container,
18572
+ });
18573
+ } finally {
18574
+ render_depth[SESSION_ID] = Math.max((render_depth[SESSION_ID] || 1) - 1, 0);
18575
+ if (render_depth[SESSION_ID] === 0) {
18576
+ await func.runtime.render.flush_html_script_queue?.();
18577
+ delete render_depth[SESSION_ID];
18578
+ }
18579
+ }
18532
18580
  };
18533
18581
  func.runtime = func.runtime || {};
18534
18582
  func.runtime.ui = func.runtime.ui || {};