@scriptc/runtime 0.0.9 → 0.0.11

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/src/scr_runtime.h CHANGED
@@ -163,6 +163,12 @@ ScrStr *scr_library_str_in(const uint8_t *p, size_t len); /* +1 */
163
163
  * (structured trap-teaching bytes naming this entry's symbol), delivered
164
164
  * through the funnel when len falls outside the marshalling class. */
165
165
  ScrBytes *scr_library_bytes_in(const uint8_t *p, size_t len, const char *trap_msg); /* +1, u8 */
166
+ /* The inbound declared-integer edge (ask 4's i64/u64 parameter classes):
167
+ * exact conversion for |v| <= 2^53-1, the host-contract trap (same
168
+ * assembled SC4012 message shape as the bytes trap) past it — silent
169
+ * rounding is a coercion the author never wrote. */
170
+ double scr_library_i64_in(int64_t v, const char *trap_msg);
171
+ double scr_library_u64_in(uint64_t v, const char *trap_msg);
166
172
  void scr_library_str_out(ScrStr *s, const uint8_t **out, size_t *out_len);
167
173
  void scr_library_bytes_out(ScrBytes *b, const uint8_t **out, size_t *out_len);
168
174
 
@@ -1362,6 +1368,10 @@ bool scr_emitter_emit_error(ScrEmitter *em, ScrStr *name, ScrError *err);
1362
1368
  double scr_emitter_listener_count(ScrEmitter *em, ScrStr *name);
1363
1369
  double scr_emitter_listener_count_fn(ScrEmitter *em, ScrStr *name, ScrClosure *fn);
1364
1370
  ScrArr *scr_emitter_event_names(ScrEmitter *em); /* +1 string[] */
1371
+ /* Pre-create a name's eventNames() rank with no listener (Node's stream
1372
+ * classes pre-create their known _events keys; empty = absent for every
1373
+ * other read). The stream constructors call this. */
1374
+ void scr_emitter_reserve(ScrEmitter *em, const char *name);
1365
1375
  ScrArr *scr_emitter_listeners(ScrEmitter *em, ScrStr *name); /* +1 closures */
1366
1376
  ScrEmitter *scr_emitter_set_max(ScrEmitter *em, double n); /* returns em +1 */
1367
1377
  double scr_emitter_get_max(ScrEmitter *em);
@@ -1562,6 +1572,13 @@ ScrDyn *scr_stream_done_dyn_l(ScrClosure *clo, ScrDyn *const *args, size_t argc)
1562
1572
  * utf8, Node's decodeStrings default); push answers the below-hwm bool. */
1563
1573
  bool scr_stream_push(ScrStream *s, ScrBytes *chunk);
1564
1574
  bool scr_stream_push_str(ScrStream *s, ScrStr *str);
1575
+ /* push(chunk, enc): the per-call literal encoding (canonical); overrides
1576
+ * the stream's defaultEncoding. Borrows both. */
1577
+ bool scr_stream_push_str_enc(ScrStream *s, ScrStr *str, ScrStr *enc);
1578
+ /* The defaultEncoding option's push side: how push(string) decodes chunks
1579
+ * (Buffer.from(chunk, enc)). Canonical literal, never "utf8". Receiver
1580
+ * answers +1 (the setEncoding chaining shape). */
1581
+ ScrStream *scr_stream_set_push_encoding(ScrStream *s, ScrStr *enc);
1565
1582
  bool scr_stream_push_null(ScrStream *s);
1566
1583
  void scr_stream_unshift(ScrStream *s, ScrBytes *chunk);
1567
1584
  void scr_stream_unshift_str(ScrStream *s, ScrStr *str);
@@ -1591,6 +1608,18 @@ ScrPromise *scr_stream_next_chunk_dyn(ScrStream *s);
1591
1608
  * Streams borrowed; +1 promises. */
1592
1609
  ScrPromise *scr_sp_finished(ScrStream *s);
1593
1610
  ScrPromise *scr_sp_pipeline(double n, ScrStream **streams);
1611
+ /* node:stream/consumers — the promise consumers over the readable
1612
+ * machinery: accumulate every chunk (string chunks as their utf8 bytes)
1613
+ * and settle at the terminal point (right after 'close', the eos timing
1614
+ * Node's consumers share) — text answers the utf8 decode, json parses
1615
+ * the text (malformed input rejects with the parse's SyntaxError; the
1616
+ * result is a +1 DOM tree), buffer the concatenated bytes. Stream
1617
+ * errors reject; an early close rejects ERR_STREAM_PREMATURE_CLOSE; a
1618
+ * stream with no readable side rejects Node's async-iterable TypeError.
1619
+ * Streams borrowed; +1 promises. */
1620
+ ScrPromise *scr_sc_text(ScrStream *s);
1621
+ ScrPromise *scr_sc_json(ScrStream *s);
1622
+ ScrPromise *scr_sc_buffer(ScrStream *s);
1594
1623
  /* Readable.from(array): +1 fully-seeded object-entry stream (one WHOLE
1595
1624
  * chunk per element — strings or Buffers per the flag; hwm 1, already
1596
1625
  * EOF'd). Borrows arr. */
@@ -2617,6 +2646,28 @@ typedef enum {
2617
2646
  * (the dyn→closure stance): a cycle THROUGH a dyn-boxed promise is
2618
2647
  * merely never collected. */
2619
2648
  SCR_DYN_PROMISE,
2649
+ /* An ISLAND (engine-held) value — the jsval→DOM crossing. Never
2650
+ * produced by the parser — it enters the DOM through the gated
2651
+ * constructor scr_dyn_from_jsval (scr_island.c): an 'any'-typed value
2652
+ * flowing into an 'unknown'/'object'/JS-residue slot. Boxes by
2653
+ * REFERENCE (a retained ScrJsval cell). The constructor SCALAR-
2654
+ * NORMALIZES: engine numbers/strings/booleans/null/undefined convert
2655
+ * to the native DOM kinds at wrap time, so JSVAL nodes only ever hold
2656
+ * engine objects, arrays, and functions (plus the symbol/bigint edge —
2657
+ * kinds the DOM cannot represent at all). Identity is the CELL's
2658
+ * engine value: strict equality routes to the engine's === (two wraps
2659
+ * of one engine value compare equal), and scr_jsval_from_dyn unwraps
2660
+ * the SAME cell back (+1) — the boundary is identity-preserving for
2661
+ * engine-born values. typeof/truthiness/String() route to the engine
2662
+ * per use (scr_dyn_jsval_ops); every DOM walk without an armed route
2663
+ * (JSON, structuredClone, deepStrictEqual, inspect, keyed access,
2664
+ * calls, iteration) throws the LOUD "not supported yet" ladder — never
2665
+ * a silent wrong answer. The dyn→cell edge is NOT visible to the cycle
2666
+ * collector (the dyn→closure stance): a cycle DOM → cell → engine
2667
+ * object → host closure → DOM is merely never collected (the
2668
+ * documented cross-boundary-cycle divergence). Enum position: LAST —
2669
+ * the LLVM backend hardcodes the preceding kind numbers. */
2670
+ SCR_DYN_JSVAL,
2620
2671
  } ScrDynKind;
2621
2672
 
2622
2673
  /* The handle-type tags the DOM can carry. The set is deliberately the
@@ -2636,6 +2687,10 @@ typedef enum {
2636
2687
  typedef struct ScrDyn ScrDyn;
2637
2688
  typedef struct ScrBytes ScrBytes; /* full definition below (C11 repeat) */
2638
2689
  typedef struct ScrClosure ScrClosure; /* full definition below (C11 repeat) */
2690
+ typedef struct ScrJsval ScrJsval; /* opaque island cell (C11 repeat; the
2691
+ * always-linked DOM core never touches
2692
+ * its engine value — only the gated ops
2693
+ * installed by scr_dyn_from_jsval do) */
2639
2694
 
2640
2695
  /* The compiler-emitted call glue carried by a SCR_DYN_FUNC box: checks the
2641
2696
  * dyn arguments against the boxed closure's declared parameter types (a
@@ -2661,6 +2716,16 @@ struct ScrDyn {
2661
2716
  * coercion and toString() decode utf8, where a plain Uint8Array joins
2662
2717
  * its elements ("1,2,3"). Everything else ignores it. */
2663
2718
  bool buffer;
2719
+ /* SCR_DYN_OBJ flavor: true for Object.create(null)'s dictionary — an
2720
+ * object with NO prototype. Method dispatch needs nothing (the DOM's
2721
+ * OBJ dispatch is already own-member-only, which IS Node's null-proto
2722
+ * answer); util.inspect prefixes "[Object: null prototype]", and
2723
+ * deepStrictEqual separates it from plain objects (Node compares
2724
+ * prototypes — the bytes `buffer` gate's stance). Keyed reads/writes,
2725
+ * Object.keys/entries/assign, JSON, and typeof are flag-blind, and
2726
+ * fresh copies (structuredClone) DROP the flag — Node's serialization
2727
+ * answers a plain object too. */
2728
+ bool null_proto;
2664
2729
  union {
2665
2730
  bool b;
2666
2731
  double num;
@@ -2688,6 +2753,11 @@ struct ScrDyn {
2688
2753
  * emitted converters guarantee it (direct box for promise<dyn>,
2689
2754
  * adapter promise otherwise). */
2690
2755
  ScrPromise *promise;
2756
+ /* SCR_DYN_JSVAL: the retained island cell (engine objects/arrays/
2757
+ * functions only — the constructor scalar-normalizes; see the kind's
2758
+ * comment). Released through the installed ops so this always-linked
2759
+ * core never references the gated island unit. */
2760
+ struct { ScrJsval *cell; } jsval;
2691
2761
  } v;
2692
2762
  };
2693
2763
 
@@ -2716,8 +2786,24 @@ ScrDyn *scr_dyn_obj_keys(const ScrDyn *v);
2716
2786
  * TypeError; every other kind answers false. */
2717
2787
  bool scr_dyn_has_own(const ScrDyn *v, const ScrStr *key);
2718
2788
  /* Object.assign over DOM values (+1 target back; ToObject TypeError on a
2719
- * nullish target). */
2789
+ * nullish target). Sources copy their own enumerable keys exactly as
2790
+ * Object.keys lists them: OBJ members, ARR/STR/BYTES index keys; nullish
2791
+ * and scalar/function/handle sources copy nothing. */
2720
2792
  ScrDyn *scr_dyn_assign(ScrDyn *target, const ScrDyn *src);
