@scriptc/compiler 0.0.11 → 0.0.13

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.
Files changed (97) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +153 -24
  2. package/ambient/scriptc.d.ts +2 -2
  3. package/dist/backend/cc.d.ts +10 -2
  4. package/dist/backend/cc.js +12 -0
  5. package/dist/backend/cc.js.map +1 -1
  6. package/dist/backend/emission/emit-async.js +1 -1
  7. package/dist/backend/emission/emit-exprs.js +235 -64
  8. package/dist/backend/emission/emit-exprs.js.map +1 -1
  9. package/dist/backend/emission/emit-island.js +1 -1
  10. package/dist/backend/emission/emit-shapes.js +1 -1
  11. package/dist/backend/emission/emit-walkers.d.ts +14 -14
  12. package/dist/backend/emission/emit-walkers.js +44 -44
  13. package/dist/backend/emission/emit-walkers.js.map +1 -1
  14. package/dist/backend/emission/emitter.d.ts +3 -3
  15. package/dist/backend/emission/emitter.js +8 -8
  16. package/dist/backend/emission/may-throw.js +1 -1
  17. package/dist/backend/llvm/dyn.d.ts +10 -10
  18. package/dist/backend/llvm/dyn.js +26 -26
  19. package/dist/backend/llvm/dyn.js.map +1 -1
  20. package/dist/backend/llvm/emitter.js +140 -49
  21. package/dist/backend/llvm/emitter.js.map +1 -1
  22. package/dist/backend/llvm/shapes.js +1 -1
  23. package/dist/backend/llvm/walkers.js +2 -2
  24. package/dist/backend/llvm/walkers.js.map +1 -1
  25. package/dist/diagnostics/diagnostic.d.ts +1 -1
  26. package/dist/diagnostics/diagnostic.js +4 -3
  27. package/dist/diagnostics/diagnostic.js.map +1 -1
  28. package/dist/frontend/lowering/crypto-tables.d.ts +7 -0
  29. package/dist/frontend/lowering/crypto-tables.js +139 -0
  30. package/dist/frontend/lowering/crypto-tables.js.map +1 -0
  31. package/dist/frontend/lowering/lib-boundary.js +5 -5
  32. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  33. package/dist/frontend/lowering/lower-assert.js +12 -12
  34. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  35. package/dist/frontend/lowering/lower-builtins.d.ts +45 -27
  36. package/dist/frontend/lowering/lower-builtins.js +203 -70
  37. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  38. package/dist/frontend/lowering/lower-calls.d.ts +4 -4
  39. package/dist/frontend/lowering/lower-calls.js +74 -66
  40. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  41. package/dist/frontend/lowering/lower-classes.js +41 -7
  42. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  43. package/dist/frontend/lowering/lower-containers.d.ts +5 -5
  44. package/dist/frontend/lowering/lower-containers.js +19 -19
  45. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  46. package/dist/frontend/lowering/lower-emitter.js +2 -2
  47. package/dist/frontend/lowering/lower-emitter.js.map +1 -1
  48. package/dist/frontend/lowering/lower-exprs.d.ts +7 -7
  49. package/dist/frontend/lowering/lower-exprs.js +227 -119
  50. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  51. package/dist/frontend/lowering/lower-inspect.js +5 -5
  52. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  53. package/dist/frontend/lowering/lower-island.js +12 -3
  54. package/dist/frontend/lowering/lower-island.js.map +1 -1
  55. package/dist/frontend/lowering/lower-modules.js +17 -17
  56. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  57. package/dist/frontend/lowering/lower-namespaces.d.ts +11 -1
  58. package/dist/frontend/lowering/lower-namespaces.js +41 -6
  59. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  60. package/dist/frontend/lowering/lower-server.d.ts +21 -0
  61. package/dist/frontend/lowering/lower-server.js +278 -23
  62. package/dist/frontend/lowering/lower-server.js.map +1 -1
  63. package/dist/frontend/lowering/lower-stmts.d.ts +1 -1
  64. package/dist/frontend/lowering/lower-stmts.js +195 -34
  65. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  66. package/dist/frontend/lowering/lower-stream.js +67 -23
  67. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  68. package/dist/frontend/lowering/lowerer.d.ts +31 -13
  69. package/dist/frontend/lowering/lowerer.js +99 -45
  70. package/dist/frontend/lowering/lowerer.js.map +1 -1
  71. package/dist/frontend/lowering/surfaces.d.ts +6 -0
  72. package/dist/frontend/lowering/surfaces.js +78 -2
  73. package/dist/frontend/lowering/surfaces.js.map +1 -1
  74. package/dist/frontend/program.js +1 -1
  75. package/dist/frontend/shared.js +7 -7
  76. package/dist/frontend/shared.js.map +1 -1
  77. package/dist/frontend/types.d.ts +2 -2
  78. package/dist/frontend/types.js +27 -15
  79. package/dist/frontend/types.js.map +1 -1
  80. package/dist/index.js +44 -8
  81. package/dist/index.js.map +1 -1
  82. package/dist/ir/nodes.d.ts +208 -106
  83. package/dist/ir/nodes.js +100 -22
  84. package/dist/ir/nodes.js.map +1 -1
  85. package/dist/ir/validate.js +96 -38
  86. package/dist/ir/validate.js.map +1 -1
  87. package/dist/library/int-infer.js +13 -0
  88. package/dist/library/int-infer.js.map +1 -1
  89. package/dist/library/profile.d.ts +8 -6
  90. package/dist/library/profile.js.map +1 -1
  91. package/dist/library/sidecar-validate.js +1 -1
  92. package/dist/library/sidecar-validate.js.map +1 -1
  93. package/dist/library/sidecar.d.ts +1 -1
  94. package/dist/library/sidecar.js +20 -7
  95. package/dist/library/sidecar.js.map +1 -1
  96. package/package.json +2 -2
  97. package/surface-manifest.json +289 -4
