@scriptc/compiler 0.1.3 → 0.1.5

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 (217) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +275 -62
  2. package/dist/backend/c/async.d.ts +25 -0
  3. package/dist/backend/c/async.js +167 -0
  4. package/dist/backend/c/async.js.map +1 -1
  5. package/dist/backend/c/c-emitter.d.ts +15 -1
  6. package/dist/backend/c/c-emitter.js +36 -11
  7. package/dist/backend/c/c-emitter.js.map +1 -1
  8. package/dist/backend/c/exprs.d.ts +2 -2
  9. package/dist/backend/c/exprs.js +556 -71
  10. package/dist/backend/c/exprs.js.map +1 -1
  11. package/dist/backend/c/stmts.js +5 -3
  12. package/dist/backend/c/stmts.js.map +1 -1
  13. package/dist/backend/c/types.d.ts +2 -3
  14. package/dist/backend/c/types.js +10 -1
  15. package/dist/backend/c/types.js.map +1 -1
  16. package/dist/backend/c/walkers.js +1 -1
  17. package/dist/backend/c/walkers.js.map +1 -1
  18. package/dist/backend/link-plan.d.ts +3 -1
  19. package/dist/backend/link-plan.js +3 -1
  20. package/dist/backend/link-plan.js.map +1 -1
  21. package/dist/backend/llvm/dyn.js +1 -1
  22. package/dist/backend/llvm/dyn.js.map +1 -1
  23. package/dist/backend/llvm/emitter.js +42 -12
  24. package/dist/backend/llvm/emitter.js.map +1 -1
  25. package/dist/backend/llvm/expr-bytes.d.ts +1 -2
  26. package/dist/backend/llvm/expr-bytes.js +28 -23
  27. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  28. package/dist/backend/llvm/expr-callbacks.d.ts +9 -0
  29. package/dist/backend/llvm/expr-callbacks.js +125 -0
  30. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  31. package/dist/backend/llvm/expr-containers.d.ts +1 -0
  32. package/dist/backend/llvm/expr-containers.js +32 -4
  33. package/dist/backend/llvm/expr-containers.js.map +1 -1
  34. package/dist/backend/llvm/expr-context.d.ts +19 -3
  35. package/dist/backend/llvm/expr-dispatch.js +1 -0
  36. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  37. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  38. package/dist/backend/llvm/expr-primitives.js +49 -13
  39. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  40. package/dist/backend/llvm/expr-primitives.test.d.ts +1 -0
  41. package/dist/backend/llvm/expr-primitives.test.js +38 -0
  42. package/dist/backend/llvm/expr-primitives.test.js.map +1 -0
  43. package/dist/backend/llvm/expr-stream-callbacks.d.ts +3 -0
  44. package/dist/backend/llvm/expr-stream-callbacks.js +69 -0
  45. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  46. package/dist/backend/llvm/lib-filesystem.js +80 -10
  47. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  48. package/dist/backend/llvm/lib-network.js +69 -10
  49. package/dist/backend/llvm/lib-network.js.map +1 -1
  50. package/dist/backend/llvm/lib-process.js +156 -6
  51. package/dist/backend/llvm/lib-process.js.map +1 -1
  52. package/dist/backend/llvm/lib-shared.js +100 -0
  53. package/dist/backend/llvm/lib-shared.js.map +1 -1
  54. package/dist/backend/llvm/lib-stream.js +23 -0
  55. package/dist/backend/llvm/lib-stream.js.map +1 -1
  56. package/dist/backend/native-toolchain.d.ts +5 -0
  57. package/dist/backend/native-toolchain.js +4 -1
  58. package/dist/backend/native-toolchain.js.map +1 -1
  59. package/dist/backend/runtime-pack.test.js +28 -10
  60. package/dist/backend/runtime-pack.test.js.map +1 -1
  61. package/dist/backend/targets.d.ts +7 -0
  62. package/dist/backend/targets.js +26 -0
  63. package/dist/backend/targets.js.map +1 -1
  64. package/dist/backend/targets.test.js +8 -1
  65. package/dist/backend/targets.test.js.map +1 -1
  66. package/dist/coverage/surface-manifest.js +14 -4
  67. package/dist/coverage/surface-manifest.js.map +1 -1
  68. package/dist/diagnostics/diagnostic.js +1 -1
  69. package/dist/diagnostics/diagnostic.js.map +1 -1
  70. package/dist/executable/executable-cache.d.ts +4 -0
  71. package/dist/executable/executable-cache.js +6 -1
  72. package/dist/executable/executable-cache.js.map +1 -1
  73. package/dist/executable/executable-cache.test.js +3 -3
  74. package/dist/executable/executable-cache.test.js.map +1 -1
  75. package/dist/frontend/fork-target.d.ts +17 -0
  76. package/dist/frontend/fork-target.js +256 -0
  77. package/dist/frontend/fork-target.js.map +1 -0
  78. package/dist/frontend/lowering/abstract-equality.d.ts +6 -0
  79. package/dist/frontend/lowering/abstract-equality.js +250 -0
  80. package/dist/frontend/lowering/abstract-equality.js.map +1 -0
  81. package/dist/frontend/lowering/containers/bytes.d.ts +1 -1
  82. package/dist/frontend/lowering/containers/bytes.js +6 -5
  83. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  84. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +7 -6
  85. package/dist/frontend/lowering/containers/string-and-regexp.js +237 -28
  86. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  87. package/dist/frontend/lowering/expressions/object-literals.js +8 -0
  88. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  89. package/dist/frontend/lowering/lower-assert.js +71 -2
  90. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  91. package/dist/frontend/lowering/lower-builtins.d.ts +54 -28
  92. package/dist/frontend/lowering/lower-builtins.js +957 -116
  93. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  94. package/dist/frontend/lowering/lower-calls.d.ts +32 -23
  95. package/dist/frontend/lowering/lower-calls.js +835 -206
  96. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  97. package/dist/frontend/lowering/lower-classes.js +41 -10
  98. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  99. package/dist/frontend/lowering/lower-containers.d.ts +7 -9
  100. package/dist/frontend/lowering/lower-containers.js +293 -51
  101. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  102. package/dist/frontend/lowering/lower-event-emitter.js +212 -21
  103. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  104. package/dist/frontend/lowering/lower-exprs.d.ts +12 -0
  105. package/dist/frontend/lowering/lower-exprs.js +263 -93
  106. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  107. package/dist/frontend/lowering/lower-inspect.d.ts +4 -0
  108. package/dist/frontend/lowering/lower-inspect.js +1 -1
  109. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  110. package/dist/frontend/lowering/lower-island.d.ts +6 -3
  111. package/dist/frontend/lowering/lower-island.js +182 -12
  112. package/dist/frontend/lowering/lower-island.js.map +1 -1
  113. package/dist/frontend/lowering/lower-modules.d.ts +6 -0
  114. package/dist/frontend/lowering/lower-modules.js +184 -38
  115. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  116. package/dist/frontend/lowering/lower-namespaces.js +7 -0
  117. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  118. package/dist/frontend/lowering/lower-server.d.ts +3 -5
  119. package/dist/frontend/lowering/lower-server.js +413 -54
  120. package/dist/frontend/lowering/lower-server.js.map +1 -1
  121. package/dist/frontend/lowering/lower-stmts.js +122 -19
  122. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  123. package/dist/frontend/lowering/lower-stream.d.ts +3 -0
  124. package/dist/frontend/lowering/lower-stream.js +7 -0
  125. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  126. package/dist/frontend/lowering/lowerer.d.ts +86 -9
  127. package/dist/frontend/lowering/lowerer.js +449 -74
  128. package/dist/frontend/lowering/lowerer.js.map +1 -1
  129. package/dist/frontend/lowering/optional-arguments.d.ts +9 -1
  130. package/dist/frontend/lowering/optional-arguments.js +67 -1
  131. package/dist/frontend/lowering/optional-arguments.js.map +1 -1
  132. package/dist/frontend/lowering/pairs-snapshot.d.ts +3 -1
  133. package/dist/frontend/lowering/pairs-snapshot.js +12 -4
  134. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  135. package/dist/frontend/lowering/surfaces.d.ts +34 -14
  136. package/dist/frontend/lowering/surfaces.js +177 -104
  137. package/dist/frontend/lowering/surfaces.js.map +1 -1
  138. package/dist/frontend/npm-static-declarations.d.ts +4 -0
  139. package/dist/frontend/npm-static-declarations.js +56 -0
  140. package/dist/frontend/npm-static-declarations.js.map +1 -1
  141. package/dist/frontend/npm-static-declarations.test.js +23 -2
  142. package/dist/frontend/npm-static-declarations.test.js.map +1 -1
  143. package/dist/frontend/npm-static-prune.d.ts +6 -0
  144. package/dist/frontend/npm-static-prune.js +203 -0
  145. package/dist/frontend/npm-static-prune.js.map +1 -0
  146. package/dist/frontend/npm-static-prune.test.d.ts +1 -0
  147. package/dist/frontend/npm-static-prune.test.js +48 -0
  148. package/dist/frontend/npm-static-prune.test.js.map +1 -0
  149. package/dist/frontend/npm-static.js +6 -5
  150. package/dist/frontend/npm-static.js.map +1 -1
  151. package/dist/frontend/npm.d.ts +15 -3
  152. package/dist/frontend/npm.js +87 -14
  153. package/dist/frontend/npm.js.map +1 -1
  154. package/dist/frontend/npm.test.js +76 -9
  155. package/dist/frontend/npm.test.js.map +1 -1
  156. package/dist/frontend/program.js +107 -14
  157. package/dist/frontend/program.js.map +1 -1
  158. package/dist/frontend/provenance.js +8 -3
  159. package/dist/frontend/provenance.js.map +1 -1
  160. package/dist/frontend/resolve.d.ts +6 -0
  161. package/dist/frontend/resolve.js +7 -4
  162. package/dist/frontend/resolve.js.map +1 -1
  163. package/dist/frontend/type-mapper.d.ts +5 -0
  164. package/dist/frontend/type-mapper.js +80 -29
  165. package/dist/frontend/type-mapper.js.map +1 -1
  166. package/dist/index.d.ts +8 -3
  167. package/dist/index.js +34 -41
  168. package/dist/index.js.map +1 -1
  169. package/dist/ir/analysis.d.ts +5 -3
  170. package/dist/ir/analysis.js +25 -11
  171. package/dist/ir/analysis.js.map +1 -1
  172. package/dist/ir/analysis.test.js +50 -2
  173. package/dist/ir/analysis.test.js.map +1 -1
  174. package/dist/ir/constant-tables.d.ts +17 -0
  175. package/dist/ir/constant-tables.js +99 -0
  176. package/dist/ir/constant-tables.js.map +1 -0
  177. package/dist/ir/constant-tables.test.d.ts +1 -0
  178. package/dist/ir/constant-tables.test.js +78 -0
  179. package/dist/ir/constant-tables.test.js.map +1 -0
  180. package/dist/ir/integer-ranges.d.ts +13 -0
  181. package/dist/ir/integer-ranges.js +122 -0
  182. package/dist/ir/integer-ranges.js.map +1 -0
  183. package/dist/ir/integer-ranges.test.d.ts +1 -0
  184. package/dist/ir/integer-ranges.test.js +63 -0
  185. package/dist/ir/integer-ranges.test.js.map +1 -0
  186. package/dist/ir/ir.d.ts +130 -76
  187. package/dist/ir/ir.js +69 -4
  188. package/dist/ir/ir.js.map +1 -1
  189. package/dist/ir/ir.test.js +20 -1
  190. package/dist/ir/ir.test.js.map +1 -1
  191. package/dist/ir/scalar-records.d.ts +8 -0
  192. package/dist/ir/scalar-records.js +216 -0
  193. package/dist/ir/scalar-records.js.map +1 -0
  194. package/dist/ir/scalar-records.test.d.ts +1 -0
  195. package/dist/ir/scalar-records.test.js +142 -0
  196. package/dist/ir/scalar-records.test.js.map +1 -0
  197. package/dist/ir/serialize.d.ts +1 -1
  198. package/dist/ir/serialize.js +1 -1
  199. package/dist/ir/serialize.js.map +1 -1
  200. package/dist/ir/validate.js +256 -20
  201. package/dist/ir/validate.js.map +1 -1
  202. package/dist/ir/validate.test.d.ts +1 -0
  203. package/dist/ir/validate.test.js +31 -0
  204. package/dist/ir/validate.test.js.map +1 -0
  205. package/dist/library/cache-primitives.d.ts +1 -1
  206. package/dist/library/cache-primitives.js +3 -3
  207. package/dist/library/cache-primitives.js.map +1 -1
  208. package/dist/library/fence-eval.js +11 -4
  209. package/dist/library/fence-eval.js.map +1 -1
  210. package/dist/library/int-infer.test.js +4 -4
  211. package/dist/library/int-infer.test.js.map +1 -1
  212. package/dist/library/library-cache.js +0 -1
  213. package/dist/library/library-cache.js.map +1 -1
  214. package/dist/library/library-cache.test.js +8 -8
  215. package/dist/library/library-cache.test.js.map +1 -1
  216. package/package.json +17 -17
  217. package/surface-manifest.json +186 -79