2793
+ /* Variadic Object.assign (the spread-source form): the compiler packs
2794
+ * every source into one fresh DOM array — pack_push retains a plain
2795
+ * source in (BORROWED), pack_push_spread flattens a spread source through
2796
+ * the spread-call walk (V8's exact TypeError texts, `what` spelling the
2797
+ * spread expression; MAY THROW pending) — then assign_all copies each
2798
+ * pack element's own members onto the target left to right and answers
2799
+ * the target retained (+1; ToObject TypeError on a nullish target). */
2800
+ void scr_dyn_pack_push(ScrDyn *pack, ScrDyn *v);
2801
+ void scr_dyn_pack_push_spread(ScrDyn *pack, const ScrDyn *src, const ScrStr *what);
2802
+ /* The iterated-path twin — a spread that is NOT the single last argument
2803
+ * takes V8's iterator-protocol failure texts, which describe the VALUE
2804
+ * ("object null", "number 5", ...) instead of spelling the expression. */
2805
+ void scr_dyn_pack_push_spread_iter(ScrDyn *pack, const ScrDyn *src);
2806
+ ScrDyn *scr_dyn_assign_all(ScrDyn *target, const ScrDyn *sources);
2721
2807
  ScrDyn *scr_dyn_obj_values(const ScrDyn *v);