@@ -15,6 +15,7 @@ import { invalidJsonModuleDiag, requiresDynamicImportDiag } from "../../diagnost
15
15
  import { builtinModuleFnOf, FS_READDIR_DOCUMENTED_OPTIONS, FS_WATCH_DOCUMENTED_OPTIONS, FS_WRITE_FILE_DOCUMENTED_OPTIONS, QS_PARSE_DOCUMENTED_OPTIONS, QS_STRINGIFY_DOCUMENTED_OPTIONS, READLINE_DOCUMENTED_OPTIONS, builtinConstLit, fenceOrDropOptionKey, isChildSurfaceMember, } from "./surfaces.js";
16
16
  import { conditionalSpreadOf, lowerDynObjectLiteral } from "./lower-exprs.js";
17
17
  import { HTTP2_CONSTANTS } from "./http2-constants.js";
18
+ import { CRYPTO_CIPHERS, CRYPTO_CONSTANTS, CRYPTO_CURVES, CRYPTO_HASHES } from "./crypto-tables.js";
18
19
  import { timerStyleCallback } from "./lower-calls.js";
19
20
  import { registerHttpClientFnBinding } from "./lower-server.js";
20
21
  import { BOOL, BYTES_U8, CHILD_T, CHILDSTREAM_T, DYN, F64, FSWATCHER_T, PROCSTREAM_T, JSVAL, NULL_T, SEARCH_PARAMS_T, SPAWNRES_T, STRING, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, funcOf, isUnitType, typeEquals, typeKey } from "../../ir/nodes.js";
@@ -376,38 +377,60 @@ export function lowerCreateRequireCall(L, call, loc) {
376
377
  loc,
377
378
  };
378
379
  }
