@yuneta/gobj-js 7.25.8 → 7.26.0

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.
@@ -23,8 +23,8 @@ function vsprintf(fmt, argv) {
23
23
  return sprintf.apply(null, [fmt].concat(argv || []));
24
24
  }
25
25
  function sprintf_format(parse_tree, argv) {
26
- var cursor = 1, tree_length = parse_tree.length, arg, output = "", i, k, ph, pad, pad_character, pad_length, is_positive, sign;
27
- for (i = 0; i < tree_length; i++) if (typeof parse_tree[i] === "string") output += parse_tree[i];
26
+ var cursor = 1, tree_length = parse_tree.length, arg, output = "", i = 0, k, ph, pad, pad_character, pad_length, is_positive, sign;
27
+ for (; i < tree_length; i++) if (typeof parse_tree[i] === "string") output += parse_tree[i];
28
28
  else if (typeof parse_tree[i] === "object") {
29
29
  ph = parse_tree[i];
30
30
  if (ph.keys) {
@@ -157,7 +157,7 @@ function command_parser(gobj, command, kw, src) {}
157
157
  function build_command_response(gobj, result, comment, schema, data) {
158
158
  return {
159
159
  result,
160
- comment: comment || {},
160
+ comment: comment || "",
161
161
  schema: schema || {},
162
162
  data: data || []
163
163
  };
@@ -211,7 +211,7 @@ var __global_command_parser_fn__ = null;
211
211
  var __global_stats_parser_fn__ = null;
212
212
  var dl_global_event_types = [];
213
213
  var _gclass_register = Object.create(null);
214
- var __jn_services__ = {};
214
+ var __jn_services__ = Object.create(null);
215
215
  var __yuno__ = null;
216
216
  var __default_service__ = null;
217
217
  var __inside__ = 0;
@@ -820,7 +820,8 @@ function set_default(gobj, sdata, it) {
820
820
  if (!is_object(jn_value)) jn_value = {};
821
821
  break;
822
822
  case data_type_t.DTP_JSON:
823
- if (is_string(svalue)) try {
823
+ if (svalue === "" || svalue === void 0) jn_value = null;
824
+ else if (is_string(svalue)) try {
824
825
  jn_value = JSON.parse(svalue);
825
826
  } catch (error) {
826
827
  log_error(`JSON parse error: ${error.message}`);
@@ -855,11 +856,17 @@ function json2item(gobj, sdata, it, jn_value_) {
855
856
  break;
856
857
  case data_type_t.DTP_INTEGER:
857
858
  jn_value2 = parseInt(jn_value_);
858
- if (isNaN(jn_value2)) log_error(`${gobj_short_name(gobj)}: attr NaN: ${it.name}`);
859
+ if (isNaN(jn_value2)) {
860
+ log_error(`${gobj_short_name(gobj)}: attr NaN: ${it.name}`);
861
+ return -1;
862
+ }
859
863
  break;
860
864
  case data_type_t.DTP_REAL:
861
865
  jn_value2 = Number(jn_value_);
862
- if (isNaN(jn_value2)) log_error(`${gobj_short_name(gobj)}: attr NaN: ${it.name}`);
866
+ if (isNaN(jn_value2)) {
867
+ log_error(`${gobj_short_name(gobj)}: attr NaN: ${it.name}`);
868
+ return -1;
869
+ }
863
870
  break;
864
871
  case data_type_t.DTP_LIST:
865
872
  if (is_string(jn_value_)) try {
@@ -886,15 +893,11 @@ function json2item(gobj, sdata, it, jn_value_) {
886
893
  }
887
894
  break;
888
895
  case data_type_t.DTP_JSON:
896
+ jn_value2 = jn_value_;
889
897
  if (is_string(jn_value_)) try {
890
898
  jn_value2 = JSON.parse(jn_value_);
891
899
  } catch (error) {
892
- log_error(`JSON parse error: ${error.message}`);
893
- }
894
- else jn_value2 = jn_value_;
895
- if (!is_array(jn_value2) && !is_object(jn_value2)) {
896
- log_error(`attr must be a json dict/list: ${it.name}`);
897
- return -1;
900
+ jn_value2 = jn_value_;
898
901
  }
899
902
  break;
900
903
  case data_type_t.DTP_POINTER: jn_value2 = jn_value_;
@@ -1199,6 +1202,10 @@ function gobj_default_service() {
1199
1202
  * find a service
1200
1203
  ************************************************************/
1201
1204
  function gobj_find_service(service_name, verbose) {
1205
+ if (!is_string(service_name)) {
1206
+ log_error(`gobj_find_service(): service name must be a string: ${service_name}`);
1207
+ return null;
1208
+ }
1202
1209
  service_name = service_name.toLowerCase();
1203
1210
  let service_gobj = __jn_services__[service_name];
1204
1211
  if (!service_gobj) {
@@ -1333,7 +1340,7 @@ function write_json_parameters(gobj, kw, jn_global) {
1333
1340
  let new_kw = kw;
1334
1341
  if (json2sdata(hs, new_kw, -1, gobj.gclass.gclass_flag & gclass_flag_t.gcflag_ignore_unknown_attrs ? 0 : print_attr_not_found, gobj) < 0) {
1335
1342
  log_error(`${gobj_short_name(gobj)} json2data() FAILED`);
1336
- trace_json(new_kw);
1343
+ trace_json_masked(new_kw);
1337
1344
  }
1338
1345
  }
1339
1346
  /************************************************************
@@ -1356,9 +1363,10 @@ function gobj_create2(gobj_name, gclass_name, kw, parent, gobj_flag) {
1356
1363
  return null;
1357
1364
  }
1358
1365
  if (is_string(parent)) {
1359
- parent = gobj_find_service(parent);
1366
+ const parent_name = parent;
1367
+ parent = gobj_find_service(parent_name);
1360
1368
  if (!parent) {
1361
- log_warning(`parent service not found: ${parent}`);
1369
+ log_warning(`parent service not found: ${parent_name}`);
1362
1370
  return null;
1363
1371
  }
1364
1372
  }
@@ -1471,6 +1479,7 @@ function gobj_destroy(gobj) {
1471
1479
  parent.gclass.gmt.mt_child_removed(parent, gobj);
1472
1480
  }
1473
1481
  if (gobj.gobj_flag & gobj_flag_t.gobj_flag_service) _deregister_service(gobj);
1482
+ if (gobj === __default_service__) __default_service__ = null;
1474
1483
  gobj_unsubscribe_list(gobj, gobj.dl_subscriptions, true);
1475
1484
  gobj_unsubscribe_list(gobj, gobj.dl_subscribings, true);
1476
1485
  if (parent) {
@@ -1816,7 +1825,7 @@ function gobj_set_bottom_gobj(gobj, bottom_gobj) {
1816
1825
  log_error(`gobj NULL of bad type`);
1817
1826
  return null;
1818
1827
  }
1819
- if (gobj.bottom_gobj) log_warning(`${gobj_short_name(gobj)}: bottom_gobj already set`);
1828
+ if (gobj.bottom_gobj && bottom_gobj) log_warning(`${gobj_short_name(gobj)}: bottom_gobj already set`);
1820
1829
  gobj.bottom_gobj = bottom_gobj;
1821
1830
  }
1822
1831
  /***************************************************************************
@@ -2231,7 +2240,7 @@ function gobj_write_attr(gobj, path, value, src) {
2231
2240
  jn_attrs[key] = value;
2232
2241
  if (is_object(gobj.priv) && gobj.priv.hasOwnProperty(key)) gobj.priv[key] = value;
2233
2242
  if (gobj.obflag & obflag_t.obflag_created && !(gobj.obflag & obflag_t.obflag_destroyed)) {
2234
- if (gobj.mt_writing) gobj.mt_writing(gobj, key);
2243
+ if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, key);
2235
2244
  }
2236
2245
  return 0;
2237
2246
  }
@@ -2255,8 +2264,8 @@ function sdata_write_default_values(gobj, include_flag, exclude_flag) {
2255
2264
  if (!it.name) continue;
2256
2265
  if (exclude_flag && it.flag & exclude_flag) continue;
2257
2266
  if (include_flag === -1 || it.flag & include_flag) {
2258
- const value = set_default(gobj, gobj.jn_attrs, it);
2259
- if (is_object(gobj.priv) && gobj.priv.hasOwnProperty(it.name)) gobj.priv[it.name] = value;
2267
+ set_default(gobj, gobj.jn_attrs, it);
2268
+ if (is_object(gobj.priv) && gobj.priv.hasOwnProperty(it.name)) gobj.priv[it.name] = gobj.jn_attrs[it.name];
2260
2269
  if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, it.name);
2261
2270
  }
2262
2271
  }
@@ -2290,7 +2299,7 @@ function gobj_write_bool_attr(gobj, name, value) {
2290
2299
  let hs = gobj_hsdata2(gobj, name, false);
2291
2300
  if (hs) {
2292
2301
  hs[name] = parseBoolean(value);
2293
- if (is_object(gobj.priv) && gobj.priv.hasOwnProperty(name)) gobj.priv[name] = value;
2302
+ if (is_object(gobj.priv) && gobj.priv.hasOwnProperty(name)) gobj.priv[name] = hs[name];
2294
2303
  if (gobj.obflag & obflag_t.obflag_created && !(gobj.obflag & obflag_t.obflag_destroyed)) {
2295
2304
  if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, name);
2296
2305
  }
@@ -2306,7 +2315,7 @@ function gobj_write_integer_attr(gobj, name, value) {
2306
2315
  let hs = gobj_hsdata2(gobj, name, false);
2307
2316
  if (hs) {
2308
2317
  hs[name] = parseInt(value);
2309
- if (is_object(gobj.priv) && gobj.priv.hasOwnProperty(name)) gobj.priv[name] = value;
2318
+ if (is_object(gobj.priv) && gobj.priv.hasOwnProperty(name)) gobj.priv[name] = hs[name];
2310
2319
  if (gobj.obflag & obflag_t.obflag_created && !(gobj.obflag & obflag_t.obflag_destroyed)) {
2311
2320
  if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, name);
2312
2321
  }
@@ -2322,7 +2331,7 @@ function gobj_write_str_attr(gobj, name, value) {
2322
2331
  let hs = gobj_hsdata2(gobj, name, false);
2323
2332
  if (hs) {
2324
2333
  hs[name] = String(value);
2325
- if (is_object(gobj.priv) && gobj.priv.hasOwnProperty(name)) gobj.priv[name] = value;
2334
+ if (is_object(gobj.priv) && gobj.priv.hasOwnProperty(name)) gobj.priv[name] = hs[name];
2326
2335
  if (gobj.obflag & obflag_t.obflag_created && !(gobj.obflag & obflag_t.obflag_destroyed)) {
2327
2336
  if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, name);
2328
2337
  }
@@ -2376,15 +2385,15 @@ function gobj_change_parent(gobj, parent) {
2376
2385
  log_error(`${gobj_short_name(gobj)}: gobj_change_parent() BAD TYPE of parent`);
2377
2386
  return -1;
2378
2387
  }
2379
- if (gobj.parent && gobj.parent.mt_child_removed) gobj.parent.mt_child_removed(gobj.parent, gobj);
2388
+ if (gobj.parent && gobj.parent.gclass.gmt.mt_child_removed) gobj.parent.gclass.gmt.mt_child_removed(gobj.parent, gobj);
2380
2389
  if (gobj.parent) {
2381
2390
  _remove_child(gobj.parent, gobj);
2382
2391
  gobj.parent = null;
2383
2392
  }
2384
2393
  _add_child(parent, gobj);
2385
- if (parent.mt_child_added) {
2394
+ if (parent.gclass.gmt.mt_child_added) {
2386
2395
  if (__trace_gobj_create_delete__(gobj)) log_debug(sprintf("👦👦🔵 child_added(%s): %s", gobj_full_name(parent), gobj_short_name(gobj)));
2387
- parent.mt_child_added(parent, gobj);
2396
+ parent.gclass.gmt.mt_child_added(parent, gobj);
2388
2397
  }
2389
2398
  return 0;
2390
2399
  }
@@ -2496,9 +2505,19 @@ function gobj_deliver_posted_events() {
2496
2505
  let snapshot = __dl_posted_events__;
2497
2506
  __dl_posted_events__ = [];
2498
2507
  let delivered = 0;
2499
- for (let msg of snapshot) {
2508
+ for (let i = 0; i < snapshot.length; i++) {
2509
+ const msg = snapshot[i];
2500
2510
  if (msg.dst.obflag & (obflag_t.obflag_destroyed | obflag_t.obflag_destroying)) continue;
2501
- gobj_send_event(msg.dst, msg.event, msg.kw, msg.src);
2511
+ try {
2512
+ gobj_send_event(msg.dst, msg.event, msg.kw, msg.src);
2513
+ } catch (e) {
2514
+ __dl_posted_events__ = snapshot.slice(i + 1).concat(__dl_posted_events__);
2515
+ if (__dl_posted_events__.length > 0 && !__posted_events_scheduled__) {
2516
+ __posted_events_scheduled__ = true;
2517
+ setTimeout(gobj_deliver_posted_events, 0);
2518
+ }
2519
+ throw e;
2520
+ }
2502
2521
  delivered++;
2503
2522
  }
2504
2523
  if (__dl_posted_events__.length > 0 && !__posted_events_scheduled__) {
@@ -2548,7 +2567,7 @@ function gobj_send_event(dst, event, kw, src) {
2548
2567
  else trace_machine(sprintf("🔃 mach(%s%s), st: %s, ev: %s, from(%s%s)", !dst.running ? "!!" : "", gobj_short_name(dst), state.state_name, event ? event : "", src && !src.running ? "!!" : "", gobj_short_name(src)));
2549
2568
  if (kw) {
2550
2569
  if (__trace_gobj_ev_kw__(dst)) {
2551
- if (json_object_size(kw)) trace_json(kw);
2570
+ if (json_object_size(kw)) trace_json_masked(kw);
2552
2571
  }
2553
2572
  }
2554
2573
  }
@@ -2568,7 +2587,7 @@ function gobj_send_event(dst, event, kw, src) {
2568
2587
  }
2569
2588
  if (kw) {
2570
2589
  if (__trace_gobj_ev_kw__(dst)) {
2571
- if (json_object_size(kw)) trace_json(kw);
2590
+ if (json_object_size(kw)) trace_json_masked(kw);
2572
2591
  }
2573
2592
  }
2574
2593
  }
@@ -2576,15 +2595,40 @@ function gobj_send_event(dst, event, kw, src) {
2576
2595
  let ret = -1;
2577
2596
  try {
2578
2597
  if (event_action.action) ret = event_action.action(dst, event, kw, src);
2579
- } finally {}
2598
+ } catch (e) {
2599
+ __inside__--;
2600
+ if (!(e && e.__gobj_logged__)) {
2601
+ log_error(`${gobj_short_name(dst)}: action of ${event} in ${dst.current_state.state_name} THREW: ${e && e.stack ? e.stack : e}`);
2602
+ try {
2603
+ e.__gobj_logged__ = true;
2604
+ } catch (e2) {}
2605
+ }
2606
+ throw e;
2607
+ }
2580
2608
  if (tracea && __trace_machine_format__ !== 1 && !(dst.obflag & obflag_t.obflag_destroyed)) trace_machine(sprintf("<- mach(%s%s^%s), st: %s, ev: %s, ret: %d", !dst.running ? "!!" : "", gobj_gclass_name(dst), gobj_name(dst), dst.current_state.state_name, event ? event : "", is_number(ret) ? ret : 0));
2581
2609
  __inside__--;
2582
2610
  return ret;
2583
2611
  }
2584
2612
  var subs_flag_t = Object.freeze({
2585
- __hard_subscription__: 1,
2586
- __own_event__: 2
2613
+ __rename_event_name__: 1,
2614
+ __hard_subscription__: 2,
2615
+ __own_event__: 4
2587
2616
  });
2617
+ /***************************************************************************
2618
+ * The event type of `event_name` in any registered gclass, null if none.
2619
+ * The C kernel's gobj_find_event_type(): any case, gclasses only.
2620
+ ***************************************************************************/
2621
+ function _find_event_type_in_gclasses(event_name) {
2622
+ let lower = String(event_name).toLowerCase();
2623
+ for (let gclass_name in _gclass_register) {
2624
+ let dl = _gclass_register[gclass_name].dl_events;
2625
+ for (let i = 0; i < dl.length; i++) {
2626
+ let event_type = dl[i];
2627
+ if (event_type.event_name && event_type.event_name.toLowerCase() === lower) return event_type;
2628
+ }
2629
+ }
2630
+ return null;
2631
+ }
2588
2632
  var subscription_desc = [
2589
2633
  SDATA(data_type_t.DTP_POINTER, "publisher", 0, null, "publisher gobj"),
2590
2634
  SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "subscriber gobj"),
@@ -2617,6 +2661,21 @@ function _create_subscription(publisher, event, kw, subscriber) {
2617
2661
  if (json_size(__config__) > 0) {
2618
2662
  let kw_clone = json_deep_copy(__config__);
2619
2663
  json_object_set_new(subs, "__config__", kw_clone);
2664
+ let renamed_event = kw_get_str(publisher, kw_clone, "__rename_event_name__", "");
2665
+ if (!empty_string(renamed_event)) {
2666
+ let event_type = _find_event_type_in_gclasses(renamed_event);
2667
+ if (event_type) {
2668
+ json_object_set_new(subs, "renamed_event", event_type.event_name);
2669
+ delete kw_clone.__rename_event_name__;
2670
+ subs_flag |= subs_flag_t.__rename_event_name__;
2671
+ let kw_global = kw_get_dict(publisher, subs, "__global__", null);
2672
+ if (!is_object(kw_global)) {
2673
+ kw_global = {};
2674
+ json_object_set_new(subs, "__global__", kw_global);
2675
+ }
2676
+ kw_global.__original_event_name__ = event;
2677
+ } else log_error(`${gobj_short_name(publisher)}: EVENT NOT FOUND (__rename_event_name__: ${renamed_event})`);
2678
+ }
2620
2679
  if (kw_has_key(kw_clone, "__hard_subscription__")) {
2621
2680
  let hard_subscription = kw_get_bool(publisher, kw_clone, "__hard_subscription__", false);
2622
2681
  json_object_del(kw_clone, "__hard_subscription__");
@@ -2636,9 +2695,52 @@ function _create_subscription(publisher, event, kw, subscriber) {
2636
2695
  return subs;
2637
2696
  }
2638
2697
  /***************************************************************************
2698
+ * The kw to find the subscriptions a (un)subscription `kw` names: `kw` as
2699
+ * _create_subscription() stores it, as the C kernel's
2700
+ * _subscription_match_kw(). The three `__config__` keys the framework
2701
+ * reads (__hard_subscription__, __own_event__, __rename_event_name__)
2702
+ * become the subs_flag and are taken out of the stored `__config__`, and
2703
+ * a renamed event adds `__original_event_name__` to the stored
2704
+ * `__global__`: with `kw` as it came, the same kw matched no subscription,
2705
+ * a repeat of it was made twice (the subscriber got each event twice) and
2706
+ * its withdrawal found nothing. A known renamed event is returned in
2707
+ * `renamed_event`, which _match_subscription() compares: a plain and a
2708
+ * renamed subscription, or two renames of one event, are two. A rename
2709
+ * that no gclass declares stays in the stored `__config__`, and in this
2710
+ * one. Up to gobj-js 7.25.8 the kw was compared as it came, and
2711
+ * `__rename_event_name__` always stayed in the stored `__config__`: a
2712
+ * plain kw with the rest of that __config__ found no repeat (two
2713
+ * subscriptions where C has one).
2714
+ * Return {kw, renamed_event}; renamed_event is "" when kw does not rename.
2715
+ ***************************************************************************/
2716
+ function _subscription_match_kw(kw, event) {
2717
+ let __config__ = kw ? kw.__config__ : null;
2718
+ if (!is_object(__config__) || !kw_has_key(__config__, "__hard_subscription__") && !kw_has_key(__config__, "__own_event__") && !kw_has_key(__config__, "__rename_event_name__")) return {
2719
+ kw,
2720
+ renamed_event: ""
2721
+ };
2722
+ let kw_match = Object.assign({}, kw);
2723
+ let config_match = Object.assign({}, __config__);
2724
+ kw_match.__config__ = config_match;
2725
+ let renamed_event = "";
2726
+ let rename = config_match.__rename_event_name__;
2727
+ let event_type = typeof rename === "string" && !empty_string(rename) ? _find_event_type_in_gclasses(rename) : null;
2728
+ if (event_type) {
2729
+ renamed_event = event_type.event_name;
2730
+ delete config_match.__rename_event_name__;
2731
+ if (event && json_size(kw_match.__global__) > 0) kw_match.__global__ = Object.assign({}, kw_match.__global__, { __original_event_name__: event });
2732
+ }
2733
+ delete config_match.__hard_subscription__;
2734
+ delete config_match.__own_event__;
2735
+ return {
2736
+ kw: kw_match,
2737
+ renamed_event
2738
+ };
2739
+ }
2740
+ /***************************************************************************
2639
2741
  * Match subscription
2640
2742
  ***************************************************************************/
2641
- function _match_subscription(subs, publisher, event, kw, subscriber) {
2743
+ function _match_subscription(subs, publisher, event, renamed_event, kw, subscriber) {
2642
2744
  let __config__ = kw_get_dict(publisher, kw, "__config__", null);
2643
2745
  let __global__ = kw_get_dict(publisher, kw, "__global__", null);
2644
2746
  let __local__ = kw_get_dict(publisher, kw, "__local__", null);
@@ -2653,6 +2755,9 @@ function _match_subscription(subs, publisher, event, kw, subscriber) {
2653
2755
  if (event) {
2654
2756
  if (event !== kw_get_str(null, subs, "event", "")) match = false;
2655
2757
  }
2758
+ if (renamed_event) {
2759
+ if (renamed_event !== kw_get_str(null, subs, "renamed_event", "")) match = false;
2760
+ }
2656
2761
  if (json_size(__config__) > 0) {
2657
2762
  let kw_config = kw_get_dict(null, subs, "__config__", null);
2658
2763
  if (json_size(kw_config) > 0) {
@@ -2687,26 +2792,29 @@ function _match_subscription(subs, publisher, event, kw, subscriber) {
2687
2792
  * kw (__config__, __global__, __local__, __filter__),
2688
2793
  * subscriber
2689
2794
  ***************************************************************************/
2690
- function _find_subscriptions(dl_subs, publisher, event, kw, subscriber) {
2795
+ function _find_subscriptions(dl_subs, publisher, event, renamed_event, kw, subscriber) {
2691
2796
  let iter = [];
2692
2797
  for (let i = 0; i < dl_subs.length; i++) {
2693
2798
  let subs = dl_subs[i];
2694
- if (_match_subscription(subs, publisher, event, kw, subscriber)) json_array_append(iter, subs);
2799
+ if (_match_subscription(subs, publisher, event, renamed_event, kw, subscriber)) json_array_append(iter, subs);
2695
2800
  }
2696
2801
  return iter;
2697
2802
  }
2698
2803
  /***************************************************************************
2699
- * Find idx of subscription in dl_subs, -1 not found
2804
+ * Find idx of the subscription `subs` itself in dl_subs, -1 not found.
2805
+ * Up to gobj-js 7.25.8 it was the first entry whose fields matched `subs`:
2806
+ * a subscription already removed took a live one that matched it (a plain
2807
+ * one matches every other of its event and subscriber).
2700
2808
  ***************************************************************************/
2701
- function _get_subs_idx(dl_subs, publisher, event, kw, subscriber) {
2702
- for (let i = 0; i < dl_subs.length; i++) {
2703
- let subs = dl_subs[i];
2704
- if (_match_subscription(subs, publisher, event, kw, subscriber)) return i;
2705
- }
2706
- return -1;
2809
+ function _get_subs_idx(dl_subs, subs) {
2810
+ return dl_subs.indexOf(subs);
2707
2811
  }
2708
2812
  /***************************************************************************
2709
- * Delete subscription in publisher and subscriber
2813
+ * Delete subscription in publisher and subscriber.
2814
+ * Return 0 removed, -1 a hard one kept (only `force` removes it), 1 it
2815
+ * was not there any more: already removed, as a stale reference is, or by
2816
+ * the mt_subscription_deleted() of an earlier entry of the same list. The
2817
+ * caller says which is an error. As in C.
2710
2818
  ***************************************************************************/
2711
2819
  function _delete_subscription(gobj, subs, force, not_inform) {
2712
2820
  let publisher = kw_get_pointer(gobj, subs, "publisher", null, kw_flag_t.KW_REQUIRED);
@@ -2715,7 +2823,12 @@ function _delete_subscription(gobj, subs, force, not_inform) {
2715
2823
  if (kw_get_int(gobj, subs, "subs_flag", null, kw_flag_t.KW_REQUIRED) & subs_flag_t.__hard_subscription__ ? 1 : 0) {
2716
2824
  if (!force) return -1;
2717
2825
  }
2718
- if (__trace_gobj_subscriptions__(subscriber) || __trace_gobj_subscriptions__(publisher)) {
2826
+ let tracea = __trace_gobj_subscriptions__(subscriber) || __trace_gobj_subscriptions__(publisher);
2827
+ if (_get_subs_idx(publisher.dl_subscriptions, subs) < 0) {
2828
+ if (tracea) trace_machine(sprintf("💜💜👎 unsubscribing event '%s': publisher %s, subscriber'%s', ALREADY REMOVED", event ? event : "", gobj_short_name(publisher), gobj_short_name(subscriber)));
2829
+ return 1;
2830
+ }
2831
+ if (tracea) {
2719
2832
  trace_machine(sprintf("💜💜👎 unsubscribing event '%s': publisher %s, subscriber'%s'", event ? event : "", gobj_short_name(publisher), gobj_short_name(subscriber)));
2720
2833
  trace_json(subs);
2721
2834
  }
@@ -2724,13 +2837,13 @@ function _delete_subscription(gobj, subs, force, not_inform) {
2724
2837
  if (publisher.gclass.gmt.mt_subscription_deleted) publisher.gclass.gmt.mt_subscription_deleted(publisher, subs);
2725
2838
  }
2726
2839
  }
2727
- let idx = _get_subs_idx(publisher.dl_subscriptions, publisher, event, subs, subscriber);
2840
+ let idx = _get_subs_idx(publisher.dl_subscriptions, subs);
2728
2841
  if (idx >= 0) json_array_remove(publisher.dl_subscriptions, idx);
2729
2842
  else {
2730
2843
  log_error(`${gobj_short_name(gobj)}: subscription in publisher not found`);
2731
2844
  trace_json(subs);
2732
2845
  }
2733
- idx = _get_subs_idx(subscriber.dl_subscribings, publisher, event, subs, subscriber);
2846
+ idx = _get_subs_idx(subscriber.dl_subscribings, subs);
2734
2847
  if (idx >= 0) json_array_remove(subscriber.dl_subscribings, idx);
2735
2848
  else {
2736
2849
  log_error(`${gobj_short_name(gobj)}: subscription in subscriber not found`);
@@ -2773,7 +2886,17 @@ function gobj_subscribe_event(publisher, event, kw, subscriber) {
2773
2886
  }
2774
2887
  }
2775
2888
  } else event = "";
2776
- let dl_subs = _find_subscriptions(publisher.dl_subscriptions, publisher, event, kw, subscriber);
2889
+ let match = _subscription_match_kw(kw, event);
2890
+ let dl_subs = _find_subscriptions(publisher.dl_subscriptions, publisher, event, match.renamed_event, match.kw, subscriber);
2891
+ let subs_hard = null;
2892
+ for (let i = 0; i < dl_subs.length; i++) if (kw_get_int(publisher, dl_subs[i], "subs_flag", 0, kw_flag_t.KW_REQUIRED) & subs_flag_t.__hard_subscription__) {
2893
+ subs_hard = dl_subs[i];
2894
+ break;
2895
+ }
2896
+ if (subs_hard) {
2897
+ log_warning(`${gobj_short_name(publisher)}: Hard subscription REPEATED, the one there is kept and returned (event: ${event}, subscriber: ${gobj_short_name(subscriber)})`);
2898
+ return subs_hard;
2899
+ }
2777
2900
  if (json_array_size(dl_subs) > 0) {
2778
2901
  log_error(`${gobj_short_name(publisher)}: ${json_array_size(dl_subs)} subscription(s) REPEATED, will be deleted and override`);
2779
2902
  trace_json(dl_subs, "subscription REPEATED");
@@ -2788,7 +2911,7 @@ function gobj_subscribe_event(publisher, event, kw, subscriber) {
2788
2911
  json_array_append(subscriber.dl_subscribings, subs);
2789
2912
  if (__trace_gobj_subscriptions__(subscriber) || __trace_gobj_subscriptions__(publisher)) {
2790
2913
  trace_machine(sprintf("💜💜👍 subscribing event '%s', publisher '%s', subscriber %s", event ? event : "", gobj_short_name(publisher), gobj_short_name(subscriber)));
2791
- if (kw && (__trace_gobj_ev_kw__(subscriber) || __trace_gobj_ev_kw__(publisher))) trace_json(kw);
2914
+ if (kw && (__trace_gobj_ev_kw__(subscriber) || __trace_gobj_ev_kw__(publisher))) trace_json_masked(kw);
2792
2915
  }
2793
2916
  if (publisher.gclass.gmt.mt_subscription_added) {
2794
2917
  let result = publisher.gclass.gmt.mt_subscription_added(publisher, subs);
@@ -2830,16 +2953,22 @@ function gobj_unsubscribe_event(publisher, event, kw, subscriber) {
2830
2953
  }
2831
2954
  }
2832
2955
  } else event = "";
2833
- let dl_subs = _find_subscriptions(publisher.dl_subscriptions, publisher, event, kw, subscriber);
2956
+ let match = _subscription_match_kw(kw, event);
2957
+ let dl_subs = _find_subscriptions(publisher.dl_subscriptions, publisher, event, match.renamed_event, match.kw, subscriber);
2834
2958
  let deleted = 0;
2959
+ let kept_hard = 0;
2960
+ let already_removed = 0;
2835
2961
  for (let i = 0; i < dl_subs.length; i++) {
2836
2962
  let subs = dl_subs[i];
2837
- _delete_subscription(publisher, subs, false, false);
2838
- deleted++;
2963
+ let ret = _delete_subscription(publisher, subs, false, false);
2964
+ if (ret === 0) deleted++;
2965
+ else if (ret < 0) kept_hard++;
2966
+ else already_removed++;
2839
2967
  }
2840
- if (!deleted) {
2968
+ if (kept_hard) log_warning(`${gobj_short_name(publisher)}: Hard subscription not removed, only gobj_unsubscribe_list() with force removes it (event: ${event}, hard: ${kept_hard})`);
2969
+ else if (!deleted && !already_removed) {
2841
2970
  log_warning(`${gobj_short_name(publisher)}: No subscription found`);
2842
- trace_json(kw, "No subscription found");
2971
+ trace_json_masked(kw, "No subscription found");
2843
2972
  }
2844
2973
  return 0;
2845
2974
  }
@@ -2848,10 +2977,12 @@ function gobj_unsubscribe_event(publisher, event, kw, subscriber) {
2848
2977
  ***************************************************************************/
2849
2978
  function gobj_unsubscribe_list(gobj, dl_subs, force) {
2850
2979
  let dl = [...dl_subs];
2980
+ let already_removed = 0;
2851
2981
  for (let i = 0; i < dl.length; i++) {
2852
2982
  let subs = dl[i];
2853
- _delete_subscription(gobj, subs, force, false);
2983
+ if (_delete_subscription(gobj, subs, force, false) > 0) already_removed++;
2854
2984
  }
2985
+ if (already_removed) log_warning(`${gobj_short_name(gobj)}: Subscription(s) already removed, nothing to remove (count: ${already_removed})`);
2855
2986
  return 0;
2856
2987
  }
2857
2988
  /***************************************************************************
@@ -2863,7 +2994,7 @@ function gobj_unsubscribe_list(gobj, dl_subs, force) {
2863
2994
  ***************************************************************************/
2864
2995
  function gobj_find_subscriptions(publisher, event, kw, subscriber) {
2865
2996
  if (kw == null) kw = {};
2866
- return _find_subscriptions(publisher.dl_subscriptions, publisher, event, kw, subscriber);
2997
+ return _find_subscriptions(publisher.dl_subscriptions, publisher, event, null, kw, subscriber);
2867
2998
  }
2868
2999
  /***************************************************************************
2869
3000
  *
@@ -2902,7 +3033,7 @@ function gobj_list_subscriptions(gobj2view) {
2902
3033
  * subscriber
2903
3034
  ***************************************************************************/
2904
3035
  function gobj_find_subscribings(subscriber, event, kw, publisher) {
2905
- return _find_subscriptions(subscriber.dl_subscribings, publisher, event, kw, subscriber);
3036
+ return _find_subscriptions(subscriber.dl_subscribings, publisher, event, null, kw, subscriber);
2906
3037
  }
2907
3038
  /***************************************************************************
2908
3039
  * Return the sum of returns of gobj_send_event
@@ -2928,7 +3059,7 @@ function gobj_publish_event(publisher, event, kw) {
2928
3059
  if (tracea) {
2929
3060
  if (__trace_machine_format__ === 1) trace_machine(sprintf("🔝🔝 %s %s%s %s", event ? event : "", !publisher.running ? "!!" : "", gobj_short_name(publisher), publisher.current_state.state_name));
2930
3061
  else trace_machine(sprintf("🔝🔝 mach(%s%s^%s), st: %s, ev: %s%s%s", !publisher.running ? "!!" : "", gobj_gclass_name(publisher), gobj_name(publisher), publisher.current_state.state_name, "", event ? event : "", ""));
2931
- if (__trace_gobj_ev_kw__(publisher) && json_object_size(kw)) trace_json(kw);
3062
+ if (__trace_gobj_ev_kw__(publisher) && json_object_size(kw)) trace_json_masked(kw);
2932
3063
  }
2933
3064
  if (publisher.gclass.gmt.mt_publish_event) {
2934
3065
  let topublish = publisher.gclass.gmt.mt_publish_event(publisher, event, kw);
@@ -2953,6 +3084,8 @@ function gobj_publish_event(publisher, event, kw) {
2953
3084
  let __global__ = kw_get_dict(publisher, subs, "__global__", null, 0);
2954
3085
  let __local__ = kw_get_dict(publisher, subs, "__local__", null, 0);
2955
3086
  let __filter__ = kw_get_dict_value(publisher, subs, "__filter__", null, 0);
3087
+ let event_name = subs.renamed_event;
3088
+ if (empty_string(event_name)) event_name = event;
2956
3089
  let topublish = 1;
2957
3090
  if (publisher.gclass.gmt.mt_publication_filter) topublish = publisher.gclass.gmt.mt_publication_filter(publisher, event, kw, subscriber);
2958
3091
  else if (json_size(__filter__) > 0) {
@@ -2976,11 +3109,11 @@ function gobj_publish_event(publisher, event, kw) {
2976
3109
  if (__config__) {}
2977
3110
  if (json_size(__global__) > 0) json_object_update(kw2publish, json_deep_copy(__global__));
2978
3111
  if (tracea) {
2979
- if (__trace_machine_format__ === 1) trace_machine(sprintf("🔝🔄 %s (%s) %s%s", event ? event : "", event ? event : "", !subscriber.running ? "!!" : "", gobj_short_name(subscriber)));
2980
- else trace_machine(sprintf("🔝🔄 mach(%s%s), st: %s, ev: %s, from(%s%s)", !subscriber.running ? "!!" : "", gobj_short_name(subscriber), gobj_current_state(subscriber), event ? event : "", publisher && !publisher.running ? "!!" : "", gobj_short_name(publisher)));
2981
- if (__trace_gobj_ev_kw__(publisher) && json_object_size(kw2publish)) trace_json(kw2publish);
3112
+ if (__trace_machine_format__ === 1) trace_machine(sprintf("🔝🔄 %s (%s) %s%s", event ? event : "", event_name ? event_name : "", !subscriber.running ? "!!" : "", gobj_short_name(subscriber)));
3113
+ else trace_machine(sprintf("🔝🔄 mach(%s%s), st: %s, ev: %s (%s), from(%s%s)", !subscriber.running ? "!!" : "", gobj_short_name(subscriber), gobj_current_state(subscriber), event ? event : "", event_name ? event_name : "", publisher && !publisher.running ? "!!" : "", gobj_short_name(publisher)));
3114
+ if (__trace_gobj_ev_kw__(publisher) && json_object_size(kw2publish)) trace_json_masked(kw2publish);
2982
3115
  }
2983
- let ret_ = gobj_send_event(subscriber, event, kw2publish, publisher);
3116
+ let ret_ = gobj_send_event(subscriber, event_name, kw2publish, publisher);
2984
3117
  if (ret_ < 0 && subs_flag & subs_flag_t.__own_event__) {
2985
3118
  sent_count = -1;
2986
3119
  break;
@@ -3004,8 +3137,9 @@ function gobj_command(gobj, command, kw, src) {
3004
3137
  return -1;
3005
3138
  }
3006
3139
  if (is_commands_tracing(gobj) || is_machine_tracing(gobj, null) && !is_machine_not_tracing(src, null)) {
3007
- trace_machine(sprintf("🌀🌀 mach(%s%s), cmd: %s, src: %s", !gobj_is_running(gobj) ? "!!" : "", gobj_short_name(gobj), command, gobj_short_name(src)));
3008
- if (__trace_gobj_ev_kw__(gobj)) trace_json(kw);
3140
+ let command_shown = mask_secrets_inline(command);
3141
+ trace_machine(sprintf("🌀🌀 mach(%s%s), cmd: %s, src: %s", !gobj_is_running(gobj) ? "!!" : "", gobj_short_name(gobj), command_shown !== null ? command_shown : command, gobj_short_name(src)));
3142
+ if (__trace_gobj_ev_kw__(gobj)) trace_json_masked(kw);
3009
3143
  }
3010
3144
  if (gobj.gclass.gmt.mt_command_parser) return gobj.gclass.gmt.mt_command_parser(gobj, command, kw, src);
3011
3145
  if (gobj.gclass.command_table) {
@@ -3141,10 +3275,22 @@ function set_remote_log_functions(remote_log_fn) {
3141
3275
  f_warning = _console.warn;
3142
3276
  }
3143
3277
  }
3278
+ /************************************************************
3279
+ * JSON.stringify for a log line: a circular object (a gobj,
3280
+ * a DOM node) must not make the log call itself throw.
3281
+ ************************************************************/
3282
+ function log_stringify(v) {
3283
+ try {
3284
+ return JSON.stringify(v);
3285
+ } catch (e) {
3286
+ return String(v);
3287
+ }
3288
+ }
3144
3289
  function format_log(format) {
3145
3290
  const args = Array.prototype.slice.call(arguments);
3146
3291
  let output = "";
3147
3292
  if (typeof format === "string") {
3293
+ if (args.length === 1) return format;
3148
3294
  let i = 1;
3149
3295
  output = format.replace(/%[sdifoO]/g, (match) => {
3150
3296
  const val = args[i++];
@@ -3154,17 +3300,17 @@ function format_log(format) {
3154
3300
  case "%i": return parseInt(val);
3155
3301
  case "%f": return parseFloat(val);
3156
3302
  case "%o":
3157
- case "%O": return typeof val === "object" ? JSON.stringify(val) : String(val);
3303
+ case "%O": return typeof val === "object" ? log_stringify(val) : String(val);
3158
3304
  default: return match;
3159
3305
  }
3160
3306
  });
3161
- const rest = args.slice(i).map((arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg));
3307
+ const rest = args.slice(i).map((arg) => typeof arg === "object" ? log_stringify(arg) : String(arg));
3162
3308
  if (rest.length > 0) output += " " + rest.join(" ");
3163
- } else output = args.map((arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)).join(" ");
3309
+ } else output = args.map((arg) => typeof arg === "object" ? log_stringify(arg) : String(arg)).join(" ");
3164
3310
  return output;
3165
3311
  }
3166
- function log_error(format) {
3167
- let msg = format_log(format);
3312
+ function log_error(format, ...args) {
3313
+ let msg = format_log(format, ...args);
3168
3314
  let hora = current_timestamp();
3169
3315
  if (f_error) {
3170
3316
  if (f_error === _console.error) {
@@ -3176,8 +3322,8 @@ function log_error(format) {
3176
3322
  }
3177
3323
  emit_log_callback("error", msg, hora);
3178
3324
  }
3179
- function log_warning(format) {
3180
- let msg = format_log(format);
3325
+ function log_warning(format, ...args) {
3326
+ let msg = format_log(format, ...args);
3181
3327
  let hora = current_timestamp();
3182
3328
  if (f_warning) {
3183
3329
  if (f_warning === _console.warn) {
@@ -3189,24 +3335,24 @@ function log_warning(format) {
3189
3335
  }
3190
3336
  emit_log_callback("warning", msg, hora);
3191
3337
  }
3192
- function log_info(format) {
3193
- let msg = format_log(format);
3338
+ function log_info(format, ...args) {
3339
+ let msg = format_log(format, ...args);
3194
3340
  let hora = current_timestamp();
3195
3341
  if (f_info) {
3196
3342
  if (console_wants("info", msg)) f_info("%c" + hora + " INFO: " + String(msg), "color:cyan");
3197
3343
  }
3198
3344
  emit_log_callback("info", msg, hora);
3199
3345
  }
3200
- function log_debug(format) {
3201
- let msg = format_log(format);
3346
+ function log_debug(format, ...args) {
3347
+ let msg = format_log(format, ...args);
3202
3348
  let hora = current_timestamp();
3203
3349
  if (f_debug) {
3204
3350
  if (console_wants("debug", msg)) f_debug("%c" + hora + " DEBUG: " + String(msg), "color:silver");
3205
3351
  }
3206
3352
  emit_log_callback("debug", msg, hora);
3207
3353
  }
3208
- function trace_msg(format) {
3209
- let msg = format_log(format);
3354
+ function trace_msg(format, ...args) {
3355
+ let msg = format_log(format, ...args);
3210
3356
  let hora = current_timestamp();
3211
3357
  if (f_debug) {
3212
3358
  if (console_wants("msg", msg)) f_debug("%c" + hora + " MSG: " + String(msg), "color:cyan");
@@ -3221,6 +3367,268 @@ function trace_json(jn, msg) {
3221
3367
  emit_log_callback("json", jn, current_timestamp());
3222
3368
  }
3223
3369
  /************************************************************
3370
+ * The names of the secrets (is_secret_name()). The same lists
3371
+ * as the C kernel's helpers.c: a name that holds one of these
3372
+ * (any case) is a secret.
3373
+ ************************************************************/
3374
+ var SECRET_NAME_PARTS = [
3375
+ "passw",
3376
+ "pwd",
3377
+ "passphrase",
3378
+ "secret",
3379
+ "token",
3380
+ "jwt",
3381
+ "bearer",
3382
+ "authorization",
3383
+ "cookie",
3384
+ "credential",
3385
+ "salt"
3386
+ ];
3387
+ var SECRET_NAME_JOINED = [
3388
+ "apikey",
3389
+ "sessionid",
3390
+ "sessionkey",
3391
+ "authdata"
3392
+ ];
3393
+ var NOT_SECRET_SEGMENTS = /* @__PURE__ */ new Set([
3394
+ "endpoint",
3395
+ "url",
3396
+ "uri",
3397
+ "domain",
3398
+ "path",
3399
+ "file",
3400
+ "public",
3401
+ "pub",
3402
+ "count",
3403
+ "counts",
3404
+ "type",
3405
+ "name",
3406
+ "len",
3407
+ "length",
3408
+ "size",
3409
+ "max",
3410
+ "min",
3411
+ "ttl",
3412
+ "timeout",
3413
+ "expiry",
3414
+ "expires",
3415
+ "mode"
3416
+ ]);
3417
+ /************************************************************
3418
+ * TRUE if `name` is the name of a secret: a password, a token,
3419
+ * a key... Any case. As the C kernel's is_secret_name().
3420
+ ************************************************************/
3421
+ function is_secret_name(name) {
3422
+ if (typeof name !== "string" || name.length < 3) return false;
3423
+ let lower = name.toLowerCase();
3424
+ let hit = false;
3425
+ for (const part of SECRET_NAME_PARTS) if (lower.indexOf(part) >= 0) {
3426
+ hit = true;
3427
+ break;
3428
+ }
3429
+ if (!hit) {
3430
+ let joined = lower.replace(/[_\-. \t]/g, "");
3431
+ for (const part of SECRET_NAME_JOINED) if (joined.indexOf(part) >= 0) {
3432
+ hit = true;
3433
+ break;
3434
+ }
3435
+ }
3436
+ if (!hit) hit = lower.indexOf("priv") >= 0 && lower.indexOf("key") >= 0;
3437
+ if (!hit) return false;
3438
+ for (const segment of lower.split(/[_\-. \t]/)) if (NOT_SECRET_SEGMENTS.has(segment)) return false;
3439
+ return true;
3440
+ }
3441
+ /************************************************************
3442
+ * Where an unquoted secret value that begins at `p` ends: at
3443
+ * the end, at the quote that closes an outer quoted value, or
3444
+ * before the next "word=" -- a plain word after a blank is still
3445
+ * part of it ("password=correct horse battery", "password=
3446
+ * hunter2"). As the C kernel's inline_secret_value_end().
3447
+ ************************************************************/
3448
+ function inline_secret_value_end(str, p, outer) {
3449
+ const blank = (c) => c === " " || c === " ";
3450
+ const closes_outer = (i) => outer && str[i] === outer && (i + 1 >= str.length || blank(str[i + 1]));
3451
+ let end = p;
3452
+ while (true) {
3453
+ while (end < str.length && !blank(str[end])) {
3454
+ if (closes_outer(end)) return end;
3455
+ end++;
3456
+ }
3457
+ if (end >= str.length) return end;
3458
+ let w = end;
3459
+ while (w < str.length && blank(str[w])) w++;
3460
+ if (w >= str.length || closes_outer(w)) return end;
3461
+ for (let e = w; e < str.length && !blank(str[e]) && !closes_outer(e); e++) if (str[e] === "=" && e > w) return end;
3462
+ end = w;
3463
+ }
3464
+ }
3465
+ /************************************************************
3466
+ * A text (a command line) with the value of every "name=value"
3467
+ * whose name is a secret's written as "********", quoted or not
3468
+ * (and the "value" of a write-attr whose attribute names a
3469
+ * secret). The rest as it is. Return null when there was nothing
3470
+ * to mask. As the C kernel's mask_secrets_inline().
3471
+ ************************************************************/
3472
+ var MASK_MAX_NAME = 128;
3473
+ var MASK_MAX_BYTES = 4194304;
3474
+ var MASK_TOO_LARGE = "<not shown: too large to mask>";
3475
+ function mask_secrets_inline(str) {
3476
+ if (typeof str !== "string" || str.indexOf("=") < 0) return null;
3477
+ if (str.length > MASK_MAX_BYTES) return MASK_TOO_LARGE;
3478
+ let value_is_secret = false;
3479
+ let re_attr = /(^|[ \t])attribute=["']?([^ \t"']*)/g;
3480
+ let m;
3481
+ while ((m = re_attr.exec(str)) !== null) if (is_secret_name(m[2].slice(-128))) value_is_secret = true;
3482
+ let parts = [];
3483
+ let copied = 0;
3484
+ let changed = false;
3485
+ let outer = "";
3486
+ let word = 0;
3487
+ let p = 0;
3488
+ const is_blank_or_end = (i) => i >= str.length || str[i] === " " || str[i] === " ";
3489
+ while (p < str.length) {
3490
+ let c = str[p];
3491
+ if (c === " " || c === " ") {
3492
+ p++;
3493
+ word = p;
3494
+ continue;
3495
+ }
3496
+ if (c === "\"" || c === "'") {
3497
+ if (!outer && (p === 0 || str[p - 1] === " " || str[p - 1] === " " || str[p - 1] === "=")) outer = c;
3498
+ else if (c === outer && is_blank_or_end(p + 1)) outer = "";
3499
+ }
3500
+ if (c !== "=") {
3501
+ p++;
3502
+ continue;
3503
+ }
3504
+ let name = str.substring(Math.max(word, p - MASK_MAX_NAME), p);
3505
+ word = p + 1;
3506
+ if (!(is_secret_name(name) || value_is_secret && name.toLowerCase() === "value")) {
3507
+ p++;
3508
+ continue;
3509
+ }
3510
+ p++;
3511
+ let quote = str[p] === "\"" || str[p] === "'" ? str[p] : "";
3512
+ let end;
3513
+ if (quote) {
3514
+ end = p + 1;
3515
+ while (end < str.length && str[end] !== quote) end++;
3516
+ if (str[end] === quote) end++;
3517
+ } else end = inline_secret_value_end(str, p, outer);
3518
+ if (end > p) {
3519
+ parts.push(str.substring(copied, p));
3520
+ parts.push("********");
3521
+ copied = end;
3522
+ changed = true;
3523
+ }
3524
+ p = end;
3525
+ word = p;
3526
+ }
3527
+ if (!changed) return null;
3528
+ parts.push(str.substring(copied));
3529
+ return parts.join("");
3530
+ }
3531
+ /************************************************************
3532
+ * A json as a log or a trace may show it: at any depth, the
3533
+ * value of a key with a secret's name is "********", whatever
3534
+ * its type (not an absent one, a null or an empty string); so is
3535
+ * the "value" of a dict whose "attribute" names a secret; and a
3536
+ * string is masked as mask_secrets_inline(). Return a masked
3537
+ * copy, or `jn` itself when there was nothing to mask. As the C
3538
+ * kernel's json_mask_secrets().
3539
+ *
3540
+ * Only JSON is walked: plain objects (their prototype is
3541
+ * Object.prototype or null) and arrays. Anything else -- a gobj,
3542
+ * a DOM node, a class instance, a typed array, a function -- is
3543
+ * passed as it is, never walked, as trace_json() always showed it
3544
+ * (a kw may carry a gobj: its parent and children make a cycle).
3545
+ * A plain object met twice is masked once, the same everywhere; a
3546
+ * cycle back to one is "<cycle>"; below MASK_MAX_DEPTH levels
3547
+ * (64, as in C) nothing is shown.
3548
+ * It never throws: a failure is the placeholder below.
3549
+ ************************************************************/
3550
+ var MASK_MAX_DEPTH = 64;
3551
+ var MASK_FAILED = "<not shown: the masking failed>";
3552
+ function is_plain_object(value) {
3553
+ if (value === null || typeof value !== "object") return false;
3554
+ let proto = Object.getPrototypeOf(value);
3555
+ return proto === Object.prototype || proto === null;
3556
+ }
3557
+ var MASK_IN_PROGRESS = Symbol("mask-in-progress");
3558
+ function _json_mask_secrets(jn, memo, depth, budget) {
3559
+ if (typeof jn === "string") {
3560
+ if (jn.length > budget.left) {
3561
+ budget.left = 0;
3562
+ return MASK_TOO_LARGE;
3563
+ }
3564
+ budget.left -= jn.length;
3565
+ let masked = mask_secrets_inline(jn);
3566
+ return masked !== null ? masked : jn;
3567
+ }
3568
+ let is_array = Array.isArray(jn);
3569
+ if (!is_array && !is_plain_object(jn)) return jn;
3570
+ if (budget.left <= 0) return MASK_TOO_LARGE;
3571
+ if (memo.has(jn)) {
3572
+ let seen = memo.get(jn);
3573
+ return seen === MASK_IN_PROGRESS ? "<cycle>" : seen;
3574
+ }
3575
+ if (depth >= MASK_MAX_DEPTH) return "<deeper not shown>";
3576
+ budget.left -= 1;
3577
+ memo.set(jn, MASK_IN_PROGRESS);
3578
+ let changed = false;
3579
+ let truncated = false;
3580
+ let result;
3581
+ if (is_array) {
3582
+ result = [];
3583
+ for (let i = 0; i < jn.length; i++) {
3584
+ if (budget.left <= 0) {
3585
+ truncated = true;
3586
+ break;
3587
+ }
3588
+ budget.left -= 1;
3589
+ let shown = _json_mask_secrets(jn[i], memo, depth + 1, budget);
3590
+ if (shown !== jn[i]) changed = true;
3591
+ result.push(shown);
3592
+ }
3593
+ if (truncated) result.push(MASK_TOO_LARGE);
3594
+ } else {
3595
+ result = Object.create(Object.getPrototypeOf(jn));
3596
+ let value_is_secret = typeof jn.attribute === "string" && is_secret_name(jn.attribute.slice(-128));
3597
+ for (const key in jn) {
3598
+ if (!Object.prototype.hasOwnProperty.call(jn, key)) continue;
3599
+ if (budget.left <= 0) {
3600
+ truncated = true;
3601
+ break;
3602
+ }
3603
+ budget.left -= 1 + key.length;
3604
+ let value = jn[key];
3605
+ let shown;
3606
+ if ((is_secret_name(key.slice(-128)) || value_is_secret && key === "value") && value !== void 0 && value !== null && value !== "") shown = "********";
3607
+ else shown = _json_mask_secrets(value, memo, depth + 1, budget);
3608
+ if (shown !== value) changed = true;
3609
+ result[key] = shown;
3610
+ }
3611
+ if (truncated) result["<more>"] = MASK_TOO_LARGE;
3612
+ }
3613
+ if (!changed && !truncated) result = jn;
3614
+ memo.set(jn, result);
3615
+ return result;
3616
+ }
3617
+ function json_mask_secrets(jn) {
3618
+ try {
3619
+ return _json_mask_secrets(jn, /* @__PURE__ */ new WeakMap(), 0, { left: MASK_MAX_BYTES });
3620
+ } catch (e) {
3621
+ return MASK_FAILED;
3622
+ }
3623
+ }
3624
+ /************************************************************
3625
+ * trace_json() of a json that can hold a credential: what
3626
+ * json_mask_secrets() masks is shown masked
3627
+ ************************************************************/
3628
+ function trace_json_masked(jn, msg) {
3629
+ trace_json(json_mask_secrets(jn), msg);
3630
+ }
3631
+ /************************************************************
3224
3632
  * Duplicate an object (new references)
3225
3633
  * using the modern structuredClone (Deep copy of a single object)
3226
3634
  ************************************************************/
@@ -3493,6 +3901,8 @@ function cmp_two_simple_json(jn_var1, jn_var2) {
3493
3901
  if (is_number(jn_var1) || is_number(jn_var2)) {
3494
3902
  let val1 = Number(jn_var1);
3495
3903
  let val2 = Number(jn_var2);
3904
+ if (Number.isNaN(val1)) val1 = 0;
3905
+ if (Number.isNaN(val2)) val2 = 0;
3496
3906
  if (val1 > val2) return 1;
3497
3907
  else if (val1 < val2) return -1;
3498
3908
  else return 0;
@@ -3522,8 +3932,8 @@ function strstr(haystack, needle, bool) {
3522
3932
  ***************************************************************************/
3523
3933
  function is_metadata_key(key) {
3524
3934
  if (!is_string(key)) return false;
3525
- let i;
3526
- for (i = 0; i < key.length; i++) {
3935
+ let i = 0;
3936
+ for (; i < key.length; i++) {
3527
3937
  if (key[i] !== "_") break;
3528
3938
  if (i > 2) break;
3529
3939
  }
@@ -3534,8 +3944,8 @@ function is_metadata_key(key) {
3534
3944
  ***************************************************************************/
3535
3945
  function is_private_key(key) {
3536
3946
  if (!is_string(key)) return false;
3537
- let i;
3538
- for (i = 0; i < key.length; i++) {
3947
+ let i = 0;
3948
+ for (; i < key.length; i++) {
3539
3949
  if (key[i] !== "_") break;
3540
3950
  if (i > 2) break;
3541
3951
  }
@@ -3560,6 +3970,28 @@ function kw_has_key(kw, key) {
3560
3970
  return false;
3561
3971
  }
3562
3972
  /************************************************************
3973
+ * A key that reaches the prototype chain instead of the data:
3974
+ * "__proto__", "constructor" or "prototype" when the object
3975
+ * does not hold it as its OWN key. A walk through one of them
3976
+ * read, or WROTE, Object.prototype: the flat id
3977
+ * "__proto__`polluted" set a key on every object of the page.
3978
+ * In C they are keys like any other, so here too: read them
3979
+ * only as own keys, and write "__proto__" as an own key.
3980
+ ************************************************************/
3981
+ function is_prototype_segment(obj, key) {
3982
+ if (key === "__proto__" || key === "constructor" || key === "prototype") return !Object.prototype.hasOwnProperty.call(obj, key);
3983
+ return false;
3984
+ }
3985
+ function set_own_key(obj, key, value) {
3986
+ if (key === "__proto__") Object.defineProperty(obj, key, {
3987
+ value,
3988
+ writable: true,
3989
+ enumerable: true,
3990
+ configurable: true
3991
+ });
3992
+ else obj[key] = value;
3993
+ }
3994
+ /************************************************************
3563
3995
  * The value at `path` (keys joined by a backtick), as the C
3564
3996
  * kw_find_path() finds it: undefined when it is not there.
3565
3997
  * A kw that is not a dict or a list is LOGGED ("kw must be list
@@ -3586,7 +4018,12 @@ function kw_find_path(gobj, kw, path, verbose) {
3586
4018
  }
3587
4019
  let ss = path.split("`");
3588
4020
  let len = ss.length;
3589
- for (let i = 0; i < len - 1; i++) {
4021
+ for (let i = 0; i < len; i++) {
4022
+ if (is_prototype_segment(kw, ss[i])) {
4023
+ if (verbose) log_error(`${prefix}path not found: '${path}'`);
4024
+ return;
4025
+ }
4026
+ if (i === len - 1) break;
3590
4027
  kw = kw[ss[i]];
3591
4028
  if (kw === void 0 || kw === null) {
3592
4029
  if (verbose) log_error(`${prefix}path not found: '${path}'`);
@@ -3646,7 +4083,7 @@ function kw_get_bool(gobj, kw, path, default_value, flag) {
3646
4083
  return v;
3647
4084
  } else if (required) {
3648
4085
  log_error(`path not found: '${path}'`);
3649
- trace_json(kw);
4086
+ trace_json_masked(kw);
3650
4087
  }
3651
4088
  return Boolean(default_value);
3652
4089
  }
@@ -3660,11 +4097,11 @@ function kw_get_bool(gobj, kw, path, default_value, flag) {
3660
4097
  } else if (wild && b === null) value = false;
3661
4098
  else if (wild) {
3662
4099
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a simple json element: '${path}'`);
3663
- trace_json(kw);
4100
+ trace_json_masked(kw);
3664
4101
  return false;
3665
4102
  } else {
3666
4103
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json boolean: '${path}'`);
3667
- trace_json(kw);
4104
+ trace_json_masked(kw);
3668
4105
  return Boolean(default_value);
3669
4106
  }
3670
4107
  if (extract) kw_delete(gobj, kw, path);
@@ -3714,7 +4151,7 @@ function kw_get_int(gobj, kw, path, default_value, flag) {
3714
4151
  return v;
3715
4152
  } else if (required) {
3716
4153
  log_error(`path not found: '${path}'`);
3717
- trace_json(kw);
4154
+ trace_json_masked(kw);
3718
4155
  }
3719
4156
  return parseInt(default_value);
3720
4157
  }
@@ -3722,14 +4159,14 @@ function kw_get_int(gobj, kw, path, default_value, flag) {
3722
4159
  if (is_number(v)) value = Math.trunc(v);
3723
4160
  else if (!wild) {
3724
4161
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json integer: '${path}'`);
3725
- trace_json(kw);
4162
+ trace_json_masked(kw);
3726
4163
  return parseInt(default_value);
3727
4164
  } else if (is_boolean(v)) value = v ? 1 : 0;
3728
4165
  else if (is_string(v)) value = strtoll_base0(v);
3729
4166
  else if (v === null) value = 0;
3730
4167
  else {
3731
4168
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a simple json element: '${path}'`);
3732
- trace_json(kw);
4169
+ trace_json_masked(kw);
3733
4170
  return 0;
3734
4171
  }
3735
4172
  if (extract) kw_delete(gobj, kw, path);
@@ -3761,7 +4198,7 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3761
4198
  return v;
3762
4199
  } else if (required) {
3763
4200
  log_error(`path not found: '${path}'`);
3764
- trace_json(kw);
4201
+ trace_json_masked(kw);
3765
4202
  }
3766
4203
  return Number(default_value);
3767
4204
  }
@@ -3769,7 +4206,7 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3769
4206
  if (is_number(v)) value = v;
3770
4207
  else if (!wild) {
3771
4208
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json real: '${path}'`);
3772
- trace_json(kw);
4209
+ trace_json_masked(kw);
3773
4210
  return Number(default_value);
3774
4211
  } else if (is_boolean(v)) value = v ? 1 : 0;
3775
4212
  else if (is_string(v)) {
@@ -3778,7 +4215,7 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3778
4215
  } else if (v === null) value = 0;
3779
4216
  else {
3780
4217
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a simple json element: '${path}'`);
3781
- trace_json(kw);
4218
+ trace_json_masked(kw);
3782
4219
  return 0;
3783
4220
  }
3784
4221
  if (extract) kw_delete(gobj, kw, path);
@@ -3830,14 +4267,14 @@ function kw_get_str(gobj, kw, path, default_value, flag) {
3830
4267
  return default_value;
3831
4268
  } else if (required && !kw_path_holds_key(kw, path)) {
3832
4269
  log_error(`path not found: '${path}'`);
3833
- trace_json(kw);
4270
+ trace_json_masked(kw);
3834
4271
  }
3835
4272
  return default_value;
3836
4273
  }
3837
4274
  if (!is_string(v)) {
3838
4275
  if (v !== null) {
3839
4276
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json str: '${path}'`);
3840
- trace_json(kw);
4277
+ trace_json_masked(kw);
3841
4278
  }
3842
4279
  return default_value;
3843
4280
  }
@@ -3860,7 +4297,7 @@ function kw_get_pointer(gobj, kw, path, default_value, flag) {
3860
4297
  return v;
3861
4298
  } else if (required) {
3862
4299
  log_error(`path not found: '${path}'`);
3863
- trace_json(kw);
4300
+ trace_json_masked(kw);
3864
4301
  }
3865
4302
  return default_value;
3866
4303
  }
@@ -3887,14 +4324,14 @@ function kw_get_dict(gobj, kw, path, default_value, flag) {
3887
4324
  }
3888
4325
  if (required) {
3889
4326
  log_error(`path not found: '${path}'`);
3890
- trace_json(kw);
4327
+ trace_json_masked(kw);
3891
4328
  }
3892
4329
  return default_value;
3893
4330
  }
3894
4331
  if (!is_object(v)) {
3895
4332
  if (required) {
3896
4333
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json dict: '${path}'`);
3897
- trace_json(kw);
4334
+ trace_json_masked(kw);
3898
4335
  }
3899
4336
  return default_value;
3900
4337
  }
@@ -3917,7 +4354,7 @@ function kw_get_dict_value(gobj, kw, path, default_value, flag) {
3917
4354
  return v;
3918
4355
  } else if (required) {
3919
4356
  log_error(`path not found: '${path}'`);
3920
- trace_json(kw);
4357
+ trace_json_masked(kw);
3921
4358
  }
3922
4359
  return default_value;
3923
4360
  }
@@ -3945,14 +4382,14 @@ function kw_get_list(gobj, kw, path, default_value, flag) {
3945
4382
  }
3946
4383
  if (required) {
3947
4384
  log_error(`path not found: '${path}'`);
3948
- trace_json(kw);
4385
+ trace_json_masked(kw);
3949
4386
  }
3950
4387
  return default_value;
3951
4388
  }
3952
4389
  if (!is_array(v)) {
3953
4390
  if (required) {
3954
4391
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json list: '${path}'`);
3955
- trace_json(kw);
4392
+ trace_json_masked(kw);
3956
4393
  }
3957
4394
  return default_value;
3958
4395
  }
@@ -3969,17 +4406,13 @@ function kw_set_dict_value(gobj, kw, path, value) {
3969
4406
  return -1;
3970
4407
  }
3971
4408
  let ss = path.split("`");
3972
- if (ss.length <= 1) {
3973
- kw[path] = value;
3974
- return 0;
3975
- }
3976
4409
  let len = ss.length;
3977
4410
  for (let i = 0; i < len; i++) {
3978
4411
  let key = ss[i];
3979
- if (i === len - 1) kw[key] = value;
4412
+ if (i === len - 1) set_own_key(kw, key, value);
3980
4413
  else {
3981
- let seg = kw[key];
3982
- if (seg === void 0) kw[key] = {};
4414
+ let seg = is_prototype_segment(kw, key) ? void 0 : kw[key];
4415
+ if (seg === void 0) set_own_key(kw, key, {});
3983
4416
  else if (!is_object(seg) && !is_array(seg)) {
3984
4417
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}kw_set_dict_value(): segment '${key}' is not a dict or a list: '${path}'`);
3985
4418
  return -1;
@@ -4034,9 +4467,9 @@ function _kw_match_simple(kw, jn_filter, prefix_path) {
4034
4467
  if (!matched) break;
4035
4468
  continue;
4036
4469
  }
4037
- let jn_record_value = kw_get_dict_value(0, kw, path, 0, 0);
4038
- if (!jn_record_value) jn_record_value = json_object_get(kw, path);
4039
- if (!jn_record_value) {
4470
+ let jn_record_value = kw_get_dict_value(0, kw, path, void 0, 0);
4471
+ if (jn_record_value === void 0) jn_record_value = json_object_get(kw, path);
4472
+ if (jn_record_value === void 0) {
4040
4473
  matched = false;
4041
4474
  break;
4042
4475
  }
@@ -4155,10 +4588,11 @@ If paths are empty return empty
4155
4588
  ***************************************************************************/
4156
4589
  function kw_clone_by_not_keys(gobj, kw, keys, verbose) {
4157
4590
  let kw_clone = {};
4591
+ if (!is_object(kw)) return kw_clone;
4158
4592
  json_object_update(kw_clone, kw);
4159
4593
  if (is_string(keys) && !empty_string(keys)) {
4160
4594
  let key = keys;
4161
- if (kw_get_dict_value(gobj, kw, key, 0, 0)) json_object_del(kw_clone, key);
4595
+ if (kw.hasOwnProperty(key)) json_object_del(kw_clone, key);
4162
4596
  else if (verbose) log_error(`${gobj_short_name(gobj)}: key not found: ${key}`);
4163
4597
  } else if (is_object(keys) && json_object_size(keys) > 0) {
4164
4598
  for (let key of Object.keys(keys)) if (kw.hasOwnProperty(key)) json_object_del(kw_clone, key);
@@ -5118,9 +5552,15 @@ parent: document.body
5118
5552
  * will be 'data-i18n' attr
5119
5553
  *
5120
5554
  * content -> string | [createElement2() or parameters of createElement2]
5555
+ * | HTMLElement | SVGElement | Text
5121
5556
  * if string begins with '<' then
5122
5557
  * it will be converted to HTMLElement
5123
5558
  * content = createOneHtml(string)
5559
+ * ⚠️ So a string is MARKUP when it starts with '<': never
5560
+ * pass DATA (a value from a backend, a name a user typed)
5561
+ * as a bare string, or "<img src=x onerror=...>" runs.
5562
+ * Pass it as a Text node, which is always text:
5563
+ * ['span', {}, document.createTextNode(value)]
5124
5564
  * if attrs['i18n'] is not empty then (or 'data-i18n' or 'data_i18next')
5125
5565
  * it will be overridden with the translation
5126
5566
  * content = translate(attrs['i18n']));
@@ -5559,7 +5999,7 @@ function flat2json(flat) {
5559
5999
  current[seg] = flat[key];
5560
6000
  } else {
5561
6001
  if (Object.prototype.hasOwnProperty.call(current, seg)) throw new Error(`flat2json: '${key}' is written twice, or once as a value and once as a container`);
5562
- current[seg] = flat[key];
6002
+ set_own_key(current, seg, flat[key]);
5563
6003
  }
5564
6004
  break;
5565
6005
  }
@@ -5572,10 +6012,10 @@ function flat2json(flat) {
5572
6012
  current[seg] = child;
5573
6013
  }
5574
6014
  } else {
5575
- child = current[seg];
6015
+ child = is_prototype_segment(current, seg) ? void 0 : current[seg];
5576
6016
  if (child === void 0) {
5577
6017
  child = next_is_index ? [] : {};
5578
- current[seg] = child;
6018
+ set_own_key(current, seg, child);
5579
6019
  }
5580
6020
  }
5581
6021
  if (child === null || typeof child !== "object") throw new Error(`flat2json: '${key}' walks through a value: the same id is a leaf and a container at once`);
@@ -6338,6 +6778,7 @@ function mt_stop$1(gobj) {
6338
6778
  ***************************************************************/
6339
6779
  function mt_play(gobj) {
6340
6780
  let default_service = gobj_default_service();
6781
+ if (!default_service) return 0;
6341
6782
  if (!gobj_is_running(default_service)) gobj_start(default_service);
6342
6783
  if (!gobj_is_playing(default_service)) gobj_play(default_service);
6343
6784
  return 0;
@@ -6346,7 +6787,8 @@ function mt_play(gobj) {
6346
6787
  * Framework Method: Pause
6347
6788
  ***************************************************************/
6348
6789
  function mt_pause(gobj) {
6349
- gobj_pause(gobj_default_service());
6790
+ let default_service = gobj_default_service();
6791
+ if (default_service && gobj_is_playing(default_service)) gobj_pause(default_service);
6350
6792
  return 0;
6351
6793
  }
6352
6794
  /***************************************************************
@@ -6602,6 +7044,7 @@ var __gclass__ = null;
6602
7044
  function mt_create(gobj) {
6603
7045
  let priv = gobj.priv;
6604
7046
  priv.gobj_timer = gobj_create_pure_child(gobj_name(gobj), "C_TIMER", {}, gobj);
7047
+ priv.ws_seq = 0;
6605
7048
  priv.url = gobj_read_str_attr(gobj, "url");
6606
7049
  priv.remote_yuno_name = gobj_read_str_attr(gobj, "remote_yuno_name");
6607
7050
  priv.remote_yuno_role = gobj_read_str_attr(gobj, "remote_yuno_role");
@@ -6636,6 +7079,16 @@ function mt_writing(gobj, path) {
6636
7079
  function mt_start(gobj) {
6637
7080
  let priv = gobj.priv;
6638
7081
  priv.retry_ms = 0;
7082
+ if (gobj_current_state(gobj) !== "ST_DISCONNECTED") {
7083
+ gobj_send_event(gobj, "EV_ON_CLOSE", {
7084
+ url: priv.url,
7085
+ ws_seq: priv.ws_seq,
7086
+ code: 1e3,
7087
+ reason: "restarted",
7088
+ was_clean: true
7089
+ }, gobj);
7090
+ clear_timeout(priv.gobj_timer);
7091
+ }
6639
7092
  priv.websocket = setup_websocket(gobj);
6640
7093
  return 0;
6641
7094
  }
@@ -6770,10 +7223,16 @@ function setup_websocket(gobj) {
6770
7223
  log_error(`${gobj_short_name(gobj)}: Failed to initialize WebSocket.`);
6771
7224
  return null;
6772
7225
  }
7226
+ const ws_seq = ++gobj.priv.ws_seq;
6773
7227
  websocket.onopen = () => {
6774
- gobj_send_event(gobj, "EV_ON_OPEN", { url }, gobj);
7228
+ if (ws_seq !== gobj.priv.ws_seq || gobj_is_destroying(gobj)) return;
7229
+ gobj_send_event(gobj, "EV_ON_OPEN", {
7230
+ url,
7231
+ ws_seq
7232
+ }, gobj);
6775
7233
  };
6776
7234
  websocket.onmessage = (e) => {
7235
+ if (ws_seq !== gobj.priv.ws_seq || gobj_is_destroying(gobj)) return;
6777
7236
  gobj_send_event(gobj, "EV_ON_MESSAGE", {
6778
7237
  url,
6779
7238
  data: e.data
@@ -6781,9 +7240,13 @@ function setup_websocket(gobj) {
6781
7240
  };
6782
7241
  websocket.onclose = (e) => {
6783
7242
  if (gobj_is_destroying(gobj)) return;
7243
+ if (ws_seq !== gobj.priv.ws_seq) return;
6784
7244
  if (!gobj_read_bool_attr(gobj_yuno(), "browser_beforeunload")) gobj_send_event(gobj, "EV_ON_CLOSE", {
6785
7245
  url,
6786
- e
7246
+ ws_seq,
7247
+ code: e.code,
7248
+ reason: e.reason,
7249
+ was_clean: e.wasClean
6787
7250
  }, gobj);
6788
7251
  else log_warning("Close websocket by unload page");
6789
7252
  };
@@ -6804,7 +7267,7 @@ function close_websocket(gobj, code = 1e3, reason = "") {
6804
7267
  try {
6805
7268
  websocket.close(code, reason);
6806
7269
  } catch (e) {
6807
- log_error("Error closing WebSocket:", e.message);
7270
+ log_error(`${gobj_short_name(gobj)}: Error closing WebSocket: ${e.message}`);
6808
7271
  }
6809
7272
  }
6810
7273
  /***************************************************************
@@ -6814,7 +7277,7 @@ function trace_inter_event(gobj, prefix, iev) {
6814
7277
  let hora = current_timestamp();
6815
7278
  try {
6816
7279
  log_debug("\n" + hora + " " + prefix + "\n");
6817
- trace_json(iev);
7280
+ trace_json_masked(iev);
6818
7281
  } catch (e) {
6819
7282
  log_debug("ERROR in trace_inter_event: " + e);
6820
7283
  }
@@ -6930,29 +7393,29 @@ function iev_create_from_json(gobj, data) {
6930
7393
  try {
6931
7394
  x = JSON.parse(data);
6932
7395
  } catch (e) {
6933
- log_error("parsing inter_event json: " + e);
7396
+ log_warning(`${gobj_short_name(gobj)}: parsing inter_event json: ${e}`);
6934
7397
  return null;
6935
7398
  }
6936
7399
  if (!(x instanceof Object)) {
6937
- log_error("parsing inter_event: websocket data not a json object");
7400
+ log_warning(`${gobj_short_name(gobj)}: parsing inter_event: websocket data not a json object`);
6938
7401
  return null;
6939
7402
  }
6940
7403
  let event = x["event"];
6941
7404
  if (!event) {
6942
- log_error("parsing inter_event: no event");
7405
+ log_warning(`${gobj_short_name(gobj)}: parsing inter_event: no event`);
6943
7406
  return null;
6944
7407
  }
6945
7408
  if (typeof event !== "string") {
6946
- log_error("parsing inter_event: event not a string");
7409
+ log_warning(`${gobj_short_name(gobj)}: parsing inter_event: event not a string`);
6947
7410
  return null;
6948
7411
  }
6949
7412
  let kw = x["kw"];
6950
7413
  if (!kw) {
6951
- log_error("parsing inter_kw: no kw");
7414
+ log_warning(`${gobj_short_name(gobj)}: parsing inter_kw: no kw`);
6952
7415
  return null;
6953
7416
  }
6954
7417
  if (!(kw instanceof Object)) {
6955
- log_error("parsing inter_event: kw not a json object");
7418
+ log_warning(`${gobj_short_name(gobj)}: parsing inter_event: kw not a json object`);
6956
7419
  return null;
6957
7420
  }
6958
7421
  return {
@@ -7012,10 +7475,9 @@ function ac_on_open(gobj, event, kw, src) {
7012
7475
  ***************************************************************/
7013
7476
  function ac_on_close(gobj, event, kw, src) {
7014
7477
  let priv = gobj.priv;
7015
- let e = kw.e;
7016
7478
  let url = kw.url;
7017
7479
  set_remote_log_functions();
7018
- log_warning(`${gobj_short_name(gobj)}: WebSocket closed ${url} (Code: ${e.code}, Reason: "${e.reason}", Clean: ${e.wasClean})`);
7480
+ log_warning(`${gobj_short_name(gobj)}: WebSocket closed ${url} (Code: ${kw.code}, Reason: "${kw.reason}", Clean: ${kw.was_clean})`);
7019
7481
  if (priv.websocket) {
7020
7482
  priv.websocket.onopen = null;
7021
7483
  priv.websocket.onmessage = null;
@@ -7032,15 +7494,15 @@ function ac_on_close(gobj, event, kw, src) {
7032
7494
  remote_yuno_service: priv.remote_yuno_service
7033
7495
  });
7034
7496
  } else {
7035
- log_warning(`${gobj_short_name(gobj)}: EV_ON_OPEN_ERROR cannot open ${url} (Code: ${e.code}, Reason: "${e.reason}", Clean: ${e.wasClean})`);
7497
+ log_warning(`${gobj_short_name(gobj)}: EV_ON_OPEN_ERROR cannot open ${url} (Code: ${kw.code}, Reason: "${kw.reason}", Clean: ${kw.was_clean})`);
7036
7498
  gobj_publish_event(gobj, "EV_ON_OPEN_ERROR", {
7037
7499
  url,
7038
7500
  remote_yuno_name: priv.remote_yuno_name,
7039
7501
  remote_yuno_role: priv.remote_yuno_role,
7040
7502
  remote_yuno_service: priv.remote_yuno_service,
7041
- code: e.code,
7042
- reason: e.reason,
7043
- was_clean: e.wasClean
7503
+ code: kw.code,
7504
+ reason: kw.reason,
7505
+ was_clean: kw.was_clean
7044
7506
  });
7045
7507
  }
7046
7508
  if (gobj_is_running(gobj)) set_timeout(priv.gobj_timer, next_retry(gobj));
@@ -7138,6 +7600,10 @@ function ac_identity_card_ack(gobj, event, kw, src) {
7138
7600
  function ac_on_message(gobj, event, kw, src) {
7139
7601
  let url = gobj.priv.url;
7140
7602
  let iev_msg = iev_create_from_json(gobj, kw.data);
7603
+ if (!iev_msg) {
7604
+ log_warning(`${gobj_short_name(gobj)}: frame dropped from ${url}: ${String(kw.data).substring(0, 256)}`);
7605
+ return -1;
7606
+ }
7141
7607
  if (is_traffic_tracing(gobj)) {
7142
7608
  let prefix = gobj_name(gobj_yuno()) + " <== " + url;
7143
7609
  let size = kw.data.length;
@@ -7163,8 +7629,14 @@ function ac_on_message(gobj, event, kw, src) {
7163
7629
  return 0;
7164
7630
  }
7165
7631
  let iev_dst_service = kw_get_str(gobj, event_id, "dst_service", "");
7166
- if (msg_type === "__subscribing__") return -1;
7167
- if (msg_type === "__unsubscribing__") return -1;
7632
+ if (msg_type === "__subscribing__") {
7633
+ log_warning(`${gobj_short_name(gobj)}: subscription event ignored, I'm client (service: ${iev_dst_service}, event: ${iev_event})`);
7634
+ return -1;
7635
+ }
7636
+ if (msg_type === "__unsubscribing__") {
7637
+ log_warning(`${gobj_short_name(gobj)}: unsubscription event ignored, I'm client (service: ${iev_dst_service}, event: ${iev_event})`);
7638
+ return -1;
7639
+ }
7168
7640
  if (gobj_has_event(gobj, iev_event, event_flag_t.EVF_PUBLIC_EVENT)) {
7169
7641
  gobj_send_event(gobj, iev_event, iev_kw, gobj);
7170
7642
  return 0;
@@ -7322,6 +7794,6 @@ function register_c_ievent_cli() {
7322
7794
  return create_gclass(GCLASS_NAME);
7323
7795
  }
7324
7796
  //#endregion
7325
- export { GObj, SDATA, SDATAAUTHZ, SDATACM, SDATACM2, SDATADF, SDATAPM, SDATAPM0, SDATA_END, SDataDesc, YUNETA_VERSION, __yuno__, build_command_response, build_path, build_stats_response, clean_name, clear_timeout, cmp_two_simple_json, command_parser, createElement2, createOneHtml, create_json_record, create_template_record, current_timestamp, data_type_t, db_list_persistent_attrs, db_load_persistent_attrs, db_remove_persistent_attrs, db_save_persistent_attrs, debounce, delete_from_list, duplicate_objects, empty_json, empty_string, escapeHtml, event_flag_t, flat2json, flat_apply, flat_diff, flat_key_join, flat_key_split, gclass_add_ev_action, gclass_add_event_type, gclass_add_state, gclass_check_fsm, gclass_create, gclass_event_type, gclass_find_by_name, gclass_flag_t, gclass_unregister, getPositionRelativeToBody, get_function_name, get_now, gobj_bottom_gobj, gobj_change_parent, gobj_change_state, gobj_command, gobj_create, gobj_create2, gobj_create_default_service, gobj_create_pure_child, gobj_create_service, gobj_create_volatil, gobj_create_yuno, gobj_current_state, gobj_default_service, gobj_deliver_posted_events, gobj_destroy, gobj_find_child, gobj_find_gobj, gobj_find_service, gobj_find_subscribings, gobj_find_subscriptions, gobj_flag_t, gobj_full_name, gobj_gclass_name, gobj_get_gclass_trace_level, gobj_get_gclass_trace_level2, gobj_get_gclass_trace_no_level, gobj_get_global_trace_level, gobj_get_global_trace_no_level, gobj_global_trace_level, gobj_global_trace_no_level, gobj_has_attr, gobj_has_event, gobj_has_output_event, gobj_hsdata, gobj_is_destroying, gobj_is_playing, gobj_is_pure_child, gobj_is_running, gobj_is_service, gobj_is_volatil, gobj_list_persistent_attrs, gobj_list_subscriptions, gobj_load_persistent_attrs, gobj_match_children, gobj_match_children_tree, gobj_match_gobj, gobj_name, gobj_parent, gobj_pause, gobj_play, gobj_post_event, gobj_posted_events_size, gobj_publish_event, gobj_read_attr, gobj_read_attrs, gobj_read_bool_attr, gobj_read_integer_attr, gobj_read_pointer_attr, gobj_read_str_attr, gobj_remove_persistent_attrs, gobj_repr_global_trace_levels, gobj_reset_volatil_attrs, gobj_save_persistent_attrs, gobj_search_path, gobj_send_event, gobj_services, gobj_set_bottom_gobj, gobj_set_deep_trace, gobj_set_gclass_no_trace, gobj_set_gclass_trace, gobj_set_global_no_trace, gobj_set_global_no_trace2, gobj_set_global_trace, gobj_set_global_trace2, gobj_set_gobj_no_trace, gobj_set_gobj_trace, gobj_set_trace_machine_format, gobj_short_name, gobj_start, gobj_start_children, gobj_start_tree, gobj_start_up, gobj_stats, gobj_stop, gobj_stop_children, gobj_stop_tree, gobj_subscribe_event, gobj_trace_level, gobj_trace_machine_format, gobj_trace_no_level, gobj_unsubscribe_event, gobj_unsubscribe_list, gobj_walk_gobj_children, gobj_walk_gobj_children_tree, gobj_write_attr, gobj_write_attrs, gobj_write_bool_attr, gobj_write_integer_attr, gobj_write_str_attr, gobj_yuno, gobj_yuno_id, gobj_yuno_name, gobj_yuno_role, id_index_in_obj_list, index_in_list, is_array, is_boolean, is_date, is_function, is_gobj, is_metadata_key, is_null, is_number, is_object, is_private_key, is_pure_number, is_string, jdb_delete, jdb_get, jdb_get_by_idx, jdb_get_topic, jdb_init, jdb_update, json2flat, json_array_append, json_array_append_new, json_array_extend, json_array_remove, json_array_size, json_deep_copy, json_is_identical, json_object_del, json_object_get, json_object_set, json_object_set_new, json_object_size, json_object_update, json_object_update_existing, json_object_update_missing, json_size, jwt2json, jwtDecode, kw_clone_by_keys, kw_clone_by_not_keys, kw_collect, kw_delete, kw_find_json_in_list, kw_find_path, kw_flag_t, kw_get_bool, kw_get_dict, kw_get_dict_value, kw_get_int, kw_get_list, kw_get_local_storage_value, kw_get_pointer, kw_get_real, kw_get_str, kw_has_key, kw_match_simple, kw_pop, kw_remove_local_storage_value, kw_select, kw_set_dict_value, kw_set_local_storage_value, kw_set_subdict_value, kwid_collect, kwid_find_one_record, kwid_get_ids, kwid_match_id, kwid_new_dict, kwid_new_list, list2options, load_json_file, log_debug, log_error, log_info, log_warning, msg_iev_get_msg_type, msg_iev_get_stack, msg_iev_push_stack, msg_iev_read_key, msg_iev_set_msg_type, msg_iev_write_key, node_uuid, parseBoolean, parseSVG, refresh_language, register_c_ievent_cli, register_c_timer, register_c_yuno, safeSrc, sdata_flag_t, send_http_json_post, set_console_log_enabled, set_console_log_filter, set_log_callback, set_remote_log_functions, set_timeout, set_timeout_periodic, sprintf, stats_parser, str_in_list, strcasecmp, strcmp, strncmp, strs_in_list, strstr, template_get_field_desc, timeTracker, trace_json, trace_level_t, trace_msg, treedb_decoder_fkey, treedb_decoder_hook, treedb_encoder_fkey, treedb_get_field_desc, treedb_hook_data_size, vsprintf, walk_type_t };
7797
+ export { GObj, SDATA, SDATAAUTHZ, SDATACM, SDATACM2, SDATADF, SDATAPM, SDATAPM0, SDATA_END, SDataDesc, YUNETA_VERSION, __yuno__, build_command_response, build_path, build_stats_response, clean_name, clear_timeout, cmp_two_simple_json, command_parser, createElement2, createOneHtml, create_json_record, create_template_record, current_timestamp, data_type_t, db_list_persistent_attrs, db_load_persistent_attrs, db_remove_persistent_attrs, db_save_persistent_attrs, debounce, delete_from_list, duplicate_objects, empty_json, empty_string, escapeHtml, event_flag_t, flat2json, flat_apply, flat_diff, flat_key_join, flat_key_split, gclass_add_ev_action, gclass_add_event_type, gclass_add_state, gclass_check_fsm, gclass_create, gclass_event_type, gclass_find_by_name, gclass_flag_t, gclass_unregister, getPositionRelativeToBody, get_function_name, get_now, gobj_bottom_gobj, gobj_change_parent, gobj_change_state, gobj_command, gobj_create, gobj_create2, gobj_create_default_service, gobj_create_pure_child, gobj_create_service, gobj_create_volatil, gobj_create_yuno, gobj_current_state, gobj_default_service, gobj_deliver_posted_events, gobj_destroy, gobj_find_child, gobj_find_gobj, gobj_find_service, gobj_find_subscribings, gobj_find_subscriptions, gobj_flag_t, gobj_full_name, gobj_gclass_name, gobj_get_gclass_trace_level, gobj_get_gclass_trace_level2, gobj_get_gclass_trace_no_level, gobj_get_global_trace_level, gobj_get_global_trace_no_level, gobj_global_trace_level, gobj_global_trace_no_level, gobj_has_attr, gobj_has_event, gobj_has_output_event, gobj_hsdata, gobj_is_destroying, gobj_is_playing, gobj_is_pure_child, gobj_is_running, gobj_is_service, gobj_is_volatil, gobj_list_persistent_attrs, gobj_list_subscriptions, gobj_load_persistent_attrs, gobj_match_children, gobj_match_children_tree, gobj_match_gobj, gobj_name, gobj_parent, gobj_pause, gobj_play, gobj_post_event, gobj_posted_events_size, gobj_publish_event, gobj_read_attr, gobj_read_attrs, gobj_read_bool_attr, gobj_read_integer_attr, gobj_read_pointer_attr, gobj_read_str_attr, gobj_remove_persistent_attrs, gobj_repr_global_trace_levels, gobj_reset_volatil_attrs, gobj_save_persistent_attrs, gobj_search_path, gobj_send_event, gobj_services, gobj_set_bottom_gobj, gobj_set_deep_trace, gobj_set_gclass_no_trace, gobj_set_gclass_trace, gobj_set_global_no_trace, gobj_set_global_no_trace2, gobj_set_global_trace, gobj_set_global_trace2, gobj_set_gobj_no_trace, gobj_set_gobj_trace, gobj_set_trace_machine_format, gobj_short_name, gobj_start, gobj_start_children, gobj_start_tree, gobj_start_up, gobj_stats, gobj_stop, gobj_stop_children, gobj_stop_tree, gobj_subscribe_event, gobj_trace_level, gobj_trace_machine_format, gobj_trace_no_level, gobj_unsubscribe_event, gobj_unsubscribe_list, gobj_walk_gobj_children, gobj_walk_gobj_children_tree, gobj_write_attr, gobj_write_attrs, gobj_write_bool_attr, gobj_write_integer_attr, gobj_write_str_attr, gobj_yuno, gobj_yuno_id, gobj_yuno_name, gobj_yuno_role, id_index_in_obj_list, index_in_list, is_array, is_boolean, is_date, is_function, is_gobj, is_metadata_key, is_null, is_number, is_object, is_private_key, is_pure_number, is_secret_name, is_string, jdb_delete, jdb_get, jdb_get_by_idx, jdb_get_topic, jdb_init, jdb_update, json2flat, json_array_append, json_array_append_new, json_array_extend, json_array_remove, json_array_size, json_deep_copy, json_is_identical, json_mask_secrets, json_object_del, json_object_get, json_object_set, json_object_set_new, json_object_size, json_object_update, json_object_update_existing, json_object_update_missing, json_size, jwt2json, jwtDecode, kw_clone_by_keys, kw_clone_by_not_keys, kw_collect, kw_delete, kw_find_json_in_list, kw_find_path, kw_flag_t, kw_get_bool, kw_get_dict, kw_get_dict_value, kw_get_int, kw_get_list, kw_get_local_storage_value, kw_get_pointer, kw_get_real, kw_get_str, kw_has_key, kw_match_simple, kw_pop, kw_remove_local_storage_value, kw_select, kw_set_dict_value, kw_set_local_storage_value, kw_set_subdict_value, kwid_collect, kwid_find_one_record, kwid_get_ids, kwid_match_id, kwid_new_dict, kwid_new_list, list2options, load_json_file, log_debug, log_error, log_info, log_warning, mask_secrets_inline, msg_iev_get_msg_type, msg_iev_get_stack, msg_iev_push_stack, msg_iev_read_key, msg_iev_set_msg_type, msg_iev_write_key, node_uuid, parseBoolean, parseSVG, refresh_language, register_c_ievent_cli, register_c_timer, register_c_yuno, safeSrc, sdata_flag_t, send_http_json_post, set_console_log_enabled, set_console_log_filter, set_log_callback, set_remote_log_functions, set_timeout, set_timeout_periodic, sprintf, stats_parser, str_in_list, strcasecmp, strcmp, strncmp, strs_in_list, strstr, template_get_field_desc, timeTracker, trace_json, trace_json_masked, trace_level_t, trace_msg, treedb_decoder_fkey, treedb_decoder_hook, treedb_encoder_fkey, treedb_get_field_desc, treedb_hook_data_size, vsprintf, walk_type_t };
7326
7798
 
7327
7799
  //# sourceMappingURL=gobj-js.es.js.map