2722
2808
  ScrDyn *scr_dyn_obj_entries(const ScrDyn *v);
2723
2809
 
@@ -2735,6 +2821,9 @@ ScrDyn *scr_dyn_new_num(double n);
2735
2821
  ScrDyn *scr_dyn_new_str(ScrStr *s);
2736
2822
  ScrDyn *scr_dyn_new_arr(void);
2737
2823
  ScrDyn *scr_dyn_new_obj(void);
2824
+ /* Object.create(null): the fresh null-prototype dictionary (see the
2825
+ * null_proto flavor flag above). */
2826
+ ScrDyn *scr_dyn_new_obj_null_proto(void);
2738
2827
  /* Wraps a fresh COPY of the u8 payload (the static→dyn boundary copies —
2739
2828
  * DataView-backed sources copy their aliased window). Borrows b. */
2740
2829
  ScrDyn *scr_dyn_new_bytes_copy(const ScrBytes *b);
@@ -2753,6 +2842,12 @@ void scr_dyn_arr_push(ScrDyn *arr, ScrDyn *item);
2753
2842
  * nullish sources spell the spread expression (`what`), everything else is
2754
2843
  * the generic "Spread syntax requires ..." text. Borrows src. */
2755
2844
  void scr_dyn_arr_push_spread(ScrDyn *arr, const ScrDyn *src, const char *what);
2845
+ /* Destructuring pack over a DOM source: iterable kinds (arrays, strings by
2846
+ * code point, bytes) collect into a fresh array (+1); every other kind
2847
+ * throws V8's destructuring TypeError — `msg` verbatim when non-empty (the
2848
+ * compile-time source spelling), else the runtime kind wording. Borrows
2849
+ * both; NULL with the exception pending on the throw. */
2850
+ ScrDyn *scr_dyn_iter_pack(const ScrDyn *src, const ScrStr *msg);
2756
2851
  void scr_dyn_obj_set(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value);
2757
2852
  /* The checked-dynamic keyed WRITE (`h.k = v` on a dyn receiver): OBJ sets
2758
2853
  * the member (JS: later writes win, insertion order); undefined/null and
@@ -2766,6 +2861,10 @@ ScrStr *scr_dyn_typeof(const ScrDyn *d);
2766
2861
  * enc — utf8 default; strings/numbers/booleans/arrays/objects answer
2767
2862
  * JS-exactly; undefined/null throw the catchable TypeError). Borrows; +1. */
2768
2863
  ScrStr *scr_dyn_to_string(const ScrDyn *d, const ScrStr *enc);
2864
+ /* The method-call spelling `d.toString(enc?)`: identical, except a
2865
+ * null-prototype dictionary throws "<what> is not a function" — its
2866
+ * prototype chain has no toString (Node's answer). */
2867
+ ScrStr *scr_dyn_to_string_method(const ScrDyn *d, const ScrStr *enc, const ScrStr *what);
2769
2868
  /* JS String() over the DOM kind (units render "null"/"undefined" where
2770
2869
  * scr_dyn_to_string throws) — the web globals' WebIDL ToString. +1. */
2771
2870
  ScrStr *scr_dyn_string_coerce(const ScrDyn *d);
