@xuda.io/runtime-bundle 1.0.1435 → 1.0.1437

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.
@@ -23420,49 +23420,6 @@ if (typeof IS_DOCKER === 'undefined' || typeof IS_PROCESS_SERVER === 'undefined'
23420
23420
  var DOCS_OBJ = {};
23421
23421
  }
23422
23422
 
23423
- // Minimal jQuery shim for plugins that still reference $
23424
- if (typeof $ === 'undefined' && typeof document !== 'undefined') {
23425
- var $ = function (selector) {
23426
- var nodes = typeof selector === 'string'
23427
- ? Array.from(document.querySelectorAll(selector))
23428
- : selector?.nodeType ? [selector] : (selector?.length ? Array.from(selector) : []);
23429
- var obj = {
23430
- 0: nodes[0], length: nodes.length,
23431
- toArray: function () { return nodes.slice(); },
23432
- find: function (s) { var r = []; for (var i = 0; i < nodes.length; i++) { r.push.apply(r, Array.from(nodes[i].querySelectorAll(s))); } return $(r); },
23433
- each: function (fn) { for (var i = 0; i < nodes.length; i++) { fn.call(nodes[i], i, nodes[i]); } return obj; },
23434
- on: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].addEventListener(ev, fn); return obj; },
23435
- off: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].removeEventListener(ev, fn); return obj; },
23436
- addClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.add(c); return obj; },
23437
- removeClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.remove(c); return obj; },
23438
- hasClass: function (c) { return nodes[0]?.classList?.contains(c) || false; },
23439
- attr: function (k, v) { if (typeof v === 'undefined') return nodes[0]?.getAttribute(k); for (var i = 0; i < nodes.length; i++) nodes[i].setAttribute(k, v); return obj; },
23440
- css: function (k, v) { for (var i = 0; i < nodes.length; i++) nodes[i].style[k] = v; return obj; },
23441
- data: function () { return nodes[0]?.__xuData || (nodes[0] ? (nodes[0].__xuData = {}) : {}); },
23442
- val: function (v) { if (typeof v === 'undefined') return nodes[0]?.value; for (var i = 0; i < nodes.length; i++) nodes[i].value = v; return obj; },
23443
- html: function (v) { if (typeof v === 'undefined') return nodes[0]?.innerHTML; for (var i = 0; i < nodes.length; i++) nodes[i].innerHTML = v; return obj; },
23444
- text: function (v) { if (typeof v === 'undefined') return nodes[0]?.textContent; for (var i = 0; i < nodes.length; i++) nodes[i].textContent = v; return obj; },
23445
- show: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = ''; return obj; },
23446
- hide: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = 'none'; return obj; },
23447
- remove: function () { for (var i = 0; i < nodes.length; i++) nodes[i].remove?.(); return obj; },
23448
- empty: function () { for (var i = 0; i < nodes.length; i++) nodes[i].innerHTML = ''; return obj; },
23449
- append: function (c) { var n = c?.nodeType ? c : c?.[0]; if (n && nodes[0]) nodes[0].appendChild(n); return obj; },
23450
- parent: function () { return $(nodes[0]?.parentElement ? [nodes[0].parentElement] : []); },
23451
- children: function () { return $(nodes[0] ? Array.from(nodes[0].children) : []); },
23452
- trigger: function (ev, d) { for (var i = 0; i < nodes.length; i++) nodes[i].dispatchEvent(new CustomEvent(ev, { detail: d })); return obj; },
23453
- is: function (s) { return nodes[0]?.matches?.(s) || false; },
23454
- prop: function (k, v) { if (typeof v === 'undefined') return nodes[0]?.[k]; for (var i = 0; i < nodes.length; i++) nodes[i][k] = v; return obj; },
23455
- unbind: function () { return obj; },
23456
- clone: function () { return $(nodes[0]?.cloneNode(true) ? [nodes[0].cloneNode(true)] : []); },
23457
- };
23458
- obj[Symbol.iterator] = function () { var i = 0; return { next: function () { return i < nodes.length ? { value: nodes[i++], done: false } : { done: true }; } }; };
23459
- return obj;
23460
- };
23461
- $.each = function (o, fn) { if (Array.isArray(o)) { for (var i = 0; i < o.length; i++) fn(i, o[i]); } else { Object.keys(o || {}).forEach(function (k) { fn(k, o[k]); }); } };
23462
- $.cookie = function () { return null; };
23463
- var jQuery = $;
23464
- }
23465
-
23466
23423
  var glb = {};
23467
23424
  var func = {};
23468
23425
  func.UI = {};