379
- /** True when `node` denotes the http2.constants OBJECT — any of its
380
- * spellings: `http2.constants` through a namespace/require binding, a
381
- * destructured or member-bound `constants` alias from the http2 module,
382
- * or `require("http2").constants` inline. The object itself never
383
- * materializes; each member read bakes as its literal. */
384
- export function isHttp2ConstantsExpr(L, node) {
380
+ /** The builtin modules whose `constants` object bakes as literals at
381
+ * every access site (the fs.constants precedent, scaled up): http2's
382
+ * full Node v24 table, and crypto's OpenSSL-constant table. The object
383
+ * itself never materializes at runtime. */
384
+ const BUILTIN_CONSTANTS_TABLES = {
385
+ http2: {
386
+ table: HTTP2_CONSTANTS,
387
+ hint: "the table bakes Node v24's 240 members as literals — this name is not one of them",
388
+ },
389
+ crypto: {
390
+ table: CRYPTO_CONSTANTS,
391
+ hint: "the table bakes Node v24's crypto.constants members as literals — this name is not one of them",
392
+ },
393
+ };
394
+ /** The module whose baked-constants OBJECT `node` denotes, or null — any
395
+ * of the spellings: `http2.constants`/`crypto.constants` through a
396
+ * namespace/require binding, a destructured or member-bound `constants`
397
+ * alias from the module, or `require("http2").constants` inline. The
398
+ * object itself never materializes; each member read bakes as its
399
+ * literal. */
400
+ export function builtinConstantsModuleOf(L, node) {
401
+ let module = null;
385
402
  if (ts.isPropertyAccessExpression(node) && !node.questionDotToken) {
386
403
  if (node.name.text !== "constants")
387
- return false;
404
+ return null;
388
405
  const bi = L.builtinMemberOf(node);
389
- if (bi && bi.module === "http2")
390
- return true;
391
- const spec = requireSpecOf(node.expression);
392
- return spec !== null && canonicalBuiltinModule(spec) === "http2";
406
+ if (bi)
407
+ module = bi.module;
408
+ else {
409
+ const spec = requireSpecOf(node.expression);
410
+ module = spec !== null ? canonicalBuiltinModule(spec) : null;
411
+ }
393
412
  }
394
- if (ts.isIdentifier(node)) {
413
+ else if (ts.isIdentifier(node)) {
395
414
  const bi = builtinImportOf(L, node);
396
- return bi !== null && bi.module === "http2" && bi.member === "constants";
415
+ if (bi !== null && bi.member === "constants")
416
+ module = bi.module;
397
417
  }
398
- return false;
418
+ return module !== null && own(BUILTIN_CONSTANTS_TABLES, module) !== undefined ? module : null;
399
419
  }
400
- /** `constants.NGHTTP2_CANCEL` (any http2.constants spelling) → the baked
401
- * literal; unknown members fence by name. Null when the receiver is not
402
- * the constants object (the property chain keeps trying). */
403
- export function lowerHttp2ConstantsProperty(L, expr) {
420
+ /** `constants.NGHTTP2_CANCEL` / `constants.SSL_OP_NO_TICKET` (any baked-
421
+ * constants spelling) → the literal; unknown members fence by name.
422
+ * Null when the receiver is not a baked constants object (the property
423
+ * chain keeps trying). */
424
+ export function lowerBuiltinConstantsProperty(L, expr) {
404
425
  if (expr.questionDotToken)
405
426
  return null;
406
- if (!isHttp2ConstantsExpr(L, expr.expression))
427
+ const module = builtinConstantsModuleOf(L, expr.expression);
428
+ if (module === null)
407
429
  return null;
408
- const value = own(HTTP2_CONSTANTS, expr.name.text);
430
+ const entry = BUILTIN_CONSTANTS_TABLES[module];
431
+ const value = own(entry.table, expr.name.text);
409
432
  if (value === undefined) {
410
- L.noLowering(`http2.constants.${expr.name.text}`, expr, "the table bakes Node v24's 240 members as literals — this name is not one of them");
433
+ L.noLowering(`${module}.constants.${expr.name.text}`, expr, entry.hint);
411
434
  }
412
435
  return builtinConstLit(value, locOf(expr));
413
436
  }
@@ -487,27 +510,30 @@ function perfNowFnValueOf(L) {
487
510
  }
488
511
  return name;
489
512
  }
490
- /** True for `const { NGHTTP2_CANCEL, ... } = http2.constants` — a plain
491
- * object destructure (identifier elements, renames allowed, no rest/
492
- * defaults/nesting) over the constants object whose every name is in
493
- * the table. The declaration is alias plumbing with no storage
494
- * (lowerVarDecl and collectGlobals both skip it); each USE reads its
495
- * baked literal (http2ConstantBindingOf). */
496
- export function http2ConstantsDestructureDecl(L, nameNode, init) {
513
+ /** True for `const { NGHTTP2_CANCEL, ... } = http2.constants` (and the
514
+ * crypto.constants twin) — a plain object destructure (identifier
515
+ * elements, renames allowed, no rest/defaults/nesting) over a baked
516
+ * constants object whose every name is in its table. The declaration is
517
+ * alias plumbing with no storage (lowerVarDecl and collectGlobals both
518
+ * skip it); each USE reads its baked literal
519
+ * (builtinConstantBindingOf). */
520
+ export function builtinConstantsDestructureDecl(L, nameNode, init) {
497
521
  if (!ts.isObjectBindingPattern(nameNode) || !init)
498
522
  return false;
499
- if (!isHttp2ConstantsExpr(L, init))
523
+ const module = builtinConstantsModuleOf(L, init);
524
+ if (module === null)
500
525
  return false;
526
+ const table = BUILTIN_CONSTANTS_TABLES[module].table;
501
527
  return nameNode.elements.every((el) => !el.dotDotDotToken &&
502
528
  el.initializer === undefined &&
503
529
  el.name !== undefined &&
504
530
  ts.isIdentifier(el.name) &&
505
531
  (el.propertyName === undefined || ts.isIdentifier(el.propertyName)) &&
506
- own(HTTP2_CONSTANTS, (el.propertyName ?? el.name).text) !== undefined);
532
+ own(table, (el.propertyName ?? el.name).text) !== undefined);
507
533
  }
508
- /** Resolves an identifier bound by an http2ConstantsDestructureDecl to its
509
- * baked literal value. Null for every other binding. */
510
- export function http2ConstantBindingOf(L, ident) {
534
+ /** Resolves an identifier bound by a builtinConstantsDestructureDecl to
535
+ * its baked literal value. Null for every other binding. */
536
+ export function builtinConstantBindingOf(L, ident) {
511
537
  const symbol = L.checker.getSymbolAtLocation(ident);
512
538
  const decl = symbol ? L.checker.declarationsOf(symbol)[0] : undefined;
513
539
  if (!decl || !ts.isBindingElement(decl) || decl.dotDotDotToken || decl.initializer)
@@ -517,14 +543,15 @@ export function http2ConstantBindingOf(L, ident) {
517
543
  const varDecl = decl.parent.parent;
518
544
  if (!ts.isVariableDeclaration(varDecl) || varDecl.initializer === undefined)
519
545
  return null;
520
- if (!isHttp2ConstantsExpr(L, varDecl.initializer))
546
+ const module = builtinConstantsModuleOf(L, varDecl.initializer);
547
+ if (module === null)
521
548
  return null;
522
549
  const key = decl.propertyName && ts.isIdentifier(decl.propertyName)
523
550
  ? decl.propertyName.text
524
551
  : decl.name !== undefined && ts.isIdentifier(decl.name) ? decl.name.text : null;
525
552
  if (key === null)
526
553
  return null;
527
- const value = own(HTTP2_CONSTANTS, key);
554
+ const value = own(BUILTIN_CONSTANTS_TABLES[module].table, key);
528
555
  if (value === undefined)
529
556
  return null;
530
557
  return builtinConstLit(value, locOf(ident));
@@ -587,7 +614,7 @@ function optionMember(p) {
587
614
  * utimes family runs on its time arguments: finite numbers pass
588
615
  * (negatives answer now/1000, Node's shape), numeric STRINGS coerce
589
616
  * through ToNumber's loose-equality gate, everything else throws
590
- * Node's exact ERR_INVALID_ARG_TYPE. The argument crosses as a DOM
617
+ * Node's exact ERR_INVALID_ARG_TYPE. The argument crosses as a dyn
591
618
  * value so the runtime renders the Received tail. Null when this is
592
619
  * not that call (the table fence stays for other shapes). */
593
620
  export function lowerFsToUnixTimestampCall(L, expr, bi, loc) {
@@ -605,7 +632,7 @@ export function lowerFsToUnixTimestampCall(L, expr, bi, loc) {
605
632
  /** The fs validation-ladder spoke (checked-dynamic lane, JS sources
606
633
  * only — TypeScript keeps its compile fences): implemented-namespace
607
634
  * calls whose misuse Node rejects with typed errors lower to fs.*Chk
608
- * libCalls that replicate the validation ladder over DOM values and
635
+ * libCalls that replicate the validation ladder over dyn values and
609
636
  * throw Node's exact ERR_INVALID_ARG_TYPE / ERR_INVALID_ARG_VALUE /
610
637
  * ERR_OUT_OF_RANGE — the honest tail (the real operation where one
611
638
  * exists, the compiler-rendered SC2020 fence otherwise) runs only
@@ -619,7 +646,7 @@ export function lowerFsLadderCall(L, expr, bi, loc) {
619
646
  const args = expr.arguments;
620
647
  if (args.some(ts.isSpreadElement))
621
648
  return null;
622
- // Every ladder argument crosses as a DOM value; an argument that
649
+ // Every ladder argument crosses as a dyn value; an argument that
623
650
  // cannot leaves the historical fence in place.
624
651
  const dynArg = (node) => {
625
652
  if (!node)
@@ -657,7 +684,7 @@ export function lowerFsLadderCall(L, expr, bi, loc) {
657
684
  // false THROUGH it, and the answer is asynchronous.
658
685
  // A provably-non-file `new URL('<literal>')` path (the suite's
659
686
  // https://foo probe): Node answers false through the callback
660
- // synchronously — the DOM has no URL kind, so the path slot
687
+ // synchronously — the checked-dynamic tree has no URL kind, so the path slot
661
688
  // carries the unvalidatable token instead (construction of a
662
689
  // parseable literal is effect-free; file: URLs keep the fence —
663
690
  // they would need the real path conversion).
@@ -779,7 +806,7 @@ export function lowerBuiltinModuleCall(L, expr, bi, fn, loc) {
779
806
  }
780
807
  // node:querystring — parse/stringify are entirely special-cased (the
781
808
  // sep/eq/options completions, parse's call-site-shaped dictionary
782
- // result, stringify's DOM-crossing object argument); decode/encode
809
+ // result, stringify's dyn-crossing object argument); decode/encode
783
810
  // are Node's own aliases of the pair (`const decode = parse` in the
784
811
  // module source) and take the same lowerings. escape/unescape ride
785
812
  // the generic table tail below.
@@ -817,7 +844,7 @@ export function lowerBuiltinModuleCall(L, expr, bi, fn, loc) {
817
844
  }
818
845
  }
819
846
  // node:diagnostics_channel — the module-level pub/sub surface. The
820
- // subscriber arguments box into the DOM (dyn) so JS harness wrappers
847
+ // subscriber arguments box into the checked-dynamic tree (dyn) so JS harness wrappers
821
848
  // (test/common's mustCall — a rest-args function value) and typed
822
849
  // closures both cross; publish and the Channel methods lower in
823
850
  // lowerDcChannelMethodCall over the f64 channel handle.
@@ -2484,7 +2511,7 @@ function isReadlineTyped(L, node) {
2484
2511
  function dcChannelNameArg(L, node) {
2485
2512
  return L.lowerExprExpecting(node, STRING);
2486
2513
  }
2487
- /** A diagnostics_channel subscriber as a DOM value: dyn callables pass
2514
+ /** A diagnostics_channel subscriber as a dyn value: dyn callables pass
2488
2515
  * through (test/common's mustCall wrapper — an untyped JS function
2489
2516
  * value), boxable typed closures ride dynFrom. Identity is preserved
2490
2517
  * either way, so unsubscribe(fn) finds the subscribe(fn) entry. */
@@ -2506,14 +2533,14 @@ function dcSubscriberArg(L, node) {
2506
2533
  canBoxFuncIntoDyn(cb.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
2507
2534
  return { kind: "dynFrom", value: cb, type: DYN, loc: locOf(node) };
2508
2535
  }
2509
- L.unsupported("SC1090", node, `channel subscribers of type '${L.fmt(cb.type)}' (subscribers cross as DOM functions — parameters must be dyn-representable)`);
2536
+ L.unsupported("SC1090", node, `channel subscribers of type '${L.fmt(cb.type)}' (subscribers cross as dyn functions — parameters must be dyn-representable)`);
2510
2537
  }
2511
- /** A published message as a DOM value: dyn passes through, everything
2538
+ /** A published message as a dyn value: dyn passes through, everything
2512
2539
  * in the dynFrom domain (JSON-safe data, bytes, %Error, boxable
2513
2540
  * functions, handle kinds) boxes; the rest fences with the domain named. */
2514
2541
  function dcMessageArg(L, node) {
2515
2542
  // An explicit `undefined` argument (tracePromise(fn, ctx, undefined,
2516
- // ...args) — Node's own no-this spelling) is the undefined DOM value,
2543
+ // ...args) — Node's own no-this spelling) is the undefined dyn value,
2517
2544
  // exactly what an omitted slot defaults to.
2518
2545
  if (ts.isIdentifier(node) && node.text === "undefined") {
2519
2546
  return dynUndefinedExpr(locOf(node));
@@ -2524,7 +2551,7 @@ function dcMessageArg(L, node) {
2524
2551
  if (canConvertToDyn(msg.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
2525
2552
  return { kind: "dynFrom", value: msg, type: DYN, loc: locOf(node) };
2526
2553
  }
2527
- L.unsupported("SC1090", node, `publishing '${L.fmt(msg.type)}' messages (messages cross as DOM values — JSON-safe data, Uint8Array, errors, and functions)`);
2554
+ L.unsupported("SC1090", node, `publishing '${L.fmt(msg.type)}' messages (messages cross as dyn values — JSON-safe data, Uint8Array, errors, and functions)`);
2528
2555
  }
2529
2556
  /** True when `node`'s checker type is diagnostics_channel's Channel
2530
2557
  * (stdlib provenance plus the ambient module, the readline.Interface
@@ -2565,7 +2592,7 @@ export function lowerDcChannelMethodCall(L, call, access) {
2565
2592
  // bindStore(store[, transform]) / unbindStore(store) / runStores(data,
2566
2593
  // fn[, thisArg[, ...args]]): the AsyncLocalStorage integration — the
2567
2594
  // store argument is the ALS f64 handle; the transform crosses as a
2568
- // DOM function (absent = identity, the undefined DOM value); runStores
2595
+ // dyn function (absent = identity, the undefined dyn value); runStores
2569
2596
  // enters the bound stores, publishes inside them, and forwards
2570
2597
  // this/arguments to fn exactly like the trace calls.
2571
2598
  if ((name === "bindStore" || name === "unbindStore") &&
@@ -2608,7 +2635,7 @@ function isAlsTyped(L, node) {
2608
2635
  }
2609
2636
  /** Method calls on AsyncLocalStorage receivers: run(store, fn, ...args),
2610
2637
  * exit(fn, ...args), getStore(), enterWith(store), disable() — over the
2611
- * f64 store handle (als.* libCalls; values cross as DOM values). Null
2638
+ * f64 store handle (als.* libCalls; values cross as dyn values). Null
2612
2639
  * for non-ALS receivers. */
2613
2640
  export function lowerAlsMethodCall(L, call, access) {
2614
2641
  if (call.questionDotToken || access.questionDotToken)
@@ -2678,8 +2705,8 @@ function isDcTracingChannelTyped(L, node) {
2678
2705
  L.isStdlibFile(d.getSourceFile()));
2679
2706
  }
2680
2707
  const DC_TRACE_EVENTS = ["start", "end", "asyncStart", "asyncEnd", "error"];
2681
- /** A TracingChannel handlers object as a DOM value: dyn passes through;
2682
- * an INLINE object literal of plain event-name properties builds the DOM
2708
+ /** A TracingChannel handlers object as a dyn value: dyn passes through;
2709
+ * an INLINE object literal of plain event-name properties builds the checked-dynamic tree
2683
2710
  * object member-by-member (each value through the message conversion —
2684
2711
  * closures box by identity, so unsubscribe still matches), covering the
2685
2712
  * `{ start: () => {} }` spelling whose record type (function members)
@@ -2708,7 +2735,7 @@ function dcHandlersArg(L, node) {
2708
2735
  }
2709
2736
  return dcMessageArg(L, node);
2710
2737
  }
2711
- /** A trace-call argument list's tail as ONE DOM array (dynArrLit over
2738
+ /** A trace-call argument list's tail as ONE dyn array (dynArrLit over
2712
2739
  * per-element conversions). Spread arguments fence — the built array
2713
2740
  * must mirror the call site's argument vector exactly. */
2714
2741
  function dcTraceArgsArr(L, args, loc) {
@@ -2721,9 +2748,9 @@ function dcTraceArgsArr(L, args, loc) {
2721
2748
  return { kind: "dynArrLit", elems, type: DYN, loc };
2722
2749
  }
2723
2750
  /** Method calls on TracingChannel receivers: subscribe/unsubscribe over
2724
- * a DOM handlers object, traceSync/traceCallback through the runtime's
2751
+ * a dyn handlers object, traceSync/traceCallback through the runtime's
2725
2752
  * publish choreography (dc.tcTraceSync/dc.tcTraceCallback — fn, context,
2726
- * thisArg, and the argument vector all cross as DOM values; context
2753
+ * thisArg, and the argument vector all cross as dyn values; context
2727
2754
  * defaults to a fresh `{}` and thisArg to undefined, Node's defaults),
2728
2755
  * and tracePromise through the reaction-fiber choreography
2729
2756
  * (dc.tcTracePromise — the result is the reaction promise, typed
@@ -2994,7 +3021,7 @@ export function strdecHelper(L, op, shapeId, loc) {
2994
3021
  }
2995
3022
  /** `JSON.parse(text)` / `JSON.stringify(value)`.
2996
3023
  * - parse → a may-throw `libCall` producing a dyn value (the runtime JSON
2997
- * DOM); malformed input throws a catchable SyntaxError-shaped string.
3024
+ * dyn); malformed input throws a catchable SyntaxError-shaped string.
2998
3025
  * The divergence override types the one-argument form `unknown`; the
2999
3026
  * lib's reviver form typechecks (returning `any`) and is fenced here.
3000
3027
  * - stringify → the type-DIRECTED `jsonStringify` node: the lib
@@ -3048,8 +3075,8 @@ export function lowerJsonMethodCall(L, call, access) {
3048
3075
  }
3049
3076
  // A dyn ROOT (`JSON.stringify(u)` over unknown / `{}` / `Object` /
3050
3077
  // `object` slots, the JSON.parse round-trip) serializes with the
3051
- // runtime's DOM walker instead of a type-directed serializer — the
3052
- // DOM is JSON-representable by construction (non-JSON values fenced
3078
+ // runtime's dyn walker instead of a type-directed serializer — the
3079
+ // dyn is JSON-representable by construction (non-JSON values fenced
3053
3080
  // at their conversion INTO the slot). Two edges, both documented:
3054
3081
  // a root the stringify drops (runtime undefined) produces the TEXT
3055
3082
  // "undefined" where Node produces the undefined VALUE (tsc's own lib
@@ -3268,6 +3295,41 @@ function lowerHashDigestChain(L, call, access) {
3268
3295
  }
3269
3296
  L.noLowering(`Hash.update of '${dataIr ? L.fmt(dataIr) : L.checker.typeToString(L.typeOf(dataNode))}' values`, dataNode, "string and Buffer/Uint8Array inputs are the lowered update forms");
3270
3297
  }
3298
+ /** The node:crypto introspection statics — build-time constants of the
3299
+ * compiled runtime, baked at the call site (the http2.constants stance
3300
+ * extended to calls): getFips() answers 0 (no FIPS provider can ever
3301
+ * load into a compiled binary — Node's own answer for a non-FIPS
3302
+ * build), and getCiphers()/getHashes()/getCurves() answer Node v24's
3303
+ * name lists as fresh string[] literals. The lists are INTROSPECTION
3304
+ * data (Node's contract is "names the provider recognizes"); the
3305
+ * operations behind the names keep their per-member fences — a program
3306
+ * that probes the list and then constructs a cipher fences at the
3307
+ * construction site, never here. Null for other members (the dispatch
3308
+ * keeps trying). */
3309
+ export function lowerCryptoModuleCall(L, expr, bi, loc) {
3310
+ if (bi.module !== "crypto")
3311
+ return null;
3312
+ const LISTS = {
3313
+ getCiphers: CRYPTO_CIPHERS,
3314
+ getHashes: CRYPTO_HASHES,
3315
+ getCurves: CRYPTO_CURVES,
3316
+ };
3317
+ const list = own(LISTS, bi.member);
3318
+ if (bi.member !== "getFips" && list === undefined)
3319
+ return null;
3320
+ if (expr.arguments.length !== 0) {
3321
+ L.noLowering(`crypto.${bi.member} with ${expr.arguments.length} arguments`, expr);
3322
+ }
3323
+ if (bi.member === "getFips") {
3324
+ return { kind: "numLit", value: 0, type: F64, loc };
3325
+ }
3326
+ return {
3327
+ kind: "arrayLit",
3328
+ elems: list.map((s) => ({ kind: "strLit", value: s, type: STRING, loc })),
3329
+ type: arrayOf(STRING),
3330
+ loc,
3331
+ };
3332
+ }
3271
3333
  /** Method calls on URL-typed receivers: `u.toString()` is Node's href
3272
3334
  * serialization (the href getter's libCall). Everything else the lib
3273
3335
  * declares fences member-qualified. Null for non-URL receivers. */
@@ -3390,7 +3452,7 @@ export function lowerSearchParamsMethodCall(L, call, access) {
3390
3452
  // One name/value slot, WHATWG USVString rules: statically-string
3391
3453
  // arguments lower directly; a symbol can never convert (V8's
3392
3454
  // TypeError, statically decided); everything else crosses into the
3393
- // DOM and coerces at runtime with the object protocol (a user
3455
+ // dyn and coerces at runtime with the object protocol (a user
3394
3456
  // toString/valueOf runs and its throw propagates).
3395
3457
  const strArg = (i) => {
3396
3458
  const node = args[i];
@@ -3402,7 +3464,7 @@ export function lowerSearchParamsMethodCall(L, call, access) {
3402
3464
  }
3403
3465
  let v;
3404
3466
  if (ts.isObjectLiteralExpression(node)) {
3405
- // Object literals take the DOM literal path directly (method
3467
+ // Object literals take the dyn literal path directly (method
3406
3468
  // members box as dyn functions — the typed record fence never
3407
3469
  // applies to the coercion probes).
3408
3470
  v = lowerDynObjectLiteral(L, node);
@@ -3415,7 +3477,7 @@ export function lowerSearchParamsMethodCall(L, call, access) {
3415
3477
  v = { kind: "dynFrom", value: raw, type: DYN, loc: raw.loc };
3416
3478
  }
3417
3479
  else if (raw.type.kind === "record") {
3418
- // A RECORD-represented value that cannot cross into the DOM (a
3480
+ // A RECORD-represented value that cannot cross into the checked-dynamic tree (a
3419
3481
  // func-carrying shape — the throwing-toString probes): run
3420
3482
  // ToPrimitive's string hint STATICALLY. A zero-parameter
3421
3483
  // toString func member is called (its throw propagates); a
@@ -3430,7 +3492,7 @@ export function lowerSearchParamsMethodCall(L, call, access) {
3430
3492
  tsMember.type.kind === "func" &&
3431
3493
  tsMember.type.params.length === 0 &&
3432
3494
  L.dynConvertible(tsMember.type)) {
3433
- // Box just the toString member into a fresh DOM carrier and
3495
+ // Box just the toString member into a fresh dyn carrier and
3434
3496
  // run the protocol at runtime — the boxed call propagates its
3435
3497
  // throw, string answers convert, and a bare (void) return is
3436
3498
  // ToString(undefined), all through one path.
@@ -3446,11 +3508,11 @@ export function lowerSearchParamsMethodCall(L, call, access) {
3446
3508
  };
3447
3509
  }
3448
3510
  else {
3449
- L.noLowering(`URLSearchParams.${name} with a '${L.fmt(raw.type)}' argument`, node, "string arguments are the lowered shape (other values coerce through the DOM — narrow unions first)");
3511
+ L.noLowering(`URLSearchParams.${name} with a '${L.fmt(raw.type)}' argument`, node, "string arguments are the lowered shape (other values coerce through the checked-dynamic tree — narrow unions first)");
3450
3512
  }
3451
3513
  }
3452
3514
  else {
3453
- L.noLowering(`URLSearchParams.${name} with a '${L.fmt(raw.type)}' argument`, node, "string arguments are the lowered shape (other values coerce through the DOM — narrow unions first)");
3515
+ L.noLowering(`URLSearchParams.${name} with a '${L.fmt(raw.type)}' argument`, node, "string arguments are the lowered shape (other values coerce through the checked-dynamic tree — narrow unions first)");
3454
3516
  }
3455
3517
  }
3456
3518
  return { kind: "libCall", fn: "dyn.toStringCoerce", args: [v], type: STRING, loc };
@@ -4552,7 +4614,7 @@ export function lowerQuerystringParseCall(L, call, loc) {
4552
4614
  return { kind: "libCall", fn: "qs.parse", args: [str, sep, eq, maxKeys], type: result, loc };
4553
4615
  }
4554
4616
  /** querystring.stringify / querystring.encode: the object crosses as a
4555
- * DOM value (dynFrom — JSON-safe records and, in JS sources, dyn values
4617
+ * dyn value (dynFrom — JSON-safe records and, in JS sources, dyn values
4556
4618
  * directly) and Node's encodeStringified rules run in the runtime
4557
4619
  * (scr_qs_stringify), so arrays expand to repeated keys and
4558
4620
  * null/undefined values are empty. The default encoder is the one
@@ -4844,19 +4906,29 @@ export function lowerProcessMethodCall(L, call, access) {
4844
4906
  // (test-event-emitter-special-event-names.js's process.on).
4845
4907
  const SIGNALS = { SIGINT: 2, SIGTERM: 15 };
4846
4908
  const signo = event !== null ? own(SIGNALS, event) : undefined;
4847
- // 'unhandledRejection': the listener crosses as a DOM function and
4909
+ // 'unhandledRejection': the listener crosses as a dyn function and
4848
4910
  // the loop-end report dispatches it (reason, promise) per
4849
4911
  // never-observed rejection instead of printing and exiting 1
4850
4912
  // (scr_async.c; the end-of-turn timing is a SEMANTICS.md
4851
- // divergence). `once`/`off` forms have no removal story yet.
4852
- if (event === "unhandledRejection" && member === "on") {
4913
+ // divergence). `once` auto-removes after one delivery and
4914
+ // `off`/`removeListener` remove by closure identity — the warning
4915
+ // registry's story. 'rejectionHandled' is the sibling registry:
4916
+ // under the loop-exhaustion model its ONE firing window is a
4917
+ // handler attached during an unhandledRejection listener (earlier
4918
+ // handling never enters the report at all — the same documented
4919
+ // divergence), dispatched synchronously with the promise.
4920
+ if (event === "unhandledRejection" || event === "rejectionHandled") {
4853
4921
  if (!ts.isExpressionStatement(call.parent)) {
4854
4922
  L.unsupported("SC1090", call, "chaining process listener registration (the result is void here — register each listener as its own statement)");
4855
4923
  }
4856
4924
  const cb = dcSubscriberArg(L, call.arguments[1]);
4857
- return { kind: "libCall", fn: "process.onUnhandledRejection", args: [cb], type: VOID, loc };
4925
+ const onceArg = { kind: "boolLit", value: member === "once", type: BOOL, loc };
4926
+ const fn = event === "unhandledRejection"
4927
+ ? (isOff ? "process.offUnhandledRejection" : "process.onUnhandledRejection")
4928
+ : (isOff ? "process.offRejectionHandled" : "process.onRejectionHandled");
4929
+ return { kind: "libCall", fn, args: isOff ? [cb] : [cb, onceArg], type: VOID, loc };
4858
4930
  }
4859
- // 'warning': the listener crosses as a DOM function; emitWarning
4931
+ // 'warning': the listener crosses as a dyn function; emitWarning
4860
4932
  // and the runtime deprecation sites dispatch synchronously
4861
4933
  // (SEMANTICS.md). off/removeListener remove by closure identity.
4862
4934
  if (event === "warning" && (member === "on" || isOff)) {
@@ -4873,7 +4945,7 @@ export function lowerProcessMethodCall(L, call, access) {
4873
4945
  };
4874
4946
  }
4875
4947
  if (signo === undefined && event !== "exit") {
4876
- L.noLowering(`process.${member}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, call.arguments[0], '"SIGINT", "SIGTERM", "exit", "warning", and "unhandledRejection" (on) are the supported process events (as literals)');
4948
+ L.noLowering(`process.${member}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, call.arguments[0], '"SIGINT", "SIGTERM", "exit", "warning", "unhandledRejection", and "rejectionHandled" are the supported process events (as literals)');
4877
4949
  }
4878
4950
  if (!ts.isExpressionStatement(call.parent)) {
4879
4951
  L.unsupported("SC1090", call, "chaining process listener registration (the result is void here — register each listener as its own statement)");
@@ -4931,7 +5003,7 @@ export function lowerProcessMethodCall(L, call, access) {
4931
5003
  }
4932
5004
  return { kind: "libCall", fn: "process.onExit", args: [cb, onceArg], type: VOID, loc };
4933
5005
  }
4934
- // process.emitWarning(...): the argument vector crosses as ONE DOM
5006
+ // process.emitWarning(...): the argument vector crosses as ONE dyn
4935
5007
  // array and the runtime applies Node's full grammar (string or Error
4936
5008
  // warning; type/ctor/options second; code/ctor third — wrong kinds
4937
5009
  // throw ERR_INVALID_ARG_TYPE). A single SPREAD of a checked-dynamic
@@ -5596,9 +5668,70 @@ export function lowerPromiseStaticCall(L, call, access) {
5596
5668
  };
5597
5669
  return { kind: "intrinsic", name: "promise.all", args: [entriesArr], type: resultT, loc };
5598
5670
  }
5671
+ // MIXED entries where some entry is already an ISLAND value (the
5672
+ // withPlugins shape: Promise.all([loadBuiltinPlugins(),
5673
+ // loadPlugins(plugins)]) with an 'any'-typed loader): the
5674
+ // ENGINE's own Promise.all runs — island entries pass through,
5675
+ // STATIC promises cross as real engine thenables (the reverse
5676
+ // bridge, payload-domain gated), plain values marshal per the
5677
+ // boundary — and the combined result stays an island value
5678
+ // (awaiting it rides the island→static promise bridge; element
5679
+ // reads are the routed keyed ops). All-static tuples keep the
5680
+ // typed fence hint below. --dynamic only by construction: jsval
5681
+ // entries exist only there.
5682
+ if (elems.some((e) => e.type.kind === "jsval")) {
5683
+ const diagsBefore = L.diags.length;
5684
+ try {
5685
+ const marshaled = argNode.elements.map((el, i) => L.jsvalIn(elems[i], el));
5686
+ return {
5687
+ kind: "jsOp",
5688
+ op: "callMethod",
5689
+ name: "all",
5690
+ args: [
5691
+ { kind: "jsOp", op: "globalGet", name: "Promise", args: [], type: JSVAL, loc },
5692
+ { kind: "jsOp", op: "arrLit", args: marshaled, type: JSVAL, loc },
5693
+ ],
5694
+ type: JSVAL,
5695
+ loc,
5696
+ };
5697
+ }
5698
+ catch (err) {
5699
+ // An entry outside every crossing domain: drop the boundary
5700
+ // diagnostics and let the shape fence below name the fix.
5701
+ if (!(err instanceof PoisonError))
5702
+ throw err;
5703
+ L.diags.splice(diagsBefore);
5704
+ }
5705
+ }
5599
5706
  L.noLowering("Promise.all over this argument shape", argNode, "the entries must share ONE promise type — Promise.all([p, q]) lowers when p and q are the same Promise<T>");
5600
5707
  }
5601
5708
  const entries = L.lowerExpr(argNode);
5709
+ // A NON-literal island argument (`Promise.all(plugins.map((p) =>
5710
+ // loadPlugin(p)))` — the loadPlugins shape, where the checker
5711
+ // spells `any[]`): the ENGINE's own Promise.all runs over the
5712
+ // marshaled array (an 'any' value passes through; an `any[]` value
5713
+ // lifts per element by reference), the result staying an island
5714
+ // value the static side awaits through the island→static bridge.
5715
+ if (entries.type.kind === "jsval" ||
5716
+ (entries.type.kind === "array" && entries.type.elem.kind === "jsval")) {
5717
+ const diagsBefore = L.diags.length;
5718
+ try {
5719
+ const arg = L.jsvalIn(entries, argNode);
5720
+ return {
5721
+ kind: "jsOp",
5722
+ op: "callMethod",
5723
+ name: "all",
5724
+ args: [{ kind: "jsOp", op: "globalGet", name: "Promise", args: [], type: JSVAL, loc }, arg],
5725
+ type: JSVAL,
5726
+ loc,
5727
+ };
5728
+ }
5729
+ catch (err) {
5730
+ if (!(err instanceof PoisonError))
5731
+ throw err;
5732
+ L.diags.splice(diagsBefore);
5733
+ }
5734
+ }
5602
5735
  if (entries.type.kind !== "array" || entries.type.elem.kind !== "promise") {
5603
5736
  // The heterogeneous-literal case: the checker's tuple overload
5604
5737
  // types the literal as a TUPLE of promises (a tuple-flagged record