@@ -2943,6 +3042,87 @@ ScrDyn *scr_dyn_new_promise_adapting(ScrPromise *src,
2943
3042
  /* BORROWED peek at the boxed promise; NULL when d is not a promise box. */
2944
3043
  ScrPromise *scr_dyn_promise_of(const ScrDyn *d);
2945
3044
 
3045
+ /* ── island values in the DOM (SCR_DYN_JSVAL) ─────────────────────────
3046
+ * Engine routing ops for JSVAL nodes, installed by the gated constructor
3047
+ * (scr_dyn_from_jsval, scr_island.c — the scr_dyn_alloc_promise hook
3048
+ * story: JSVAL nodes exist only after the constructor ran, so the ops
3049
+ * are always installed when a dispatch arm meets the kind, and a
3050
+ * dynamic-free link never references engine symbols). Contracts mirror
3051
+ * the scr_jsval_* entries they route to. */
3052
+ typedef struct ScrDynJsvalOps {
3053
+ void (*release)(ScrJsval *cell);
3054
+ ScrStr *(*type_of)(ScrJsval *cell); /* engine typeof; +1, never throws */
3055
+ bool (*truthy)(ScrJsval *cell); /* engine ToBoolean; never throws */
3056
+ /* String(v) in the engine (the full ToString protocol — user toString
3057
+ * runs, its throw bridges): +1, or NULL with the exception pending. */
3058
+ ScrStr *(*to_str)(ScrJsval *cell);
3059
+ bool (*strict_eq)(ScrJsval *a, ScrJsval *b); /* engine ===; never throws */
3060
+ bool (*is_array)(ScrJsval *cell); /* Array.isArray, engine-side */
3061
+ bool (*is_error)(ScrJsval *cell); /* native Error instance, engine-side */
3062
+ /* ── the routed operation set (lane dyn-routing-ops) ────────────────
3063
+ * Each routes to the engine at the moment of use and converts at the
3064
+ * boundary: dyn ARGUMENTS cross through scr_jsval_from_dyn (wrapped
3065
+ * cells unwrap by reference, DOM data deep-copies, DOM FUNC boxes
3066
+ * cross through the generic host-function shim), engine RESULTS come
3067
+ * back through scr_dyn_from_jsval (scalar-normalizing). Fallible ops
3068
+ * bridge the ENGINE's exception catchably and answer NULL/false/-1. */
3069
+ ScrDyn *(*key_get)(ScrJsval *cell, const ScrStr *k); /* o[k]; +1 or NULL pending */
3070
+ bool (*key_set)(ScrJsval *cell, const ScrStr *k, const ScrDyn *v); /* false = pending */
3071
+ ScrDyn *(*call)(ScrJsval *cell, ScrDyn *const *args, size_t argc); /* f(...); +1 or NULL pending */
3072
+ /* o.m(...) — the ENGINE's own prototypes run (JS-exact flatMap/map/
3073
+ * forEach/...). A missing or non-callable member throws Node's
3074
+ * "<what> is not a function" (the call site's spelling — V8's text,
3075
+ * front-run before the engine's terser claim). */
3076
+ ScrDyn *(*invoke)(ScrJsval *cell, const char *method, ScrDyn *const *args, size_t argc, const char *what);
3077
+ bool (*is_nullish)(ScrJsval *cell); /* engine undefined/null; never throws
3078
+ * (always false today — the wrap
3079
+ * constructor scalar-normalizes) */
3080
+ /* Object.keys/values/entries (mode 0/1/2) as a NATIVE DOM array (+1):
3081
+ * keys are DOM strings, values wrap per element, entries are native
3082
+ * DOM pairs. NULL with the engine's exception pending on refusal. */
3083
+ ScrDyn *(*obj_walk)(ScrJsval *cell, int mode);
3084
+ int (*has_own)(ScrJsval *cell, const ScrStr *k); /* 0/1; -1 = pending */
3085
+ /* Object.assign(target, src) with the ENGINE target: src converts per
3086
+ * member semantics (a wrapped src spreads by reference; DOM data
3087
+ * enters as the usual deep copy). false = pending. */
3088
+ bool (*assign)(ScrJsval *cell, const ScrDyn *src);
3089
+ /* JSON.stringify text of the engine value (+1) — the engine's own
3090
+ * stringify (toJSON protocols, cycle TypeErrors). NULL + pending when
3091
+ * not JSON-representable. */
3092
+ ScrStr *(*to_json)(ScrJsval *cell);
3093
+ } ScrDynJsvalOps;
3094
+
3095
+ /* The allocator view the gated constructor uses (installs the ops);
3096
+ * ownership of `cell` MOVES in (the caller retains first). */
3097
+ ScrDyn *scr_dyn_alloc_jsval(ScrJsval *cell, const ScrDynJsvalOps *ops);
3098
+ /* The installed ops (traps on a missing install — impossible unless a
3099
+ * JSVAL node was forged without the constructor). */
3100
+ const ScrDynJsvalOps *scr_dyn_jsval_ops(void);
3101
+ /* dynTest arms that need the ENGINE's answer on a JSVAL node. Each
3102
+ * answers false for every other kind (callers test unconditionally —
3103
+ * the emitted narrowing tests stay branch-free). Never throw. */
3104
+ bool scr_dyn_isl_typeof_is(const ScrDyn *d, const char *name);
3105
+ bool scr_dyn_isl_is_array(const ScrDyn *d);
3106
+ bool scr_dyn_isl_is_error(const ScrDyn *d);
3107
+ /* The JSVAL honesty ladder: when d is a JSVAL node, THROWS the catchable
3108
+ * "<what> on an island value held in 'unknown' is not supported yet"
3109
+ * Error and returns false; every other kind returns false untouched.
3110
+ * Callers gate un-armed operations with it — never a silent wrong
3111
+ * answer (the retired fence-box bug). */
3112
+ bool scr_dyn_isl_fence(const ScrDyn *d, const char *what);
3113
+ /* The emitted keyed READ's JSVAL arm (sc_dyn_key_get): routes o[k] to the
3114
+ * engine through the installed ops and wraps the result back (+1, scalars
3115
+ * normalized) — the retired `.length -> fence` row. d MUST be a JSVAL
3116
+ * node; NULL with the engine's exception bridged catchably. */
3117
+ ScrDyn *scr_dyn_isl_key_get(const ScrDyn *d, const ScrStr *k);
3118
+ /* The `??`/optional-chain nullish test over a DOM value: UNDEF/NULL
3119
+ * native, JSVAL through the engine's own test (defensively — the wrap
3120
+ * constructor scalar-normalizes engine null/undefined away), every other
3121
+ * kind false. Never throws. */
3122
+ bool scr_dyn_is_nullish(const ScrDyn *d);
3123
+ /* scr_dyn_isl_tostr_buf (the display walkers' JSVAL arm) is declared
3124
+ * with the ScrJsonBuf surface below. */
3125
+
2946
3126
  /* ── the ambient receiver (JS `this` inside listener/callback bodies) ──
2947
3127
  * Node calls a handle's listeners with `this` bound to the emitting
2948
3128
  * handle (server.listen(0, function() { this.address().port })), and a
@@ -2991,6 +3171,24 @@ const char *scr_dyn_specific_type(const ScrDyn *v, char *buf, size_t cap);
2991
3171
  * error.argTypeThrow libCall). Borrows all three; always throws. */
2992
3172
  void scr_throw_arg_type(const ScrStr *argname, const ScrStr *expected, const ScrDyn *got);
2993
3173
  void scr_dyn_arg_type_fail(const char *argname, const char *expected, const ScrDyn *got);
3174
+ /* The property flavor ("The \"options.x\" property must be ...") — the
3175
+ * option-bag validators' gate (error.propTypeThrow). Always throws. */
3176
+ void scr_throw_prop_type(const ScrStr *name, const ScrStr *expected, const ScrDyn *got);
3177
+ void scr_dyn_prop_type_fail(const char *name, const char *expected, const ScrDyn *got);
3178
+ /* Node's ERR_INVALID_ARG_VALUE ("The argument 'encoding' is invalid
3179
+ * encoding. Received 'no'") — reason NULL renders "is invalid".
3180
+ * TypeError; always throws catchably. */
3181
+ void scr_dyn_arg_value_fail(const char *name, const char *reason, const ScrDyn *got);
3182
+ /* The ERR_INVALID_ARG_VALUE/%j "Received" renderer (inspect-lite:
3183
+ * strings quote, scalars print plain, deep shapes sketch). */
3184
+ const char *scr_dyn_inspect_lite(const ScrDyn *v, char *buf, size_t cap);
3185
+ /* A ladder's post-validation refuse: throws the compiler-rendered SC2020
3186
+ * statement-fence text verbatim (Node's validation errors run first). */
3187
+ void scr_throw_lowering_fence(const ScrStr *msg);
3188
+ /* ERR_OUT_OF_RANGE's "Received" number rendering (Node's
3189
+ * addNumericalSeparator underscores past 2^32) — scr_bytes.c's renderer,
3190
+ * shared by the fs/net/tls option-ladder validators. */
3191
+ size_t scr_num_received(double v, char out[48]);
2994
3192
  /* Listener-closure builders for the handle dispatchers' .on(...) paths:
2995
3193
  * a runtime-built ScrClosure whose capture is the boxed dyn listener and
2996
3194
  * whose invoke boxes the event tuple back into the DOM and calls through
@@ -3065,6 +3263,12 @@ void scr_jb_put_f64(ScrJsonBuf *b, double v);
3065
3263
  * as \u00XX, everything else (UTF-8 included) verbatim — exactly the JS
3066
3264
  * JSON.stringify escape set for well-formed strings. */
3067
3265
  void scr_jb_put_json_str(ScrJsonBuf *b, const ScrStr *s);
3266
+ /* String(v) of a JSVAL node appended into b (the emitted sc_ds display
3267
+ * walkers' arm; scr_dyn_display/to_string route here too): the engine's
3268
+ * ToString. A bridged failure (throwing user toString, a symbol) leaves
3269
+ * the exception PENDING and appends nothing — the loud path, never a
3270
+ * fabricated rendering. */
3271
+ void scr_dyn_isl_tostr_buf(ScrJsonBuf *b, const ScrDyn *d);
3068
3272
  /* JSON-serialize a DOM value into the buffer — the sc_jw_* walker for the
3069
3273
  * dyn leaves the compiler cannot type: object members holding undefined
3070
3274
  * DROP, array slots holding undefined print null (exactly Node). */
@@ -3312,6 +3516,11 @@ bool scr_immediate_has_ref(double handle);
3312
3516
  * teardown (they must never run yet must not leak). cb ownership moves
3313
3517
  * in. */
3314
3518
  void scr_next_tick(ScrClosure *cb);
3519
+ /* A raw C-hook entry on the SAME queue: the stream unit enqueues one
3520
+ * marker per deferred stream emission, so stream ticks and user
3521
+ * nextTicks run in true FIFO order (in Node they are the same queue).
3522
+ * Teardown drops markers without running them. */
3523
+ void scr_next_tick_raw(void (*fn)(void));
3315
3524
  void scr_nticks_teardown(void);
3316
3525
  /* ── the events unit (scr_events.c — OPTIONAL, link-gated) ────────────
3317
3526
  * Process signal/exit events and the piped-stdin surface. The unit links
@@ -3738,11 +3947,27 @@ ScrJsval *scr_jsval_from_f64(double v);
3738
3947
  ScrJsval *scr_jsval_from_bool(bool v);
3739
3948
  ScrJsval *scr_jsval_from_str(const ScrStr *s);
3740
3949
  ScrJsval *scr_jsval_from_json(const ScrStr *json);
3741
- /* A CHECKED-DYNAMIC (DOM) value entering the island — deep copy, data
3742
- * kinds only (a boxed function/handle/promise throws the catchable
3743
- * TypeError). NULL with a pending exception on failure. Borrows d. */
3950
+ /* A CHECKED-DYNAMIC (DOM) value entering the island — deep copy for data
3951
+ * kinds (a boxed handle/promise throws the catchable TypeError). A JSVAL
3952
+ * node unwraps to its OWN cell (+1) an engine value that crossed into
3953
+ * the DOM and back is the SAME engine value, by reference (nested JSVAL
3954
+ * members embed their engine values directly). A boxed FUNCTION crosses
3955
+ * as one generic host-function shim over its uniform ScrDynThunk: the
3956
+ * shim wraps engine arguments as DOM values (scalar-normalizing), calls
3957
+ * the thunk, and converts the DOM result back — each crossing mints a
3958
+ * fresh engine function (identity is not preserved for re-crossings;
3959
+ * SEMANTICS.md). NULL with a pending exception on failure. Borrows d. */
3744
3960
  ScrJsval *scr_jsval_from_dyn(const ScrDyn *d);
3745
3961
 
3962
+ /* The jsval→DOM crossing (the IR's dynFromJsval): wraps an island value
3963
+ * as a SCR_DYN_JSVAL node, SCALAR-NORMALIZING first — engine numbers/
3964
+ * strings/booleans/null/undefined convert to the native DOM kinds (the
3965
+ * strict exits cannot fail on engine-reported scalars), so JSVAL nodes
3966
+ * only ever hold engine objects/arrays/functions (and the symbol/bigint
3967
+ * edge). Installs the DOM's engine-routing ops on first use. Borrows
3968
+ * the cell (retains it into the node); +1 out; never throws. */
3969
+ ScrDyn *scr_dyn_from_jsval(ScrJsval *cell);
3970
+
3746
3971
  /* Engine operations. Arithmetic yields a fresh cell (NULL = bridged);
3747
3972
  * comparisons yield 0/1 (-1 = bridged); truthy/not never fail. */
3748
3973
  ScrJsval *scr_jsval_binop(int op, ScrJsval *a, ScrJsval *b);
@@ -4016,13 +4241,15 @@ double scr_bit_not(double a);
4016
4241
  /* ── typed arrays / Buffer (scr_bytes.c) ──────────────────────────────
4017
4242
  * ONE runtime representation for Uint8Array/Uint32Array/Float32Array,
4018
4243
  * Node's Buffer (a Uint8Array subclass), and DataView: a refcounted,
4019
- * MUTABLE, fixed-length element buffer. Typed arrays OWN their storage
4020
- * (backing == NULL) subarray()/slice() both COPY (slice matches JS;
4021
- * subarray's sharing is a documented divergence, SEMANTICS.md) so a
4022
- * typed array never aliases another and its byteOffset is always 0. The
4023
- * ONE view kind is DataView (scr_dataview_new): a u8-elem ScrBytes whose
4024
- * `data` points INTO an owner's storage and whose `backing` retains that
4025
- * owner, so reads/writes through the view alias the source JS-exactly.
4244
+ * MUTABLE, fixed-length element buffer. An ScrBytes either OWNS its
4245
+ * storage (backing == NULL, byteOffset 0) or is a VIEW: its `data` points
4246
+ * INTO an owner's storage and its `backing` retains that owner (chain
4247
+ * depth is always exactly 1 views over views resolve to the owner at
4248
+ * construction), so reads/writes through the view alias the source
4249
+ * JS-exactly. Views come from DataView (scr_dataview_new) and from
4250
+ * subarray()/Buffer-slice() (scr_bytes_subarray Buffer's slice is
4251
+ * subarray's deprecated alias in Node); only the plain typed arrays'
4252
+ * slice() copies (scr_bytes_slice, matching JS).
4026
4253
  * Elements are scalars only and the backing edge is acyclic by
4027
4254
  * construction (owners point at nothing): never part of a cycle, no
4028
4255
  * trace. Element reads widen to double; writes coerce JS-exactly (ToUint8
@@ -4045,10 +4272,10 @@ typedef struct ScrBytes {
4045
4272
  size_t len; /* ELEMENT count, fixed at construction */
4046
4273
  ScrBytesElem elem;
4047
4274
  uint8_t *data; /* len * elem_size bytes; owned unless backing is set */
4048
- /* NULL for owners (every typed array/Buffer). A DataView sets this to
4049
- * the retained OWNER it aliases (chain depth is always exactly 1: views
4050
- * over a view's .buffer resolve to the owner at construction) and its
4051
- * `data` points into backing->data — released, never freed. */
4275
+ /* NULL for owners. A view (DataView, subarray, Buffer-slice) sets this
4276
+ * to the retained OWNER it aliases (chain depth is always exactly 1:
4277
+ * views over views resolve to the owner at construction) and its `data`
4278
+ * points into backing->data — released, never freed. */
4052
4279
  struct ScrBytes *backing;
4053
4280
  } ScrBytes;
