@yuneta/gobj-js 7.26.23 → 7.26.25
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.
- package/README.md +72 -3
- package/dist/gobj-js.cjs.js +424 -71
- package/dist/gobj-js.cjs.js.map +1 -1
- package/dist/gobj-js.cjs.min.js +2095 -1867
- package/dist/gobj-js.cjs.min.js.map +1 -1
- package/dist/gobj-js.es.js +424 -72
- package/dist/gobj-js.es.js.map +1 -1
- package/dist/gobj-js.es.min.js +1837 -1609
- package/dist/gobj-js.es.min.js.map +1 -1
- package/dist/gobj-js.iife.js +424 -71
- package/dist/gobj-js.iife.js.map +1 -1
- package/dist/gobj-js.iife.min.js +2215 -1987
- package/dist/gobj-js.iife.min.js.map +1 -1
- package/dist/gobj-js.umd.js +424 -71
- package/dist/gobj-js.umd.js.map +1 -1
- package/dist/gobj-js.umd.min.js +2215 -1987
- package/dist/gobj-js.umd.min.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -286,6 +286,48 @@ const attrs_table = [
|
|
|
286
286
|
|
|
287
287
|
**A value is read as the attribute's type, as in C** (`gobj_write_attr()`, the kw of `gobj_create()`, `gobj_write_attrs()`, the persistent attrs; 7.26.22+): a string for a boolean, integer, real, list or dict is read from its text by the C command parser's grammar (`command_parameter_from_json()`: `"yes"` is `true`, `"42"` is 42, `"007"` and `"12abc"` are refused), a number or a boolean as the exact type (`2.7` to an integer is refused). A refused value is not written: one `log_error` names the attr, its type, why and the value (masked, capped; a `SDF_SECRET` one never shown). A key of a kw whose value is `undefined` is an absent key; `gobj_write_attr()` of `undefined` to a typed attr is refused. The typed writers read the value as THEIR type by the same grammar (`gobj_write_integer_attr(g, "x", 2.5)` is refused, `gobj_write_bool_attr(g, "on", "yes")` is `true`), and `gobj_write_str_attr()` writes `null`/`undefined` as `""`, never the text `"null"`.
|
|
288
288
|
|
|
289
|
+
**A refused write keeps the value the attribute had** (BREAKING in 7.26.22, kept
|
|
290
|
+
by decision: the C kernel's `json2item()` does the same). `undefined`, `null`, an
|
|
291
|
+
empty text or a text that is not a boolean, given to `gobj_write_bool_attr()`, is
|
|
292
|
+
not `false`: the function returns -1, logs one ERROR, and the attribute does not
|
|
293
|
+
change. The same for `gobj_write_attr()` of `null` or `""` to a `DTP_REAL`.
|
|
294
|
+
Compute the value before the write when it can be absent:
|
|
295
|
+
|
|
296
|
+
```javascript
|
|
297
|
+
gobj_write_bool_attr(gobj, "selectable", true);
|
|
298
|
+
gobj_write_bool_attr(gobj, "selectable", kw.selectable); // kw has none: -1, ERROR,
|
|
299
|
+
// "selectable" is still true
|
|
300
|
+
gobj_write_bool_attr(gobj, "selectable", kw.selectable === true); // false
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
A value with no json text (a circular object such as a gobj or a DOM node, a
|
|
304
|
+
`BigInt`) given to a string attribute is refused the same way, and is never
|
|
305
|
+
thrown (7.26.24). So is a value that is not json ALL THE WAY DOWN given to a
|
|
306
|
+
string, a `DTP_DICT` or a `DTP_LIST` (7.26.25): a cycle anywhere inside, a
|
|
307
|
+
`BigInt` inside (`[1n]`), a `Map`, a `Set`, a `Date`, a typed array, an instance
|
|
308
|
+
of a class. They were written, and burst (or turned into `"{}"`) when the value
|
|
309
|
+
was serialized, far from the write. A key whose value is `undefined` or a
|
|
310
|
+
function is dropped, as `JSON.stringify()` drops it:
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
gobj_write_attr(gobj, "settings", {a: 1, b: undefined}); // 0: b goes when serialized
|
|
314
|
+
gobj_write_attr(gobj, "settings", new Map([["a", 1]])); // -1, ERROR "a value with no json text"
|
|
315
|
+
gobj_write_str_attr(gobj, "name", new Map()); // -1: it was the text "{}"
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
A `DTP_JSON` attribute is not checked: it takes any value, as before.
|
|
319
|
+
|
|
320
|
+
A json TEXT is read as the C parser reads it: one that C
|
|
321
|
+
refuses is refused in JS too -- an escaped NUL (`"\u0000"`), a lone surrogate,
|
|
322
|
+
an integer out of int64, a real that overflows (`1e309`; to a `DTP_JSON` it is
|
|
323
|
+
the text `"1e309"`, not `Infinity`), a text nested deeper than 2048 levels (a
|
|
324
|
+
scalar is a level too; 7.26.25). A number beyond int64 is "a real" to a dict,
|
|
325
|
+
as in C (`1e20`), and `9223372036854775807` is taken by an integer (JSON.parse()
|
|
326
|
+
makes it 2^63, kept as such). Two differences remain, because a JS number
|
|
327
|
+
cannot carry them: an integer beyond 2^53 is rounded, and `2.0` (and `-0.0`) is
|
|
328
|
+
the integer (see `tests/fixtures/attr_types_parity.json`, which the C test
|
|
329
|
+
`tests/c/attr_types` of yunetas reads too).
|
|
330
|
+
|
|
289
331
|
### Events & Pub-Sub
|
|
290
332
|
|
|
291
333
|
GObjects communicate via events with JSON payloads:
|
|
@@ -463,6 +505,7 @@ gobj_current_state(gobj) // → state name string
|
|
|
463
505
|
gobj_change_state(gobj, new_state) // trigger FSM transition
|
|
464
506
|
gobj_has_event(gobj, event, event_flag) // → boolean; pass 0 to ignore flag
|
|
465
507
|
gobj_has_output_event(gobj, event, event_flag) // same; checks EVF_OUTPUT_EVENT
|
|
508
|
+
gobj_find_event_type(event, event_flag, verbose) // the event type in ANY registered gclass, or null
|
|
466
509
|
```
|
|
467
510
|
|
|
468
511
|
### Attribute Access
|
|
@@ -720,6 +763,8 @@ mask_secrets_inline("sent Bearer mF_9.B5f-4.1JqM") // → "sent Bearer ********
|
|
|
720
763
|
mask_secrets_inline("the bearer of this letter") // → null: prose
|
|
721
764
|
mask_secrets_inline("\"password\": hunter2") // → "\"password\": ********"
|
|
722
765
|
mask_secrets_inline("GET https://h/get?token=abc&x=1") // → "GET https://h/get?token=********&x=1"
|
|
766
|
+
mask_secrets_inline("a=1&user%5Bpassword%5D=x") // → "a=1&user%5Bpassword%5D=********"
|
|
767
|
+
mask_secrets_inline("https://bob:hunter2@host/x") // → "https://bob:********@host/x"
|
|
723
768
|
json_mask_secrets({user: "a", password: "x"}) // → {user: "a", password: "********"}
|
|
724
769
|
json_mask_secrets({note: "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4In0.c2ln"})
|
|
725
770
|
// → {note: "********"}: a JWT under any key
|
|
@@ -960,7 +1005,11 @@ Events published: `EV_TIMEOUT`, `EV_TIMEOUT_PERIODIC`. They go to the
|
|
|
960
1005
|
`subscriber` attr, else, for a pure child, to its parent, which the timer
|
|
961
1006
|
subscribes in `mt_create` — the C timer's rule. Up to 7.26.21 a pure child
|
|
962
1007
|
SENT the timeout to its parent instead of publishing it (and to its parent
|
|
963
|
-
even when it had a `subscriber`).
|
|
1008
|
+
even when it had a `subscriber`). BREAKING in 7.26.22: the parent's
|
|
1009
|
+
`EV_TIMEOUT` action now runs inside the timer's publication, so destroying
|
|
1010
|
+
the timer or the parent there is the ERROR *"Destroying a gobj while its tree
|
|
1011
|
+
is publishing"*. Defer it with `gobj_post_event()` to yourself; re-arming or
|
|
1012
|
+
clearing the timer in the action is fine.
|
|
964
1013
|
|
|
965
1014
|
Attributes: `subscriber`, `periodic`, `msec`
|
|
966
1015
|
|
|
@@ -982,7 +1031,25 @@ let remote = gobj_create_service("backend", "C_IEVENT_CLI", {
|
|
|
982
1031
|
|
|
983
1032
|
Key attributes: `url`, `jwt`, `wanted_yuno_role`, `wanted_yuno_name`, `wanted_yuno_service`, `remote_yuno_role`, `remote_yuno_name`, `remote_yuno_service`, `required_services`, `timeout_retry`, `timeout_retry_max`
|
|
984
1033
|
|
|
985
|
-
Its events (`EV_ON_OPEN`, `EV_ON_CLOSE`, `EV_ON_OPEN_ERROR`, `EV_ON_ID_NAK` and every message that names no service) are PUBLISHED: to the `subscriber` attr, else, for a pure child, to its parent, which it subscribes in `mt_create` — one subscription, as the C transport. Up to 7.26.21 a pure child SENT three of them to its parent and subscribed nobody, so its parent never heard `EV_ON_CLOSE` / `EV_ON_OPEN_ERROR
|
|
1034
|
+
Its events (`EV_ON_OPEN`, `EV_ON_CLOSE`, `EV_ON_OPEN_ERROR`, `EV_ON_ID_NAK` and every message that names no service) are PUBLISHED: to the `subscriber` attr, else, for a pure child, to its parent, which it subscribes in `mt_create` — one subscription, as the C transport. Up to 7.26.21 a pure child SENT three of them to its parent and subscribed nobody, so its parent never heard `EV_ON_CLOSE` / `EV_ON_OPEN_ERROR`: a host of a pure child must declare both in its FSM (BREAKING in 7.26.22).
|
|
1035
|
+
|
|
1036
|
+
A message that names no service is published only when its event is declared PUBLIC by some registered gclass (`gobj_find_event_type(name, EVF_PUBLIC_EVENT)`, as C's `gclass_find_public_event()`; 7.26.24 took any declaration, 7.26.25 requires it public); any other is dropped with a WARNING, its name masked. The events the transport says itself (`EV_ON_OPEN`, `EV_ON_CLOSE`, `EV_ON_OPEN_ERROR`, `EV_ON_ID_NAK`, `EV_TIMEOUT`, `EV_ON_MESSAGE`, and `EV_IDENTITY_CARD_ACK` in session) are never taken from the server, in any case of letters and whatever service the message names: a WARNING, dropped (7.26.25). A backend event an app receives must therefore be declared `EVF_PUBLIC_EVENT` in the gclass that receives it:
|
|
1037
|
+
|
|
1038
|
+
```javascript
|
|
1039
|
+
const event_types = [
|
|
1040
|
+
["EV_MT_COMMAND_ANSWER", event_flag_t.EVF_PUBLIC_EVENT],
|
|
1041
|
+
["EV_REALTIME_ALARM", event_flag_t.EVF_PUBLIC_EVENT],
|
|
1042
|
+
];
|
|
1043
|
+
``` What the server gets wrong is a WARNING, never an ERROR. Before the session only `EV_IDENTITY_CARD_ACK` is taken; a `dst_role` or `dst_yuno` that is not this yuno's closes the channel too (an empty one is legal: anybody's), as the C transport does; an event that the named service does not take as public is dropped (7.26.24). A channel closed for a fault of the server is closed with **4002**, not 1000 (a browser may send only 1000 or 3000-4999, so 1002 cannot be used), so `EV_ON_CLOSE` says the session was cut (7.26.25).
|
|
1044
|
+
|
|
1045
|
+
`EV_ON_CLOSE` carries `code`, `reason` (masked) and `was_clean`, and so does `EV_ON_OPEN_ERROR` (7.26.24). A session that ends cleanly (a stop, a logout, the server closing with 1000 or 1001) is logged by nobody; a session CUT -- not clean, or any other code (1006, 1008, 1011) -- is one WARNING with the code and the reason masked:
|
|
1046
|
+
|
|
1047
|
+
```javascript
|
|
1048
|
+
// in the subscriber's EV_ON_CLOSE action
|
|
1049
|
+
if(!kw.was_clean || (kw.code !== 1000 && kw.code !== 1001)) {
|
|
1050
|
+
show_banner(t("connection lost")); // the WARNING is already logged
|
|
1051
|
+
}
|
|
1052
|
+
```
|
|
986
1053
|
|
|
987
1054
|
**`required_services`** (default `[]`) is the list this link advertises in its
|
|
988
1055
|
identity_card, which the remote's `C_AUTHZ` uses to authorize commands. It is
|
|
@@ -997,7 +1064,9 @@ naming services it does not host.
|
|
|
997
1064
|
what breaks lockstep, so N links that dropped together do not stampede a backend
|
|
998
1065
|
that is just coming back. The backoff resets when a session is actually reached,
|
|
999
1066
|
and on `mt_start` — a deliberate reconnect never inherits a previous run's
|
|
1000
|
-
penalty.
|
|
1067
|
+
penalty. A session the transport closes for a fault of the server (4002) does not
|
|
1068
|
+
count as reached: the backoff goes on from where it was (7.26.25), so a server
|
|
1069
|
+
that breaks every session is not reconnected at the first delay for ever. For the old fixed-interval behaviour set `timeout_retry_max` equal to
|
|
1001
1070
|
`timeout_retry`.
|
|
1002
1071
|
|
|
1003
1072
|
---
|