@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.
@@ -5,49 +5,6 @@ if (typeof IS_DOCKER === 'undefined' || typeof IS_PROCESS_SERVER === 'undefined'
5
5
  var DOCS_OBJ = {};
6
6
  }
7
7
 
8
- // Minimal jQuery shim for plugins that still reference $
9
- if (typeof $ === 'undefined' && typeof document !== 'undefined') {
10
- var $ = function (selector) {
11
- var nodes = typeof selector === 'string'
12
- ? Array.from(document.querySelectorAll(selector))
13
- : selector?.nodeType ? [selector] : (selector?.length ? Array.from(selector) : []);
14
- var obj = {
15
- 0: nodes[0], length: nodes.length,
16
- toArray: function () { return nodes.slice(); },
17
- 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); },
18
- each: function (fn) { for (var i = 0; i < nodes.length; i++) { fn.call(nodes[i], i, nodes[i]); } return obj; },
19
- on: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].addEventListener(ev, fn); return obj; },
20
- off: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].removeEventListener(ev, fn); return obj; },
21
- addClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.add(c); return obj; },
22
- removeClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.remove(c); return obj; },
23
- hasClass: function (c) { return nodes[0]?.classList?.contains(c) || false; },
24
- 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; },
25
- css: function (k, v) { for (var i = 0; i < nodes.length; i++) nodes[i].style[k] = v; return obj; },
26
- data: function () { return nodes[0]?.__xuData || (nodes[0] ? (nodes[0].__xuData = {}) : {}); },
27
- 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; },
28
- 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; },
29
- 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; },
30
- show: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = ''; return obj; },
31
- hide: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = 'none'; return obj; },
32
- remove: function () { for (var i = 0; i < nodes.length; i++) nodes[i].remove?.(); return obj; },
33
- empty: function () { for (var i = 0; i < nodes.length; i++) nodes[i].innerHTML = ''; return obj; },
34
- append: function (c) { var n = c?.nodeType ? c : c?.[0]; if (n && nodes[0]) nodes[0].appendChild(n); return obj; },
35
- parent: function () { return $(nodes[0]?.parentElement ? [nodes[0].parentElement] : []); },
36
- children: function () { return $(nodes[0] ? Array.from(nodes[0].children) : []); },
37
- trigger: function (ev, d) { for (var i = 0; i < nodes.length; i++) nodes[i].dispatchEvent(new CustomEvent(ev, { detail: d })); return obj; },
38
- is: function (s) { return nodes[0]?.matches?.(s) || false; },
39
- 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; },
40
- unbind: function () { return obj; },
41
- clone: function () { return $(nodes[0]?.cloneNode(true) ? [nodes[0].cloneNode(true)] : []); },
42
- };
43
- obj[Symbol.iterator] = function () { var i = 0; return { next: function () { return i < nodes.length ? { value: nodes[i++], done: false } : { done: true }; } }; };
44
- return obj;
45
- };
46
- $.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]); }); } };
47
- $.cookie = function () { return null; };
48
- var jQuery = $;
49
- }
50
-
51
8
  var glb = {};
52
9
  var func = {};
53
10
  func.UI = {};