4054
4281
 
@@ -4153,10 +4380,21 @@ void scr_bytes_set(ScrBytes *b, double i, double v);
4153
4380
 
4154
4381
  /* TypedArray.prototype.slice(start, end): relative indices clamp like
4155
4382
  * string/array slice (ToIntegerOrInfinity, negatives from the end); the
4156
- * result is a fresh same-kind copy. subarray() lowers here too — a COPY,
4157
- * the documented divergence. Never throws. */
4383
+ * result is a fresh same-kind copy. Never throws. */
4158
4384
  ScrBytes *scr_bytes_slice(const ScrBytes *b, double start, double end); /* +1 */
4159
4385
 
4386
+ /* TypedArray.prototype.fill on non-u8 receivers: per-element fill with
4387
+ * the element write's coercion, slice-clamped relative indices; answers
4388
+ * the receiver +1 (chaining). Never throws. */
4389
+ ScrBytes *scr_bytes_fill_elem(ScrBytes *b, double v, double start, double end); /* +1 */
4390
+
4391
+ /* TypedArray.prototype.subarray(start, end) — and Buffer's slice(), its
4392
+ * deprecated alias: a same-elem VIEW aliasing the receiver's storage
4393
+ * (mutations visible both ways, JS-exactly). The view retains the OWNER
4394
+ * (chain depth exactly 1, the DataView rule) and its byteOffset composes.
4395
+ * Same index clamping as slice; never throws. */
4396
+ ScrBytes *scr_bytes_subarray(ScrBytes *b, double start, double end); /* +1 */
4397
+
4160
4398
  /* dst.set(src, offset): same-kind bulk copy (memmove — dst may be src).
4161
4399
  * offset goes through ToIntegerOrInfinity; a negative offset or
4162
4400
  * src.len + offset > dst.len THROWS Node's "offset is out of bounds"
@@ -4236,6 +4474,23 @@ ScrBytes *scr_buffer_new_string_fail(const ScrDyn *got);
4236
4474
  * numbers coerce (negatives answer now/1000), the rest throw Node's
4237
4475
  * ERR_INVALID_ARG_TYPE. Borrowed. */
