@yuneta/gobj-js 7.7.3 → 7.8.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.
@@ -2633,6 +2633,10 @@
2633
2633
  function set_log_callback(fn) {
2634
2634
  __log_callback__ = typeof fn === "function" ? fn : null;
2635
2635
  }
2636
+ var __console_output_enabled__ = true;
2637
+ function set_console_log_enabled(enabled) {
2638
+ __console_output_enabled__ = enabled ? true : false;
2639
+ }
2636
2640
  var __in_log_callback__ = false;
2637
2641
  function emit_log_callback(level, msg, hora) {
2638
2642
  if (__log_callback__ && !__in_log_callback__) {
@@ -2678,9 +2682,10 @@
2678
2682
  function log_error(format) {
2679
2683
  let msg = format_log(format);
2680
2684
  let hora = current_timestamp();
2681
- if (f_error) if (f_error === window.console.error) f_error("%c" + hora + " ERROR: " + String(msg), "color:red");
2682
- else {
2683
- window.console.error("%c" + hora + " ERROR: " + String(msg), "color:red");
2685
+ if (f_error) if (f_error === window.console.error) {
2686
+ if (__console_output_enabled__) f_error("%c" + hora + " ERROR: " + String(msg), "color:red");
2687
+ } else {
2688
+ if (__console_output_enabled__) window.console.error("%c" + hora + " ERROR: " + String(msg), "color:red");
2684
2689
  f_error(`${hora} ERROR: ${String(msg)}`);
2685
2690
  }
2686
2691
  emit_log_callback("error", msg, hora);
@@ -2688,9 +2693,10 @@
2688
2693
  function log_warning(format) {
2689
2694
  let msg = format_log(format);
2690
2695
  let hora = current_timestamp();
2691
- if (f_warning) if (f_warning === window.console.warn) f_warning("%c" + hora + " WARNING: " + String(msg), "color:yellow");
2692
- else {
2693
- window.console.warn("%c" + hora + " WARNING: " + String(msg), "color:yellow");
2696
+ if (f_warning) if (f_warning === window.console.warn) {
2697
+ if (__console_output_enabled__) f_warning("%c" + hora + " WARNING: " + String(msg), "color:yellow");
2698
+ } else {
2699
+ if (__console_output_enabled__) window.console.warn("%c" + hora + " WARNING: " + String(msg), "color:yellow");
2694
2700
  f_warning(`${hora} WARNING: ${String(msg)}`);
2695
2701
  }
2696
2702
  emit_log_callback("warning", msg, hora);
@@ -2698,24 +2704,32 @@
2698
2704
  function log_info(format) {
2699
2705
  let msg = format_log(format);
2700
2706
  let hora = current_timestamp();
2701
- if (f_info) f_info("%c" + hora + " INFO: " + String(msg), "color:cyan");
2707
+ if (f_info) {
2708
+ if (__console_output_enabled__) f_info("%c" + hora + " INFO: " + String(msg), "color:cyan");
2709
+ }
2702
2710
  emit_log_callback("info", msg, hora);
2703
2711
  }
2704
2712
  function log_debug(format) {
2705
2713
  let msg = format_log(format);
2706
2714
  let hora = current_timestamp();
2707
- if (f_debug) f_debug("%c" + hora + " DEBUG: " + String(msg), "color:silver");
2715
+ if (f_debug) {
2716
+ if (__console_output_enabled__) f_debug("%c" + hora + " DEBUG: " + String(msg), "color:silver");
2717
+ }
2708
2718
  emit_log_callback("debug", msg, hora);
2709
2719
  }
2710
2720
  function trace_msg(format) {
2711
2721
  let msg = format_log(format);
2712
2722
  let hora = current_timestamp();
2713
- if (f_debug) f_debug("%c" + hora + " MSG: " + String(msg), "color:cyan");
2723
+ if (f_debug) {
2724
+ if (__console_output_enabled__) f_debug("%c" + hora + " MSG: " + String(msg), "color:cyan");
2725
+ }
2714
2726
  emit_log_callback("msg", msg, hora);
2715
2727
  }
2716
2728
  function trace_json(jn, msg) {
2717
- if (msg) window.console.warn("=====> " + msg);
2718
- window.console.dir(jn);
2729
+ if (__console_output_enabled__) {
2730
+ if (msg) window.console.warn("=====> " + msg);
2731
+ window.console.dir(jn);
2732
+ }
2719
2733
  emit_log_callback("json", jn, current_timestamp());
2720
2734
  }
2721
2735
  /************************************************************
@@ -3528,17 +3542,26 @@
3528
3542
  }
3529
3543
  /********************************************
3530
3544
  * Save a local attribute
3545
+ *
3546
+ * Returns 0 on success, -1 when the value did NOT reach the store.
3547
+ * It used to return nothing and only console.warn, so every caller up the
3548
+ * chain (db_save_persistent_attrs -> gobj_save_persistent_attrs -> the app)
3549
+ * reported success on a store that had rejected the write: a full or blocked
3550
+ * localStorage (quota, private mode) silently discarded the change while the
3551
+ * UI showed it as saved.
3531
3552
  ********************************************/
3532
3553
  function kw_set_local_storage_value(key, value) {
3533
- if (typeof window === "undefined" || !window.localStorage) return;
3554
+ if (typeof window === "undefined" || !window.localStorage) return 0;
3534
3555
  if (!key || value === void 0) {
3535
- window.console.warn(`Invalid key or value for localStorage: key=${key}, value=${value}`);
3536
- return;
3556
+ log_error(`kw_set_local_storage_value(): invalid key or value: key=${key}`);
3557
+ return -1;
3537
3558
  }
3538
3559
  try {
3539
3560
  window.localStorage.setItem(key, JSON.stringify(value));
3561
+ return 0;
3540
3562
  } catch (e) {
3541
- window.console.warn(`Error saving localStorage key "${key}":`, e);
3563
+ log_error(`kw_set_local_storage_value(): cannot save "${key}" (storage full or blocked?): ${e && e.message ? e.message : e}`);
3564
+ return -1;
3542
3565
  }
3543
3566
  }
3544
3567
  /********************************************
@@ -4513,6 +4536,10 @@
4513
4536
  let value = elem.getAttribute("data-i18n-aria-label");
4514
4537
  if (value) elem.setAttribute("aria-label", t(value));
4515
4538
  });
4539
+ element.querySelectorAll("[data-i18n-placeholder]").forEach(function(elem) {
4540
+ let value = elem.getAttribute("data-i18n-placeholder");
4541
+ if (value) elem.setAttribute("placeholder", t(value));
4542
+ });
4516
4543
  }
4517
4544
  /************************************************************
4518
4545
  * Example Usage
@@ -4694,13 +4721,16 @@
4694
4721
  }
4695
4722
  }
4696
4723
  /************************************************************
4697
- *
4724
+ * Returns 0 on success, -1 when the attrs did NOT reach the store
4725
+ * (quota exceeded, private mode, storage disabled). Callers must check
4726
+ * it: a discarded write with a UI that shows the value as saved is the
4727
+ * worst of both worlds.
4698
4728
  ************************************************************/
4699
4729
  function db_save_persistent_attrs(gobj, keys) {
4700
4730
  let attrs = kw_clone_by_keys(gobj, gobj_read_attrs(gobj, sdata_flag_t.SDF_PERSIST, 0), keys, false);
4701
4731
  let jn_file = kw_get_local_storage_value(_get_persistent_path(gobj), null, false);
4702
4732
  if (jn_file && is_object(jn_file)) json_object_update_missing(attrs, jn_file);
4703
- kw_set_local_storage_value(_get_persistent_path(gobj), attrs);
4733
+ return kw_set_local_storage_value(_get_persistent_path(gobj), attrs);
4704
4734
  }
4705
4735
  /************************************************************
4706
4736
  *
@@ -5449,7 +5479,9 @@
5449
5479
  SDATA(data_type_t.DTP_STRING, "jwt", sdata_flag_t.SDF_PERSIST, "", "JWT"),
5450
5480
  SDATA(data_type_t.DTP_STRING, "cert_pem", sdata_flag_t.SDF_PERSIST, "", "SSL server certification, PEM str format"),
5451
5481
  SDATA(data_type_t.DTP_JSON, "extra_info", sdata_flag_t.SDF_RD, "{}", "dict data set by user, added to the identity card msg."),
5452
- SDATA(data_type_t.DTP_INTEGER, "timeout_retry", sdata_flag_t.SDF_RD, "5000", "timeout waiting idAck"),
5482
+ SDATA(data_type_t.DTP_LIST, "required_services", sdata_flag_t.SDF_RD, "[]", "Services this LINK requires (identity card). Empty = the yuno's `required_services`, as before. A yuno with several links to DIFFERENT backends must set it per link: the yuno-wide list is the union, so every backend is told the service names of all the others."),
5483
+ SDATA(data_type_t.DTP_INTEGER, "timeout_retry", sdata_flag_t.SDF_RD, "5000", "First reconnect delay (ms). It BACKS OFF from here, doubling up to timeout_retry_max, and resets when a session is reached"),
5484
+ SDATA(data_type_t.DTP_INTEGER, "timeout_retry_max", sdata_flag_t.SDF_RD, "60000", "Cap of the reconnect backoff (ms). Set it equal to timeout_retry for the old fixed-interval behaviour"),
5453
5485
  SDATA(data_type_t.DTP_INTEGER, "timeout_idack", sdata_flag_t.SDF_RD, "5000", "timeout waiting idAck"),
5454
5486
  SDATA(data_type_t.DTP_POINTER, "subscriber", 0, 0, "subscriber of output-events. If null then subscriber is the parent"),
5455
5487
  SDATA_END()
@@ -5462,7 +5494,8 @@
5462
5494
  gobj_timer: null,
5463
5495
  inform_on_close: false,
5464
5496
  websocket: null,
5465
- inside_on_open: false
5497
+ inside_on_open: false,
5498
+ retry_ms: 0
5466
5499
  };
5467
5500
  var __gclass__ = null;
5468
5501
  /******************************
@@ -5510,6 +5543,7 @@
5510
5543
  function mt_start(gobj) {
5511
5544
  let priv = gobj.priv;
5512
5545
  gobj_start(priv.gobj_timer);
5546
+ priv.retry_ms = 0;
5513
5547
  priv.websocket = setup_websocket(gobj);
5514
5548
  return 0;
5515
5549
  }
@@ -5768,6 +5802,8 @@
5768
5802
  let yuno_version = gobj_read_str_attr(gobj_yuno(), "yuno_version");
5769
5803
  let yuno_release = gobj_read_str_attr(gobj_yuno(), "yuno_release");
5770
5804
  let yuno_tag = gobj_read_str_attr(gobj_yuno(), "yuno_tag");
5805
+ let required_services = gobj_read_attr(gobj, "required_services");
5806
+ if (!required_services || !required_services.length) required_services = gobj_read_attr(gobj_yuno(), "required_services");
5771
5807
  let kw = {
5772
5808
  "yuno_role": gobj_yuno_role(),
5773
5809
  "yuno_id": gobj_yuno_id(),
@@ -5786,7 +5822,7 @@
5786
5822
  "id": node_uuid(),
5787
5823
  "user_agent": typeof window !== "undefined" ? window.navigator.userAgent : "",
5788
5824
  "language": typeof window !== "undefined" ? window.navigator.language : "",
5789
- "required_services": gobj_read_attr(gobj_yuno(), "required_services")
5825
+ "required_services": required_services
5790
5826
  };
5791
5827
  msg_iev_push_stack(gobj, kw, IEVENT_STACK_ID, build_cli_ievent_request(gobj, gobj_name(gobj_parent(gobj)), null));
5792
5828
  msg_iev_set_msg_type(gobj, kw, "__identity__");
@@ -5915,9 +5951,37 @@
5915
5951
  was_clean: e.wasClean
5916
5952
  });
5917
5953
  }
5918
- if (gobj_is_running(gobj)) set_timeout(priv.gobj_timer, gobj_read_integer_attr(gobj, "timeout_retry"));
5954
+ if (gobj_is_running(gobj)) set_timeout(priv.gobj_timer, next_retry(gobj));
5919
5955
  return 0;
5920
5956
  }
5957
+ /***************************************************************
5958
+ * How long to wait before the next reconnect attempt.
5959
+ *
5960
+ * The delay used to be a constant (`timeout_retry`, 5s), for ever. A
5961
+ * backend that is down — or a URL with a typo, which never comes back —
5962
+ * was therefore hit every 5 seconds for the whole life of the tab, by
5963
+ * EVERY link pointed at it, all in lockstep. It backs off now: from
5964
+ * `timeout_retry`, doubling, capped at `timeout_retry_max`.
5965
+ *
5966
+ * The jitter (±20%) is what breaks the lockstep. Without it, N links that
5967
+ * went down together retry together for ever — a thundering herd against a
5968
+ * backend that is just coming back up. It is the one place a random number
5969
+ * earns its keep.
5970
+ *
5971
+ * Reset to zero when a session is actually reached
5972
+ * (ac_identity_card_ack), so a link that flaps once does not carry a
5973
+ * minute-long penalty into its next real drop.
5974
+ ***************************************************************/
5975
+ function next_retry(gobj) {
5976
+ let priv = gobj.priv;
5977
+ let base = gobj_read_integer_attr(gobj, "timeout_retry");
5978
+ let max = gobj_read_integer_attr(gobj, "timeout_retry_max");
5979
+ if (max < base) max = base;
5980
+ priv.retry_ms = priv.retry_ms ? Math.min(priv.retry_ms * 2, max) : base;
5981
+ let jitter = priv.retry_ms * .2;
5982
+ let ms = priv.retry_ms - jitter + Math.random() * 2 * jitter;
5983
+ return Math.max(1, Math.round(ms));
5984
+ }
5921
5985
  /********************************************
5922
5986
  *
5923
5987
  ********************************************/
@@ -5958,6 +6022,7 @@
5958
6022
  } else {
5959
6023
  gobj_change_state(gobj, "ST_SESSION");
5960
6024
  priv.inside_on_open = true;
6025
+ priv.retry_ms = 0;
5961
6026
  if (!priv.inform_on_close) {
5962
6027
  priv.inform_on_close = true;
5963
6028
  let kw_on_open = {
@@ -6381,6 +6446,7 @@
6381
6446
  exports.safeSrc = safeSrc;
6382
6447
  exports.sdata_flag_t = sdata_flag_t;
6383
6448
  exports.send_http_json_post = send_http_json_post;
6449
+ exports.set_console_log_enabled = set_console_log_enabled;
6384
6450
  exports.set_log_callback = set_log_callback;
6385
6451
  exports.set_remote_log_functions = set_remote_log_functions;
6386
6452
  exports.set_timeout = set_timeout;