@@ -865,25 +865,26 @@ export function lowerServerCloseOverrideAssignment(lowerer, left, right, loc) {
865
865
  loc,
866
866
  };
867
867
  }
868
- /** `res.statusCode = 404` / `res.statusMessage = "Nope"` — Node's
869
- * writable ServerResponse properties (the implicit head reads them):
870
- * routed from lower-stmts' property-assignment path beside the
871
- * close-override hook. Null when the target isn't one of the two. */
868
+ /** Writable ServerResponse properties consulted by the implicit head and
869
+ * the strict body-length check. Null when the target isn't one of them. */
872
870
  export function lowerHttpResPropertyAssignment(lowerer, left, right, loc) {
873
871
  if (!ts.isPropertyAccessExpression(left) || left.questionDotToken)
874
872
  return null;
875
873
  const name = left.name.text;
876
- if (name !== "statusCode" && name !== "statusMessage")
874
+ if (name !== "statusCode" && name !== "statusMessage" &&
875
+ name !== "sendDate" && name !== "strictContentLength")
877
876
  return null;
878
877
  if (lowerer.mapTypeOf(lowerer.typeOf(left.expression))?.kind !== "httpRes")
879
878
  return null;
880
879
  if (!lowerer.isStdlibMember(left))
881
880
  return null;
882
- const receiver = lowerer.lowerExpr(left.expression);
881
+ const receiver = coerceToHandle(lowerer, left.expression, HTTPRES_T);
883
882
  const value = name === "statusCode"
884
883
  ? lowerer.lowerExprExpecting(right, F64)
885
- : lowerer.lowerExprExpecting(right, STRING);
886
- const fn = name === "statusCode" ? "http.resStatusSet" : "http.resStatusMsgSet";
884
+ : lowerer.lowerExprExpecting(right, name === "statusMessage" ? STRING : BOOL);
885
+ const fn = name === "statusCode" ? "http.resStatusSet"
886
+ : name === "statusMessage" ? "http.resStatusMsgSet"
887
+ : name === "sendDate" ? "http.resSendDateSet" : "http.resStrictContentLengthSet";
887
888
  return {
888
889
  kind: "exprStmt",
889
890
  expr: { kind: "libCall", fn, args: [receiver, value], type: VOID, loc },
@@ -924,6 +925,28 @@ function lowerNetServerMethodCall(lowerer, call, access) {
924
925
  const name = access.name.text;
925
926
  const loc = locOf(call);
926
927
  const args = call.arguments;
928
+ if (name === "setTimeout") {
929
+ if (args.length < 1 || args.length > 2)
930
+ lowerer.noLowering("server.setTimeout arguments", call, "pass milliseconds and an optional socket callback");
931
+ const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
932
+ const ms = lowerer.lowerExprExpecting(args[0], F64);
933
+ const cb = args.length === 2
934
+ ? lowerCallbackArg(lowerer, args[1], "server timeout callbacks", 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]).cb
935
+ : null;
936
+ const fn = cb === null ? "http.serverSetTimeout" : "http.serverSetTimeoutCb";
937
+ const callArgs = cb === null ? [receiver, ms] : [receiver, ms, cb];
938
+ if (resultIsDiscarded(call))
939
+ return { kind: "libCall", fn, args: callArgs, type: VOID, loc };
940
+ return receiverReturningCall(lowerer, fn, callArgs, NETSERVER_T, loc);
941
+ }
942
+ if (name === "closeAllConnections" || name === "closeIdleConnections") {
943
+ requireStatementPosition(lowerer, call, `server.${name}()`);
944
+ if (args.length !== 0)
945
+ lowerer.noLowering(`server.${name} arguments`, call, `${name}() takes no arguments`);
946
+ const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
947
+ const fn = name === "closeAllConnections" ? "http.serverCloseAllConnections" : "http.serverCloseIdleConnections";
948
+ return { kind: "libCall", fn, args: [receiver], type: VOID, loc };
949
+ }
927
950
  if (name === "listen") {
928
951
  if (args.length < 1 || args.length > 3) {
929
952
  lowerer.noLowering(`listen with ${args.length} arguments`, call, "the supported form is listen(port[, host][, callback]) — port 0 binds an ephemeral port");
@@ -1140,6 +1163,10 @@ function lowerNetServerMethodCall(lowerer, call, access) {
1140
1163
  const { cb } = lowerCallbackArg(lowerer, args[1], "close listeners", 0, () => false, "use ()", []);
1141
1164
  return { kind: "libCall", fn: "net.serverOnClose", args: [receiver, cb, once], type: VOID, loc };
1142
1165
  }
1166
+ if (event === "timeout") {
1167
+ const { cb } = lowerCallbackArg(lowerer, args[1], "timeout listeners", 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
1168
+ return { kind: "libCall", fn: "http.serverOnTimeout", args: [receiver, cb, once], type: VOID, loc };
1169
+ }
1143
1170
  if (event === "listening") {
1144
1171
  // The deferred bind emit — listen(port, cb)'s event twin: fires
1145
1172
  // once after a successful listen; late registrations on an
@@ -1517,6 +1544,23 @@ function headersSnapshotHelper(lowerer, shapeId, loc) {
1517
1544
  callArgs: [varRef("r.0", HTTPREQ_T, loc)],
1518
1545
  });
1519
1546
  }
1547
+ function trailersSnapshotHelper(lowerer, shapeId, loc) {
1548
+ return pairsSnapshotHelper(lowerer, shapeId, loc, {
1549
+ keyPrefix: "trailers",
1550
+ libCall: "http.reqTrailerPairs",
1551
+ params: [{ localId: "r.0", name: "r", type: HTTPREQ_T }],
1552
+ callArgs: [varRef("r.0", HTTPREQ_T, loc)],
1553
+ });
1554
+ }
1555
+ function distinctSnapshotHelper(lowerer, shapeId, loc, collection) {
1556
+ return pairsSnapshotHelper(lowerer, shapeId, loc, {
1557
+ keyPrefix: collection,
1558
+ libCall: collection === "headersDistinct" ? "http.reqHeaderPairs" : "http.reqTrailerPairs",
1559
+ lookupValue: collection === "headersDistinct" ? "http.reqHeaderValues" : "http.reqTrailerValues",
1560
+ params: [{ localId: "r.0", name: "r", type: HTTPREQ_T }],
1561
+ callArgs: [varRef("r.0", HTTPREQ_T, loc)],
1562
+ });
1563
+ }
1520
1564
  /** The `endStream` boolean of an h2 options object literal, as a literal
1521
1565
  * bool. Returns undefined when absent (or the arg is absent). Fences on
1522
1566
  * a non-literal endStream value or unknown keys that would matter. */
@@ -1789,6 +1833,10 @@ export function lowerServerProperty(lowerer, expr) {
1789
1833
  // req.headers.NAME — the `string | undefined` union (envGet's type).
1790
1834
  const recvKind = lowerer.mapTypeOf(lowerer.typeOf(expr.expression))?.kind;
1791
1835
  if (recvKind === "netServer" && lowerer.isStdlibMember(expr)) {
1836
+ if (expr.name.text === "listening") {
1837
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSERVER_T);
1838
+ return { kind: "libCall", fn: "net.serverListening", args: [receiver], type: BOOL, loc };
1839
+ }
1792
1840
  const field = httpServerTimeoutField(expr.name.text);
1793
1841
  if (field !== null) {
1794
1842
  const receiver = coerceToHandle(lowerer, expr.expression, NETSERVER_T);
@@ -1809,7 +1857,7 @@ export function lowerServerProperty(lowerer, expr) {
1809
1857
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1810
1858
  return { kind: "libCall", fn: "http.reqStatusCode", args: [receiver], type: lowerer.withUndefinedArm(F64), loc };
1811
1859
  }
1812
- if (name === "socket") {
1860
+ if (name === "socket" || name === "connection") {
1813
1861
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1814
1862
  return { kind: "libCall", fn: "http.reqSocket", args: [receiver], type: NETSOCKET_T, loc };
1815
1863
  }
@@ -1829,11 +1877,12 @@ export function lowerServerProperty(lowerer, expr) {
1829
1877
  const fn = name === "aborted" ? "http.reqAborted" : "http.reqComplete";
1830
1878
  return { kind: "libCall", fn, args: [receiver], type: BOOL, loc };
1831
1879
  }
1832
- if (name === "rawHeaders") {
1880
+ if (name === "rawHeaders" || name === "rawTrailers") {
1833
1881
  // [name, value, name, value, ...] in arrival order, names in their
1834
1882
  // ORIGINAL case — Node's shape; a fresh string[] per read.
1835
1883
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1836
- return { kind: "libCall", fn: "http.reqRawHeaders", args: [receiver], type: arrayOf(STRING), loc };
1884
+ const fn = name === "rawHeaders" ? "http.reqRawHeaders" : "http.reqRawTrailers";
1885
+ return { kind: "libCall", fn, args: [receiver], type: arrayOf(STRING), loc };
1837
1886
  }
1838
1887
  if (name === "statusMessage") {
1839
1888
  // `string | undefined` — the reason phrase on client responses (""
@@ -1870,19 +1919,21 @@ export function lowerServerProperty(lowerer, expr) {
1870
1919
  // guarded-no-op / unguarded-TypeError stance; other reads fence.
1871
1920
  lowerer.noLowering(`reading '${name}' (an HTTP/2-only member) from a request`, expr, "compatibility requests do not expose their backing h2 stream/session yet; guarded method calls no-op and other reads have no lowering");
1872
1921
  }
1873
- if (name === "headers") {
1874
- // `req.headers` as a VALUE — the `{ ...req.headers }` spread and
1875
- // record flows: a fresh snapshot record per read (Node's spread
1876
- // copies too; the per-name READS keep their direct lowerings).
1922
+ if (name === "headers" || name === "trailers" || name === "headersDistinct" || name === "trailersDistinct") {
1923
+ // Whole-object reads materialize a typed snapshot record. Per-name
1924
+ // reads retain their direct lowerings.
1877
1925
  const mapped = lowerer.mapTypeOf(lowerer.typeOf(expr));
1878
1926
  if (mapped?.kind === "record") {
1879
- const helper = headersSnapshotHelper(lowerer, mapped.shapeId, loc);
1927
+ const helper = name === "headers"
1928
+ ? headersSnapshotHelper(lowerer, mapped.shapeId, loc)
1929
+ : name === "trailers" ? trailersSnapshotHelper(lowerer, mapped.shapeId, loc)
1930
+ : distinctSnapshotHelper(lowerer, mapped.shapeId, loc, name);
1880
1931
  if (helper !== null) {
1881
1932
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1882
1933
  return { kind: "call", callee: helper, args: [receiver], type: mapped, loc };
1883
1934
  }
1884
1935
  }
1885
- lowerer.unsupported("SC1090", expr, "req.headers as a value of this type (read one header: req.headers.name or req.headers[name])");
1936
+ lowerer.unsupported("SC1090", expr, `req.${name} as a value of this type (read one field: req.${name}.name or req.${name}[name])`);
1886
1937
  }
1887
1938
  }
1888
1939
  if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "stream") {
@@ -1951,15 +2002,61 @@ export function lowerServerProperty(lowerer, expr) {
1951
2002
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
1952
2003
  return { kind: "libCall", fn: "http.clientDestroyed", args: [receiver], type: BOOL, loc };
1953
2004
  }
1954
- if (isHttpReqHeaders(lowerer, expr.expression)) {
2005
+ if (recvKind === "httpClientReq" && lowerer.isStdlibMember(expr) &&
2006
+ (expr.name.text === "socket" || expr.name.text === "connection")) {
2007
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
2008
+ return { kind: "libCall", fn: "http.clientSocket", args: [receiver], type: NETSOCKET_T, loc };
2009
+ }
2010
+ if (recvKind === "httpClientReq" && lowerer.isStdlibMember(expr) && expr.name.text === "writableCorked") {
2011
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
2012
+ return { kind: "libCall", fn: "http.clientWritableCorked", args: [receiver], type: F64, loc };
2013
+ }
2014
+ if (recvKind === "httpClientReq" && lowerer.isStdlibMember(expr)) {
2015
+ const name = expr.name.text;
2016
+ const strFn = name === "method" ? "http.clientMethod"
2017
+ : name === "path" ? "http.clientPath"
2018
+ : name === "host" ? "http.clientHost"
2019
+ : name === "protocol" ? "http.clientProtocol" : null;
2020
+ if (strFn !== null) {
2021
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
2022
+ return { kind: "libCall", fn: strFn, args: [receiver], type: STRING, loc };
2023
+ }
2024
+ const boolFn = name === "aborted" ? "http.clientAborted"
2025
+ : name === "headersSent" ? "http.clientHeadersSent"
2026
+ : name === "writableEnded" || name === "finished" ? "http.clientWritableEnded"
2027
+ : name === "writableFinished" ? "http.clientWritableFinished"
2028
+ : name === "reusedSocket" ? "http.clientReusedSocket" : null;
2029
+ if (boolFn !== null) {
2030
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
2031
+ return { kind: "libCall", fn: boolFn, args: [receiver], type: BOOL, loc };
2032
+ }
2033
+ }
2034
+ if (httpReqFieldCollection(lowerer, expr.expression) !== null) {
2035
+ const collection = httpReqFieldCollection(lowerer, expr.expression);
1955
2036
  const receiver = coerceToHandle(lowerer, expr.expression.expression, HTTPREQ_T);
1956
2037
  const key = { kind: "strLit", value: expr.name.text, type: STRING, loc };
1957
- return { kind: "libCall", fn: "http.reqHeader", args: [receiver, key], type: lowerer.envValueType(), loc };
2038
+ const fn = collection === "headers" ? "http.reqHeader"
2039
+ : collection === "trailers" ? "http.reqTrailer"
2040
+ : collection === "headersDistinct" ? "http.reqHeaderValues" : "http.reqTrailerValues";
2041
+ const type = collection.endsWith("Distinct") ? lowerer.withUndefinedArm(arrayOf(STRING)) : lowerer.envValueType();
2042
+ return { kind: "libCall", fn, args: [receiver, key], type, loc };
1958
2043
  }
1959
2044
  if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "headersSent") {
1960
2045
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
1961
2046
  return { kind: "libCall", fn: "http.resHeadersSent", args: [receiver], type: BOOL, loc };
1962
2047
  }
2048
+ if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "writableEnded") {
2049
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
2050
+ return { kind: "libCall", fn: "http.resWritableEnded", args: [receiver], type: BOOL, loc };
2051
+ }
2052
+ if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "finished") {
2053
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
2054
+ return { kind: "libCall", fn: "http.resWritableEnded", args: [receiver], type: BOOL, loc };
2055
+ }
2056
+ if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "writableCorked") {
2057
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
2058
+ return { kind: "libCall", fn: "http.resWritableCorked", args: [receiver], type: F64, loc };
2059
+ }
1963
2060
  if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "statusCode") {
1964
2061
  // 200 until assigned — Node's fresh-response default; the assignment
1965
2062
  // twin lives in lowerHttpResPropertyAssignment.
@@ -1967,11 +2064,30 @@ export function lowerServerProperty(lowerer, expr) {
1967
2064
  return { kind: "libCall", fn: "http.resStatusGet", args: [receiver], type: F64, loc };
1968
2065
  }
1969
2066
  if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "statusMessage") {
1970
- // The assigned reason phrase, or the current status code's default
1971
- // when none was set (Node answers undefined until the head goes out
1972
- // — divergence: this surface is string-typed, the checker's shape).
2067
+ // Unset until the head is sent; then the assigned or default reason.
1973
2068
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
1974
- return { kind: "libCall", fn: "http.resStatusMsgGet", args: [receiver], type: STRING, loc };
2069
+ return { kind: "libCall", fn: "http.resStatusMsgGet", args: [receiver], type: lowerer.withUndefinedArm(STRING), loc };
2070
+ }
2071
+ if (recvKind === "httpRes" && lowerer.isStdlibMember(expr)) {
2072
+ const name = expr.name.text;
2073
+ if (name === "req") {
2074
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
2075
+ return { kind: "libCall", fn: "http.resRequest", args: [receiver], type: HTTPREQ_T, loc };
2076
+ }
2077
+ if (name === "socket" || name === "connection") {
2078
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
2079
+ const type = { kind: "union", unionId: lowerer.unions.intern([NETSOCKET_T, NULL_T]) };
2080
+ return { kind: "libCall", fn: "http.resSocket", args: [receiver], type, loc };
2081
+ }
2082
+ if (name === "writableFinished") {
2083
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
2084
+ return { kind: "libCall", fn: "http.resWritableFinished", args: [receiver], type: BOOL, loc };
2085
+ }
2086
+ if (name === "sendDate" || name === "strictContentLength") {
2087
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
2088
+ const fn = name === "sendDate" ? "http.resSendDateGet" : "http.resStrictContentLengthGet";
2089
+ return { kind: "libCall", fn, args: [receiver], type: BOOL, loc };
2090
+ }
1975
2091
  }
1976
2092
  if (recvKind === "http2Session" && lowerer.isStdlibMember(expr)) {
1977
2093
  const m = expr.name.text;
@@ -2084,6 +2200,7 @@ function lowerHttpServerOptions(lowerer, node, what) {
2084
2200
  lowerer.noLowering(`${what} with a non-literal options argument`, node, "pass the options as an object literal: { requireHostHeader?, joinDuplicateHeaders? }");
2085
2201
  }
2086
2202
  let joinDup = false;
2203
+ let allowMissingHost = false;
2087
2204
  let keepAliveTimeoutBuffer = null;
2088
2205
  for (const prop of node.properties) {
2089
2206
  let initializer;
@@ -2099,13 +2216,15 @@ function lowerHttpServerOptions(lowerer, node, what) {
2099
2216
  }
2100
2217
  const key = prop.name.text;
2101
2218
  if (key === "requireHostHeader") {
2102
- // The literal `false` only: it asks for exactly this parser's
2103
- // behavior (requests without Host are served). Node's default
2104
- // (true: answer 400) is the behavior this slice does not have, so
2105
- // `true`/dynamic values fence instead of silently not enforcing.
2106
- if (initializer === null || initializer.kind !== ts.SyntaxKind.FalseKeyword) {
2107
- lowerer.noLowering(`${what} with a non-\`false\` requireHostHeader option`, prop, "this parser never answers 400 for a missing Host header — requireHostHeader: false is the honest (and only) lowered value");
2219
+ if (initializer !== null && initializer.kind === ts.SyntaxKind.FalseKeyword) {
2220
+ allowMissingHost = true;
2221
+ continue;
2222
+ }
2223
+ if (initializer !== null && initializer.kind === ts.SyntaxKind.TrueKeyword) {
2224
+ allowMissingHost = false;
2225
+ continue;
2108
2226
  }
2227
+ lowerer.noLowering(`${what} with a non-literal requireHostHeader option`, prop, "the lowered forms are the literals requireHostHeader: true and false");
2109
2228
  continue;
2110
2229
  }
2111
2230
  if (key === "joinDuplicateHeaders") {
@@ -2116,7 +2235,8 @@ function lowerHttpServerOptions(lowerer, node, what) {
2116
2235
  continue;
2117
2236
  }
2118
2237
  if (initializer !== null && initializer.kind === ts.SyntaxKind.FalseKeyword) {
2119
- continue; /* Node's default: repeats keep the first value */
2238
+ joinDup = false; /* Node's default: repeats keep the first value */
2239
+ continue;
2120
2240
  }
2121
2241
  lowerer.noLowering(`${what} with a non-literal joinDuplicateHeaders option`, prop, "the lowered forms are the literals joinDuplicateHeaders: true (repeats join \", \") and false (the keep-first default)");
2122
2242
  }
@@ -2139,10 +2259,10 @@ function lowerHttpServerOptions(lowerer, node, what) {
2139
2259
  keepAliveTimeoutBuffer = value;
2140
2260
  continue;
2141
2261
  }
2142
- fenceOrDropOptionKey(lowerer, prop, key, what, HTTP_SERVER_DOCUMENTED_OPTIONS, "requireHostHeader: false, joinDuplicateHeaders, and keepAliveTimeoutBuffer are the supported options");
2262
+ fenceOrDropOptionKey(lowerer, prop, key, what, HTTP_SERVER_DOCUMENTED_OPTIONS, "requireHostHeader, joinDuplicateHeaders, and keepAliveTimeoutBuffer are the supported options");
2143
2263
  // An undocumented key, dropped like Node drops it.
2144
2264
  }
2145
- return { joinDup, keepAliveTimeoutBuffer };
2265
+ return { joinDup, allowMissingHost, keepAliveTimeoutBuffer };
2146
2266
  }
2147
2267
  /** The shared createServer([options][, handler]) shapes behind
2148
2268
  * http.createServer, http.Server, and `new http.Server`: no arguments
@@ -2168,18 +2288,18 @@ function lowerHttpCreateServerForms(lowerer, expr, what, loc) {
2168
2288
  }
2169
2289
  const opts = optsNode !== null
2170
2290
  ? lowerHttpServerOptions(lowerer, optsNode, what)
2171
- : { joinDup: false, keepAliveTimeoutBuffer: null };
2291
+ : { joinDup: false, allowMissingHost: false, keepAliveTimeoutBuffer: null };
2172
2292
  const server = handlerNode !== null
2173
2293
  ? { kind: "libCall", fn: "http.createServer", args: [lowerRequestHandlerArg(lowerer, handlerNode)], type: NETSERVER_T, loc }
2174
2294
  : { kind: "libCall", fn: "http.createServerEmpty", args: [], type: NETSERVER_T, loc };
2175
- if (!opts.joinDup && opts.keepAliveTimeoutBuffer === null)
2295
+ if (!opts.joinDup && !opts.allowMissingHost && opts.keepAliveTimeoutBuffer === null)
2176
2296
  return server;
2177
2297
  // The option-setting composition: an interned helper takes the option
2178
2298
  // values first (preserving Node's options-before-handler evaluation
2179
2299
  // order), then the fresh server, applies the modeled fields, and answers
2180
2300
  // the server as the constructor/factory result.
2181
2301
  const hasBuffer = opts.keepAliveTimeoutBuffer !== null;
2182
- const key = `server.opts:${opts.joinDup ? 1 : 0}:${hasBuffer ? 1 : 0}`;
2302
+ const key = `server.opts:${opts.joinDup ? 1 : 0}:${opts.allowMissingHost ? 1 : 0}:${hasBuffer ? 1 : 0}`;
2183
2303
  const existing = lowerer.arrHofHelpers.get(key);
2184
2304
  const name = existing ?? `%server.opts.${lowerer.arrHofHelpers.size}`;
2185
2305
  if (!existing) {
@@ -2206,6 +2326,13 @@ function lowerHttpCreateServerForms(lowerer, expr, what, loc) {
2206
2326
  loc,
2207
2327
  });
2208
2328
  }
2329
+ if (opts.allowMissingHost) {
2330
+ body.push({
2331
+ kind: "exprStmt",
2332
+ expr: { kind: "libCall", fn: "http.serverAllowMissingHostHeader", args: [ref], type: VOID, loc },
2333
+ loc,
2334
+ });
2335
+ }
2209
2336
  body.push({ kind: "return", value: ref, loc });
2210
2337
  lowerer.liftedFns.push({
2211
2338
  name,
@@ -2351,13 +2478,33 @@ export function lowerHttpServerNew(lowerer, expr) {
2351
2478
  * (req, res), (req), or () — runtime adapters bridge each shape.
2352
2479
  * Everything else the module declares fences qualified. */
2353
2480
  function lowerHttpModuleCall(lowerer, expr, bi, loc) {
2481
+ if (bi.member === "validateHeaderName") {
2482
+ requireStatementPosition(lowerer, expr, "http.validateHeaderName(...)");
2483
+ if (expr.arguments.length < 1 || expr.arguments.length > 2 || expr.arguments.some(ts.isSpreadElement)) {
2484
+ lowerer.noLowering("http.validateHeaderName arguments", expr, "pass a header name and an optional label");
2485
+ }
2486
+ const name = lowerer.lowerExprExpecting(expr.arguments[0], STRING);
2487
+ const label = expr.arguments.length === 2
2488
+ ? lowerer.lowerExprExpecting(expr.arguments[1], STRING)
2489
+ : strLit("Header name", loc);
2490
+ return { kind: "libCall", fn: "http.validateHeaderName", args: [name, label], type: VOID, loc };
2491
+ }
2492
+ if (bi.member === "validateHeaderValue") {
2493
+ requireStatementPosition(lowerer, expr, "http.validateHeaderValue(...)");
2494
+ if (expr.arguments.length !== 2 || expr.arguments.some(ts.isSpreadElement)) {
2495
+ lowerer.noLowering("http.validateHeaderValue arguments", expr, "pass a header name and a value");
2496
+ }
2497
+ const name = lowerer.lowerExprExpecting(expr.arguments[0], STRING);
2498
+ const value = lowerer.lowerExprExpecting(expr.arguments[1], DYN);
2499
+ return { kind: "libCall", fn: "http.validateHeaderValue", args: [name, value], type: VOID, loc };
2500
+ }
2354
2501
  if (bi.member === "createServer" || bi.member === "Server") {
2355
2502
  return lowerHttpCreateServerForms(lowerer, expr, `http.${bi.member}`, loc);
2356
2503
  }
2357
2504
  if (bi.member === "request" || bi.member === "get") {
2358
2505
  return lowerHttpClientCall(lowerer, expr, bi.member, loc);
2359
2506
  }
2360
- lowerer.noLowering(`http.${bi.member}`, expr, "createServer, Server, request, and get are the lowered http module functions", lowerer.resolveValueSymbol(expr.expression));
2507
+ lowerer.noLowering(`http.${bi.member}`, expr, "createServer, Server, request, get, validateHeaderName, and validateHeaderValue are the lowered http module functions", lowerer.resolveValueSymbol(expr.expression));
2361
2508
  }
2362
2509
  /** The cert/key PEM option of tls.createServer / https.createServer: an
2363
2510
  * OBJECT LITERAL whose lowered `cert` and `key` entries are strings or
@@ -3593,6 +3740,28 @@ function lowerClientHeadersOption(lowerer, node) {
3593
3740
  }
3594
3741
  return { kind: "call", callee: helper, args: [v], type: arrayOf(STRING), loc };
3595
3742
  }
3743
+ /** OutgoingMessage.addTrailers accepts an object or a pair-list literal.
3744
+ * Flatten the latter in source order; non-literal nested arrays currently
3745
+ * fence rather than reaching the C runtime with the wrong wire shape. */
3746
+ function lowerHttpTrailersOption(lowerer, node) {
3747
+ if (!ts.isArrayLiteralExpression(node))
3748
+ return lowerClientHeadersOption(lowerer, node);
3749
+ const loc = locOf(node);
3750
+ const flat = [];
3751
+ for (const entry of node.elements) {
3752
+ if (!ts.isArrayLiteralExpression(entry) || entry.elements.length !== 2) {
3753
+ lowerer.noLowering("addTrailers pair list", entry, "use an object/Record or literal [name, value] pairs");
3754
+ }
3755
+ const pair = entry;
3756
+ const name = pair.elements[0];
3757
+ const value = pair.elements[1];
3758
+ if (ts.isSpreadElement(name) || ts.isSpreadElement(value)) {
3759
+ lowerer.noLowering("addTrailers pair with spread", entry, "use direct string name/value expressions");
3760
+ }
3761
+ flat.push(lowerer.lowerExprExpecting(name, STRING), lowerer.lowerExprExpecting(value, STRING));
3762
+ }
3763
+ return { kind: "arrayLit", elems: flat, type: arrayOf(STRING), loc };
3764
+ }
3596
3765
  /** Method calls on ClientRequest receivers: write/end/destroy and
3597
3766
  * on/once("response" | "error" | "timeout" | "close"). Null for other
3598
3767
  * receivers. */
@@ -3604,6 +3773,83 @@ function lowerHttpClientMethodCall(lowerer, call, access) {
3604
3773
  const name = access.name.text;
3605
3774
  const loc = locOf(call);
3606
3775
  const args = call.arguments;
3776
+ if (name === "setHeader") {
3777
+ requireStatementPosition(lowerer, call, "request.setHeader(...)");
3778
+ if (args.length !== 2)
3779
+ lowerer.noLowering("request.setHeader arguments", call, "pass a name and string value");
3780
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
3781
+ const header = lowerer.lowerExprExpecting(args[0], STRING);
3782
+ const value = lowerer.lowerExprExpecting(args[1], STRING);
3783
+ return { kind: "libCall", fn: "http.clientSetHeader", args: [receiver, header, value], type: VOID, loc };
3784
+ }
3785
+ if (name === "getHeader" || name === "hasHeader" || name === "removeHeader") {
3786
+ if (name === "removeHeader")
3787
+ requireStatementPosition(lowerer, call, "request.removeHeader(...)");
3788
+ if (args.length !== 1)
3789
+ lowerer.noLowering(`request.${name} arguments`, call, `pass one header name`);
3790
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
3791
+ const header = lowerer.lowerExprExpecting(args[0], STRING);
3792
+ const fn = name === "getHeader" ? "http.clientGetHeader"
3793
+ : name === "hasHeader" ? "http.clientHasHeader" : "http.clientRemoveHeader";
3794
+ const type = name === "getHeader" ? lowerer.envValueType() : name === "hasHeader" ? BOOL : VOID;
3795
+ return { kind: "libCall", fn, args: [receiver, header], type, loc };
3796
+ }
3797
+ if (name === "getHeaderNames" || name === "getRawHeaderNames" || name === "getHeaders") {
3798
+ if (args.length !== 0)
3799
+ lowerer.noLowering(`request.${name} arguments`, call, `${name}() takes no arguments`);
3800
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
3801
+ const fn = name === "getHeaderNames" ? "http.clientGetHeaderNames"
3802
+ : name === "getRawHeaderNames" ? "http.clientGetRawHeaderNames" : "http.clientGetHeaders";
3803
+ return { kind: "libCall", fn, args: [receiver], type: name === "getHeaders" ? DYN : arrayOf(STRING), loc };
3804
+ }
3805
+ if (name === "flushHeaders" || name === "cork" || name === "uncork") {
3806
+ requireStatementPosition(lowerer, call, `request.${name}()`);
3807
+ if (args.length !== 0)
3808
+ lowerer.noLowering(`request.${name} with arguments`, call, `${name}() takes no arguments`);
3809
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
3810
+ const fn = name === "flushHeaders" ? "http.clientFlushHeaders"
3811
+ : name === "cork" ? "http.clientCork" : "http.clientUncork";
3812
+ return { kind: "libCall", fn, args: [receiver], type: VOID, loc };
3813
+ }
3814
+ if (name === "setNoDelay") {
3815
+ requireStatementPosition(lowerer, call, "request.setNoDelay(...)");
3816
+ if (args.length > 1)
3817
+ lowerer.noLowering("request.setNoDelay arguments", call, "pass an optional boolean");
3818
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
3819
+ const enable = args.length === 0 ? boolLit(true, loc) : lowerer.lowerExprExpecting(args[0], BOOL);
3820
+ return { kind: "libCall", fn: "http.clientSetNoDelay", args: [receiver, enable], type: VOID, loc };
3821
+ }
3822
+ if (name === "setSocketKeepAlive") {
3823
+ requireStatementPosition(lowerer, call, "request.setSocketKeepAlive(...)");
3824
+ if (args.length > 2)
3825
+ lowerer.noLowering("request.setSocketKeepAlive arguments", call, "pass an optional boolean and initial delay in milliseconds");
3826
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
3827
+ const enable = args.length === 0 ? boolLit(true, loc) : lowerer.lowerExprExpecting(args[0], BOOL);
3828
+ const delay = args.length < 2 ? numLit(0, loc) : lowerer.lowerExprExpecting(args[1], F64);
3829
+ return { kind: "libCall", fn: "http.clientSetSocketKeepAlive", args: [receiver, enable, delay], type: VOID, loc };
3830
+ }
3831
+ if (name === "setTimeout") {
3832
+ if (args.length < 1 || args.length > 2)
3833
+ lowerer.noLowering("request.setTimeout arguments", call, "pass milliseconds and an optional callback");
3834
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
3835
+ const ms = lowerer.lowerExprExpecting(args[0], F64);
3836
+ const cb = args.length === 2
3837
+ ? lowerCallbackArg(lowerer, args[1], "request timeout callbacks", 0, () => false, "use ()", []).cb
3838
+ : null;
3839
+ const fn = cb === null ? "http.clientSetTimeout" : "http.clientSetTimeoutCb";
3840
+ const callArgs = cb === null ? [receiver, ms] : [receiver, ms, cb];
3841
+ if (resultIsDiscarded(call))
3842
+ return { kind: "libCall", fn, args: callArgs, type: VOID, loc };
3843
+ return receiverReturningCall(lowerer, fn, callArgs, HTTPCLIENTREQ_T, loc);
3844
+ }
3845
+ if (name === "addTrailers") {
3846
+ requireStatementPosition(lowerer, call, "request.addTrailers(...)");
3847
+ if (args.length !== 1)
3848
+ lowerer.noLowering("request.addTrailers argument count", call, "pass one trailer object or pair-list literal");
3849
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
3850
+ const pairs = lowerHttpTrailersOption(lowerer, args[0]);
3851
+ return { kind: "libCall", fn: "http.clientAddTrailers", args: [receiver, pairs], type: VOID, loc };
3852
+ }
3607
3853
  if (name === "write" || name === "end") {
3608
3854
  requireStatementPosition(lowerer, call, `request.${name}(...)`);
3609
3855
  const minArgs = name === "write" ? 1 : 0;
@@ -3630,13 +3876,13 @@ function lowerHttpClientMethodCall(lowerer, call, access) {
3630
3876
  }
3631
3877
  lowerer.noLowering(`${name} of '${lowerer.fmt(data.type)}' data`, args[0] ?? call, NARROW_DATA_HINT);
3632
3878
  }
3633
- if (name === "destroy") {
3634
- requireStatementPosition(lowerer, call, "request.destroy()");
3879
+ if (name === "destroy" || name === "abort") {
3880
+ requireStatementPosition(lowerer, call, `request.${name}()`);
3635
3881
  if (args.length !== 0) {
3636
- lowerer.noLowering(`destroy with ${args.length} arguments`, call, "destroy() takes no arguments here");
3882
+ lowerer.noLowering(`${name} with ${args.length} arguments`, call, `${name}() takes no arguments here`);
3637
3883
  }
3638
3884
  const receiver = lowerer.lowerExpr(access.expression);
3639
- return { kind: "libCall", fn: "http.clientDestroy", args: [receiver], type: VOID, loc };
3885
+ return { kind: "libCall", fn: name === "destroy" ? "http.clientDestroy" : "http.clientAbort", args: [receiver], type: VOID, loc };
3640
3886
  }
3641
3887
  if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
3642
3888
  requireStatementPosition(lowerer, call, `request.${name}(...)`);
@@ -3648,13 +3894,19 @@ function lowerHttpClientMethodCall(lowerer, call, access) {
3648
3894
  const { cb } = lowerCallbackArg(lowerer, args[1], "response listeners", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3649
3895
  return { kind: "libCall", fn: "http.clientOnResponse", args: [receiver, cb, once], type: VOID, loc };
3650
3896
  }
3897
+ if (event === "socket") {
3898
+ const { cb } = lowerCallbackArg(lowerer, args[1], "socket listeners", 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
3899
+ return { kind: "libCall", fn: "http.clientOnSocket", args: [receiver, cb, once], type: VOID, loc };
3900
+ }
3651
3901
  if (event === "error") {
3652
3902
  const { cb } = lowerCallbackArg(lowerer, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
3653
3903
  return { kind: "libCall", fn: "http.clientOnError", args: [receiver, cb, once], type: VOID, loc };
3654
3904
  }
3655
- if (event === "timeout" || event === "close") {
3905
+ if (event === "timeout" || event === "close" || event === "finish" || event === "abort") {
3656
3906
  const { cb } = lowerCallbackArg(lowerer, args[1], `${event} listeners`, 0, () => false, "use ()", []);
3657
- const fn = event === "timeout" ? "http.clientOnTimeout" : "http.clientOnClose";
3907
+ const fn = event === "timeout" ? "http.clientOnTimeout"
3908
+ : event === "close" ? "http.clientOnClose"
3909
+ : event === "abort" ? "http.clientOnAbort" : "http.clientOnFinish";
3658
3910
  return { kind: "libCall", fn, args: [receiver, cb, once], type: VOID, loc };
3659
3911
  }
3660
3912
  if (event === "upgrade") {
@@ -3676,9 +3928,9 @@ function lowerHttpClientMethodCall(lowerer, call, access) {
3676
3928
  }
3677
3929
  return { kind: "libCall", fn: "http.clientOnUpgrade", args: [receiver, cb, once], type: VOID, loc };
3678
3930
  }
3679
- lowerer.noLowering(`request.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"response", "upgrade", "error", "timeout", and "close" are the supported request events (as literals)');
3931
+ lowerer.noLowering(`request.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"response", "socket", "upgrade", "error", "timeout", "finish", "abort", and "close" are the supported request events (as literals)');
3680
3932
  }
3681
- lowerer.noLowering(`ClientRequest.${name}`, call, "write, end, destroy, destroyed, and on/once of response/error/timeout/close are the supported ClientRequest members", lowerer.checker.getSymbolAtLocation(access.name));
3933
+ lowerer.noLowering(`ClientRequest.${name}`, call, "header reads/mutations, write, end, destroy, and on/once of response/error/timeout/close are the supported ClientRequest members", lowerer.checker.getSymbolAtLocation(access.name));
3682
3934
  }
3683
3935
  /** True when `node` is the h2-only stream/session CALL shape —
3684
3936
  * `req.stream.destroy()` / `req.session.m(...)` on an identifier
@@ -3728,31 +3980,37 @@ export function lowerSocketInstanceOf(lowerer, expr, loc) {
3728
3980
  }
3729
3981
  /** True when `node` reads `.headers` off an IncomingMessage — the
3730
3982
  * receiver shape of both header-read forms. */
3731
- function isHttpReqHeaders(lowerer, node) {
3732
- return (ts.isPropertyAccessExpression(node) &&
3983
+ function httpReqFieldCollection(lowerer, node) {
3984
+ if (ts.isPropertyAccessExpression(node) &&
3733
3985
  !node.questionDotToken &&
3734
- node.name.text === "headers" &&
3986
+ (node.name.text === "headers" || node.name.text === "trailers" ||
3987
+ node.name.text === "headersDistinct" || node.name.text === "trailersDistinct") &&
3735
3988
  lowerer.mapTypeOf(lowerer.typeOf(node.expression))?.kind === "httpReq" &&
3736
- lowerer.isStdlibMember(node));
3989
+ lowerer.isStdlibMember(node))
3990
+ return node.name.text;
3991
+ return null;
3737
3992
  }
3738
3993
  /** `req.headers["x-name"]` — the element twin of the property read below;
3739
3994
  * called from lowerElementAccess (the process.env precedent). Answers the
3740
3995
  * interned `string | undefined` union; names match case-insensitively
3741
3996
  * (the runtime stores them lowercased, like Node). */
3742
3997
  export function lowerHttpHeadersElement(lowerer, expr) {
3743
- if (!isHttpReqHeaders(lowerer, expr.expression))
3998
+ const collection = httpReqFieldCollection(lowerer, expr.expression);
3999
+ if (collection === null)
3744
4000
  return null;
3745
4001
  const recv = expr.expression.expression;
3746
4002
  const key = lowerer.lowerExpr(expr.argumentExpression);
3747
4003
  if (key.type.kind !== "string") {
3748
- lowerer.unsupported("SC1090", expr.argumentExpression, "indexing req.headers with non-string keys");
4004
+ lowerer.unsupported("SC1090", expr.argumentExpression, `indexing req.${collection} with non-string keys`);
3749
4005
  }
3750
4006
  const receiver = lowerer.lowerExpr(recv);
3751
4007
  return {
3752
4008
  kind: "libCall",
3753
- fn: "http.reqHeader",
4009
+ fn: collection === "headers" ? "http.reqHeader"
4010
+ : collection === "trailers" ? "http.reqTrailer"
4011
+ : collection === "headersDistinct" ? "http.reqHeaderValues" : "http.reqTrailerValues",
3754
4012
  args: [receiver, key],
3755
- type: lowerer.envValueType(),
4013
+ type: collection.endsWith("Distinct") ? lowerer.withUndefinedArm(arrayOf(STRING)) : lowerer.envValueType(),
3756
4014
  loc: locOf(expr),
3757
4015
  };
3758
4016
  }
@@ -3766,6 +4024,17 @@ function lowerHttpReqMethodCall(lowerer, call, access) {
3766
4024
  const name = access.name.text;
3767
4025
  const loc = locOf(call);
3768
4026
  const args = call.arguments;
4027
+ if (name === "setTimeout") {
4028
+ requireStatementPosition(lowerer, call, "message.setTimeout(...)");
4029
+ if (args.length < 1 || args.length > 2)
4030
+ lowerer.noLowering("message.setTimeout arguments", call, "pass milliseconds and an optional callback");
4031
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPREQ_T);
4032
+ const ms = lowerer.lowerExprExpecting(args[0], F64);
4033
+ if (args.length === 1)
4034
+ return { kind: "libCall", fn: "http.reqSetTimeout", args: [receiver, ms], type: VOID, loc };
4035
+ const { cb } = lowerCallbackArg(lowerer, args[1], "message timeout callbacks", 0, () => false, "use ()", []);
4036
+ return { kind: "libCall", fn: "http.reqSetTimeoutCb", args: [receiver, ms, cb], type: VOID, loc };
4037
+ }
3769
4038
  if (name === "resume" || name === "destroy") {
3770
4039
  requireStatementPosition(lowerer, call, `req.${name}()`);
3771
4040
  if (args.length !== 0) {
@@ -3848,6 +4117,92 @@ function lowerHttpResMethodCall(lowerer, call, access) {
3848
4117
  const name = access.name.text;
3849
4118
  const loc = locOf(call);
3850
4119
  const args = call.arguments;
4120
+ if (name === "setTimeout") {
4121
+ if (args.length < 1 || args.length > 2) {
4122
+ lowerer.noLowering(`res.setTimeout with ${args.length} arguments`, call, "use setTimeout(milliseconds[, callback])");
4123
+ }
4124
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
4125
+ const ms = lowerer.lowerExprExpecting(args[0], F64);
4126
+ const cb = args.length === 2
4127
+ ? lowerCallbackArg(lowerer, args[1], "response timeout callbacks", 0, () => false, "use ()", []).cb
4128
+ : null;
4129
+ const fn = cb === null ? "http.resSetTimeout" : "http.resSetTimeoutCb";
4130
+ const callArgs = cb === null ? [receiver, ms] : [receiver, ms, cb];
4131
+ if (resultIsDiscarded(call))
4132
+ return { kind: "libCall", fn, args: callArgs, type: VOID, loc };
4133
+ return receiverReturningCall(lowerer, fn, callArgs, HTTPRES_T, loc);
4134
+ }
4135
+ if (name === "writeContinue" || name === "writeProcessing" || name === "writeEarlyHints") {
4136
+ requireStatementPosition(lowerer, call, `res.${name}(...)`);
4137
+ if (lowerer.typeOf(access.expression).getSymbol()?.name === "Http2ServerResponse") {
4138
+ lowerer.noLowering(`Http2ServerResponse.${name}`, call, "HTTP/2 informational responses are not supported by the static runtime yet");
4139
+ }
4140
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
4141
+ if (name !== "writeEarlyHints") {
4142
+ if (args.length !== 0)
4143
+ lowerer.noLowering(`res.${name} callback`, call, `${name}() supports no callback here`);
4144
+ return { kind: "libCall", fn: name === "writeContinue" ? "http.resWriteContinue" : "http.resWriteProcessing", args: [receiver], type: VOID, loc };
4145
+ }
4146
+ if (args.length !== 1)
4147
+ lowerer.noLowering("res.writeEarlyHints arguments", call, "pass one header object or Record<string, string> without a callback");
4148
+ const node = args[0];
4149
+ let pairs;
4150
+ if (ts.isObjectLiteralExpression(node)) {
4151
+ const elems = [];
4152
+ for (const prop of node.properties) {
4153
+ const key = ts.isPropertyAssignment(prop) ? staticHeaderKeyOf(lowerer, prop) : null;
4154
+ if (!ts.isPropertyAssignment(prop) || key === null) {
4155
+ lowerer.noLowering("writeEarlyHints headers with dynamic keys, spreads, or shorthand entries", prop, "use literal header keys and string values");
4156
+ }
4157
+ const value = lowerer.lowerExpr(prop.initializer);
4158
+ if (value.type.kind !== "string") {
4159
+ lowerer.noLowering(`writeEarlyHints value of type '${lowerer.fmt(value.type)}'`, prop.initializer, "header values must be strings here");
4160
+ }
4161
+ elems.push({ kind: "strLit", value: key, type: STRING, loc }, value);
4162
+ }
4163
+ pairs = { kind: "arrayLit", elems, type: arrayOf(STRING), loc };
4164
+ }
4165
+ else {
4166
+ const value = lowerer.lowerExpr(node);
4167
+ if (value.type.kind !== "record") {
4168
+ lowerer.noLowering(`writeEarlyHints headers of '${lowerer.fmt(value.type)}'`, node, "pass an object literal or a Record<string, string>");
4169
+ }
4170
+ const helper = lowerer.envToPairsHelper(value.type.shapeId, loc);
4171
+ if (helper === null) {
4172
+ lowerer.noLowering("writeEarlyHints header values", node, "use a Record<string, string> with string values");
4173
+ }
4174
+ pairs = { kind: "call", callee: helper, args: [value], type: arrayOf(STRING), loc };
4175
+ }
4176
+ return { kind: "libCall", fn: "http.resWriteEarlyHints", args: [receiver, pairs], type: VOID, loc };
4177
+ }
4178
+ if (name === "getHeaderNames" || name === "getRawHeaderNames" || name === "getHeaders") {
4179
+ if (args.length !== 0)
4180
+ lowerer.noLowering(`res.${name} arguments`, call, `${name}() takes no arguments`);
4181
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
4182
+ const fn = name === "getHeaderNames" ? "http.resGetHeaderNames"
4183
+ : name === "getRawHeaderNames" ? "http.resGetRawHeaderNames" : "http.resGetHeaders";
4184
+ return { kind: "libCall", fn, args: [receiver], type: name === "getHeaders" ? DYN : arrayOf(STRING), loc };
4185
+ }
4186
+ if (name === "flushHeaders" || name === "cork" || name === "uncork") {
4187
+ requireStatementPosition(lowerer, call, `res.${name}()`);
4188
+ if (args.length !== 0)
4189
+ lowerer.noLowering(`res.${name} with arguments`, call, `${name}() takes no arguments`);
4190
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
4191
+ const fn = name === "flushHeaders" ? "http.resFlushHeaders"
4192
+ : name === "cork" ? "http.resCork" : "http.resUncork";
4193
+ return { kind: "libCall", fn, args: [receiver], type: VOID, loc };
4194
+ }
4195
+ if (name === "addTrailers") {
4196
+ requireStatementPosition(lowerer, call, "res.addTrailers(...)");
4197
+ if (lowerer.typeOf(access.expression).getSymbol()?.name === "Http2ServerResponse") {
4198
+ lowerer.noLowering("Http2ServerResponse.addTrailers", call, "HTTP/2 response trailers are not supported by the static runtime yet");
4199
+ }
4200
+ if (args.length !== 1)
4201
+ lowerer.noLowering("res.addTrailers argument count", call, "pass one trailer object or pair-list literal");
4202
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
4203
+ const pairs = lowerHttpTrailersOption(lowerer, args[0]);
4204
+ return { kind: "libCall", fn: "http.resAddTrailers", args: [receiver, pairs], type: VOID, loc };
4205
+ }
3851
4206
  if (name === "setHeader") {
3852
4207
  requireStatementPosition(lowerer, call, "res.setHeader(...)");
3853
4208
  if (args.length !== 2) {
@@ -4094,8 +4449,12 @@ function lowerHttpResMethodCall(lowerer, call, access) {
4094
4449
  const { cb } = lowerCallbackArg(lowerer, args[1], "close listeners", 0, () => false, "use ()", []);
4095
4450
  return { kind: "libCall", fn: "http.resOnClose", args: [receiver, cb, once], type: VOID, loc };
4096
4451
  }
4097
- lowerer.noLowering(`res.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"close" is the supported response event (as a literal)');
4452
+ if (event === "finish") {
4453
+ const { cb } = lowerCallbackArg(lowerer, args[1], "finish listeners", 0, () => false, "use ()", []);
4454
+ return { kind: "libCall", fn: "http.resOnFinish", args: [receiver, cb], type: VOID, loc };
4455
+ }
4456
+ lowerer.noLowering(`res.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"close" and "finish" are the supported response events (as literals)');
4098
4457
  }
4099
- lowerer.noLowering(`ServerResponse.${name}`, call, "setHeader, getHeader, hasHeader, removeHeader, writeHead, write, end, destroy, headersSent, statusCode, statusMessage, and on/once of close are the supported ServerResponse members", lowerer.checker.getSymbolAtLocation(access.name));
4458
+ lowerer.noLowering(`ServerResponse.${name}`, call, "setHeader, getHeader, hasHeader, removeHeader, writeHead, writeContinue, writeProcessing, writeEarlyHints, setTimeout, write, end, destroy, response state reads, and on/once of close are the supported ServerResponse members", lowerer.checker.getSymbolAtLocation(access.name));
4100
4459
  }
4101
4460
  //# sourceMappingURL=lower-server.js.map