4238
4476
  double scr_fs_to_unix_timestamp(const ScrDyn *t);
4477
+ /* The fs argument-validation ladders (the fs.*Chk libCalls): Node-order
4478
+ * validation over DOM values with Node's exact typed errors; a pass
4479
+ * meets the real operation where one exists (mkdtempSync, macOS
4480
+ * lchmodSync) or the compiler-rendered fence. All borrowed; the Chk
4481
+ * forms without results always leave an exception pending. */
4482
+ ScrDyn *scr_fs_exists_async(const ScrDyn *path, const ScrDyn *cb);
4483
+ void scr_fs_mkdtemp_chk(const ScrDyn *prefix, const ScrDyn *cb, const ScrStr *fence);
4484
+ ScrStr *scr_fs_mkdtemp_sync_chk(const ScrDyn *prefix, const ScrDyn *opts, const ScrStr *fence);
4485
+ void scr_fs_read_file_chk(const ScrDyn *path, const ScrDyn *opts, const ScrDyn *cb, const ScrStr *fence);
4486
+ void scr_fs_opendir_chk(const ScrDyn *path, const ScrDyn *opts, const ScrStr *fence);
4487
+ void scr_fs_watch_file_chk(const ScrDyn *path, const ScrDyn *listener, const ScrStr *fence);
4488
+ void scr_fs_lchmod_chk(const ScrDyn *path, const ScrDyn *mode, const ScrDyn *cb, const ScrStr *fence);
4489
+ ScrDyn *scr_fs_lchmod_sync_chk(const ScrDyn *path, const ScrDyn *mode);
4490
+ ScrPromise *scr_fsp_lchmod_chk(const ScrDyn *path, const ScrDyn *mode);
4491
+ void scr_fs_read_chk(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn *offset,
4492
+ const ScrDyn *length, const ScrDyn *position, const ScrStr *fence);
4493
+ void scr_fs_stream_opts_chk(const ScrDyn *path, const ScrDyn *opts, const ScrStr *fence);
4239
4494
  /* The checked-dynamic max-listeners ladders (scr_events_emitter.c). */
