@yuneta/gobj-js 7.26.26 → 7.26.27

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.
@@ -2393,11 +2393,13 @@ var gobjJs = (function(exports) {
2393
2393
  let child;
2394
2394
  if (walk_type & walk_type_t.WALK_LAST2FIRST) for (let i = iter.length; i > 0; i--) {
2395
2395
  child = iter[i - 1];
2396
+ if (gobj_is_destroying(child)) continue;
2396
2397
  let ret = walk_ret(cb_walking(child, user_data, user_data2));
2397
2398
  if (ret < 0) return ret;
2398
2399
  }
2399
2400
  else for (let i = 0; i < iter.length; i++) {
2400
2401
  child = iter[i];
2402
+ if (gobj_is_destroying(child)) continue;
2401
2403
  let ret = walk_ret(cb_walking(child, user_data, user_data2));
2402
2404
  if (ret < 0) return ret;
2403
2405
  }
@@ -2412,18 +2414,21 @@ var gobjJs = (function(exports) {
2412
2414
  * or
2413
2415
  * WALK_LAST2FIRST
2414
2416
  ***************************************************************/
2415
- function rc_walk_by_level(iter, walk_type, cb_walking, user_data, user_data2) {
2417
+ function rc_walk_by_level(iter_, walk_type, cb_walking, user_data, user_data2) {
2418
+ let iter = [...iter_];
2416
2419
  let ret = rc_walk_by_list(iter, walk_type, cb_walking, user_data, user_data2);
2417
2420
  if (ret < 0) return ret;
2418
2421
  let child;
2419
2422
  if (walk_type & walk_type_t.WALK_LAST2FIRST) for (let i = iter.length; i > 0; i--) {
2420
2423
  child = iter[i - 1];
2421
- ret = rc_walk_by_level([...child.dl_children], walk_type, cb_walking, user_data, user_data2);
2424
+ if (gobj_is_destroying(child)) continue;
2425
+ ret = rc_walk_by_level(child.dl_children, walk_type, cb_walking, user_data, user_data2);
2422
2426
  if (ret < 0) return ret;
2423
2427
  }
2424
2428
  else for (let i = 0; i < iter.length; i++) {
2425
2429
  child = iter[i];
2426
- ret = rc_walk_by_level([...child.dl_children], walk_type, cb_walking, user_data, user_data2);
2430
+ if (gobj_is_destroying(child)) continue;
2431
+ ret = rc_walk_by_level(child.dl_children, walk_type, cb_walking, user_data, user_data2);
2427
2432
  if (ret < 0) return ret;
2428
2433
  }
2429
2434
  return ret;
@@ -2443,23 +2448,27 @@ var gobjJs = (function(exports) {
2443
2448
  * or
2444
2449
  * WALK_LAST2FIRST
2445
2450
  ***************************************************************/
2446
- function rc_walk_by_tree(iter, walk_type, cb_walking, user_data, user_data2) {
2447
- if (walk_type & walk_type_t.WALK_BYLEVEL) return rc_walk_by_level(iter, walk_type, cb_walking, user_data, user_data2);
2451
+ function rc_walk_by_tree(iter_, walk_type, cb_walking, user_data, user_data2) {
2452
+ if (walk_type & walk_type_t.WALK_BYLEVEL) return rc_walk_by_level(iter_, walk_type, cb_walking, user_data, user_data2);
2453
+ let iter = [...iter_];
2448
2454
  let ret;
2449
2455
  let child;
2450
2456
  if (walk_type & walk_type_t.WALK_BOTTOM2TOP) for (let i = iter.length; i > 0; i--) {
2451
2457
  child = iter[i - 1];
2452
- ret = rc_walk_by_tree([...child.dl_children], walk_type, cb_walking, user_data, user_data2);
2458
+ if (gobj_is_destroying(child)) continue;
2459
+ ret = rc_walk_by_tree(child.dl_children, walk_type, cb_walking, user_data, user_data2);
2453
2460
  if (ret < 0) return ret;
2461
+ if (gobj_is_destroying(child)) continue;
2454
2462
  ret = walk_ret(cb_walking(child, user_data, user_data2));
2455
2463
  if (ret < 0) return ret;
2456
2464
  }
2457
2465
  else for (let i = 0; i < iter.length; i++) {
2458
2466
  child = iter[i];
2467
+ if (gobj_is_destroying(child)) continue;
2459
2468
  ret = walk_ret(cb_walking(child, user_data, user_data2));
2460
2469
  if (ret < 0) return ret;
2461
- else if (ret === 0) {
2462
- ret = rc_walk_by_tree([...child.dl_children], walk_type, cb_walking, user_data, user_data2);
2470
+ else if (ret === 0 && !gobj_is_destroying(child)) {
2471
+ ret = rc_walk_by_tree(child.dl_children, walk_type, cb_walking, user_data, user_data2);
2463
2472
  if (ret < 0) return ret;
2464
2473
  }
2465
2474
  }
@@ -6044,40 +6053,83 @@ var gobjJs = (function(exports) {
6044
6053
  return kw_clone;
6045
6054
  }
6046
6055
  /********************************************
6056
+ * The browser's localStorage, or null when there is none (outside a
6057
+ * browser).
6058
+ *
6059
+ * With the site's data blocked (Chrome with cookies blocked, a sandboxed
6060
+ * iframe), READING the window.localStorage property already throws a
6061
+ * SecurityError, not only its getItem(): every app reads its locale at
6062
+ * start, so the app did not start. Such a store is answered as one whose
6063
+ * every call throws that error, so each helper fails as it fails for any
6064
+ * store that refuses it: a read gives the default, a write -1.
6065
+ ********************************************/
6066
+ function local_store() {
6067
+ if (typeof window === "undefined") return null;
6068
+ let store;
6069
+ try {
6070
+ store = window.localStorage;
6071
+ } catch (e) {
6072
+ const refuse = () => {
6073
+ throw e;
6074
+ };
6075
+ return {
6076
+ getItem: refuse,
6077
+ setItem: refuse,
6078
+ removeItem: refuse
6079
+ };
6080
+ }
6081
+ return store || null;
6082
+ }
6083
+ /********************************************
6084
+ * A failure of the store that would repeat on every read is warned
6085
+ * once per key, until a read of the key goes well again.
6086
+ ********************************************/
6087
+ var local_storage_warned = /* @__PURE__ */ new Set();
6088
+ function warn_local_storage_once(key, msg) {
6089
+ if (local_storage_warned.has(key)) return;
6090
+ local_storage_warned.add(key);
6091
+ log_warning(msg);
6092
+ }
6093
+ /********************************************
6047
6094
  * Get a local attribute
6048
6095
  *
6049
6096
  * The json the entry holds, or `default_value` when there is none
6050
6097
  * (written there too with `create`). A json null is no value, as
6051
6098
  * json_absent() in C: the default. An entry that is not json (a
6052
- * corrupt or foreign write) is one WARNING and is REMOVED, so the
6099
+ * corrupt or foreign write) is a WARNING and is REMOVED, so the
6053
6100
  * next read finds no entry: it used to console.warn on every read,
6054
- * for ever. Its text is never shown (JSON.parse() quotes it in its
6055
- * error, and an entry can hold a token). A store that cannot be read
6056
- * is warned once per key. Outside a browser: the default.
6101
+ * for ever; a new corrupt entry is a new WARNING. Its text is never
6102
+ * shown (JSON.parse() quotes it in its error, and an entry can hold a
6103
+ * token). A store that cannot be read (blocked) is warned once per
6104
+ * key, and the default is NOT written there. Outside a browser: the
6105
+ * default.
6057
6106
  ********************************************/
6058
- var local_storage_warned = /* @__PURE__ */ new Set();
6059
- function warn_local_storage_once(key, what) {
6060
- if (local_storage_warned.has(key)) return;
6061
- local_storage_warned.add(key);
6062
- log_warning(`kw_get_local_storage_value(): localStorage key "${key}" ${what}`);
6063
- }
6064
6107
  function kw_get_local_storage_value(key, default_value, create = false) {
6065
- if (typeof window === "undefined" || !window.localStorage) return default_value;
6108
+ const store = local_store();
6109
+ if (!store) return default_value;
6110
+ const where = `kw_get_local_storage_value(): localStorage key "${key}"`;
6066
6111
  let text;
6067
6112
  try {
6068
- text = window.localStorage.getItem(key);
6113
+ text = store.getItem(key);
6069
6114
  } catch (e) {
6070
- warn_local_storage_once(key, "cannot be read (storage blocked?): the default is used");
6115
+ warn_local_storage_once(key, `${where} cannot be read (storage blocked?): the default is used`);
6071
6116
  return default_value;
6072
6117
  }
6073
6118
  let value = null;
6074
6119
  if (text !== null) try {
6075
6120
  value = JSON.parse(text);
6076
6121
  } catch (e) {
6077
- warn_local_storage_once(key, "does not hold json: removed, the default is used");
6078
- kw_remove_local_storage_value(key);
6079
6122
  value = null;
6123
+ try {
6124
+ store.removeItem(key);
6125
+ log_warning(`${where} does not hold json: removed, the default is used`);
6126
+ local_storage_warned.delete(key);
6127
+ } catch (e2) {
6128
+ warn_local_storage_once(key, `${where} does not hold json and cannot be removed: the default is used`);
6129
+ }
6130
+ text = void 0;
6080
6131
  }
6132
+ if (text !== void 0) local_storage_warned.delete(key);
6081
6133
  if (value === null) {
6082
6134
  if (create) kw_set_local_storage_value(key, default_value);
6083
6135
  return default_value;
@@ -6093,15 +6145,26 @@ var gobjJs = (function(exports) {
6093
6145
  * reported success on a store that had rejected the write: a full or blocked
6094
6146
  * localStorage (quota, private mode) silently discarded the change while the
6095
6147
  * UI showed it as saved.
6148
+ *
6149
+ * A value with no json text is refused with an ERROR, as a typed writer
6150
+ * refuses it (json_text_of()): a function was stored as the text
6151
+ * "undefined", and a NaN, a Date or a Map as a text that reads back as
6152
+ * another value. Checked in Node.js too, where there is no store.
6096
6153
  ********************************************/
6097
6154
  function kw_set_local_storage_value(key, value) {
6098
- if (typeof window === "undefined" || !window.localStorage) return 0;
6099
- if (!key || value === void 0) {
6100
- log_error(`kw_set_local_storage_value(): invalid key or value: key=${key}`);
6155
+ if (!key) {
6156
+ log_error(`kw_set_local_storage_value(): invalid key: key=${key}`);
6101
6157
  return -1;
6102
6158
  }
6159
+ const text = json_text_of(value);
6160
+ if (text === void 0) {
6161
+ log_error(`kw_set_local_storage_value(): cannot save "${key}": a value with no json text`);
6162
+ return -1;
6163
+ }
6164
+ const store = local_store();
6165
+ if (!store) return 0;
6103
6166
  try {
6104
- window.localStorage.setItem(key, JSON.stringify(value));
6167
+ store.setItem(key, text);
6105
6168
  return 0;
6106
6169
  } catch (e) {
6107
6170
  log_error(`kw_set_local_storage_value(): cannot save "${key}" (storage full or blocked?): ${e && e.message ? e.message : e}`);
@@ -6112,15 +6175,16 @@ var gobjJs = (function(exports) {
6112
6175
  * Remove local attribute
6113
6176
  ********************************************/
6114
6177
  function kw_remove_local_storage_value(key) {
6115
- if (typeof window === "undefined" || !window.localStorage) return;
6178
+ const store = local_store();
6179
+ if (!store) return;
6116
6180
  if (!key) {
6117
- window.console.warn(`Invalid key for localStorage removal: ${key}`);
6181
+ log_error(`kw_remove_local_storage_value(): invalid key: key=${key}`);
6118
6182
  return;
6119
6183
  }
6120
6184
  try {
6121
- window.localStorage.removeItem(key);
6185
+ store.removeItem(key);
6122
6186
  } catch (e) {
6123
- window.console.warn(`Error removing localStorage key "${key}":`, e);
6187
+ log_warning(`kw_remove_local_storage_value(): cannot remove "${key}" (storage blocked?): ${e && e.message ? e.message : e}`);
6124
6188
  }
6125
6189
  }
6126
6190
  /*************************************************************
@@ -7313,11 +7377,21 @@ var gobjJs = (function(exports) {
7313
7377
  ************************************************************/
7314
7378
  function node_uuid() {
7315
7379
  let uuid = "";
7316
- if (typeof window !== "undefined" && window.localStorage) {
7317
- uuid = window.localStorage.getItem("host_uuid");
7380
+ const store = local_store();
7381
+ if (store) {
7382
+ try {
7383
+ uuid = store.getItem("host_uuid");
7384
+ } catch (e) {
7385
+ uuid = null;
7386
+ warn_local_storage_once("host_uuid", "node_uuid(): localStorage cannot be read (storage blocked?): a uuid of this page only");
7387
+ }
7318
7388
  if (!uuid && window.crypto?.randomUUID) {
7319
7389
  uuid = window.crypto.randomUUID();
7320
- window.localStorage.setItem("host_uuid", uuid);
7390
+ try {
7391
+ store.setItem("host_uuid", uuid);
7392
+ } catch (e) {
7393
+ warn_local_storage_once("host_uuid", "node_uuid(): localStorage cannot be written (storage full or blocked?): a uuid of this page only");
7394
+ }
7321
7395
  }
7322
7396
  } else if (typeof globalThis !== "undefined" && globalThis.crypto?.randomUUID) uuid = globalThis.crypto.randomUUID();
7323
7397
  else uuid = "00000000-0000-0000-0000-000000000000";
@@ -8606,7 +8680,7 @@ var gobjJs = (function(exports) {
8606
8680
  SDATA(data_type_t.DTP_STRING, "cert_pem", sdata_flag_t.SDF_PERSIST, "", "SSL server certification, PEM str format"),
8607
8681
  SDATA(data_type_t.DTP_JSON, "extra_info", sdata_flag_t.SDF_RD, "{}", "dict data set by user, added to the identity card msg."),
8608
8682
  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."),
8609
- 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"),
8683
+ SDATA(data_type_t.DTP_INTEGER, "timeout_retry", sdata_flag_t.SDF_RD, "5000", "First reconnect delay (ms), at least 1000. It BACKS OFF from here, doubling up to timeout_retry_max, and resets when a session is reached"),
8610
8684
  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"),
8611
8685
  SDATA(data_type_t.DTP_INTEGER, "timeout_idack", sdata_flag_t.SDF_RD, "5000", "timeout waiting idAck"),
8612
8686
  SDATA(data_type_t.DTP_POINTER, "subscriber", 0, 0, "subscriber of output-events. If null then subscriber is the parent"),
@@ -8631,7 +8705,8 @@ var gobjJs = (function(exports) {
8631
8705
  inside_on_open: false,
8632
8706
  retry_ms: 0,
8633
8707
  retry_ms_before_session: 0,
8634
- session_since: 0
8708
+ session_since: 0,
8709
+ retry_floor_warned: false
8635
8710
  };
8636
8711
  var __gclass__ = null;
8637
8712
  /******************************
@@ -8903,7 +8978,7 @@ var gobjJs = (function(exports) {
8903
8978
  function close_for_peer_fault(gobj, reason) {
8904
8979
  let priv = gobj.priv;
8905
8980
  if (gobj_current_state(gobj) === "ST_SESSION") {
8906
- if (performance.now() - priv.session_since < Math.max(gobj_read_integer_attr(gobj, "timeout_retry"), gobj_read_integer_attr(gobj, "timeout_retry_max"))) priv.retry_ms = priv.retry_ms_before_session;
8981
+ if (performance.now() - priv.session_since < retry_bounds(gobj).max) priv.retry_ms = priv.retry_ms_before_session;
8907
8982
  priv.retry_ms_before_session = 0;
8908
8983
  }
8909
8984
  close_websocket(gobj, CLOSE_PEER_FAULT, reason);
@@ -9175,6 +9250,32 @@ var gobjJs = (function(exports) {
9175
9250
  return 0;
9176
9251
  }
9177
9252
  /***************************************************************
9253
+ * The first delay of the backoff and its cap.
9254
+ *
9255
+ * A first delay below RETRY_FLOOR_MS is raised to it, with a WARNING
9256
+ * once: `timeout_retry` 0 never left 0 (0 doubled is 0), so a server
9257
+ * that closed before the ack was reconnected in a loop with no wait,
9258
+ * hundreds of connections a second.
9259
+ ***************************************************************/
9260
+ var RETRY_FLOOR_MS = 1e3;
9261
+ function retry_bounds(gobj) {
9262
+ let priv = gobj.priv;
9263
+ let base = gobj_read_integer_attr(gobj, "timeout_retry");
9264
+ let max = gobj_read_integer_attr(gobj, "timeout_retry_max");
9265
+ if (!(base >= RETRY_FLOOR_MS)) {
9266
+ if (!priv.retry_floor_warned) {
9267
+ priv.retry_floor_warned = true;
9268
+ log_warning(`${gobj_short_name(gobj)}: timeout_retry ${base} ms is below ${RETRY_FLOOR_MS} ms: ${RETRY_FLOOR_MS} ms is used`);
9269
+ }
9270
+ base = RETRY_FLOOR_MS;
9271
+ }
9272
+ if (!(max >= base)) max = base;
9273
+ return {
9274
+ base,
9275
+ max
9276
+ };
9277
+ }
9278
+ /***************************************************************
9178
9279
  * How long to wait before the next reconnect attempt.
9179
9280
  *
9180
9281
  * The delay used to be a constant (`timeout_retry`, 5s), for ever. A
@@ -9195,9 +9296,7 @@ var gobjJs = (function(exports) {
9195
9296
  ***************************************************************/
9196
9297
  function next_retry(gobj) {
9197
9298
  let priv = gobj.priv;
9198
- let base = gobj_read_integer_attr(gobj, "timeout_retry");
9199
- let max = gobj_read_integer_attr(gobj, "timeout_retry_max");
9200
- if (max < base) max = base;
9299
+ const { base, max } = retry_bounds(gobj);
9201
9300
  priv.retry_ms = priv.retry_ms ? Math.min(priv.retry_ms * 2, max) : base;
9202
9301
  let jitter = priv.retry_ms * .2;
9203
9302
  let ms = priv.retry_ms - jitter + Math.random() * 2 * jitter;
@@ -9695,6 +9794,7 @@ var gobjJs = (function(exports) {
9695
9794
  exports.json_object_update_existing = json_object_update_existing;
9696
9795
  exports.json_object_update_missing = json_object_update_missing;
9697
9796
  exports.json_size = json_size;
9797
+ exports.json_text_of = json_text_of;
9698
9798
  exports.jwt2json = jwt2json;
9699
9799
  exports.jwtDecode = jwtDecode;
9700
9800
  exports.kw_clone_by_keys = kw_clone_by_keys;