@@ -121,23 +78,27 @@ glb.PROTECTED_VARS = ['_NULL', '_THIS', '_FOR_KEY', '_FOR_VAL', '_ROWNO', '_ROWI
121
78
 
122
79
  func.common = {};
123
80
  func.runtime.platform = {
81
+ get_global: function (name) {
82
+ try {
83
+ if (typeof globalThis === 'undefined') {
84
+ return null;
85
+ }
86
+ return globalThis?.[name] || null;
87
+ } catch (error) {
88
+ return null;
89
+ }
90
+ },
124
91
  has_window: function () {
125
- return typeof window !== 'undefined';
92
+ return !!func.runtime.platform.get_window();
126
93
  },
127
94
  has_document: function () {
128
- return typeof document !== 'undefined';
95
+ return !!func.runtime.platform.get_document();
129
96
  },
130
97
  get_window: function () {
131
- if (func.runtime.platform.has_window()) {
132
- return window;
133
- }
134
- return null;
98
+ return func.runtime.platform.get_global('window');
135
99
  },
136
100
  get_document: function () {
137
- if (func.runtime.platform.has_document()) {
138
- return document;
139
- }
140
- return null;
101
+ return func.runtime.platform.get_global('document');
141
102
  },
142
103
  get_location: function () {
143
104
  const win = func.runtime.platform.get_window();
@@ -148,27 +109,23 @@ func.runtime.platform = {
148
109
  if (win?.navigator) {
149
110
  return win.navigator;
150
111
  }
151
- if (typeof navigator !== 'undefined') {
152
- return navigator;
153
- }
154
- return null;
112
+ return func.runtime.platform.get_global('navi' + 'gator');
155
113
  },
156
114
  is_html_element: function (value) {
157
- if (typeof HTMLElement === 'undefined') {
115
+ const html_element = func.runtime.platform.get_global('HTML' + 'Element');
116
+ if (typeof html_element !== 'function') {
158
117
  return false;
159
118
  }
160
- return value instanceof HTMLElement;
119
+ return value instanceof html_element;
161
120
  },
162
121
  get_storage: function (type) {
163
122
  const win = func.runtime.platform.get_window();
123
+ const storage_key = type === 'session' ? 'session' + 'Storage' : 'local' + 'Storage';
164
124
  try {
165
125
  if (!win) {
166
126
  return null;
167
127
  }
168
- if (type === 'session') {
169
- return win.sessionStorage || null;
170
- }
171
- return win.localStorage || null;
128
+ return win?.[storage_key] || null;
172
129
  } catch (error) {
173
130
  return null;
174
131
  }
@@ -325,9 +282,8 @@ func.runtime.platform.emit = function (name, data) {
325
282
  handlers[i](data);
326
283
  }
327
284
  }
328
- // also fire on DOM if in browser (for backward compatibility with custom event listeners)
329
- if (func.runtime.platform.has_document()) {
330
- document.dispatchEvent(new CustomEvent(name, { detail: Array.isArray(data) ? data : [data] }));
285
+ if (typeof func.runtime.platform.dispatch_document_event === 'function') {
286
+ func.runtime.platform.dispatch_document_event(name, data);
331
287
  }
332
288
  } finally {
333
289
  func.runtime.platform._emitting[name] = false;
@@ -335,35 +291,111 @@ func.runtime.platform.emit = function (name, data) {
335
291
  };
336
292
 
337
293
  // ── Platform helpers for DOM-independent resource loading ──
338
- func.runtime.platform.load_script = function (url, type, callback) {
339
- if (typeof document !== 'undefined') {
340
- const script = document.createElement('script');
341
- script.src = url;
342
- if (type) script.type = type;
343
- script.onload = callback;
344
- document.head.appendChild(script);
345
- } else if (callback) {
346
- callback();
347
- }
348
- };
349
- func.runtime.platform.load_css = function (href) {
350
- if (typeof document === 'undefined') return;
294
+ func.runtime.platform.apply_element_attributes = function (node, attributes, excluded_keys = []) {
295
+ if (!node?.setAttribute || !attributes) {
296
+ return node;
297
+ }
298
+
299
+ const excluded = new Set(excluded_keys || []);
300
+ const attr_keys = Object.keys(attributes);
301
+ for (let index = 0; index < attr_keys.length; index++) {
302
+ const key = attr_keys[index];
303
+ if (!key || excluded.has(key)) {
304
+ continue;
305
+ }
306
+
307
+ const value = attributes[key];
308
+ if (value === false || typeof value === 'undefined') {
309
+ continue;
310
+ }
311
+
312
+ node.setAttribute(key, value === null ? '' : `${value}`);
313
+ }
314
+
315
+ return node;
316
+ };
317
+ func.runtime.platform.load_script = function (url, type, callback, attributes) {
318
+ const doc = func.runtime.platform.get_document();
319
+ if (!doc?.createElement || !doc?.head?.appendChild) {
320
+ if (callback) {
321
+ callback();
322
+ }
323
+ return;
324
+ }
325
+ const find_existing_script = function () {
326
+ const asset_key = attributes?.['data-xuda-asset-key'];
327
+ const scripts = doc.querySelectorAll ? Array.from(doc.querySelectorAll('script')) : [];
328
+ return scripts.find(function (script) {
329
+ if (asset_key && script.getAttribute('data-xuda-asset-key') === asset_key) {
330
+ return true;
331
+ }
332
+ return !!(url && script.getAttribute('src') === url);
333
+ }) || null;
334
+ };
335
+
336
+ const existing_script = find_existing_script();
337
+ if (existing_script) {
338
+ if (callback) {
339
+ if (existing_script.getAttribute('data-xuda-loaded') === 'true' || !url) {
340
+ callback();
341
+ } else {
342
+ existing_script.addEventListener('load', callback, { once: true });
343
+ existing_script.addEventListener('error', callback, { once: true });
344
+ }
345
+ }
346
+ return existing_script;
347
+ }
348
+
349
+ const script = doc.createElement('script');
350
+ script.src = url;
351
+ if (type) script.type = type;
352
+ func.runtime.platform.apply_element_attributes(script, attributes, ['src', 'type']);
353
+ script.onload = function () {
354
+ script.setAttribute('data-xuda-loaded', 'true');
355
+ if (callback) {
356
+ callback();
357
+ }
358
+ };
359
+ script.onerror = function () {
360
+ if (callback) {
361
+ callback();
362
+ }
363
+ };
364
+ doc.head.appendChild(script);
365
+ return script;
366
+ };
367
+ func.runtime.platform.load_css = function (href, attributes) {
368
+ const doc = func.runtime.platform.get_document();
369
+ if (!doc?.createElement || !doc?.head) {
370
+ return;
371
+ }
351
372
  try {
352
- if (document.querySelector('link[href="' + href + '"]')) return;
373
+ const asset_key = attributes?.['data-xuda-asset-key'];
374
+ const existing_links = doc.querySelectorAll ? Array.from(doc.querySelectorAll('link')) : [];
375
+ const existing = existing_links.find(function (link) {
376
+ if (asset_key && link.getAttribute('data-xuda-asset-key') === asset_key) {
377
+ return true;
378
+ }
379
+ return !!(href && link.getAttribute('href') === href);
380
+ });
381
+ if (existing) return existing;
353
382
  } catch (err) {
354
383
  return;
355
384
  }
356
- const link = document.createElement('link');
385
+ const link = doc.createElement('link');
357
386
  link.rel = 'stylesheet';
358
387
  link.type = 'text/css';
359
388
  link.href = href;
360
- document.head.insertBefore(link, document.head.firstChild);
389
+ func.runtime.platform.apply_element_attributes(link, attributes, ['href']);
390
+ doc.head.insertBefore(link, doc.head.firstChild);
391
+ return link;
361
392
  };
362
393
  func.runtime.platform.remove_js_css = function (filename, filetype) {
363
- if (typeof document === 'undefined') return;
394
+ const doc = func.runtime.platform.get_document();
395
+ if (!doc?.getElementsByTagName) return;
364
396
  const tagName = filetype === 'js' ? 'script' : filetype === 'css' ? 'link' : 'none';
365
397
  const attr = filetype === 'js' ? 'src' : filetype === 'css' ? 'href' : 'none';
366
- const elements = document.getElementsByTagName(tagName);
398
+ const elements = doc.getElementsByTagName(tagName);
367
399
  for (let i = elements.length - 1; i >= 0; i--) {
368
400
  if (elements[i] && elements[i].getAttribute(attr) != null && elements[i].getAttribute(attr).indexOf(filename) !== -1) {
369
401
  elements[i].parentNode.removeChild(elements[i]);
@@ -371,15 +403,17 @@ func.runtime.platform.remove_js_css = function (filename, filetype) {
371
403
  }
372
404
  };
373
405
  func.runtime.platform.inject_css = function (cssText) {
374
- if (typeof document === 'undefined' || !cssText) return;
375
- const style = document.createElement('style');
406
+ const doc = func.runtime.platform.get_document();
407
+ if (!doc?.createElement || !doc?.head?.appendChild || !cssText) return;
408
+ const style = doc.createElement('style');
376
409
  style.type = 'text/css';
377
410
  style.textContent = cssText;
378
- document.head.appendChild(style);
411
+ doc.head.appendChild(style);
379
412
  };
380
413
  func.runtime.platform.set_title = function (title) {
381
- if (typeof document !== 'undefined') {
382
- document.title = title;
414
+ const doc = func.runtime.platform.get_document();
415
+ if (doc) {
416
+ doc.title = title;
383
417
  }
384
418
  };
385
419
  func.runtime.platform.set_cursor = function (element, cursor) {
@@ -645,6 +679,147 @@ func.runtime.workers.delete_promise = function (SESSION_ID, worker_id, promise_q
645
679
  delete registry_entry.promise_queue[promise_queue_id];
646
680
  return true;
647
681
  };
682
+ func.runtime.render.clone_runtime_options = function (value) {
683
+ if (typeof structuredClone === 'function') {
684
+ try {
685
+ return structuredClone(value);
686
+ } catch (_) {}
687
+ }
688
+
689
+ if (Array.isArray(value)) {
690
+ return value.map(function (item) {
691
+ return func.runtime.render.clone_runtime_options(item);
692
+ });
693
+ }
694
+
695
+ if (value && typeof value === 'object') {
696
+ const cloned = {};
697
+ const keys = Object.keys(value);
698
+ for (let index = 0; index < keys.length; index++) {
699
+ const key = keys[index];
700
+ cloned[key] = func.runtime.render.clone_runtime_options(value[key]);
701
+ }
702
+ return cloned;
703
+ }
704
+
705
+ return value;
706
+ };
707
+ func.runtime.render.normalize_runtime_bootstrap = function (raw_options = {}) {
708
+ const options = raw_options || {};
709
+ let app_computing_mode = options.app_computing_mode || '';
710
+ let app_render_mode = options.app_render_mode || '';
711
+ let app_client_activation = options.app_client_activation || '';
712
+ let ssr_payload = options.ssr_payload || null;
713
+
714
+ if (typeof ssr_payload === 'string') {
715
+ try {
716
+ ssr_payload = JSON.parse(ssr_payload);
717
+ } catch (_) {
718
+ ssr_payload = null;
719
+ }
720
+ }
721
+
722
+ if (ssr_payload && typeof ssr_payload === 'object') {
723
+ ssr_payload = func.runtime.render.clone_runtime_options(ssr_payload);
724
+ }
725
+
726
+ if (!app_computing_mode) {
727
+ if (app_render_mode === 'ssr_first_page' || app_render_mode === 'ssr_full') {
728
+ app_computing_mode = 'server';
729
+ } else {
730
+ app_computing_mode = 'main';
731
+ }
732
+ }
733
+
734
+ switch (app_computing_mode) {
735
+ case 'main':
736
+ app_render_mode = 'csr';
737
+ app_client_activation = 'none';
738
+ break;
739
+
740
+ case 'worker':
741
+ app_render_mode = 'csr';
742
+ app_client_activation = 'none';
743
+ break;
744
+
745
+ default:
746
+ app_computing_mode = 'server';
747
+ if (app_render_mode !== 'ssr_full') {
748
+ app_render_mode = 'ssr_first_page';
749
+ }
750
+ app_client_activation = app_render_mode === 'ssr_full' ? 'hydrate' : 'takeover';
751
+ break;
752
+ }
753
+
754
+ if (ssr_payload && typeof ssr_payload === 'object') {
755
+ if (!ssr_payload.app_render_mode) {
756
+ ssr_payload.app_render_mode = app_render_mode;
757
+ }
758
+ if (!ssr_payload.app_client_activation) {
759
+ ssr_payload.app_client_activation = app_client_activation;
760
+ }
761
+ if (!ssr_payload.app_computing_mode) {
762
+ ssr_payload.app_computing_mode = app_computing_mode;
763
+ }
764
+ }
765
+
766
+ return {
767
+ app_computing_mode,
768
+ app_render_mode,
769
+ app_client_activation,
770
+ ssr_payload,
771
+ };
772
+ };
773
+ func.runtime.render.apply_runtime_bootstrap_defaults = function (target = {}) {
774
+ const normalized = func.runtime.render.normalize_runtime_bootstrap(target);
775
+ target.app_computing_mode = normalized.app_computing_mode;
776
+ target.app_render_mode = normalized.app_render_mode;
777
+ target.app_client_activation = normalized.app_client_activation;
778
+ target.ssr_payload = normalized.ssr_payload;
779
+ return normalized;
780
+ };
781
+ func.runtime.render.is_server_render_mode = function (target = {}) {
782
+ const normalized = func.runtime.render.normalize_runtime_bootstrap(target?.opt || target);
783
+ return normalized.app_computing_mode === 'server' && normalized.app_render_mode !== 'csr';
784
+ };
785
+ func.runtime.render.is_takeover_mode = function (target = {}) {
786
+ const normalized = func.runtime.render.normalize_runtime_bootstrap(target?.opt || target);
787
+ return normalized.app_client_activation === 'takeover';
788
+ };
789
+ func.runtime.render.is_hydration_mode = function (target = {}) {
790
+ const normalized = func.runtime.render.normalize_runtime_bootstrap(target?.opt || target);
791
+ return normalized.app_client_activation === 'hydrate';
792
+ };
793
+ func.runtime.render.get_ssr_payload = function (target = {}) {
794
+ if (target?.opt?.ssr_payload) {
795
+ return target.opt.ssr_payload;
796
+ }
797
+ if (target?.ssr_payload) {
798
+ return target.ssr_payload;
799
+ }
800
+ const win = func.runtime.platform.get_window();
801
+ return win?.__XUDA_SSR__ || null;
802
+ };
803
+ func.runtime.render.should_use_ssr_payload = function (SESSION_ID, paramsP) {
804
+ const session = SESSION_OBJ?.[SESSION_ID];
805
+ const payload = func.runtime.render.get_ssr_payload(session);
806
+ if (!payload || payload._consumed) {
807
+ return false;
808
+ }
809
+ if (paramsP?.prog_id && payload.prog_id && payload.prog_id !== paramsP.prog_id) {
810
+ return false;
811
+ }
812
+ return true;
813
+ };
814
+ func.runtime.render.mark_ssr_payload_consumed = function (SESSION_ID) {
815
+ const session = SESSION_OBJ?.[SESSION_ID];
816
+ const payload = func.runtime.render.get_ssr_payload(session);
817
+ if (!payload || typeof payload !== 'object') {
818
+ return false;
819
+ }
820
+ payload._consumed = true;
821
+ return true;
822
+ };
648
823
  func.runtime.render.get_root_data_system = function (SESSION_ID) {
649
824
  return SESSION_OBJ[SESSION_ID]?.DS_GLB?.[0]?.data_system || null;
650
825
  };
@@ -1048,10 +1223,10 @@ func.runtime.resources.load_cdn = async function (SESSION_ID, resource) {
1048
1223
  await func.utils.load_js_on_demand(normalized_resource.src);
1049
1224
  break;
1050
1225
  case 'css':
1051
- await func.utils.load_js_on_demand(normalized_resource.src);
1226
+ func.runtime.platform.load_css(normalized_resource.src);
1052
1227
  break;
1053
1228
  case 'module':
1054
- func.utils.load_js_on_demand(normalized_resource.src, 'module');
1229
+ await func.utils.load_js_on_demand(normalized_resource.src, 'module');
1055
1230
  break;
1056
1231
  default:
1057
1232
  await func.utils.load_js_on_demand(normalized_resource.src);
@@ -1067,12 +1242,36 @@ func.runtime.resources.load_cdn = async function (SESSION_ID, resource) {
1067
1242
  func.runtime.resources.get_plugin_manifest_entry = function (_session, plugin_name) {
1068
1243
  return APP_OBJ[_session.app_id]?.app_plugins_purchased?.[plugin_name] || null;
1069
1244
  };
1070
- func.runtime.resources.get_plugin_module_path = function (plugin, resource) {
1245
+ func.runtime.resources.get_plugin_resource_candidates = function (_session, plugin, resource) {
1071
1246
  const manifest_entry = plugin?.manifest?.[resource];
1072
- return `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
1247
+ const default_path = `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
1248
+ const candidates = [];
1249
+ if (_session?.worker_type === 'Dev' && manifest_entry?.dist && /\.mjs$/.test(resource)) {
1250
+ candidates.push(`src/${resource}`);
1251
+ }
1252
+ candidates.push(default_path);
1253
+ return Array.from(new Set(candidates.filter(Boolean)));
1254
+ };
1255
+ func.runtime.resources.get_plugin_module_path = function (plugin, resource, _session) {
1256
+ return func.runtime.resources.get_plugin_resource_candidates(_session, plugin, resource)[0] || resource;
1073
1257
  };
1074
1258
  func.runtime.resources.get_plugin_module_url = async function (SESSION_ID, plugin_name, plugin, resource) {
1075
- return await func.utils.get_plugin_npm_cdn(SESSION_ID, plugin_name, func.runtime.resources.get_plugin_module_path(plugin, resource));
1259
+ const _session = SESSION_OBJ[SESSION_ID];
1260
+ return await func.utils.get_plugin_npm_cdn(SESSION_ID, plugin_name, func.runtime.resources.get_plugin_module_path(plugin, resource, _session));
1261
+ };
1262
+ func.runtime.resources.import_plugin_module = async function (SESSION_ID, plugin_name, plugin, resource) {
1263
+ const _session = SESSION_OBJ[SESSION_ID];
1264
+ const candidates = func.runtime.resources.get_plugin_resource_candidates(_session, plugin, resource);
1265
+ let last_error = null;
1266
+ for (let index = 0; index < candidates.length; index++) {
1267
+ const candidate = candidates[index];
1268
+ try {
1269
+ return await func.utils.get_plugin_resource(SESSION_ID, plugin_name, candidate);
1270
+ } catch (error) {
1271
+ last_error = error;
1272
+ }
1273
+ }
1274
+ throw last_error || new Error(`plugin resource not found: ${plugin_name}/${resource}`);
1076
1275
  };
1077
1276
  func.runtime.resources.load_plugin_runtime_css = async function (SESSION_ID, plugin_name, plugin) {
1078
1277
  if (!plugin?.manifest?.['runtime.mjs']?.dist || !plugin?.manifest?.['runtime.mjs']?.css) {
@@ -1102,12 +1301,10 @@ func.runtime.resources.run_ui_plugin = async function (SESSION_ID, paramsP, $elm
1102
1301
 
1103
1302
  await func.runtime.resources.load_plugin_runtime_css(SESSION_ID, plugin_name, plugin);
1104
1303
 
1105
- const plugin_index_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'index.mjs');
1106
- const plugin_index_resources = await import(plugin_index_src);
1304
+ const plugin_index_resources = await func.runtime.resources.import_plugin_module(SESSION_ID, plugin_name, plugin, 'index.mjs');
1107
1305
  const properties = await func.runtime.resources.resolve_plugin_properties(SESSION_ID, paramsP.dsSessionP, value?.attributes, plugin_index_resources.properties);
1108
1306
 
1109
- const plugin_runtime_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
1110
- const plugin_runtime_resources = await import(plugin_runtime_src);
1307
+ const plugin_runtime_resources = await func.runtime.resources.import_plugin_module(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
1111
1308
 
1112
1309
  if (plugin_runtime_resources.cdn && Array.isArray(plugin_runtime_resources.cdn)) {
1113
1310
  for await (const resource of plugin_runtime_resources.cdn) {
@@ -1190,25 +1387,52 @@ func.runtime.widgets.get_fields_data = async function (context, fields, props) {
1190
1387
 
1191
1388
  return { code: return_code, data: data_obj };
1192
1389
  };
1390
+ func.runtime.widgets.get_resource_candidates = function (context, resource) {
1391
+ return func.runtime.resources.get_plugin_resource_candidates(context._session, context.plugin, resource);
1392
+ };
1393
+ func.runtime.widgets.normalize_capabilities = function (definition) {
1394
+ const capabilities = definition?.capabilities || {};
1395
+ return {
1396
+ browser: capabilities.browser !== false,
1397
+ headless: capabilities.headless === true,
1398
+ };
1399
+ };
1400
+ func.runtime.widgets.supports_current_environment = function (definition) {
1401
+ const capabilities = func.runtime.widgets.normalize_capabilities(definition);
1402
+ if (func.runtime.platform.has_document()) {
1403
+ return capabilities.browser !== false;
1404
+ }
1405
+ return !!capabilities.headless;
1406
+ };
1193
1407
  func.runtime.widgets.get_resource_path = function (context, resource) {
1408
+ const relative_path = func.runtime.widgets.get_resource_candidates(context, resource)[0] || resource;
1194
1409
  if (context._session.worker_type === 'Dev') {
1195
- return `../../plugins/${context.plugin_name}/${resource}`;
1410
+ return `../../plugins/${context.plugin_name}/${relative_path}`;
1196
1411
  }
1197
- const manifest_entry = context.plugin?.manifest?.[resource];
1198
- const dist_prefix = manifest_entry?.dist ? 'dist/' : '';
1199
- return `https://${context._session.domain}/plugins/${context.plugin_name}/${dist_prefix}${resource}?gtp_token=${context._session.gtp_token}&app_id=${context._session.app_id}`;
1412
+ return `https://${context._session.domain}/plugins/${context.plugin_name}/${relative_path}?gtp_token=${context._session.gtp_token}&app_id=${context._session.app_id}`;
1200
1413
  };
1201
1414
  func.runtime.widgets.load_css_style = function (context) {
1202
1415
  func.utils.load_css_on_demand(func.runtime.widgets.get_resource_path(context, 'style.css'));
1203
1416
  return true;
1204
1417
  };
1205
1418
  func.runtime.widgets.get_resource = async function (context, resource) {
1206
- const manifest_entry = context.plugin?.manifest?.[resource];
1207
- const path = `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
1208
- return await func.utils.get_plugin_resource(context.SESSION_ID, context.plugin_name, path);
1419
+ const candidates = func.runtime.widgets.get_resource_candidates(context, resource);
1420
+ let last_error = null;
1421
+ for (let index = 0; index < candidates.length; index++) {
1422
+ const candidate = candidates[index];
1423
+ try {
1424
+ return await func.utils.get_plugin_resource(context.SESSION_ID, context.plugin_name, candidate);
1425
+ } catch (error) {
1426
+ last_error = error;
1427
+ }
1428
+ }
1429
+ throw last_error || new Error(`widget resource not found: ${context.plugin_name}/${resource}`);
1430
+ };
1431
+ func.runtime.widgets.get_definition = async function (context) {
1432
+ return await func.runtime.widgets.get_resource(context, 'index.mjs');
1209
1433
  };
1210
1434
  func.runtime.widgets.get_methods = async function (context) {
1211
- const index = await func.runtime.widgets.get_resource(context, 'index.mjs');
1435
+ const index = await func.runtime.widgets.get_definition(context);
1212
1436
  return index?.methods || {};
1213
1437
  };
1214
1438
  func.runtime.widgets.load_runtime_css = async function (context) {
@@ -1219,7 +1443,7 @@ func.runtime.widgets.load_runtime_css = async function (context) {
1219
1443
  func.utils.load_css_on_demand(plugin_runtime_css_url);
1220
1444
  return true;
1221
1445
  };
1222
- func.runtime.widgets.build_params = function (context, $containerP, plugin_setup, api_utils, extra = {}) {
1446
+ func.runtime.widgets.build_params = function (context, container_node, container_data, plugin_setup, api_utils, extra = {}) {
1223
1447
  return {
1224
1448
  SESSION_ID: context.SESSION_ID,
1225
1449
  method: context.method,
@@ -1228,14 +1452,28 @@ func.runtime.widgets.build_params = function (context, $containerP, plugin_setup
1228
1452
  sourceP: context.sourceP,
1229
1453
  propsP: context.propsP,
1230
1454
  plugin_name: context.plugin_name,
1231
- $containerP,
1455
+ container_node,
1456
+ container_data,
1232
1457
  plugin_setup,
1233
1458
  report_error: function (descP, warn) {
1234
1459
  return func.runtime.widgets.report_error(context, descP, warn);
1235
1460
  },
1461
+ log_error: function (descP, warn) {
1462
+ return func.runtime.widgets.report_error(context, descP, warn);
1463
+ },
1236
1464
  call_plugin_api: async function (plugin_nameP, dataP) {
1237
1465
  return await func.utils.call_plugin_api(context.SESSION_ID, plugin_nameP, dataP);
1238
1466
  },
1467
+ set_SYS_GLOBAL_OBJ_WIDGET_INFO: async function (docP) {
1468
+ return await func.utils.set_SYS_GLOBAL_OBJ_WIDGET_INFO(context.SESSION_ID, docP);
1469
+ },
1470
+ run_widgetCallbackEvent: async function () {
1471
+ const event_id = context.propsP?.widgetCallbackEvent;
1472
+ if (!event_id || !api_utils?.invoke_event) {
1473
+ return false;
1474
+ }
1475
+ return await api_utils.invoke_event(event_id);
1476
+ },
1239
1477
  api_utils,
1240
1478
  ...extra,
1241
1479
  };