4240
4495
  ScrEmitter *scr_emitter_set_max_chk(ScrEmitter *em, const ScrDyn *n);
4241
4496
  void scr_emitter_set_default_max_chk(const ScrDyn *n, const ScrStr *name);
@@ -4503,6 +4758,16 @@ void scr_net_server_on_connection(ScrNetServer *s, ScrClosure *cb /*moves*/, Scr
4503
4758
  * server never fires it, like Node). */
4504
4759
  void scr_net_server_on_secure_connection(ScrNetServer *s, ScrClosure *cb /*moves*/, ScrNetConnFn fn, bool once);
4505
4760
  ScrNetSocket *scr_net_connect(double port, ScrStr *host /*borrowed, nullable*/, ScrClosure *cb /*moves, nullable*/); /* +1 */
4761
+ /* connect with a validated autoSelectFamilyAttemptTimeout option: the
4762
+ * budget runs Node's validateInt32-from-1 ladder (ERR_OUT_OF_RANGE /
4763
+ * ERR_INVALID_ARG_TYPE) and is then inert — the single dial has nothing
4764
+ * to time. +1, or NULL with the throw pending. */
4765
+ ScrNetSocket *scr_net_connect_attempt(double port, ScrStr *host /*borrowed*/, const ScrDyn *t /*borrowed*/);
4766
+ /* net.connect/createConnection over a RUNTIME option bag (computed
4767
+ * keys): Node-order validation (objectMode trio, port, host,
4768
+ * autoSelectFamily, attempt budget), then the compiler-rendered fence —
4769
+ * always leaves an exception pending. Borrowed. */
4770
+ void scr_net_connect_opts_chk(const ScrDyn *opts, const ScrStr *fence);
4506
4771
  /* connect with a caller lookup (net.connect({ ..., lookup })): invokes
4507
4772
  * lookup(hostname, options, answer-closure) synchronously; answer_fn is
4508
4773
  * the emitted per-shape thunk that decodes the answer down to
@@ -4717,6 +4982,13 @@ void scr_tls_h2_client_wrap(ScrNetSocket *sock, ScrStr *host /*borrowed*/, bool
4717
4982
  * the default pair, exactly Node. */