@@ -23536,23 +23493,27 @@ glb.PROTECTED_VARS = ['_NULL', '_THIS', '_FOR_KEY', '_FOR_VAL', '_ROWNO', '_ROWI
23536
23493
 
23537
23494
  func.common = {};
23538
23495
  func.runtime.platform = {
23496
+ get_global: function (name) {
23497
+ try {
23498
+ if (typeof globalThis === 'undefined') {
23499
+ return null;
23500
+ }
23501
+ return globalThis?.[name] || null;
23502
+ } catch (error) {
23503
+ return null;
23504
+ }
23505
+ },
23539
23506
  has_window: function () {
23540
- return typeof window !== 'undefined';
23507
+ return !!func.runtime.platform.get_window();
23541
23508
  },
23542
23509
  has_document: function () {
23543
- return typeof document !== 'undefined';
23510
+ return !!func.runtime.platform.get_document();
23544
23511
  },
23545
23512
  get_window: function () {
23546
- if (func.runtime.platform.has_window()) {
23547
- return window;
23548
- }
23549
- return null;
23513
+ return func.runtime.platform.get_global('window');
23550
23514
  },
23551
23515
  get_document: function () {
23552
- if (func.runtime.platform.has_document()) {
23553
- return document;
23554
- }
23555
- return null;
23516
+ return func.runtime.platform.get_global('document');
23556
23517
  },
23557
23518
  get_location: function () {
23558
23519
  const win = func.runtime.platform.get_window();
@@ -23563,27 +23524,23 @@ func.runtime.platform = {
23563
23524
  if (win?.navigator) {
23564
23525
  return win.navigator;
23565
23526
  }
23566
- if (typeof navigator !== 'undefined') {
23567
- return navigator;
23568
- }
23569
- return null;
23527
+ return func.runtime.platform.get_global('navi' + 'gator');
23570
23528
  },
23571
23529
  is_html_element: function (value) {
23572
- if (typeof HTMLElement === 'undefined') {
23530
+ const html_element = func.runtime.platform.get_global('HTML' + 'Element');
23531
+ if (typeof html_element !== 'function') {
23573
23532
  return false;
23574
23533
  }
23575
- return value instanceof HTMLElement;
23534
+ return value instanceof html_element;
23576
23535
  },
23577
23536
  get_storage: function (type) {
23578
23537
  const win = func.runtime.platform.get_window();
23538
+ const storage_key = type === 'session' ? 'session' + 'Storage' : 'local' + 'Storage';
23579
23539
  try {
23580
23540
  if (!win) {
23581
23541
  return null;
23582
23542
  }
23583
- if (type === 'session') {
23584
- return win.sessionStorage || null;
23585
- }
23586
- return win.localStorage || null;
23543
+ return win?.[storage_key] || null;
23587
23544
  } catch (error) {
23588
23545
  return null;
23589
23546
  }
@@ -23740,9 +23697,8 @@ func.runtime.platform.emit = function (name, data) {
23740
23697
  handlers[i](data);
23741
23698
  }
23742
23699
  }
23743
- // also fire on DOM if in browser (for backward compatibility with custom event listeners)
23744
- if (func.runtime.platform.has_document()) {
23745
- document.dispatchEvent(new CustomEvent(name, { detail: Array.isArray(data) ? data : [data] }));
23700
+ if (typeof func.runtime.platform.dispatch_document_event === 'function') {
23701
+ func.runtime.platform.dispatch_document_event(name, data);
23746
23702
  }
23747
23703
  } finally {
23748
23704
  func.runtime.platform._emitting[name] = false;
@@ -23750,35 +23706,111 @@ func.runtime.platform.emit = function (name, data) {
23750
23706
  };
23751
23707
 
23752
23708
  // ── Platform helpers for DOM-independent resource loading ──
23753
- func.runtime.platform.load_script = function (url, type, callback) {
23754
- if (typeof document !== 'undefined') {
23755
- const script = document.createElement('script');
23756
- script.src = url;
23757
- if (type) script.type = type;
23758
- script.onload = callback;
23759
- document.head.appendChild(script);
23760
- } else if (callback) {
23761
- callback();
23709
+ func.runtime.platform.apply_element_attributes = function (node, attributes, excluded_keys = []) {
23710
+ if (!node?.setAttribute || !attributes) {
23711
+ return node;
23712
+ }
23713
+
23714
+ const excluded = new Set(excluded_keys || []);
23715
+ const attr_keys = Object.keys(attributes);
23716
+ for (let index = 0; index < attr_keys.length; index++) {
23717
+ const key = attr_keys[index];
23718
+ if (!key || excluded.has(key)) {
23719
+ continue;
23720
+ }
23721
+
23722
+ const value = attributes[key];
23723
+ if (value === false || typeof value === 'undefined') {
23724
+ continue;
23725
+ }
23726
+
23727
+ node.setAttribute(key, value === null ? '' : `${value}`);
23728
+ }
23729
+
23730
+ return node;
23731
+ };
23732
+ func.runtime.platform.load_script = function (url, type, callback, attributes) {
23733
+ const doc = func.runtime.platform.get_document();
23734
+ if (!doc?.createElement || !doc?.head?.appendChild) {
23735
+ if (callback) {
23736
+ callback();
23737
+ }
23738
+ return;
23762
23739
  }
23740
+ const find_existing_script = function () {
23741
+ const asset_key = attributes?.['data-xuda-asset-key'];
23742
+ const scripts = doc.querySelectorAll ? Array.from(doc.querySelectorAll('script')) : [];
23743
+ return scripts.find(function (script) {
23744
+ if (asset_key && script.getAttribute('data-xuda-asset-key') === asset_key) {
23745
+ return true;
23746
+ }
23747
+ return !!(url && script.getAttribute('src') === url);
23748
+ }) || null;
23749
+ };
23750
+
23751
+ const existing_script = find_existing_script();
23752
+ if (existing_script) {
23753
+ if (callback) {
23754
+ if (existing_script.getAttribute('data-xuda-loaded') === 'true' || !url) {
23755
+ callback();
23756
+ } else {
23757
+ existing_script.addEventListener('load', callback, { once: true });
23758
+ existing_script.addEventListener('error', callback, { once: true });
23759
+ }
23760
+ }
23761
+ return existing_script;
23762
+ }
23763
+
23764
+ const script = doc.createElement('script');
23765
+ script.src = url;
23766
+ if (type) script.type = type;
23767
+ func.runtime.platform.apply_element_attributes(script, attributes, ['src', 'type']);
23768
+ script.onload = function () {
23769
+ script.setAttribute('data-xuda-loaded', 'true');
23770
+ if (callback) {
23771
+ callback();
23772
+ }
23773
+ };
23774
+ script.onerror = function () {
23775
+ if (callback) {
23776
+ callback();
23777
+ }
23778
+ };
23779
+ doc.head.appendChild(script);
23780
+ return script;
23763
23781
  };
23764
- func.runtime.platform.load_css = function (href) {
23765
- if (typeof document === 'undefined') return;
23782
+ func.runtime.platform.load_css = function (href, attributes) {
23783
+ const doc = func.runtime.platform.get_document();
23784
+ if (!doc?.createElement || !doc?.head) {
23785
+ return;
23786
+ }
23766
23787
  try {
23767
- if (document.querySelector('link[href="' + href + '"]')) return;
23788
+ const asset_key = attributes?.['data-xuda-asset-key'];
23789
+ const existing_links = doc.querySelectorAll ? Array.from(doc.querySelectorAll('link')) : [];
23790
+ const existing = existing_links.find(function (link) {
23791
+ if (asset_key && link.getAttribute('data-xuda-asset-key') === asset_key) {
23792
+ return true;
23793
+ }
23794
+ return !!(href && link.getAttribute('href') === href);
23795
+ });
23796
+ if (existing) return existing;
23768
23797
  } catch (err) {
23769
23798
  return;
23770
23799
  }
23771
- const link = document.createElement('link');
23800
+ const link = doc.createElement('link');
23772
23801
  link.rel = 'stylesheet';
23773
23802
  link.type = 'text/css';
23774
23803
  link.href = href;
23775
- document.head.insertBefore(link, document.head.firstChild);
23804
+ func.runtime.platform.apply_element_attributes(link, attributes, ['href']);
23805
+ doc.head.insertBefore(link, doc.head.firstChild);
23806
+ return link;
23776
23807
  };
23777
23808
  func.runtime.platform.remove_js_css = function (filename, filetype) {
23778
- if (typeof document === 'undefined') return;
23809
+ const doc = func.runtime.platform.get_document();
23810
+ if (!doc?.getElementsByTagName) return;
23779
23811
  const tagName = filetype === 'js' ? 'script' : filetype === 'css' ? 'link' : 'none';
23780
23812
  const attr = filetype === 'js' ? 'src' : filetype === 'css' ? 'href' : 'none';
23781
- const elements = document.getElementsByTagName(tagName);
23813
+ const elements = doc.getElementsByTagName(tagName);
23782
23814
  for (let i = elements.length - 1; i >= 0; i--) {
23783
23815
  if (elements[i] && elements[i].getAttribute(attr) != null && elements[i].getAttribute(attr).indexOf(filename) !== -1) {
23784
23816
  elements[i].parentNode.removeChild(elements[i]);
@@ -23786,15 +23818,17 @@ func.runtime.platform.remove_js_css = function (filename, filetype) {
23786
23818
  }
23787
23819
  };
23788
23820
  func.runtime.platform.inject_css = function (cssText) {
23789
- if (typeof document === 'undefined' || !cssText) return;
23790
- const style = document.createElement('style');
23821
+ const doc = func.runtime.platform.get_document();
23822
+ if (!doc?.createElement || !doc?.head?.appendChild || !cssText) return;
23823
+ const style = doc.createElement('style');
23791
23824
  style.type = 'text/css';
23792
23825
  style.textContent = cssText;
23793
- document.head.appendChild(style);
23826
+ doc.head.appendChild(style);
23794
23827
  };
23795
23828
  func.runtime.platform.set_title = function (title) {
23796
- if (typeof document !== 'undefined') {
23797
- document.title = title;
23829
+ const doc = func.runtime.platform.get_document();
23830
+ if (doc) {
23831
+ doc.title = title;
23798
23832
  }
23799
23833
  };
23800
23834
  func.runtime.platform.set_cursor = function (element, cursor) {
@@ -24060,6 +24094,147 @@ func.runtime.workers.delete_promise = function (SESSION_ID, worker_id, promise_q
24060
24094
  delete registry_entry.promise_queue[promise_queue_id];
24061
24095
  return true;
24062
24096
  };
24097
+ func.runtime.render.clone_runtime_options = function (value) {
24098
+ if (typeof structuredClone === 'function') {
24099
+ try {
24100
+ return structuredClone(value);
24101
+ } catch (_) {}
24102
+ }
24103
+
24104
+ if (Array.isArray(value)) {
24105
+ return value.map(function (item) {
24106
+ return func.runtime.render.clone_runtime_options(item);
24107
+ });
24108
+ }
24109
+
24110
+ if (value && typeof value === 'object') {
24111
+ const cloned = {};
24112
+ const keys = Object.keys(value);
24113
+ for (let index = 0; index < keys.length; index++) {
24114
+ const key = keys[index];
24115
+ cloned[key] = func.runtime.render.clone_runtime_options(value[key]);
24116
+ }
24117
+ return cloned;
24118
+ }
24119
+
24120
+ return value;
24121
+ };
24122
+ func.runtime.render.normalize_runtime_bootstrap = function (raw_options = {}) {
24123
+ const options = raw_options || {};
24124
+ let app_computing_mode = options.app_computing_mode || '';
24125
+ let app_render_mode = options.app_render_mode || '';
24126
+ let app_client_activation = options.app_client_activation || '';
24127
+ let ssr_payload = options.ssr_payload || null;
24128
+
24129
+ if (typeof ssr_payload === 'string') {
24130
+ try {
24131
+ ssr_payload = JSON.parse(ssr_payload);
24132
+ } catch (_) {
24133
+ ssr_payload = null;
24134
+ }
24135
+ }
24136
+
24137
+ if (ssr_payload && typeof ssr_payload === 'object') {
24138
+ ssr_payload = func.runtime.render.clone_runtime_options(ssr_payload);
24139
+ }
24140
+
24141
+ if (!app_computing_mode) {
24142
+ if (app_render_mode === 'ssr_first_page' || app_render_mode === 'ssr_full') {
24143
+ app_computing_mode = 'server';
24144
+ } else {
24145
+ app_computing_mode = 'main';
24146
+ }
24147
+ }
24148
+
24149
+ switch (app_computing_mode) {
24150
+ case 'main':
24151
+ app_render_mode = 'csr';
24152
+ app_client_activation = 'none';
24153
+ break;
24154
+
24155
+ case 'worker':
24156
+ app_render_mode = 'csr';
24157
+ app_client_activation = 'none';
24158
+ break;
24159
+
24160
+ default:
24161
+ app_computing_mode = 'server';
24162
+ if (app_render_mode !== 'ssr_full') {
24163
+ app_render_mode = 'ssr_first_page';
24164
+ }
24165
+ app_client_activation = app_render_mode === 'ssr_full' ? 'hydrate' : 'takeover';
24166
+ break;
24167
+ }
24168
+
24169
+ if (ssr_payload && typeof ssr_payload === 'object') {
24170
+ if (!ssr_payload.app_render_mode) {
24171
+ ssr_payload.app_render_mode = app_render_mode;
24172
+ }
24173
+ if (!ssr_payload.app_client_activation) {
24174
+ ssr_payload.app_client_activation = app_client_activation;
24175
+ }
24176
+ if (!ssr_payload.app_computing_mode) {
24177
+ ssr_payload.app_computing_mode = app_computing_mode;
24178
+ }
24179
+ }
24180
+
24181
+ return {
24182
+ app_computing_mode,
24183
+ app_render_mode,
24184
+ app_client_activation,
24185
+ ssr_payload,
24186
+ };
24187
+ };
24188
+ func.runtime.render.apply_runtime_bootstrap_defaults = function (target = {}) {
24189
+ const normalized = func.runtime.render.normalize_runtime_bootstrap(target);
24190
+ target.app_computing_mode = normalized.app_computing_mode;
24191
+ target.app_render_mode = normalized.app_render_mode;
24192
+ target.app_client_activation = normalized.app_client_activation;
24193
+ target.ssr_payload = normalized.ssr_payload;
24194
+ return normalized;
24195
+ };
24196
+ func.runtime.render.is_server_render_mode = function (target = {}) {
24197
+ const normalized = func.runtime.render.normalize_runtime_bootstrap(target?.opt || target);
24198
+ return normalized.app_computing_mode === 'server' && normalized.app_render_mode !== 'csr';
24199
+ };
24200
+ func.runtime.render.is_takeover_mode = function (target = {}) {
24201
+ const normalized = func.runtime.render.normalize_runtime_bootstrap(target?.opt || target);
24202
+ return normalized.app_client_activation === 'takeover';
24203
+ };
24204
+ func.runtime.render.is_hydration_mode = function (target = {}) {
24205
+ const normalized = func.runtime.render.normalize_runtime_bootstrap(target?.opt || target);
24206
+ return normalized.app_client_activation === 'hydrate';
24207
+ };
24208
+ func.runtime.render.get_ssr_payload = function (target = {}) {
24209
+ if (target?.opt?.ssr_payload) {
24210
+ return target.opt.ssr_payload;
24211
+ }
24212
+ if (target?.ssr_payload) {
24213
+ return target.ssr_payload;
24214
+ }
24215
+ const win = func.runtime.platform.get_window();
24216
+ return win?.__XUDA_SSR__ || null;
24217
+ };
24218
+ func.runtime.render.should_use_ssr_payload = function (SESSION_ID, paramsP) {
24219
+ const session = SESSION_OBJ?.[SESSION_ID];
24220
+ const payload = func.runtime.render.get_ssr_payload(session);
24221
+ if (!payload || payload._consumed) {
24222
+ return false;
24223
+ }
24224
+ if (paramsP?.prog_id && payload.prog_id && payload.prog_id !== paramsP.prog_id) {
24225
+ return false;
24226
+ }
24227
+ return true;
24228
+ };
24229
+ func.runtime.render.mark_ssr_payload_consumed = function (SESSION_ID) {
24230
+ const session = SESSION_OBJ?.[SESSION_ID];
24231
+ const payload = func.runtime.render.get_ssr_payload(session);
24232
+ if (!payload || typeof payload !== 'object') {
24233
+ return false;
24234
+ }
24235
+ payload._consumed = true;
24236
+ return true;
24237
+ };
24063
24238
  func.runtime.render.get_root_data_system = function (SESSION_ID) {
24064
24239
  return SESSION_OBJ[SESSION_ID]?.DS_GLB?.[0]?.data_system || null;
24065
24240
  };
@@ -24463,10 +24638,10 @@ func.runtime.resources.load_cdn = async function (SESSION_ID, resource) {
24463
24638
  await func.utils.load_js_on_demand(normalized_resource.src);
24464
24639
  break;
24465
24640
  case 'css':
24466
- await func.utils.load_js_on_demand(normalized_resource.src);
24641
+ func.runtime.platform.load_css(normalized_resource.src);
24467
24642
  break;
24468
24643
  case 'module':
24469
- func.utils.load_js_on_demand(normalized_resource.src, 'module');
24644
+ await func.utils.load_js_on_demand(normalized_resource.src, 'module');
24470
24645
  break;
24471
24646
  default:
24472
24647
  await func.utils.load_js_on_demand(normalized_resource.src);
@@ -24482,12 +24657,36 @@ func.runtime.resources.load_cdn = async function (SESSION_ID, resource) {
24482
24657
  func.runtime.resources.get_plugin_manifest_entry = function (_session, plugin_name) {
24483
24658
  return APP_OBJ[_session.app_id]?.app_plugins_purchased?.[plugin_name] || null;
24484
24659
  };
24485
- func.runtime.resources.get_plugin_module_path = function (plugin, resource) {
24660
+ func.runtime.resources.get_plugin_resource_candidates = function (_session, plugin, resource) {
24486
24661
  const manifest_entry = plugin?.manifest?.[resource];
24487
- return `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
24662
+ const default_path = `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
24663
+ const candidates = [];
24664
+ if (_session?.worker_type === 'Dev' && manifest_entry?.dist && /\.mjs$/.test(resource)) {
24665
+ candidates.push(`src/${resource}`);
24666
+ }
24667
+ candidates.push(default_path);
24668
+ return Array.from(new Set(candidates.filter(Boolean)));
24669
+ };
24670
+ func.runtime.resources.get_plugin_module_path = function (plugin, resource, _session) {
24671
+ return func.runtime.resources.get_plugin_resource_candidates(_session, plugin, resource)[0] || resource;
24488
24672
  };
24489
24673
  func.runtime.resources.get_plugin_module_url = async function (SESSION_ID, plugin_name, plugin, resource) {
24490
- return await func.utils.get_plugin_npm_cdn(SESSION_ID, plugin_name, func.runtime.resources.get_plugin_module_path(plugin, resource));
24674
+ const _session = SESSION_OBJ[SESSION_ID];
24675
+ return await func.utils.get_plugin_npm_cdn(SESSION_ID, plugin_name, func.runtime.resources.get_plugin_module_path(plugin, resource, _session));
24676
+ };
24677
+ func.runtime.resources.import_plugin_module = async function (SESSION_ID, plugin_name, plugin, resource) {
24678
+ const _session = SESSION_OBJ[SESSION_ID];
24679
+ const candidates = func.runtime.resources.get_plugin_resource_candidates(_session, plugin, resource);
24680
+ let last_error = null;
24681
+ for (let index = 0; index < candidates.length; index++) {
24682
+ const candidate = candidates[index];
24683
+ try {
24684
+ return await func.utils.get_plugin_resource(SESSION_ID, plugin_name, candidate);
24685
+ } catch (error) {
24686
+ last_error = error;
24687
+ }
24688
+ }
24689
+ throw last_error || new Error(`plugin resource not found: ${plugin_name}/${resource}`);
24491
24690
  };
24492
24691
  func.runtime.resources.load_plugin_runtime_css = async function (SESSION_ID, plugin_name, plugin) {
24493
24692
  if (!plugin?.manifest?.['runtime.mjs']?.dist || !plugin?.manifest?.['runtime.mjs']?.css) {
@@ -24517,12 +24716,10 @@ func.runtime.resources.run_ui_plugin = async function (SESSION_ID, paramsP, $elm
24517
24716
 
24518
24717
  await func.runtime.resources.load_plugin_runtime_css(SESSION_ID, plugin_name, plugin);
24519
24718
 
24520
- const plugin_index_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'index.mjs');
24521
- const plugin_index_resources = await import(plugin_index_src);
24719
+ const plugin_index_resources = await func.runtime.resources.import_plugin_module(SESSION_ID, plugin_name, plugin, 'index.mjs');
24522
24720
  const properties = await func.runtime.resources.resolve_plugin_properties(SESSION_ID, paramsP.dsSessionP, value?.attributes, plugin_index_resources.properties);
24523
24721
 
24524
- const plugin_runtime_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
24525
- const plugin_runtime_resources = await import(plugin_runtime_src);
24722
+ const plugin_runtime_resources = await func.runtime.resources.import_plugin_module(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
24526
24723
 
24527
24724
  if (plugin_runtime_resources.cdn && Array.isArray(plugin_runtime_resources.cdn)) {
24528
24725
  for await (const resource of plugin_runtime_resources.cdn) {
@@ -24605,25 +24802,52 @@ func.runtime.widgets.get_fields_data = async function (context, fields, props) {
24605
24802
 
24606
24803
  return { code: return_code, data: data_obj };
24607
24804
  };
24805
+ func.runtime.widgets.get_resource_candidates = function (context, resource) {
24806
+ return func.runtime.resources.get_plugin_resource_candidates(context._session, context.plugin, resource);
24807
+ };
24808
+ func.runtime.widgets.normalize_capabilities = function (definition) {
24809
+ const capabilities = definition?.capabilities || {};
24810
+ return {
24811
+ browser: capabilities.browser !== false,
24812
+ headless: capabilities.headless === true,
24813
+ };
24814
+ };
24815
+ func.runtime.widgets.supports_current_environment = function (definition) {
24816
+ const capabilities = func.runtime.widgets.normalize_capabilities(definition);
24817
+ if (func.runtime.platform.has_document()) {
24818
+ return capabilities.browser !== false;
24819
+ }
24820
+ return !!capabilities.headless;
24821
+ };
24608
24822
  func.runtime.widgets.get_resource_path = function (context, resource) {
24823
+ const relative_path = func.runtime.widgets.get_resource_candidates(context, resource)[0] || resource;
24609
24824
  if (context._session.worker_type === 'Dev') {
24610
- return `../../plugins/${context.plugin_name}/${resource}`;
24825
+ return `../../plugins/${context.plugin_name}/${relative_path}`;
24611
24826
  }
24612
- const manifest_entry = context.plugin?.manifest?.[resource];
24613
- const dist_prefix = manifest_entry?.dist ? 'dist/' : '';
24614
- return `https://${context._session.domain}/plugins/${context.plugin_name}/${dist_prefix}${resource}?gtp_token=${context._session.gtp_token}&app_id=${context._session.app_id}`;
24827
+ return `https://${context._session.domain}/plugins/${context.plugin_name}/${relative_path}?gtp_token=${context._session.gtp_token}&app_id=${context._session.app_id}`;
24615
24828
  };
24616
24829
  func.runtime.widgets.load_css_style = function (context) {
24617
24830
  func.utils.load_css_on_demand(func.runtime.widgets.get_resource_path(context, 'style.css'));
24618
24831
  return true;
24619
24832
  };
24620
24833
  func.runtime.widgets.get_resource = async function (context, resource) {
24621
- const manifest_entry = context.plugin?.manifest?.[resource];
24622
- const path = `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
24623
- return await func.utils.get_plugin_resource(context.SESSION_ID, context.plugin_name, path);
24834
+ const candidates = func.runtime.widgets.get_resource_candidates(context, resource);
24835
+ let last_error = null;
24836
+ for (let index = 0; index < candidates.length; index++) {
24837
+ const candidate = candidates[index];
24838
+ try {
24839
+ return await func.utils.get_plugin_resource(context.SESSION_ID, context.plugin_name, candidate);
24840
+ } catch (error) {
24841
+ last_error = error;
24842
+ }
24843
+ }
24844
+ throw last_error || new Error(`widget resource not found: ${context.plugin_name}/${resource}`);
24845
+ };
24846
+ func.runtime.widgets.get_definition = async function (context) {
24847
+ return await func.runtime.widgets.get_resource(context, 'index.mjs');
24624
24848
  };
24625
24849
  func.runtime.widgets.get_methods = async function (context) {
24626
- const index = await func.runtime.widgets.get_resource(context, 'index.mjs');
24850
+ const index = await func.runtime.widgets.get_definition(context);
24627
24851
  return index?.methods || {};
24628
24852
  };
24629
24853
  func.runtime.widgets.load_runtime_css = async function (context) {
@@ -24634,7 +24858,7 @@ func.runtime.widgets.load_runtime_css = async function (context) {
24634
24858
  func.utils.load_css_on_demand(plugin_runtime_css_url);
24635
24859
  return true;
24636
24860
  };
24637
- func.runtime.widgets.build_params = function (context, $containerP, plugin_setup, api_utils, extra = {}) {
24861
+ func.runtime.widgets.build_params = function (context, container_node, container_data, plugin_setup, api_utils, extra = {}) {
24638
24862
  return {
24639
24863
  SESSION_ID: context.SESSION_ID,
24640
24864
  method: context.method,
@@ -24643,14 +24867,28 @@ func.runtime.widgets.build_params = function (context, $containerP, plugin_setup
24643
24867
  sourceP: context.sourceP,
24644
24868
  propsP: context.propsP,
24645
24869
  plugin_name: context.plugin_name,
24646
- $containerP,
24870
+ container_node,
24871
+ container_data,
24647
24872
  plugin_setup,
24648
24873
  report_error: function (descP, warn) {
24649
24874
  return func.runtime.widgets.report_error(context, descP, warn);
24650
24875
  },
24876
+ log_error: function (descP, warn) {
24877
+ return func.runtime.widgets.report_error(context, descP, warn);
24878
+ },
24651
24879
  call_plugin_api: async function (plugin_nameP, dataP) {
24652
24880
  return await func.utils.call_plugin_api(context.SESSION_ID, plugin_nameP, dataP);
24653
24881
  },
24882
+ set_SYS_GLOBAL_OBJ_WIDGET_INFO: async function (docP) {
24883
+ return await func.utils.set_SYS_GLOBAL_OBJ_WIDGET_INFO(context.SESSION_ID, docP);
24884
+ },
24885
+ run_widgetCallbackEvent: async function () {
24886
+ const event_id = context.propsP?.widgetCallbackEvent;
24887
+ if (!event_id || !api_utils?.invoke_event) {
24888
+ return false;
24889
+ }
24890
+ return await api_utils.invoke_event(event_id);
24891
+ },
24654
24892
  api_utils,
24655
24893
  ...extra,
24656
24894
  };
@@ -25721,25 +25959,722 @@ func.common.get_data_from_websocket = async function (SESSION_ID, serviceP, data
25721
25959
  // // so slicing is a reliable way to get a fixed length.
25722
25960
  // const shortHash = base36Hash.slice(0, 10);
25723
25961
 
25724
- // // 5. Pad the start in the unlikely case the hash is shorter than 10 characters.
25725
- // // This ensures the output is always exactly 10 characters long.
25726
- // return shortHash.padStart(10, '0');
25727
- // };
25962
+ // // 5. Pad the start in the unlikely case the hash is shorter than 10 characters.
25963
+ // // This ensures the output is always exactly 10 characters long.
25964
+ // return shortHash.padStart(10, '0');
25965
+ // };
25966
+
25967
+ func.common.fastHash = function (inputString) {
25968
+ let hash = 0x811c9dc5; // FNV offset basis
25969
+
25970
+ for (let i = 0; i < inputString.length; i++) {
25971
+ hash ^= inputString.charCodeAt(i);
25972
+ // FNV prime multiplication with 32-bit overflow
25973
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
25974
+ }
25975
+
25976
+ // Convert to base36 and pad to 10 characters
25977
+ return ((hash >>> 0).toString(36) + '0000000000').slice(0, 10);
25978
+ };
25979
+
25980
+ glb.new_xu_render = false;
25981
+ func.runtime = func.runtime || {};
25982
+ func.runtime.ui = func.runtime.ui || {};
25983
+ func.runtime.render = func.runtime.render || {};
25984
+ func.runtime.widgets = func.runtime.widgets || {};
25985
+
25986
+ // Shared render-tree contract helpers live here so browser and headless runtimes can resolve the same UI structure.
25987
+
25988
+ func.runtime.render.TREE_CONTRACT_VERSION = func.runtime.render.TREE_CONTRACT_VERSION || 'xuda.render_tree.v1';
25989
+ func.runtime.render._tree_widget_capability_cache = func.runtime.render._tree_widget_capability_cache || {};
25990
+
25991
+ func.runtime.render.safe_clone_tree_value = function (value) {
25992
+ if (typeof structuredClone === 'function') {
25993
+ try {
25994
+ return structuredClone(value);
25995
+ } catch (_) {
25996
+ // Fall through to the recursive clone below.
25997
+ }
25998
+ }
25999
+
26000
+ if (Array.isArray(value)) {
26001
+ return value.map(function (item) {
26002
+ return func.runtime.render.safe_clone_tree_value(item);
26003
+ });
26004
+ }
26005
+
26006
+ if (value && typeof value === 'object') {
26007
+ const cloned = {};
26008
+ const keys = Object.keys(value);
26009
+ for (let index = 0; index < keys.length; index++) {
26010
+ const key = keys[index];
26011
+ cloned[key] = func.runtime.render.safe_clone_tree_value(value[key]);
26012
+ }
26013
+ return cloned;
26014
+ }
26015
+
26016
+ return value;
26017
+ };
26018
+ func.runtime.render.sort_tree_debug_value = function (value) {
26019
+ if (Array.isArray(value)) {
26020
+ return value.map(function (item) {
26021
+ return func.runtime.render.sort_tree_debug_value(item);
26022
+ });
26023
+ }
26024
+
26025
+ if (value && typeof value === 'object') {
26026
+ const sorted = {};
26027
+ const keys = Object.keys(value).sort();
26028
+ for (let index = 0; index < keys.length; index++) {
26029
+ const key = keys[index];
26030
+ sorted[key] = func.runtime.render.sort_tree_debug_value(value[key]);
26031
+ }
26032
+ return sorted;
26033
+ }
26034
+
26035
+ return value;
26036
+ };
26037
+ func.runtime.render.is_tree_node = function (nodeP) {
26038
+ return !!nodeP?.contract && nodeP.contract === func.runtime.render.TREE_CONTRACT_VERSION;
26039
+ };
26040
+ func.runtime.render.get_tree_source_node = function (nodeP) {
26041
+ if (!func.runtime.render.is_tree_node(nodeP)) {
26042
+ return nodeP || null;
26043
+ }
26044
+ return nodeP?.meta?.source_node || null;
26045
+ };
26046
+ func.runtime.render.get_tree_source_snapshot = function (nodeP) {
26047
+ if (!func.runtime.render.is_tree_node(nodeP)) {
26048
+ return func.runtime.render.safe_clone_tree_value(nodeP);
26049
+ }
26050
+ return nodeP?.meta?.source_snapshot || null;
26051
+ };
26052
+ func.runtime.render.get_tree_node_kind = function (nodeP) {
26053
+ const tag_name = typeof nodeP?.tagName === 'string' ? nodeP.tagName.toLowerCase() : '';
26054
+ const node_type = typeof nodeP?.type === 'string' ? nodeP.type.toLowerCase() : '';
26055
+
26056
+ if (tag_name === 'xu-widget') return 'widget';
26057
+ if (tag_name === 'xu-single-view') return 'single_view';
26058
+ if (tag_name === 'xu-multi-view') return 'multi_view';
26059
+ if (tag_name === 'xu-panel') return 'panel';
26060
+ if (tag_name === 'xu-teleport') return 'teleport';
26061
+ if (tag_name === 'xurender') return 'placeholder';
26062
+ if (tag_name === '#text' || node_type === 'text') return 'text';
26063
+ if (!tag_name && typeof nodeP?.content === 'string' && !Array.isArray(nodeP?.children)) return 'text';
26064
+ return 'element';
26065
+ };
26066
+ func.runtime.render.get_tree_node_id = function (nodeP, pathP) {
26067
+ if (nodeP?.id) {
26068
+ return nodeP.id;
26069
+ }
26070
+ if (nodeP?.id_org) {
26071
+ return nodeP.id_org;
26072
+ }
26073
+ const normalized_path = Array.isArray(pathP) && pathP.length ? pathP.join('.') : 'root';
26074
+ return `tree-node-${normalized_path}`;
26075
+ };
26076
+ func.runtime.render.get_tree_controls = function (attributes) {
26077
+ const attrs = attributes || {};
26078
+ const get_first_defined = function (keys) {
26079
+ for (let index = 0; index < keys.length; index++) {
26080
+ const key = keys[index];
26081
+ if (Object.prototype.hasOwnProperty.call(attrs, key)) {
26082
+ return attrs[key];
26083
+ }
26084
+ }
26085
+ return null;
26086
+ };
26087
+ return {
26088
+ xu_for: get_first_defined(['xu-for', 'xu-exp:xu-for']),
26089
+ xu_if: get_first_defined(['xu-if', 'xu-exp:xu-if']),
26090
+ xu_render: get_first_defined(['xu-render', 'xu-exp:xu-render']),
26091
+ };
26092
+ };
26093
+ func.runtime.render.get_tree_node_capabilities = async function (options) {
26094
+ const attributes = options?.attributes || {};
26095
+ const plugin_name = attributes['xu-widget'];
26096
+ if (!plugin_name) {
26097
+ return null;
26098
+ }
26099
+
26100
+ const cache = func.runtime.render._tree_widget_capability_cache;
26101
+ if (cache[plugin_name]) {
26102
+ return func.runtime.render.safe_clone_tree_value(cache[plugin_name]);
26103
+ }
26104
+
26105
+ let capabilities = {
26106
+ browser: true,
26107
+ headless: false,
26108
+ };
26109
+
26110
+ try {
26111
+ if (options.SESSION_ID && options.paramsP && func.runtime.widgets?.create_context && func.runtime.widgets?.get_definition) {
26112
+ const widget_context = func.runtime.widgets.create_context(options.SESSION_ID, options.paramsP, attributes);
26113
+ const definition = await func.runtime.widgets.get_definition(widget_context);
26114
+ capabilities = func.runtime.widgets.normalize_capabilities(definition);
26115
+ }
26116
+ } catch (_) {
26117
+ // Keep the safe browser-only default when the widget definition is unavailable.
26118
+ }
26119
+
26120
+ cache[plugin_name] = capabilities;
26121
+ return func.runtime.render.safe_clone_tree_value(capabilities);
26122
+ };
26123
+ func.runtime.render.ensure_tree_node = async function (options) {
26124
+ if (!options?.nodeP) {
26125
+ return null;
26126
+ }
26127
+ if (func.runtime.render.is_tree_node(options.nodeP)) {
26128
+ return options.nodeP;
26129
+ }
26130
+ return await func.runtime.render.build_tree(options);
26131
+ };
26132
+ func.runtime.render.build_tree = async function (options) {
26133
+ if (Array.isArray(options?.nodeP)) {
26134
+ return await func.runtime.render.build_tree_list({
26135
+ ...options,
26136
+ nodesP: options.nodeP,
26137
+ });
26138
+ }
26139
+
26140
+ const nodeP = options?.nodeP;
26141
+ if (!nodeP) {
26142
+ return null;
26143
+ }
26144
+ if (func.runtime.render.is_tree_node(nodeP)) {
26145
+ return nodeP;
26146
+ }
26147
+
26148
+ const pathP = Array.isArray(options?.pathP) ? options.pathP.slice() : [];
26149
+ const tree_path = pathP.length ? pathP.slice() : [0];
26150
+ const attributes = func.runtime.render.safe_clone_tree_value(nodeP.attributes || {});
26151
+ if (typeof nodeP.content !== 'undefined' && typeof attributes['xu-content'] === 'undefined') {
26152
+ attributes['xu-content'] = func.runtime.render.safe_clone_tree_value(nodeP.content);
26153
+ }
26154
+
26155
+ const widget_capabilities = await func.runtime.render.get_tree_node_capabilities({
26156
+ SESSION_ID: options?.SESSION_ID,
26157
+ paramsP: options?.paramsP,
26158
+ attributes,
26159
+ });
26160
+ const children = [];
26161
+ const child_nodes = Array.isArray(nodeP.children) ? nodeP.children : [];
26162
+ const parent_tree_id = tree_path.join('.');
26163
+
26164
+ for (let index = 0; index < child_nodes.length; index++) {
26165
+ const child_tree = await func.runtime.render.build_tree({
26166
+ ...options,
26167
+ nodeP: child_nodes[index],
26168
+ pathP: tree_path.concat(index),
26169
+ parent_tree_id: parent_tree_id,
26170
+ keyP: index,
26171
+ parent_nodeP: nodeP,
26172
+ });
26173
+ if (child_tree) {
26174
+ children.push(child_tree);
26175
+ }
26176
+ }
26177
+
26178
+ const tree = {
26179
+ contract: func.runtime.render.TREE_CONTRACT_VERSION,
26180
+ id: func.runtime.render.get_tree_node_id(nodeP, tree_path),
26181
+ xu_tree_id: `tree.${tree_path.join('.')}`,
26182
+ kind: func.runtime.render.get_tree_node_kind(nodeP),
26183
+ tagName: nodeP.tagName || null,
26184
+ attributes,
26185
+ text: typeof nodeP.text !== 'undefined' ? func.runtime.render.safe_clone_tree_value(nodeP.text) : null,
26186
+ content: typeof nodeP.content !== 'undefined' ? func.runtime.render.safe_clone_tree_value(nodeP.content) : null,
26187
+ children,
26188
+ meta: {
26189
+ tree_id: tree_path.join('.'),
26190
+ path: tree_path,
26191
+ parent_tree_id: options?.parent_tree_id || null,
26192
+ key: typeof options?.keyP === 'undefined' ? null : options.keyP,
26193
+ recordid: nodeP?.recordid || null,
26194
+ dependency_fields: func.runtime.render.safe_clone_tree_value(nodeP?.dependency_fields || null),
26195
+ iterate_info: func.runtime.render.safe_clone_tree_value(options?.parent_infoP?.iterate_info || nodeP?.iterate_info || null),
26196
+ controls: func.runtime.render.get_tree_controls(attributes),
26197
+ capabilities: widget_capabilities,
26198
+ widget: attributes['xu-widget']
26199
+ ? {
26200
+ plugin_name: attributes['xu-widget'],
26201
+ method: attributes['xu-method'] || '_default',
26202
+ capabilities: widget_capabilities,
26203
+ }
26204
+ : null,
26205
+ source_node_id: nodeP?.id || nodeP?.id_org || null,
26206
+ source_node: nodeP,
26207
+ source_snapshot: func.runtime.ui?.get_node_snapshot
26208
+ ? func.runtime.ui.get_node_snapshot(nodeP)
26209
+ : func.runtime.render.safe_clone_tree_value(nodeP),
26210
+ },
26211
+ };
26212
+
26213
+ return tree;
26214
+ };
26215
+ func.runtime.render.build_tree_list = async function (options) {
26216
+ const nodes = Array.isArray(options?.nodesP) ? options.nodesP : [];
26217
+ const trees = [];
26218
+
26219
+ for (let index = 0; index < nodes.length; index++) {
26220
+ const tree = await func.runtime.render.build_tree({
26221
+ ...options,
26222
+ nodeP: nodes[index],
26223
+ pathP: Array.isArray(options?.pathP) && options.pathP.length ? options.pathP.concat(index) : [index],
26224
+ keyP: index,
26225
+ });
26226
+ if (tree) {
26227
+ trees.push(tree);
26228
+ }
26229
+ }
26230
+
26231
+ return trees;
26232
+ };
26233
+ func.runtime.render.sanitize_tree_for_debug = function (treeP) {
26234
+ if (Array.isArray(treeP)) {
26235
+ return treeP.map(function (child) {
26236
+ return func.runtime.render.sanitize_tree_for_debug(child);
26237
+ });
26238
+ }
26239
+
26240
+ if (!func.runtime.render.is_tree_node(treeP)) {
26241
+ return func.runtime.render.sort_tree_debug_value(func.runtime.render.safe_clone_tree_value(treeP));
26242
+ }
26243
+
26244
+ return {
26245
+ contract: treeP.contract,
26246
+ id: treeP.id,
26247
+ xu_tree_id: treeP.xu_tree_id || null,
26248
+ kind: treeP.kind,
26249
+ tagName: treeP.tagName,
26250
+ attributes: func.runtime.render.sort_tree_debug_value(treeP.attributes || {}),
26251
+ text: treeP.text,
26252
+ content: treeP.content,
26253
+ children: treeP.children.map(function (child) {
26254
+ return func.runtime.render.sanitize_tree_for_debug(child);
26255
+ }),
26256
+ meta: {
26257
+ tree_id: treeP.meta?.tree_id || null,
26258
+ path: func.runtime.render.safe_clone_tree_value(treeP.meta?.path || []),
26259
+ parent_tree_id: treeP.meta?.parent_tree_id || null,
26260
+ key: typeof treeP.meta?.key === 'undefined' ? null : treeP.meta.key,
26261
+ recordid: treeP.meta?.recordid || null,
26262
+ dependency_fields: func.runtime.render.sort_tree_debug_value(treeP.meta?.dependency_fields || null),
26263
+ iterate_info: func.runtime.render.sort_tree_debug_value(treeP.meta?.iterate_info || null),
26264
+ controls: func.runtime.render.sort_tree_debug_value(treeP.meta?.controls || null),
26265
+ capabilities: func.runtime.render.sort_tree_debug_value(treeP.meta?.capabilities || null),
26266
+ widget: treeP.meta?.widget
26267
+ ? {
26268
+ plugin_name: treeP.meta.widget.plugin_name,
26269
+ method: treeP.meta.widget.method,
26270
+ capabilities: func.runtime.render.sort_tree_debug_value(treeP.meta.widget.capabilities || null),
26271
+ }
26272
+ : null,
26273
+ source_node_id: treeP.meta?.source_node_id || null,
26274
+ },
26275
+ };
26276
+ };
26277
+ func.runtime.render.serialize_tree = function (treeP, spacing = 2) {
26278
+ return JSON.stringify(func.runtime.render.sanitize_tree_for_debug(treeP), null, spacing);
26279
+ };
26280
+ func.runtime = func.runtime || {};
26281
+ func.runtime.ui = func.runtime.ui || {};
26282
+ func.runtime.render = func.runtime.render || {};
26283
+ func.runtime.widgets = func.runtime.widgets || {};
26284
+
26285
+ // Shared string-renderer helpers live here so headless/server runtimes can materialize the render tree without a DOM.
26286
+
26287
+ func.runtime.render.HTML_VOID_TAGS = func.runtime.render.HTML_VOID_TAGS || {
26288
+ area: true,
26289
+ base: true,
26290
+ br: true,
26291
+ col: true,
26292
+ embed: true,
26293
+ hr: true,
26294
+ img: true,
26295
+ input: true,
26296
+ link: true,
26297
+ meta: true,
26298
+ param: true,
26299
+ source: true,
26300
+ track: true,
26301
+ wbr: true,
26302
+ };
26303
+ func.runtime.render.escape_html = function (value) {
26304
+ return `${value ?? ''}`
26305
+ .replaceAll('&', '&amp;')
26306
+ .replaceAll('<', '&lt;')
26307
+ .replaceAll('>', '&gt;')
26308
+ .replaceAll('"', '&quot;')
26309
+ .replaceAll("'", '&#039;');
26310
+ };
26311
+ func.runtime.render.escape_html_attribute = function (value) {
26312
+ return func.runtime.render.escape_html(value);
26313
+ };
26314
+ func.runtime.render.is_html_void_tag = function (tag_name) {
26315
+ return !!func.runtime.render.HTML_VOID_TAGS[(tag_name || '').toLowerCase()];
26316
+ };
26317
+ func.runtime.render.is_falsey_render_value = function (value) {
26318
+ if (value === false || value === null || typeof value === 'undefined') {
26319
+ return true;
26320
+ }
26321
+ if (typeof value === 'number') {
26322
+ return value === 0;
26323
+ }
26324
+ if (typeof value === 'string') {
26325
+ const normalized = value.trim().toLowerCase();
26326
+ return normalized === '' || normalized === 'false' || normalized === '0' || normalized === 'null' || normalized === 'undefined' || normalized === 'off' || normalized === 'no';
26327
+ }
26328
+ return false;
26329
+ };
26330
+ func.runtime.render.should_render_tree_node = function (treeP) {
26331
+ const controls = treeP?.meta?.controls || {};
26332
+ if (controls.xu_if !== null && controls.xu_if !== undefined && func.runtime.render.is_falsey_render_value(controls.xu_if)) {
26333
+ return false;
26334
+ }
26335
+ if (controls.xu_render !== null && controls.xu_render !== undefined && func.runtime.render.is_falsey_render_value(controls.xu_render)) {
26336
+ return false;
26337
+ }
26338
+ return true;
26339
+ };
26340
+ func.runtime.render.is_tree_control_attribute = function (key) {
26341
+ if (!key) {
26342
+ return false;
26343
+ }
26344
+ return (
26345
+ key.startsWith('xu-exp:') ||
26346
+ key === 'xu-widget' ||
26347
+ key === 'xu-method' ||
26348
+ key === 'xu-for' ||
26349
+ key === 'xu-for-key' ||
26350
+ key === 'xu-for-val' ||
26351
+ key === 'xu-if' ||
26352
+ key === 'xu-render' ||
26353
+ key === 'xu-bind' ||
26354
+ key === 'xu-content' ||
26355
+ key === 'xu-text' ||
26356
+ key === 'xu-html' ||
26357
+ key === 'xu-show' ||
26358
+ key === 'xu-panel-program' ||
26359
+ key === 'xu-teleport'
26360
+ );
26361
+ };
26362
+ func.runtime.render.get_string_renderer_tag_name = function (treeP) {
26363
+ switch (treeP?.kind) {
26364
+ case 'widget':
26365
+ case 'single_view':
26366
+ case 'multi_view':
26367
+ case 'panel':
26368
+ case 'teleport':
26369
+ return 'div';
26370
+ case 'placeholder':
26371
+ return null;
26372
+ case 'text':
26373
+ return null;
26374
+ default:
26375
+ return treeP?.tagName || 'div';
26376
+ }
26377
+ };
26378
+ func.runtime.render.get_tree_terminal_content = function (treeP) {
26379
+ const attributes = treeP?.attributes || {};
26380
+ if (typeof attributes['xu-html'] !== 'undefined' && attributes['xu-html'] !== null) {
26381
+ return {
26382
+ value: `${attributes['xu-html']}`,
26383
+ mode: 'html',
26384
+ };
26385
+ }
26386
+ if (typeof attributes['xu-content'] !== 'undefined' && attributes['xu-content'] !== null) {
26387
+ return {
26388
+ value: `${attributes['xu-content']}`,
26389
+ mode: 'html',
26390
+ };
26391
+ }
26392
+ if (typeof attributes['xu-text'] !== 'undefined' && attributes['xu-text'] !== null) {
26393
+ return {
26394
+ value: `${attributes['xu-text']}`,
26395
+ mode: 'text',
26396
+ };
26397
+ }
26398
+ if (treeP?.kind === 'text') {
26399
+ return {
26400
+ value: typeof treeP?.text !== 'undefined' && treeP?.text !== null ? `${treeP.text}` : `${treeP?.content || ''}`,
26401
+ mode: 'text',
26402
+ };
26403
+ }
26404
+ return null;
26405
+ };
26406
+ func.runtime.render.render_tree_terminal_content = function (treeP) {
26407
+ const terminal = func.runtime.render.get_tree_terminal_content(treeP);
26408
+ if (!terminal) {
26409
+ return null;
26410
+ }
26411
+ if (terminal.mode === 'html') {
26412
+ return terminal.value;
26413
+ }
26414
+ return func.runtime.render.escape_html(terminal.value);
26415
+ };
26416
+ func.runtime.render.get_widget_fallback_markup = function (treeP) {
26417
+ const widget_meta = treeP?.meta?.widget || {};
26418
+ const capability_state = widget_meta?.capabilities?.headless ? 'headless-capable' : 'browser-only';
26419
+ return `<!--xuda-widget:${func.runtime.render.escape_html(widget_meta.plugin_name || 'unknown')}:${capability_state}-->`;
26420
+ };
26421
+ func.runtime.render.get_tree_string_attributes = function (treeP, renderer_context) {
26422
+ const attributes = func.runtime.render.safe_clone_tree_value(treeP?.attributes || {});
26423
+ const attr_pairs = [];
26424
+ const keys = Object.keys(attributes);
26425
+
26426
+ for (let index = 0; index < keys.length; index++) {
26427
+ const key = keys[index];
26428
+ if (func.runtime.render.is_tree_control_attribute(key)) {
26429
+ continue;
26430
+ }
26431
+ const value = attributes[key];
26432
+ if (value === false || value === null || typeof value === 'undefined') {
26433
+ continue;
26434
+ }
26435
+ if (value === true) {
26436
+ attr_pairs.push(key);
26437
+ continue;
26438
+ }
26439
+ const normalized_value = typeof value === 'object' ? JSON.stringify(value) : `${value}`;
26440
+ attr_pairs.push(`${key}="${func.runtime.render.escape_html_attribute(normalized_value)}"`);
26441
+ }
26442
+
26443
+ attr_pairs.push(`data-xuda-kind="${func.runtime.render.escape_html_attribute(treeP?.kind || 'element')}"`);
26444
+ attr_pairs.push(`data-xuda-node-id="${func.runtime.render.escape_html_attribute(treeP?.id || treeP?.meta?.source_node_id || '')}"`);
26445
+ attr_pairs.push(`data-xuda-tree-id="${func.runtime.render.escape_html_attribute(treeP?.meta?.tree_id || '')}"`);
26446
+
26447
+ if (treeP?.kind === 'widget' && treeP?.meta?.widget) {
26448
+ attr_pairs.push(`data-xuda-widget="${func.runtime.render.escape_html_attribute(treeP.meta.widget.plugin_name || '')}"`);
26449
+ attr_pairs.push(`data-xuda-widget-method="${func.runtime.render.escape_html_attribute(treeP.meta.widget.method || '_default')}"`);
26450
+ attr_pairs.push(`data-xuda-widget-capability="${func.runtime.render.escape_html_attribute(treeP.meta.widget.capabilities?.headless ? 'headless' : 'browser')}"`);
26451
+ }
26452
+
26453
+ if (treeP?.kind === 'teleport' && treeP?.attributes?.['xu-teleport']) {
26454
+ attr_pairs.push(`data-xuda-teleport-target="${func.runtime.render.escape_html_attribute(treeP.attributes['xu-teleport'])}"`);
26455
+ }
26456
+
26457
+ if ((treeP?.meta?.controls?.xu_for !== null && treeP?.meta?.controls?.xu_for !== undefined) && !renderer_context?.strip_iteration_markers) {
26458
+ attr_pairs.push('data-xuda-xu-for="pending"');
26459
+ }
26460
+
26461
+ return attr_pairs.length ? ' ' + attr_pairs.join(' ') : '';
26462
+ };
26463
+ func.runtime.render.render_tree_children_to_string = async function (treeP, renderer_context) {
26464
+ if (!Array.isArray(treeP?.children) || !treeP.children.length) {
26465
+ return '';
26466
+ }
26467
+ let html = '';
26468
+ for (let index = 0; index < treeP.children.length; index++) {
26469
+ html += await func.runtime.render.render_tree_to_string(treeP.children[index], {
26470
+ ...renderer_context,
26471
+ parent_tree: treeP,
26472
+ });
26473
+ }
26474
+ return html;
26475
+ };
26476
+ func.runtime.render.render_tree_to_string = async function (treeP, renderer_context = {}) {
26477
+ if (!treeP) {
26478
+ return '';
26479
+ }
26480
+ if (Array.isArray(treeP)) {
26481
+ let html = '';
26482
+ for (let index = 0; index < treeP.length; index++) {
26483
+ html += await func.runtime.render.render_tree_to_string(treeP[index], renderer_context);
26484
+ }
26485
+ return html;
26486
+ }
26487
+
26488
+ const ensured_tree = await func.runtime.render.ensure_tree_node({
26489
+ SESSION_ID: renderer_context?.SESSION_ID,
26490
+ nodeP: treeP,
26491
+ paramsP: renderer_context?.paramsP,
26492
+ parent_infoP: renderer_context?.parent_infoP,
26493
+ keyP: renderer_context?.keyP,
26494
+ parent_nodeP: renderer_context?.parent_nodeP,
26495
+ });
26496
+
26497
+ if (!ensured_tree || !func.runtime.render.should_render_tree_node(ensured_tree)) {
26498
+ return '';
26499
+ }
26500
+
26501
+ if (ensured_tree.kind === 'placeholder') {
26502
+ if (renderer_context?.include_placeholders) {
26503
+ return `<!--xuda-placeholder:${func.runtime.render.escape_html(ensured_tree.id || '')}-->`;
26504
+ }
26505
+ return '';
26506
+ }
26507
+
26508
+ if (ensured_tree.kind === 'text') {
26509
+ return func.runtime.render.render_tree_terminal_content(ensured_tree) || '';
26510
+ }
26511
+
26512
+ const tag_name = func.runtime.render.get_string_renderer_tag_name(ensured_tree);
26513
+ if (!tag_name || tag_name.toLowerCase() === 'script') {
26514
+ return '';
26515
+ }
26516
+
26517
+ const attributes = func.runtime.render.get_tree_string_attributes(ensured_tree, renderer_context);
26518
+ const terminal_content = func.runtime.render.render_tree_terminal_content(ensured_tree);
26519
+ let children_html = terminal_content !== null ? terminal_content : await func.runtime.render.render_tree_children_to_string(ensured_tree, renderer_context);
26520
+
26521
+ if (ensured_tree.kind === 'widget' && !children_html) {
26522
+ children_html = func.runtime.render.get_widget_fallback_markup(ensured_tree);
26523
+ }
26524
+
26525
+ if (func.runtime.render.is_html_void_tag(tag_name)) {
26526
+ return `<${tag_name}${attributes}>`;
26527
+ }
26528
+
26529
+ return `<${tag_name}${attributes}>${children_html}</${tag_name}>`;
26530
+ };
26531
+ func.runtime.render.render_to_string = async function (options = {}) {
26532
+ const treeP = await func.runtime.render.ensure_tree_node({
26533
+ SESSION_ID: options.SESSION_ID,
26534
+ nodeP: options.treeP || options.nodeP,
26535
+ paramsP: options.paramsP,
26536
+ parent_infoP: options.parent_infoP,
26537
+ keyP: options.keyP,
26538
+ parent_nodeP: options.parent_nodeP,
26539
+ });
26540
+
26541
+ return await func.runtime.render.render_tree_to_string(treeP, options);
26542
+ };
26543
+ func.runtime.render.get_server_render_mode = function (options = {}) {
26544
+ const normalized = func.runtime.render.normalize_runtime_bootstrap({
26545
+ app_computing_mode: options.app_computing_mode,
26546
+ app_render_mode: options.app_render_mode,
26547
+ app_client_activation: options.app_client_activation,
26548
+ });
26549
+
26550
+ return normalized;
26551
+ };
26552
+ func.runtime.render.build_server_render_params = async function (options = {}) {
26553
+ const SESSION_ID = options.SESSION_ID;
26554
+ const prog_id = options.prog_id;
26555
+ const dsSessionP = options.dsSessionP;
26556
+ const _session = SESSION_OBJ?.[SESSION_ID] || {};
26557
+ const _ds = _session?.DS_GLB?.[dsSessionP] || {};
26558
+ const viewDoc = options.viewDoc || (await func.utils?.VIEWS_OBJ?.get?.(SESSION_ID, prog_id));
26559
+
26560
+ if (!viewDoc?.properties) {
26561
+ throw new Error(`view document not found for ${prog_id}`);
26562
+ }
26563
+
26564
+ const base_params = _ds?.screen_params ? func.runtime.render.safe_clone_tree_value(_ds.screen_params) : {};
26565
+ const screenId = options.screenId || base_params.screenId || `ssr_${prog_id}_${dsSessionP || '0'}`;
26566
+ const paramsP = {
26567
+ ...base_params,
26568
+ prog_id,
26569
+ sourceScreenP: null,
26570
+ $callingContainerP: null,
26571
+ triggerIdP: null,
26572
+ callingDataSource_objP: _ds,
26573
+ rowIdP: typeof options.rowIdP !== 'undefined' ? options.rowIdP : (_ds?.currentRecordId || null),
26574
+ renderType: viewDoc.properties?.renderType,
26575
+ parameters_obj_inP: options.parameters_obj_inP || base_params.parameters_obj_inP || options.parameters_raw_obj || {},
26576
+ source_functionP: options.source_functionP || base_params.source_functionP || 'render_string',
26577
+ is_panelP: false,
26578
+ screen_type: options.screen_type || base_params.screen_type || 'render_string',
26579
+ screenInfo: viewDoc,
26580
+ call_screen_propertiesP: base_params.call_screen_propertiesP,
26581
+ parentDataSourceNoP: typeof _ds?.parentDataSourceNo === 'undefined' || _ds?.parentDataSourceNo === null ? 0 : _ds.parentDataSourceNo,
26582
+ parameters_raw_obj: options.parameters_raw_obj || base_params.parameters_raw_obj || {},
26583
+ dsSessionP,
26584
+ screenId,
26585
+ containerIdP: base_params.containerIdP || `ssr_container_${screenId}`,
26586
+ };
26587
+
26588
+ if (_ds) {
26589
+ _ds.screen_params = paramsP;
26590
+ }
26591
+
26592
+ return paramsP;
26593
+ };
26594
+ func.runtime.render.build_prog_tree = async function (options = {}) {
26595
+ const SESSION_ID = options.SESSION_ID;
26596
+ const prog_id = options.prog_id;
26597
+ const viewDoc = options.viewDoc || (await func.utils?.VIEWS_OBJ?.get?.(SESSION_ID, prog_id));
26598
+
26599
+ if (!viewDoc?.progUi?.length) {
26600
+ throw new Error(`progUi not found for ${prog_id}`);
26601
+ }
26602
+
26603
+ const paramsP = options.paramsP || (await func.runtime.render.build_server_render_params({
26604
+ ...options,
26605
+ SESSION_ID,
26606
+ prog_id,
26607
+ viewDoc,
26608
+ }));
26609
+ const root_index = typeof options.root_index === 'number' ? options.root_index : 0;
26610
+ const root_node = func.runtime.render.safe_clone_tree_value(viewDoc.progUi[root_index]);
26611
+ const tree = await func.runtime.render.build_tree({
26612
+ SESSION_ID,
26613
+ nodeP: root_node,
26614
+ paramsP,
26615
+ });
26616
+
26617
+ return {
26618
+ tree,
26619
+ paramsP,
26620
+ viewDoc,
26621
+ };
26622
+ };
26623
+ func.runtime.render.build_ssr_payload = function (render_program, options = {}) {
26624
+ const runtime_profile = func.runtime.render.get_server_render_mode(options);
26625
+ return {
26626
+ contract: 'xuda.ssr.v1',
26627
+ prog_id: options.prog_id,
26628
+ screenId: render_program.paramsP.screenId,
26629
+ containerId: render_program.paramsP.containerIdP,
26630
+ app_computing_mode: runtime_profile.app_computing_mode,
26631
+ app_render_mode: runtime_profile.app_render_mode,
26632
+ app_client_activation: runtime_profile.app_client_activation,
26633
+ tree_contract: func.runtime.render.TREE_CONTRACT_VERSION,
26634
+ };
26635
+ };
26636
+ func.runtime.render.build_ssr_screen_html = function (html, render_program, options = {}) {
26637
+ const payload = func.runtime.render.build_ssr_payload(render_program, options);
26638
+ const screenId = func.runtime.render.escape_html_attribute(payload.screenId || '');
26639
+ const containerId = func.runtime.render.escape_html_attribute(payload.containerId || '');
26640
+ const activation = func.runtime.render.escape_html_attribute(payload.app_client_activation || 'takeover');
26641
+
26642
+ return `<div data-xuda-ssr-embed="true" class="xu_embed_div"><div id="${screenId}" class="xu_embed_container" data-xuda-ssr-screen="true" data-xuda-ssr-screen-id="${screenId}" data-xuda-activation="${activation}" style="display: contents;"><div id="${containerId}" data-xuda-ssr-root-frame="true" data-xuda-ssr-screen-id="${screenId}" data-xuda-activation="${activation}" style="display: contents;">${html}</div></div></div>`;
26643
+ };
26644
+ func.runtime.render.render_prog_to_string = async function (options = {}) {
26645
+ const render_program = await func.runtime.render.build_prog_tree(options);
26646
+ const html = await func.runtime.render.render_to_string({
26647
+ ...options,
26648
+ SESSION_ID: options.SESSION_ID,
26649
+ treeP: render_program.tree,
26650
+ paramsP: render_program.paramsP,
26651
+ });
26652
+ const ssr_payload = func.runtime.render.build_ssr_payload(render_program, options);
26653
+ const screen_html = func.runtime.render.build_ssr_screen_html(html, render_program, options);
25728
26654
 
25729
- func.common.fastHash = function (inputString) {
25730
- let hash = 0x811c9dc5; // FNV offset basis
26655
+ return {
26656
+ prog_id: options.prog_id,
26657
+ dsSessionP: render_program.paramsP.dsSessionP,
26658
+ screenId: render_program.paramsP.screenId,
26659
+ html,
26660
+ screen_html,
26661
+ tree_json: func.runtime.render.serialize_tree(render_program.tree),
26662
+ paramsP: render_program.paramsP,
26663
+ ssr_payload,
26664
+ };
26665
+ };
26666
+ func.runtime = func.runtime || {};
26667
+ func.runtime.platform = func.runtime.platform || {};
25731
26668
 
25732
- for (let i = 0; i < inputString.length; i++) {
25733
- hash ^= inputString.charCodeAt(i);
25734
- // FNV prime multiplication with 32-bit overflow
25735
- hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
26669
+ func.runtime.platform.dispatch_document_event = function (name, data) {
26670
+ if (typeof document === 'undefined' || typeof CustomEvent === 'undefined') {
26671
+ return false;
25736
26672
  }
25737
-
25738
- // Convert to base36 and pad to 10 characters
25739
- return ((hash >>> 0).toString(36) + '0000000000').slice(0, 10);
26673
+ document.dispatchEvent(new CustomEvent(name, {
26674
+ detail: Array.isArray(data) ? data : [data],
26675
+ }));
26676
+ return true;
25740
26677
  };
25741
-
25742
- glb.new_xu_render = false;
25743
26678
  glb.DEBUG_INFO_OBJ = {};
25744
26679
  // var CONNECTION_ATTEMPTS = 0;
25745
26680
  glb.APP_INFO = {};
@@ -28065,6 +29000,15 @@ func.runtime.ui.ensure_embed_container = function (SESSION_ID) {
28065
29000
  const $root_element = func.runtime.ui.get_root_element(SESSION_ID);
28066
29001
  let $embed_container = func.runtime.ui.find_by_selector($root_element, `#embed_${SESSION_ID}`, true);
28067
29002
 
29003
+ if (!$embed_container.length) {
29004
+ const $ssr_embed_container = func.runtime.ui.find_by_selector($root_element, `[data-xuda-ssr-embed="true"]`, true);
29005
+ const ssr_embed_node = func.runtime.ui.get_first_node($ssr_embed_container);
29006
+ if (ssr_embed_node) {
29007
+ ssr_embed_node.id = 'embed_' + SESSION_ID;
29008
+ $embed_container = func.runtime.ui._wrap_matches([ssr_embed_node]);
29009
+ }
29010
+ }
29011
+
28068
29012
  if (!$embed_container.length) {
28069
29013
  const embed_node = document.createElement('div');
28070
29014
  embed_node.id = 'embed_' + SESSION_ID;
@@ -28100,12 +29044,44 @@ func.runtime.ui.get_root_tag_name = function () {
28100
29044
  }
28101
29045
  return root_tag_name;
28102
29046
  };
29047
+ func.runtime.ui.find_ssr_screen_host = function ($container, screenId, containerId) {
29048
+ const container_node = func.runtime.ui.get_first_node($container);
29049
+ if (!container_node || !screenId) {
29050
+ return null;
29051
+ }
29052
+
29053
+ const dialog_node =
29054
+ container_node.querySelector?.(`#${CSS?.escape ? CSS.escape(screenId) : screenId}`) ||
29055
+ container_node.querySelector?.(`[data-xuda-ssr-screen-id="${screenId}"]`);
29056
+ if (!dialog_node) {
29057
+ return null;
29058
+ }
29059
+
29060
+ const root_frame_node =
29061
+ (containerId ? dialog_node.querySelector?.(`#${CSS?.escape ? CSS.escape(containerId) : containerId}`) : null) ||
29062
+ dialog_node.querySelector?.('[data-xuda-ssr-root-frame="true"]');
29063
+ if (!root_frame_node) {
29064
+ return null;
29065
+ }
29066
+
29067
+ return {
29068
+ $dialogDiv: func.runtime.ui._wrap_matches([dialog_node]),
29069
+ $rootFrame: func.runtime.ui._wrap_matches([root_frame_node]),
29070
+ reused_ssr_host: true,
29071
+ };
29072
+ };
28103
29073
  func.runtime.ui.create_screen_host = function (SESSION_ID, screen_type, params, $callingContainerP, screenId) {
28104
29074
  var $dialogDiv;
28105
29075
  var $rootFrame;
29076
+ let reused_ssr_host = false;
28106
29077
 
28107
29078
  switch (screen_type) {
28108
29079
  case 'embed': {
29080
+ const ssr_host = func.runtime.ui.find_ssr_screen_host($callingContainerP, screenId, params?.containerIdP);
29081
+ if (ssr_host) {
29082
+ return ssr_host;
29083
+ }
29084
+
28109
29085
  const dialogNode = document.createElement('div');
28110
29086
  dialogNode.id = screenId;
28111
29087
  dialogNode.setAttribute('ui_engine', UI_FRAMEWORK_INSTALLED);
@@ -28155,6 +29131,7 @@ func.runtime.ui.create_screen_host = function (SESSION_ID, screen_type, params,
28155
29131
  return {
28156
29132
  $dialogDiv,
28157
29133
  $rootFrame,
29134
+ reused_ssr_host,
28158
29135
  };
28159
29136
  };
28160
29137
  func.runtime.ui.find_xu_ui_in_root = function (SESSION_ID, xu_ui_id) {
@@ -28188,7 +29165,7 @@ func.runtime.ui.find_element_data_in_root = function (SESSION_ID, dataKey, prope
28188
29165
  }
28189
29166
  return func.runtime.ui.find_in_root(SESSION_ID, '[xu-panel-wrapper-id]');
28190
29167
  }
28191
- return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui.as_jquery(func.runtime.ui.get_root_element(SESSION_ID)), property, value);
29168
+ return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui.get_root_element(SESSION_ID), property, value);
28192
29169
  };
28193
29170
  func.runtime.ui.find_element_data_in_parent = function ($container, dataKey, property, value) {
28194
29171
  const container_node = func.runtime.ui.get_first_node($container);
@@ -28202,7 +29179,7 @@ func.runtime.ui.find_element_data_in_parent = function ($container, dataKey, pro
28202
29179
  }
28203
29180
  return func.runtime.ui.find_by_selector(parent_node, `[xu-ui-id="${value}"]`);
28204
29181
  }
28205
- return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui.as_jquery(parent_node), property, value);
29182
+ return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui._wrap_matches([parent_node]), property, value);
28206
29183
  };
28207
29184
  func.runtime.ui.sync_child_parent_container = function ($div) {
28208
29185
  const div_node = func.runtime.ui.get_first_node($div);
@@ -28309,40 +29286,14 @@ func.runtime.ui.clear_screen_blockers = function () {
28309
29286
  }
28310
29287
  };
28311
29288
 
28312
- // @deprecated — no-op shim now that jQuery is removed from the bundle.
28313
29289
  func.runtime.ui.as_jquery = function (target) {
28314
- if (target?.jquery) {
28315
- return target;
28316
- }
28317
29290
  const node = func.runtime.ui.get_first_node(target);
28318
- // Return a minimal jQuery-like wrapper so legacy callers don't crash.
28319
- const _node_data = {};
28320
- const _arr = node ? [node] : [];
28321
- return {
28322
- 0: node,
28323
- length: _arr.length,
28324
- toArray: function () { return _arr.slice(); },
28325
- data: function (key, value) {
28326
- if (typeof key === 'undefined') return _node_data;
28327
- if (typeof value !== 'undefined') { _node_data[key] = value; return this; }
28328
- return _node_data[key];
28329
- },
28330
- attr: function (key, value) {
28331
- if (!node) return undefined;
28332
- if (typeof value !== 'undefined') { node.setAttribute(key, value); return this; }
28333
- return node?.getAttribute?.(key);
28334
- },
28335
- removeData: function () { for (const k in _node_data) delete _node_data[k]; return this; },
28336
- children: function () { return { toArray: function () { return node ? Array.from(node.children) : []; } }; },
28337
- };
29291
+ return func.runtime.ui._wrap_matches(node ? [node] : []);
28338
29292
  };
28339
29293
  func.runtime.ui.get_first_node = function (target) {
28340
29294
  if (!target) {
28341
29295
  return null;
28342
29296
  }
28343
- if (target?.jquery) {
28344
- return target[0] || null;
28345
- }
28346
29297
  if (target?.nodeType) {
28347
29298
  return target;
28348
29299
  }
@@ -28360,9 +29311,10 @@ func.runtime.ui.get_data = function (target) {
28360
29311
  if (meta) return meta;
28361
29312
  }
28362
29313
  }
28363
- // fallback: store per-element data on the node itself
28364
29314
  if (target_node) {
28365
- if (!target_node.__xuData) target_node.__xuData = {};
29315
+ if (!target_node.__xuData) {
29316
+ target_node.__xuData = {};
29317
+ }
28366
29318
  return target_node.__xuData;
28367
29319
  }
28368
29320
  return {};
@@ -28744,6 +29696,11 @@ func.runtime.ui.build_container_xu_data = function (options) {
28744
29696
  func.runtime.ui.apply_container_meta = function ($div, options) {
28745
29697
  const div_node = func.runtime.ui.get_first_node($div);
28746
29698
  func.runtime.ui.set_attr(div_node, 'xu-ui-id', options.ui_id);
29699
+ func.runtime.ui.set_attr(div_node, 'data-xuda-kind', options.treeP?.kind || options.nodeP?.tagName || 'element');
29700
+ func.runtime.ui.set_attr(div_node, 'data-xuda-node-id', options.nodeP?.id || options.nodeP?.id_org || '');
29701
+ if (options.treeP?.meta?.tree_id !== null && typeof options.treeP?.meta?.tree_id !== 'undefined') {
29702
+ func.runtime.ui.set_attr(div_node, 'data-xuda-tree-id', options.treeP.meta.tree_id);
29703
+ }
28747
29704
  const xuData = func.runtime.ui.build_container_xu_data(options);
28748
29705
  if (options.parent_infoP?.iterate_info) {
28749
29706
  xuData.iterate_info = options.parent_infoP.iterate_info;
@@ -28838,6 +29795,38 @@ func.runtime.ui.create_container_element = function (div_typeP, attr_str, prop,
28838
29795
  }
28839
29796
  return func.runtime.ui.create_element(div, attr_str);
28840
29797
  };
29798
+ func.runtime.ui.find_hydration_candidate = function (options) {
29799
+ if (!func.runtime.render.is_hydration_mode(SESSION_OBJ?.[options.SESSION_ID])) {
29800
+ return null;
29801
+ }
29802
+ if (!func.runtime.render.should_use_ssr_payload(options.SESSION_ID, options.paramsP)) {
29803
+ return null;
29804
+ }
29805
+ if (options.is_placeholder || !options.treeP?.meta?.tree_id) {
29806
+ return null;
29807
+ }
29808
+
29809
+ const append_node = func.runtime.ui.get_first_node(options.$appendTo || options.$container);
29810
+ if (!append_node) {
29811
+ return null;
29812
+ }
29813
+
29814
+ const children = func.runtime.ui.get_children(append_node);
29815
+ for (let index = 0; index < children.length; index++) {
29816
+ const child = children[index];
29817
+ if (child?.__xuda_hydration_claimed) {
29818
+ continue;
29819
+ }
29820
+ if (func.runtime.ui.get_attr(child, 'data-xuda-tree-id') !== `${options.treeP.meta.tree_id}`) {
29821
+ continue;
29822
+ }
29823
+ child.__xuda_hydration_claimed = true;
29824
+ func.runtime.ui.set_attr(child, 'data-xuda-client-activation', 'hydrate');
29825
+ return child;
29826
+ }
29827
+
29828
+ return null;
29829
+ };
28841
29830
  func.runtime.ui.build_xu_ui_id_seed = function (nodeP, dsSessionP, key_path, currentRecordId) {
28842
29831
  const nodeId = nodeP.xu_tree_id || nodeP.id;
28843
29832
  const elem_key = `${nodeId}-${key_path}-${currentRecordId}`;
@@ -28890,7 +29879,11 @@ func.runtime.ui.create_container = async function (options) {
28890
29879
  try {
28891
29880
  const key_path = func.runtime.ui.build_container_key_path(container_xu_data, options.keyP, options.parent_infoP, options.nodeP, options.parent_nodeP);
28892
29881
  const elem_key = `${options.nodeP.xu_tree_id || options.nodeP.id}-${key_path}-${currentRecordId}`;
28893
- const $div = func.runtime.ui.create_container_element(options.div_typeP, options.attr_str, options.prop, options.nodeP, $appendTo);
29882
+ const hydration_candidate = func.runtime.ui.find_hydration_candidate({
29883
+ ...options,
29884
+ $appendTo,
29885
+ });
29886
+ const $div = hydration_candidate || func.runtime.ui.create_container_element(options.div_typeP, options.attr_str, options.prop, options.nodeP, $appendTo);
28894
29887
  const new_ui_id = await func.runtime.ui.generate_xu_ui_id(options.SESSION_ID, options.nodeP, options.$container, options.paramsP, options.keyP, {
28895
29888
  container_xu_data,
28896
29889
  currentRecordId,
@@ -28916,9 +29909,10 @@ func.runtime.ui.create_container = async function (options) {
28916
29909
  parent_infoP: options.parent_infoP,
28917
29910
  is_placeholder: options.is_placeholder,
28918
29911
  classP: options.classP,
29912
+ treeP: options.treeP,
28919
29913
  });
28920
29914
 
28921
- if (options.div_typeP !== 'svg') {
29915
+ if (!hydration_candidate && options.div_typeP !== 'svg') {
28922
29916
  func.runtime.ui.append_to($div, $appendTo);
28923
29917
  }
28924
29918
  return $div;
@@ -31599,9 +32593,10 @@ func.runtime.ui.init_screen = async function (options) {
31599
32593
 
31600
32594
  const _session = SESSION_OBJ[SESSION_ID];
31601
32595
  const screenInfo = structuredClone(screen_ret);
32596
+ const ssr_payload = func.runtime.render.should_use_ssr_payload(SESSION_ID, { prog_id }) ? func.runtime.render.get_ssr_payload(_session) : null;
31602
32597
 
31603
32598
  const screen_type = source_functionP?.split('_')?.[1];
31604
- const screenId = (glb.screen_num++).toString();
32599
+ const screenId = ssr_payload?.screenId || (glb.screen_num++).toString();
31605
32600
 
31606
32601
  if (SCREEN_BLOCKER_OBJ[prog_id + (sourceScreenP ? '_' + sourceScreenP : '')]) {
31607
32602
  const wait_for_SCREEN_BLOCKER_release = function () {
@@ -31643,6 +32638,8 @@ func.runtime.ui.init_screen = async function (options) {
31643
32638
  call_screen_propertiesP,
31644
32639
  parentDataSourceNoP: _session.DS_GLB?.[callingDataSource_objP?.dsSession]?.dsSession || callingDataSource_objP?.parentDataSourceNo || 0,
31645
32640
  parameters_raw_obj,
32641
+ containerIdP: ssr_payload?.containerId || null,
32642
+ ssr_payload,
31646
32643
  };
31647
32644
 
31648
32645
  const screen_host = func.runtime.ui.create_screen_host(SESSION_ID, screen_type, params, $callingContainerP, screenId);
@@ -31675,6 +32672,10 @@ func.runtime.ui.init_screen = async function (options) {
31675
32672
  func.runtime.ui.set_style($rootFrame, 'display', 'contents');
31676
32673
  }
31677
32674
 
32675
+ if (screen_host.reused_ssr_host && func.runtime.render.is_takeover_mode(_session)) {
32676
+ func.runtime.ui.empty($rootFrame);
32677
+ }
32678
+
31678
32679
  if (!is_panelP) func.UI.utils.indicator.screen.busy();
31679
32680
 
31680
32681
  const ret = await func.datasource.create(
@@ -31716,7 +32717,24 @@ func.runtime.ui.init_screen = async function (options) {
31716
32717
  }
31717
32718
  let node = structuredClone(viewDoc.progUi);
31718
32719
  if (!node.length) return console.warn('ui node empty');
31719
- const ret_render_$container = await func.runtime.render.render_ui_tree(SESSION_ID, $rootFrame, node[0], null, params, jobNoP, null, null, null, null, null, $rootFrame);
32720
+ const root_tree = await func.runtime.render.build_tree({
32721
+ SESSION_ID,
32722
+ nodeP: node[0],
32723
+ paramsP: params,
32724
+ });
32725
+ const ret_render_$container = await func.runtime.render.render_tree(root_tree, {
32726
+ SESSION_ID,
32727
+ $container: $rootFrame,
32728
+ parent_infoP: null,
32729
+ paramsP: params,
32730
+ jobNoP,
32731
+ is_skeleton: null,
32732
+ keyP: null,
32733
+ refreshed_ds: null,
32734
+ parent_nodeP: null,
32735
+ check_existP: null,
32736
+ $root_container: $rootFrame,
32737
+ });
31720
32738
 
31721
32739
  if (!is_panelP) func.UI.utils.indicator.screen.normal();
31722
32740
 
@@ -31800,7 +32818,7 @@ func.runtime.ui.ensure_nav = function (SESSION_ID, $container) {
31800
32818
  }
31801
32819
  var nav_el = document.createElement('xu-nav');
31802
32820
  func.runtime.ui.append($container, nav_el);
31803
- var $nav = func.runtime.ui.as_jquery(nav_el);
32821
+ var $nav = func.runtime.ui._wrap_matches([nav_el]);
31804
32822
  func.UI.component.init_xu_nav($container, $nav);
31805
32823
  return $nav;
31806
32824
  };
@@ -32141,6 +33159,7 @@ func.runtime.ui.render_single_view_node = async function (options) {
32141
33159
  parent_infoP: options.parent_infoP,
32142
33160
  jobNoP: options.jobNoP,
32143
33161
  keyP: options.keyP,
33162
+ treeP: options.treeP,
32144
33163
  parent_nodeP: options.parent_nodeP,
32145
33164
  prop: options.prop,
32146
33165
  div_typeP: 'div',
@@ -32269,6 +33288,7 @@ func.runtime.ui.render_panel_node = async function (options) {
32269
33288
  parent_infoP: options.parent_infoP,
32270
33289
  jobNoP: options.jobNoP,
32271
33290
  keyP: options.keyP,
33291
+ treeP: options.treeP,
32272
33292
  parent_nodeP: options.parent_nodeP,
32273
33293
  prop: options.prop,
32274
33294
  $appendToP: $wrapper,
@@ -32598,6 +33618,14 @@ func.runtime.ui.screen_loading_done = async function (options) {
32598
33618
  });
32599
33619
 
32600
33620
  const _session = SESSION_OBJ[options.SESSION_ID];
33621
+ if (func.runtime.render.should_use_ssr_payload(options.SESSION_ID, options.paramsP)) {
33622
+ const root_node = func.runtime.ui.get_root_node(options.SESSION_ID);
33623
+ if (root_node) {
33624
+ func.runtime.ui.set_attr(root_node, 'data-xuda-client-activation', _session.opt.app_client_activation || 'none');
33625
+ func.runtime.ui.set_attr(root_node, 'data-xuda-ssr-status', _session.opt.app_client_activation === 'hydrate' ? 'hydrated' : 'taken-over');
33626
+ }
33627
+ func.runtime.render.mark_ssr_payload_consumed(options.SESSION_ID);
33628
+ }
32601
33629
  func.events.delete_job(options.SESSION_ID, options.jobNoP);
32602
33630
  func.UI.utils.screen_blocker(false, options.paramsP.prog_id + (options.paramsP.sourceScreenP ? '_' + options.paramsP.sourceScreenP : ''));
32603
33631
  if (_session.prog_id === options.paramsP.prog_id) {
@@ -32630,7 +33658,7 @@ func.runtime.ui._to_node_array = func.runtime.ui._to_node_array || function (inp
32630
33658
  if (!input) {
32631
33659
  return [];
32632
33660
  }
32633
- if (input.jquery) {
33661
+ if (typeof input?.toArray === 'function' && typeof input?.length === 'number' && !input?.nodeType) {
32634
33662
  return input.toArray();
32635
33663
  }
32636
33664
  if (Array.isArray(input)) {
@@ -34440,6 +35468,9 @@ func.runtime.render.get_screen_context = function (SESSION_ID, $container, param
34440
35468
  };
34441
35469
  func.runtime.render.get_node_attributes = function (nodeP) {
34442
35470
  try {
35471
+ if (func.runtime.render.is_tree_node?.(nodeP)) {
35472
+ return nodeP.attributes;
35473
+ }
34443
35474
  return nodeP?.attributes;
34444
35475
  } catch (error) {
34445
35476
  return undefined;
@@ -34557,6 +35588,7 @@ func.runtime.render.prepare_draw_context = async function (options) {
34557
35588
  parent_infoP: options.parent_infoP,
34558
35589
  jobNoP: options.jobNoP,
34559
35590
  keyP: options.keyP,
35591
+ treeP: options.treeP,
34560
35592
  parent_nodeP: options.parent_nodeP,
34561
35593
  prop: options.prop,
34562
35594
  div_typeP: options.element,
@@ -34579,6 +35611,7 @@ func.runtime.render.prepare_draw_context = async function (options) {
34579
35611
  parent_infoP: options.parent_infoP,
34580
35612
  jobNoP: options.jobNoP,
34581
35613
  keyP: options.keyP,
35614
+ treeP: options.treeP,
34582
35615
  parent_nodeP: options.parent_nodeP,
34583
35616
  prop: options.prop,
34584
35617
  div_typeP: options.element,
@@ -35435,18 +36468,28 @@ func.runtime.widgets.render_node = async function (options) {
35435
36468
  parent_infoP: options.parent_infoP,
35436
36469
  jobNoP: options.jobNoP,
35437
36470
  keyP: options.keyP,
36471
+ treeP: options.treeP,
35438
36472
  parent_nodeP: options.parent_nodeP,
35439
36473
  prop: options.prop,
35440
36474
  classP: 'widget_wrapper',
35441
36475
  });
35442
36476
 
36477
+ if (func.runtime.render.is_hydration_mode(SESSION_OBJ?.[options.SESSION_ID]) && func.runtime.render.should_use_ssr_payload(options.SESSION_ID, options.paramsP)) {
36478
+ func.runtime.ui.empty($div);
36479
+ }
36480
+
35443
36481
  const widget_context = func.runtime.widgets.create_context(options.SESSION_ID, options.paramsP, options.prop);
35444
36482
  const { plugin_name, method, propsP, plugin: _plugin } = widget_context;
35445
36483
  const report_error = function (descP, warn) {
35446
36484
  return func.runtime.widgets.report_error(widget_context, descP, warn);
35447
36485
  };
35448
36486
 
35449
- const methods = await func.runtime.widgets.get_methods(widget_context);
36487
+ const definition = await func.runtime.widgets.get_definition(widget_context);
36488
+ if (!func.runtime.widgets.supports_current_environment(definition)) {
36489
+ return report_error(`plugin ${plugin_name} is not available in the current environment`, true);
36490
+ }
36491
+
36492
+ const methods = definition?.methods || {};
35450
36493
  if (methods && !methods[method]) {
35451
36494
  return report_error('method not found');
35452
36495
  }
@@ -35507,7 +36550,13 @@ func.runtime.widgets.render_node = async function (options) {
35507
36550
  job_id: options.jobNoP,
35508
36551
  });
35509
36552
 
35510
- const params = func.runtime.widgets.build_params(widget_context, $div, plugin_setup_ret.data, api_utils);
36553
+ const params = func.runtime.widgets.build_params(
36554
+ widget_context,
36555
+ func.runtime.ui.get_first_node($div),
36556
+ func.runtime.ui.get_data($div),
36557
+ plugin_setup_ret.data,
36558
+ api_utils,
36559
+ );
35511
36560
  const fx = await func.runtime.widgets.get_resource(widget_context, 'runtime.mjs');
35512
36561
 
35513
36562
  await func.runtime.widgets.load_runtime_css(widget_context);
@@ -35531,9 +36580,306 @@ func.runtime.widgets = func.runtime.widgets || {};
35531
36580
 
35532
36581
  // Browser-only special node renderers live here so the core render tree can stay focused.
35533
36582
 
36583
+ const normalize_runtime_tag_name = function (tag_name) {
36584
+ return `${tag_name || ''}`.trim().toLowerCase();
36585
+ };
36586
+
36587
+ const get_runtime_node_attributes = function (nodeP) {
36588
+ if (!nodeP?.attributes || typeof nodeP.attributes !== 'object') {
36589
+ return {};
36590
+ }
36591
+
36592
+ return nodeP.attributes;
36593
+ };
36594
+
36595
+ const get_runtime_node_content = function (nodeP) {
36596
+ if (typeof nodeP?.content === 'string') {
36597
+ return nodeP.content;
36598
+ }
36599
+
36600
+ if (typeof nodeP?.text === 'string') {
36601
+ return nodeP.text;
36602
+ }
36603
+
36604
+ if (!Array.isArray(nodeP?.children)) {
36605
+ return '';
36606
+ }
36607
+
36608
+ return nodeP.children
36609
+ .map(function (child) {
36610
+ if (typeof child === 'string') {
36611
+ return child;
36612
+ }
36613
+ if (typeof child?.content === 'string') {
36614
+ return child.content;
36615
+ }
36616
+ if (typeof child?.text === 'string') {
36617
+ return child.text;
36618
+ }
36619
+ return '';
36620
+ })
36621
+ .join('');
36622
+ };
36623
+
36624
+ const get_runtime_asset_key = function (options, tag_name) {
36625
+ const source_node = options.treeP || options.nodeP || {};
36626
+ const parts = [
36627
+ 'xuda-html-asset',
36628
+ options.paramsP?.prog_id || '',
36629
+ tag_name,
36630
+ source_node.id || source_node.id_org || '',
36631
+ typeof options.keyP === 'undefined' || options.keyP === null ? '' : `${options.keyP}`,
36632
+ ].filter(function (part) {
36633
+ return `${part || ''}`.trim() !== '';
36634
+ });
36635
+
36636
+ return parts.join(':');
36637
+ };
36638
+
36639
+ const get_runtime_asset_signature = function (attributes, content) {
36640
+ const normalized_attributes = {};
36641
+ const attr_keys = Object.keys(attributes || {}).sort();
36642
+
36643
+ for (let index = 0; index < attr_keys.length; index++) {
36644
+ const key = attr_keys[index];
36645
+ normalized_attributes[key] = attributes[key];
36646
+ }
36647
+
36648
+ return JSON.stringify({
36649
+ attributes: normalized_attributes,
36650
+ content: `${content || ''}`,
36651
+ });
36652
+ };
36653
+
36654
+ const escape_runtime_asset_selector_value = function (value) {
36655
+ const win = func.runtime.platform.get_window?.();
36656
+ if (win?.CSS?.escape) {
36657
+ return win.CSS.escape(value);
36658
+ }
36659
+
36660
+ return `${value || ''}`.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
36661
+ };
36662
+
36663
+ const find_runtime_head_asset = function (head, tag_name, asset_key) {
36664
+ if (!head?.querySelector || !asset_key) {
36665
+ return null;
36666
+ }
36667
+
36668
+ return head.querySelector(`${tag_name}[data-xuda-asset-key="${escape_runtime_asset_selector_value(asset_key)}"]`);
36669
+ };
36670
+
36671
+ const find_runtime_head_asset_by_attr = function (head, tag_name, attr_name, attr_value) {
36672
+ if (!head?.querySelectorAll || !attr_name || !attr_value) {
36673
+ return null;
36674
+ }
36675
+
36676
+ const candidates = Array.from(head.querySelectorAll(tag_name));
36677
+ return (
36678
+ candidates.find(function (candidate) {
36679
+ return candidate.getAttribute(attr_name) === attr_value || candidate[attr_name] === attr_value;
36680
+ }) || null
36681
+ );
36682
+ };
36683
+
36684
+ const wait_for_runtime_asset_load = function (node) {
36685
+ if (!node?.addEventListener) {
36686
+ return Promise.resolve(node);
36687
+ }
36688
+
36689
+ if (node.getAttribute?.('data-xuda-loaded') === 'true') {
36690
+ return Promise.resolve(node);
36691
+ }
36692
+
36693
+ if (!node.getAttribute?.('data-xuda-asset-key')) {
36694
+ return Promise.resolve(node);
36695
+ }
36696
+
36697
+ const tag_name = normalize_runtime_tag_name(node.tagName);
36698
+ if (tag_name !== 'script' && !(tag_name === 'link' && normalize_runtime_tag_name(node.getAttribute?.('rel')) === 'stylesheet')) {
36699
+ return Promise.resolve(node);
36700
+ }
36701
+
36702
+ return new Promise(function (resolve) {
36703
+ const done = function () {
36704
+ node.setAttribute?.('data-xuda-loaded', 'true');
36705
+ resolve(node);
36706
+ };
36707
+
36708
+ node.addEventListener('load', done, { once: true });
36709
+ node.addEventListener('error', done, { once: true });
36710
+ });
36711
+ };
36712
+
36713
+ const remove_runtime_head_asset = function (node) {
36714
+ if (node?.parentNode?.removeChild) {
36715
+ node.parentNode.removeChild(node);
36716
+ }
36717
+ };
36718
+
36719
+ const apply_runtime_asset_metadata = function (node, asset_key, signature) {
36720
+ if (!node?.setAttribute) {
36721
+ return node;
36722
+ }
36723
+
36724
+ if (asset_key) {
36725
+ node.setAttribute('data-xuda-asset-key', asset_key);
36726
+ }
36727
+ node.setAttribute('data-xuda-asset-signature', signature);
36728
+ return node;
36729
+ };
36730
+
36731
+ const create_runtime_head_element = function (doc, tag_name, attributes, asset_key, signature) {
36732
+ const node = doc.createElement(tag_name);
36733
+ apply_runtime_asset_metadata(node, asset_key, signature);
36734
+ func.runtime.platform.apply_element_attributes(node, attributes);
36735
+ return node;
36736
+ };
36737
+
36738
+ const upsert_runtime_head_element = async function (options) {
36739
+ const doc = func.runtime.platform.get_document?.();
36740
+ const head = doc?.head;
36741
+ const tag_name = normalize_runtime_tag_name(options.tag_name);
36742
+
36743
+ if (!doc?.createElement || !head?.appendChild || !tag_name) {
36744
+ return null;
36745
+ }
36746
+
36747
+ const asset_key = options.asset_key || '';
36748
+ const signature = options.signature || '';
36749
+ const attributes = options.attributes || {};
36750
+ const content = typeof options.content === 'string' ? options.content : '';
36751
+
36752
+ const existing_by_key = find_runtime_head_asset(head, tag_name, asset_key);
36753
+ if (existing_by_key && existing_by_key.getAttribute('data-xuda-asset-signature') === signature) {
36754
+ return options.await_load ? await wait_for_runtime_asset_load(existing_by_key) : existing_by_key;
36755
+ }
36756
+
36757
+ if (existing_by_key) {
36758
+ remove_runtime_head_asset(existing_by_key);
36759
+ }
36760
+
36761
+ if (options.find_existing_attr?.name && options.find_existing_attr?.value) {
36762
+ const existing_by_attr = find_runtime_head_asset_by_attr(head, tag_name, options.find_existing_attr.name, options.find_existing_attr.value);
36763
+ if (existing_by_attr) {
36764
+ apply_runtime_asset_metadata(existing_by_attr, asset_key, signature);
36765
+ existing_by_attr.setAttribute?.('data-xuda-loaded', 'true');
36766
+ return existing_by_attr;
36767
+ }
36768
+ }
36769
+
36770
+ const node = create_runtime_head_element(doc, tag_name, attributes, asset_key, signature);
36771
+
36772
+ if (tag_name === 'script' && attributes.src && !Object.prototype.hasOwnProperty.call(attributes, 'async')) {
36773
+ const script_type = normalize_runtime_tag_name(attributes.type);
36774
+ if (script_type !== 'module') {
36775
+ node.async = false;
36776
+ }
36777
+ }
36778
+
36779
+ if (tag_name === 'style' || (tag_name === 'script' && !attributes.src)) {
36780
+ node.textContent = content;
36781
+ }
36782
+
36783
+ head.appendChild(node);
36784
+
36785
+ if (tag_name !== 'script' && tag_name !== 'link') {
36786
+ node.setAttribute('data-xuda-loaded', 'true');
36787
+ }
36788
+
36789
+ return options.await_load ? await wait_for_runtime_asset_load(node) : node;
36790
+ };
36791
+
36792
+ const render_runtime_html_asset = async function (options) {
36793
+ if (options.is_skeleton) {
36794
+ return options.$container;
36795
+ }
36796
+
36797
+ const nodeP = options.treeP || options.nodeP || {};
36798
+ const tag_name = normalize_runtime_tag_name(nodeP.tagName);
36799
+ const attributes = { ...get_runtime_node_attributes(nodeP) };
36800
+ const content = get_runtime_node_content(nodeP);
36801
+ const asset_key = get_runtime_asset_key(options, tag_name);
36802
+ const signature = get_runtime_asset_signature(attributes, content);
36803
+
36804
+ switch (tag_name) {
36805
+ case 'title':
36806
+ func.runtime.platform.set_title(content);
36807
+ return options.$container;
36808
+ case 'style':
36809
+ await upsert_runtime_head_element({
36810
+ tag_name,
36811
+ attributes,
36812
+ content,
36813
+ asset_key,
36814
+ signature,
36815
+ });
36816
+ return options.$container;
36817
+ case 'meta':
36818
+ if (!Object.keys(attributes).length) {
36819
+ return options.$container;
36820
+ }
36821
+ await upsert_runtime_head_element({
36822
+ tag_name,
36823
+ attributes,
36824
+ asset_key,
36825
+ signature,
36826
+ });
36827
+ return options.$container;
36828
+ case 'link': {
36829
+ const href = `${attributes.href || ''}`.trim();
36830
+ if (!href) {
36831
+ return options.$container;
36832
+ }
36833
+ await upsert_runtime_head_element({
36834
+ tag_name,
36835
+ attributes,
36836
+ asset_key,
36837
+ signature,
36838
+ find_existing_attr: {
36839
+ name: 'href',
36840
+ value: href,
36841
+ },
36842
+ await_load: normalize_runtime_tag_name(attributes.rel) === 'stylesheet',
36843
+ });
36844
+ return options.$container;
36845
+ }
36846
+ case 'script': {
36847
+ const src = `${attributes.src || ''}`.trim();
36848
+ if (!src && !content.trim()) {
36849
+ return options.$container;
36850
+ }
36851
+ await upsert_runtime_head_element({
36852
+ tag_name,
36853
+ attributes,
36854
+ content,
36855
+ asset_key,
36856
+ signature,
36857
+ find_existing_attr: src
36858
+ ? {
36859
+ name: 'src',
36860
+ value: src,
36861
+ }
36862
+ : null,
36863
+ await_load: !!src,
36864
+ });
36865
+ return options.$container;
36866
+ }
36867
+ default:
36868
+ return null;
36869
+ }
36870
+ };
36871
+
35534
36872
  func.runtime.render.render_special_node = async function (options) {
35535
- if (options.nodeP.content && options.nodeP.attributes) {
35536
- options.nodeP.attributes['xu-content'] = options.nodeP.content;
36873
+ const treeP = options.treeP || null;
36874
+ const nodeP = options.nodeP || func.runtime.render.get_tree_source_node(treeP);
36875
+ const render_tag_name = treeP?.tagName || nodeP?.tagName;
36876
+ const normalized_render_tag_name = normalize_runtime_tag_name(render_tag_name);
36877
+ const is_native_html_asset = ['title', 'style', 'meta', 'link', 'script'].includes(normalized_render_tag_name);
36878
+
36879
+ if (!is_native_html_asset && treeP?.content && nodeP?.attributes) {
36880
+ nodeP.attributes['xu-content'] = treeP.content;
36881
+ } else if (!is_native_html_asset && nodeP?.content && nodeP.attributes) {
36882
+ nodeP.attributes['xu-content'] = nodeP.content;
35537
36883
  }
35538
36884
 
35539
36885
  const renderers = {
@@ -35543,6 +36889,7 @@ func.runtime.render.render_special_node = async function (options) {
35543
36889
  SESSION_ID: options.SESSION_ID,
35544
36890
  $container: options.$container,
35545
36891
  $root_container: options.$root_container,
36892
+ treeP,
35546
36893
  nodeP: options.nodeP,
35547
36894
  parent_infoP: options.parent_infoP,
35548
36895
  paramsP: options.paramsP,
@@ -35559,6 +36906,7 @@ func.runtime.render.render_special_node = async function (options) {
35559
36906
  SESSION_ID: options.SESSION_ID,
35560
36907
  $container: options.$container,
35561
36908
  $root_container: options.$root_container,
36909
+ treeP,
35562
36910
  nodeP: options.nodeP,
35563
36911
  parent_infoP: options.parent_infoP,
35564
36912
  paramsP: options.paramsP,
@@ -35578,6 +36926,7 @@ func.runtime.render.render_special_node = async function (options) {
35578
36926
  SESSION_ID: options.SESSION_ID,
35579
36927
  $container: options.$container,
35580
36928
  $root_container: options.$root_container,
36929
+ treeP,
35581
36930
  nodeP: options.nodeP,
35582
36931
  parent_infoP: options.parent_infoP,
35583
36932
  paramsP: options.paramsP,
@@ -35594,6 +36943,7 @@ func.runtime.render.render_special_node = async function (options) {
35594
36943
  SESSION_ID: options.SESSION_ID,
35595
36944
  $container: options.$container,
35596
36945
  $root_container: options.$root_container,
36946
+ treeP,
35597
36947
  nodeP: options.nodeP,
35598
36948
  parent_infoP: options.parent_infoP,
35599
36949
  paramsP: options.paramsP,
@@ -35605,9 +36955,24 @@ func.runtime.render.render_special_node = async function (options) {
35605
36955
  refreshed_ds: options.refreshed_ds,
35606
36956
  });
35607
36957
  },
36958
+ title: async function () {
36959
+ return await render_runtime_html_asset(options);
36960
+ },
36961
+ style: async function () {
36962
+ return await render_runtime_html_asset(options);
36963
+ },
36964
+ meta: async function () {
36965
+ return await render_runtime_html_asset(options);
36966
+ },
36967
+ link: async function () {
36968
+ return await render_runtime_html_asset(options);
36969
+ },
36970
+ script: async function () {
36971
+ return await render_runtime_html_asset(options);
36972
+ },
35608
36973
  };
35609
36974
 
35610
- const renderer = renderers[options.nodeP.tagName];
36975
+ const renderer = renderers[normalized_render_tag_name];
35611
36976
  if (!renderer) {
35612
36977
  return { handled: false };
35613
36978
  }
@@ -35721,8 +37086,9 @@ func.runtime.widgets = func.runtime.widgets || {};
35721
37086
  // Browser-only render tree entrypoints live here so draw/cache helpers can stay focused.
35722
37087
 
35723
37088
  func.runtime.render.create_tree_runtime = function (options) {
37089
+ const render_node = options.nodeP || func.runtime.render.get_tree_source_node(options.treeP);
35724
37090
  const render_context = func.runtime.render.get_screen_context(options.SESSION_ID, options.$container, options.paramsP, options.is_skeleton);
35725
- const prop = func.runtime.render.get_node_attributes(options.nodeP);
37091
+ const prop = func.runtime.render.get_node_attributes(options.treeP || render_node);
35726
37092
  const is_mobile = render_context.is_mobile ? true : false;
35727
37093
  const hover_handlers = func.runtime.render.create_hover_handlers({
35728
37094
  SESSION_ID: options.SESSION_ID,
@@ -35737,13 +37103,22 @@ func.runtime.render.create_tree_runtime = function (options) {
35737
37103
  return await func.runtime.ui.close_modal_session(options.SESSION_ID, modal_id);
35738
37104
  };
35739
37105
  const iterate_child = async function ($divP, nodeP, parent_infoP, $root_container, before_record_function) {
37106
+ const child_tree = await func.runtime.render.ensure_tree_node({
37107
+ SESSION_ID: options.SESSION_ID,
37108
+ nodeP: nodeP || options.treeP || render_node,
37109
+ parent_infoP,
37110
+ paramsP: options.paramsP,
37111
+ keyP: options.keyP,
37112
+ parent_nodeP: render_node,
37113
+ pathP: options.treeP?.meta?.path || [],
37114
+ });
35740
37115
  return await func.runtime.render.iterate_children({
35741
37116
  $divP,
35742
- nodeP,
37117
+ nodeP: child_tree,
35743
37118
  is_mobile,
35744
37119
  before_record_function,
35745
37120
  render_child: async function (key, child) {
35746
- await options.render_child($divP, child, parent_infoP, key, nodeP, $root_container);
37121
+ await options.render_child($divP, child, parent_infoP, key, render_node, $root_container);
35747
37122
  },
35748
37123
  });
35749
37124
  };
@@ -35773,7 +37148,7 @@ func.runtime.render.draw_node = async function (options) {
35773
37148
  check_existP: options.check_existP,
35774
37149
  $root_container: options.$root_container,
35775
37150
  prop: options.prop,
35776
- element: options.nodeP.tagName,
37151
+ element: options.treeP?.tagName || options.nodeP.tagName,
35777
37152
  hover_handlers: options.hover_handlers,
35778
37153
  include_hover_click: options.include_hover_click,
35779
37154
  iterate_child: options.iterate_child,
@@ -35796,21 +37171,33 @@ func.runtime.render.draw_node = async function (options) {
35796
37171
  nodeP: options.nodeP,
35797
37172
  });
35798
37173
  };
35799
- func.runtime.render.render_ui_tree = async function (SESSION_ID, $container, nodeP, parent_infoP, paramsP, jobNoP, is_skeleton, keyP, refreshed_ds, parent_nodeP, check_existP, $root_container) {
35800
- if (!nodeP) return;
35801
- const perf_end = func.runtime?.perf?.start?.(SESSION_ID, 'render_ui_tree');
35802
- func.runtime?.perf?.increment_map?.(SESSION_ID, 'render_node_counts', nodeP.id || nodeP.id_org || nodeP.tagName || 'unknown');
37174
+ func.runtime.render.render_tree = async function (treeP, renderer_context) {
37175
+ if (!treeP) return;
37176
+ const nodeP = func.runtime.render.get_tree_source_node(treeP);
37177
+ const perf_end = func.runtime?.perf?.start?.(renderer_context.SESSION_ID, 'render_ui_tree');
37178
+ func.runtime?.perf?.increment_map?.(renderer_context.SESSION_ID, 'render_node_counts', treeP.id || nodeP?.id || nodeP?.id_org || treeP.tagName || 'unknown');
35803
37179
  try {
35804
37180
  const tree_runtime = func.runtime.render.create_tree_runtime({
35805
- SESSION_ID,
35806
- $container,
37181
+ SESSION_ID: renderer_context.SESSION_ID,
37182
+ $container: renderer_context.$container,
37183
+ treeP,
35807
37184
  nodeP,
35808
- parent_infoP,
35809
- paramsP,
35810
- jobNoP,
35811
- is_skeleton,
37185
+ parent_infoP: renderer_context.parent_infoP,
37186
+ paramsP: renderer_context.paramsP,
37187
+ jobNoP: renderer_context.jobNoP,
37188
+ is_skeleton: renderer_context.is_skeleton,
37189
+ keyP: renderer_context.keyP,
35812
37190
  render_child: async function ($divP, child, parent_infoP, key, parentNodeP, rootContainerP) {
35813
- await func.runtime.render.render_ui_tree(SESSION_ID, $divP, child, parent_infoP, paramsP, jobNoP, is_skeleton, key, null, parentNodeP, null, rootContainerP);
37191
+ await func.runtime.render.render_tree(child, {
37192
+ ...renderer_context,
37193
+ $container: $divP,
37194
+ parent_infoP,
37195
+ keyP: key,
37196
+ refreshed_ds: null,
37197
+ parent_nodeP: parentNodeP,
37198
+ check_existP: null,
37199
+ $root_container: rootContainerP,
37200
+ });
35814
37201
  },
35815
37202
  });
35816
37203
  const render_context = tree_runtime.render_context;
@@ -35822,23 +37209,24 @@ func.runtime.render.render_ui_tree = async function (SESSION_ID, $container, nod
35822
37209
  const iterate_child = tree_runtime.iterate_child;
35823
37210
 
35824
37211
  func.runtime.render.log_tree_debug({
35825
- SESSION_ID,
35826
- paramsP,
37212
+ SESSION_ID: renderer_context.SESSION_ID,
37213
+ paramsP: renderer_context.paramsP,
35827
37214
  nodeP,
35828
37215
  _ds,
35829
37216
  });
35830
37217
  const special_render = await func.runtime.render.render_special_node({
35831
- SESSION_ID,
35832
- $container,
35833
- $root_container,
37218
+ SESSION_ID: renderer_context.SESSION_ID,
37219
+ $container: renderer_context.$container,
37220
+ $root_container: renderer_context.$root_container,
37221
+ treeP,
35834
37222
  nodeP,
35835
- parent_infoP,
35836
- paramsP,
35837
- jobNoP,
35838
- is_skeleton,
35839
- keyP,
35840
- refreshed_ds,
35841
- parent_nodeP,
37223
+ parent_infoP: renderer_context.parent_infoP,
37224
+ paramsP: renderer_context.paramsP,
37225
+ jobNoP: renderer_context.jobNoP,
37226
+ is_skeleton: renderer_context.is_skeleton,
37227
+ keyP: renderer_context.keyP,
37228
+ refreshed_ds: renderer_context.refreshed_ds,
37229
+ parent_nodeP: renderer_context.parent_nodeP,
35842
37230
  prop,
35843
37231
  render_context,
35844
37232
  hover_handlers,
@@ -35846,22 +37234,23 @@ func.runtime.render.render_ui_tree = async function (SESSION_ID, $container, nod
35846
37234
  close_modal,
35847
37235
  });
35848
37236
  if (special_render.handled) {
35849
- func.runtime?.perf?.increment?.(SESSION_ID, 'render_special_node_hits');
37237
+ func.runtime?.perf?.increment?.(renderer_context.SESSION_ID, 'render_special_node_hits');
35850
37238
  return special_render.result;
35851
37239
  }
35852
37240
  return await func.runtime.render.draw_node({
35853
- SESSION_ID,
35854
- $container,
35855
- $root_container,
37241
+ SESSION_ID: renderer_context.SESSION_ID,
37242
+ $container: renderer_context.$container,
37243
+ $root_container: renderer_context.$root_container,
37244
+ treeP,
35856
37245
  nodeP,
35857
- parent_infoP,
35858
- paramsP,
35859
- jobNoP,
35860
- is_skeleton,
35861
- keyP,
35862
- refreshed_ds,
35863
- parent_nodeP,
35864
- check_existP,
37246
+ parent_infoP: renderer_context.parent_infoP,
37247
+ paramsP: renderer_context.paramsP,
37248
+ jobNoP: renderer_context.jobNoP,
37249
+ is_skeleton: renderer_context.is_skeleton,
37250
+ keyP: renderer_context.keyP,
37251
+ refreshed_ds: renderer_context.refreshed_ds,
37252
+ parent_nodeP: renderer_context.parent_nodeP,
37253
+ check_existP: renderer_context.check_existP,
35865
37254
  prop,
35866
37255
  hover_handlers,
35867
37256
  include_hover_click,
@@ -35870,6 +37259,31 @@ func.runtime.render.render_ui_tree = async function (SESSION_ID, $container, nod
35870
37259
  } finally {
35871
37260
  perf_end?.();
35872
37261
  }
37262
+ };
37263
+ func.runtime.render.render_ui_tree = async function (SESSION_ID, $container, nodeP, parent_infoP, paramsP, jobNoP, is_skeleton, keyP, refreshed_ds, parent_nodeP, check_existP, $root_container) {
37264
+ if (!nodeP) return;
37265
+ const treeP = await func.runtime.render.ensure_tree_node({
37266
+ SESSION_ID,
37267
+ nodeP,
37268
+ parent_infoP,
37269
+ paramsP,
37270
+ keyP,
37271
+ parent_nodeP,
37272
+ });
37273
+
37274
+ return await func.runtime.render.render_tree(treeP, {
37275
+ SESSION_ID,
37276
+ $container,
37277
+ parent_infoP,
37278
+ paramsP,
37279
+ jobNoP,
37280
+ is_skeleton,
37281
+ keyP,
37282
+ refreshed_ds,
37283
+ parent_nodeP,
37284
+ check_existP,
37285
+ $root_container,
37286
+ });
35873
37287
  };
35874
37288
  func.runtime = func.runtime || {};
35875
37289
  func.runtime.ui = func.runtime.ui || {};
@@ -36537,7 +37951,7 @@ func.runtime.render.handle_xu_ref = async function (options) {
36537
37951
  func.runtime.render.handle_xu_bind = async function (options) {
36538
37952
  if (options.is_skeleton) return {};
36539
37953
 
36540
- const $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(options.$elm) : func.runtime.ui.as_jquery(options.$elm);
37954
+ const $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(options.$elm) : options.$elm;
36541
37955
  const elm_data = func.runtime.ui.get_data($elm);
36542
37956
  const xuData = elm_data?.xuData;
36543
37957
  const bind_expression =
@@ -37393,6 +38807,7 @@ func.runtime.render.handle_xu_panel_program = async function (options) {
37393
38807
  parent_infoP: options.parent_infoP,
37394
38808
  jobNoP: options.jobNoP,
37395
38809
  keyP: options.keyP,
38810
+ treeP: options.treeP,
37396
38811
  parent_nodeP: options.parent_nodeP,
37397
38812
  prop: options.nodeP.attributes,
37398
38813
  $appendToP: $wrapper,
@@ -44943,6 +46358,12 @@ function xuda(...args) {
44943
46358
  if (typeof opt !== 'object') {
44944
46359
  return console.error('Xuda Error - opt argument is not an object');
44945
46360
  }
46361
+
46362
+ if (!opt.ssr_payload && func.runtime.platform.get_window()?.__XUDA_SSR__) {
46363
+ opt.ssr_payload = func.runtime.platform.get_window().__XUDA_SSR__;
46364
+ }
46365
+ func.runtime.render.apply_runtime_bootstrap_defaults(opt);
46366
+
44946
46367
  glb.URL_PARAMS = func.common.getJsonFromUrl(platform.get_url_href());
44947
46368
 
44948
46369
  glb.worker_type = 'Worker';