4718
4983
  typedef struct ScrSecureCtx ScrSecureCtx;
4719
4984
  ScrSecureCtx *scr_tls_create_secure_context(const char *cert, size_t cert_len, const char *key, size_t key_len); /* +1 */
4985
+ /* createSecureContext over a RUNTIME options record: Node's typed option
4986
+ * validations first, then the pem walk (+1, or NULL with the exception
4987
+ * pending). Borrowed. */
4988
+ ScrSecureCtx *scr_tls_create_secure_context_dyn(const ScrDyn *opts);
4989
+ /* tls.getCACertificates(type): validateString + the documented name set,
4990
+ * then the compiler-rendered fence — always leaves an exception pending. */
4991
+ void scr_tls_ca_certs_chk(const ScrDyn *type, const ScrStr *fence);
4720
4992
  ScrSecureCtx *scr_secure_ctx_retain(ScrSecureCtx *c);
4721
4993
  void scr_secure_ctx_release(ScrSecureCtx *c);
4722
4994
  void *scr_secure_ctx_retain_v(void *p);
@@ -5140,6 +5412,13 @@ void scr_dgram_bind(ScrDgramSocket *s, double port, ScrStr *host /*borrowed*/, S
5140
5412
  void scr_dgram_connect(ScrDgramSocket *s, double port, ScrStr *host /*borrowed*/, ScrClosure *cb /*moves, nullable*/);
5141
5413
  void scr_dgram_send_str(ScrDgramSocket *s, ScrStr *data /*borrowed*/, double port, ScrStr *host /*borrowed*/);
5142
5414
  void scr_dgram_send_bytes(ScrDgramSocket *s, ScrBytes *data /*borrowed*/, double port, ScrStr *host /*borrowed*/);
5415
+ /* The send argument-validation ladder over DOM arguments (Node's
5416
+ * signature shuffle, slice bounds, list/type contracts, port/address
5417
+ * validation, and the connected-state errors); a fully-validated
5418
+ * unconnected single-payload send RUNS, the rest meet the fence. */
5419
+ void scr_dgram_send_chk(ScrDgramSocket *s, const ScrDyn *buffer, const ScrDyn *a1,
5420
+ const ScrDyn *a2, const ScrDyn *a3, const ScrDyn *a4,
5421
+ const ScrStr *fence);
5143
5422
  /* address() parts: ip THROWS "Not running" before bind/connect (+1
5144
5423
  * otherwise); family/port are only called after ip succeeded. */
5145
5424
  ScrStr *scr_dgram_addr_ip(ScrDgramSocket *s); /* +1, may throw */