@scriptc/compiler 0.1.4 → 0.1.6

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 (158) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +75 -11
  2. package/dist/backend/c/c-emitter.d.ts +5 -1
  3. package/dist/backend/c/c-emitter.js +22 -9
  4. package/dist/backend/c/c-emitter.js.map +1 -1
  5. package/dist/backend/c/exprs.d.ts +2 -2
  6. package/dist/backend/c/exprs.js +298 -27
  7. package/dist/backend/c/exprs.js.map +1 -1
  8. package/dist/backend/c/stmts.js +5 -3
  9. package/dist/backend/c/stmts.js.map +1 -1
  10. package/dist/backend/c/types.d.ts +2 -3
  11. package/dist/backend/c/types.js +8 -1
  12. package/dist/backend/c/types.js.map +1 -1
  13. package/dist/backend/c/walkers.js +1 -1
  14. package/dist/backend/c/walkers.js.map +1 -1
  15. package/dist/backend/link-plan.d.ts +1 -0
  16. package/dist/backend/link-plan.js +2 -1
  17. package/dist/backend/link-plan.js.map +1 -1
  18. package/dist/backend/llvm/dyn.js +1 -1
  19. package/dist/backend/llvm/dyn.js.map +1 -1
  20. package/dist/backend/llvm/emitter.js +25 -9
  21. package/dist/backend/llvm/emitter.js.map +1 -1
  22. package/dist/backend/llvm/expr-bytes.d.ts +1 -2
  23. package/dist/backend/llvm/expr-bytes.js +22 -17
  24. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  25. package/dist/backend/llvm/expr-containers.d.ts +1 -0
  26. package/dist/backend/llvm/expr-containers.js +58 -4
  27. package/dist/backend/llvm/expr-containers.js.map +1 -1
  28. package/dist/backend/llvm/expr-context.d.ts +6 -2
  29. package/dist/backend/llvm/expr-primitives.js +22 -7
  30. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  31. package/dist/backend/llvm/lib-filesystem.js +20 -0
  32. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  33. package/dist/backend/llvm/lib-network.js +53 -10
  34. package/dist/backend/llvm/lib-network.js.map +1 -1
  35. package/dist/backend/llvm/lib-process.js +4 -3
  36. package/dist/backend/llvm/lib-process.js.map +1 -1
  37. package/dist/backend/llvm/lib-shared.js +65 -0
  38. package/dist/backend/llvm/lib-shared.js.map +1 -1
  39. package/dist/backend/native-toolchain.d.ts +2 -0
  40. package/dist/backend/native-toolchain.js +2 -1
  41. package/dist/backend/native-toolchain.js.map +1 -1
  42. package/dist/backend/targets.d.ts +3 -0
  43. package/dist/backend/targets.js +13 -0
  44. package/dist/backend/targets.js.map +1 -1
  45. package/dist/coverage/surface-manifest.js +12 -5
  46. package/dist/coverage/surface-manifest.js.map +1 -1
  47. package/dist/executable/executable-cache.d.ts +2 -0
  48. package/dist/executable/executable-cache.js +3 -1
  49. package/dist/executable/executable-cache.js.map +1 -1
  50. package/dist/executable/executable-cache.test.js +3 -3
  51. package/dist/executable/executable-cache.test.js.map +1 -1
  52. package/dist/frontend/lowering/array-indexed-mutation.d.ts +8 -0
  53. package/dist/frontend/lowering/array-indexed-mutation.js +176 -0
  54. package/dist/frontend/lowering/array-indexed-mutation.js.map +1 -0
  55. package/dist/frontend/lowering/containers/bytes.d.ts +1 -1
  56. package/dist/frontend/lowering/containers/bytes.js +6 -5
  57. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  58. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +14 -6
  59. package/dist/frontend/lowering/containers/string-and-regexp.js +420 -34
  60. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  61. package/dist/frontend/lowering/expressions/object-literals.js +8 -0
  62. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  63. package/dist/frontend/lowering/indexed-comparison.d.ts +6 -0
  64. package/dist/frontend/lowering/indexed-comparison.js +30 -0
  65. package/dist/frontend/lowering/indexed-comparison.js.map +1 -0
  66. package/dist/frontend/lowering/lower-builtins.d.ts +5 -6
  67. package/dist/frontend/lowering/lower-builtins.js +24 -16
  68. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  69. package/dist/frontend/lowering/lower-calls.d.ts +3 -2
  70. package/dist/frontend/lowering/lower-calls.js +522 -89
  71. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  72. package/dist/frontend/lowering/lower-classes.js +5 -29
  73. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  74. package/dist/frontend/lowering/lower-containers.d.ts +15 -11
  75. package/dist/frontend/lowering/lower-containers.js +588 -146
  76. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  77. package/dist/frontend/lowering/lower-exprs.d.ts +12 -0
  78. package/dist/frontend/lowering/lower-exprs.js +145 -11
  79. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  80. package/dist/frontend/lowering/lower-island.js +17 -6
  81. package/dist/frontend/lowering/lower-island.js.map +1 -1
  82. package/dist/frontend/lowering/lower-server.d.ts +2 -4
  83. package/dist/frontend/lowering/lower-server.js +288 -32
  84. package/dist/frontend/lowering/lower-server.js.map +1 -1
  85. package/dist/frontend/lowering/lower-stmts.js +4 -4
  86. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  87. package/dist/frontend/lowering/lowerer.js +37 -2
  88. package/dist/frontend/lowering/lowerer.js.map +1 -1
  89. package/dist/frontend/lowering/optional-arguments.d.ts +9 -1
  90. package/dist/frontend/lowering/optional-arguments.js +67 -1
  91. package/dist/frontend/lowering/optional-arguments.js.map +1 -1
  92. package/dist/frontend/lowering/pairs-snapshot.d.ts +3 -1
  93. package/dist/frontend/lowering/pairs-snapshot.js +12 -4
  94. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  95. package/dist/frontend/lowering/surfaces.d.ts +10 -14
  96. package/dist/frontend/lowering/surfaces.js +50 -28
  97. package/dist/frontend/lowering/surfaces.js.map +1 -1
  98. package/dist/frontend/npm-static-prune.d.ts +6 -0
  99. package/dist/frontend/npm-static-prune.js +203 -0
  100. package/dist/frontend/npm-static-prune.js.map +1 -0
  101. package/dist/frontend/npm-static-prune.test.d.ts +1 -0
  102. package/dist/frontend/npm-static-prune.test.js +48 -0
  103. package/dist/frontend/npm-static-prune.test.js.map +1 -0
  104. package/dist/frontend/npm.js +7 -6
  105. package/dist/frontend/npm.js.map +1 -1
  106. package/dist/frontend/program.js +15 -4
  107. package/dist/frontend/program.js.map +1 -1
  108. package/dist/frontend/provenance.js +8 -3
  109. package/dist/frontend/provenance.js.map +1 -1
  110. package/dist/frontend/type-mapper.js +16 -5
  111. package/dist/frontend/type-mapper.js.map +1 -1
  112. package/dist/index.d.ts +3 -3
  113. package/dist/index.js +13 -41
  114. package/dist/index.js.map +1 -1
  115. package/dist/ir/analysis.d.ts +5 -3
  116. package/dist/ir/analysis.js +25 -11
  117. package/dist/ir/analysis.js.map +1 -1
  118. package/dist/ir/analysis.test.js +50 -2
  119. package/dist/ir/analysis.test.js.map +1 -1
  120. package/dist/ir/constant-tables.d.ts +17 -0
  121. package/dist/ir/constant-tables.js +99 -0
  122. package/dist/ir/constant-tables.js.map +1 -0
  123. package/dist/ir/constant-tables.test.d.ts +1 -0
  124. package/dist/ir/constant-tables.test.js +78 -0
  125. package/dist/ir/constant-tables.test.js.map +1 -0
  126. package/dist/ir/integer-ranges.d.ts +13 -0
  127. package/dist/ir/integer-ranges.js +122 -0
  128. package/dist/ir/integer-ranges.js.map +1 -0
  129. package/dist/ir/integer-ranges.test.d.ts +1 -0
  130. package/dist/ir/integer-ranges.test.js +63 -0
  131. package/dist/ir/integer-ranges.test.js.map +1 -0
  132. package/dist/ir/ir.d.ts +56 -35
  133. package/dist/ir/ir.js +9 -1
  134. package/dist/ir/ir.js.map +1 -1
  135. package/dist/ir/ir.test.js +6 -0
  136. package/dist/ir/ir.test.js.map +1 -1
  137. package/dist/ir/scalar-records.d.ts +8 -0
  138. package/dist/ir/scalar-records.js +216 -0
  139. package/dist/ir/scalar-records.js.map +1 -0
  140. package/dist/ir/scalar-records.test.d.ts +1 -0
  141. package/dist/ir/scalar-records.test.js +142 -0
  142. package/dist/ir/scalar-records.test.js.map +1 -0
  143. package/dist/ir/validate.js +135 -34
  144. package/dist/ir/validate.js.map +1 -1
  145. package/dist/ir/validate.test.d.ts +1 -0
  146. package/dist/ir/validate.test.js +48 -0
  147. package/dist/ir/validate.test.js.map +1 -0
  148. package/dist/library/cache-primitives.d.ts +1 -1
  149. package/dist/library/cache-primitives.js +3 -3
  150. package/dist/library/cache-primitives.js.map +1 -1
  151. package/dist/library/fence-eval.js +11 -4
  152. package/dist/library/fence-eval.js.map +1 -1
  153. package/dist/library/library-cache.js +0 -1
  154. package/dist/library/library-cache.js.map +1 -1
  155. package/dist/library/library-cache.test.js +3 -3
  156. package/dist/library/library-cache.test.js.map +1 -1
  157. package/package.json +17 -17
  158. package/surface-manifest.json +90 -45
@@ -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
@@ -1525,6 +1552,15 @@ function trailersSnapshotHelper(lowerer, shapeId, loc) {
1525
1552
  callArgs: [varRef("r.0", HTTPREQ_T, loc)],
1526
1553
  });
1527
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
+ }
1528
1564
  /** The `endStream` boolean of an h2 options object literal, as a literal
1529
1565
  * bool. Returns undefined when absent (or the arg is absent). Fences on
1530
1566
  * a non-literal endStream value or unknown keys that would matter. */
@@ -1797,6 +1833,10 @@ export function lowerServerProperty(lowerer, expr) {
1797
1833
  // req.headers.NAME — the `string | undefined` union (envGet's type).
1798
1834
  const recvKind = lowerer.mapTypeOf(lowerer.typeOf(expr.expression))?.kind;
1799
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
+ }
1800
1840
  const field = httpServerTimeoutField(expr.name.text);
1801
1841
  if (field !== null) {
1802
1842
  const receiver = coerceToHandle(lowerer, expr.expression, NETSERVER_T);
@@ -1817,7 +1857,7 @@ export function lowerServerProperty(lowerer, expr) {
1817
1857
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1818
1858
  return { kind: "libCall", fn: "http.reqStatusCode", args: [receiver], type: lowerer.withUndefinedArm(F64), loc };
1819
1859
  }
1820
- if (name === "socket") {
1860
+ if (name === "socket" || name === "connection") {
1821
1861
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1822
1862
  return { kind: "libCall", fn: "http.reqSocket", args: [receiver], type: NETSOCKET_T, loc };
1823
1863
  }
@@ -1879,15 +1919,15 @@ export function lowerServerProperty(lowerer, expr) {
1879
1919
  // guarded-no-op / unguarded-TypeError stance; other reads fence.
1880
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");
1881
1921
  }
1882
- if (name === "headers" || name === "trailers") {
1883
- // `req.headers` as a VALUE — the `{ ...req.headers }` spread and
1884
- // record flows: a fresh snapshot record per read (Node's spread
1885
- // 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.
1886
1925
  const mapped = lowerer.mapTypeOf(lowerer.typeOf(expr));
1887
1926
  if (mapped?.kind === "record") {
1888
1927
  const helper = name === "headers"
1889
1928
  ? headersSnapshotHelper(lowerer, mapped.shapeId, loc)
1890
- : trailersSnapshotHelper(lowerer, mapped.shapeId, loc);
1929
+ : name === "trailers" ? trailersSnapshotHelper(lowerer, mapped.shapeId, loc)
1930
+ : distinctSnapshotHelper(lowerer, mapped.shapeId, loc, name);
1891
1931
  if (helper !== null) {
1892
1932
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1893
1933
  return { kind: "call", callee: helper, args: [receiver], type: mapped, loc };
@@ -1895,9 +1935,6 @@ export function lowerServerProperty(lowerer, expr) {
1895
1935
  }
1896
1936
  lowerer.unsupported("SC1090", expr, `req.${name} as a value of this type (read one field: req.${name}.name or req.${name}[name])`);
1897
1937
  }
1898
- if (name === "headersDistinct" || name === "trailersDistinct") {
1899
- lowerer.unsupported("SC1090", expr, `req.${name} as a value (read one name with req.${name}[name])`);
1900
- }
1901
1938
  }
1902
1939
  if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "stream") {
1903
1940
  lowerer.noLowering("reading 'stream' (an HTTP/2-only member) from a response", expr, "compatibility responses do not expose their backing h2 stream yet — guard method calls with '?.' or drop the use");
@@ -1965,10 +2002,35 @@ export function lowerServerProperty(lowerer, expr) {
1965
2002
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
1966
2003
  return { kind: "libCall", fn: "http.clientDestroyed", args: [receiver], type: BOOL, loc };
1967
2004
  }
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
+ }
1968
2010
  if (recvKind === "httpClientReq" && lowerer.isStdlibMember(expr) && expr.name.text === "writableCorked") {
1969
2011
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
1970
2012
  return { kind: "libCall", fn: "http.clientWritableCorked", args: [receiver], type: F64, loc };
1971
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
+ }
1972
2034
  if (httpReqFieldCollection(lowerer, expr.expression) !== null) {
1973
2035
  const collection = httpReqFieldCollection(lowerer, expr.expression);
1974
2036
  const receiver = coerceToHandle(lowerer, expr.expression.expression, HTTPREQ_T);
@@ -1983,6 +2045,14 @@ export function lowerServerProperty(lowerer, expr) {
1983
2045
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
1984
2046
  return { kind: "libCall", fn: "http.resHeadersSent", args: [receiver], type: BOOL, loc };
1985
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
+ }
1986
2056
  if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "writableCorked") {
1987
2057
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
1988
2058
  return { kind: "libCall", fn: "http.resWritableCorked", args: [receiver], type: F64, loc };
@@ -1994,11 +2064,30 @@ export function lowerServerProperty(lowerer, expr) {
1994
2064
  return { kind: "libCall", fn: "http.resStatusGet", args: [receiver], type: F64, loc };
1995
2065
  }
1996
2066
  if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "statusMessage") {
1997
- // The assigned reason phrase, or the current status code's default
1998
- // when none was set (Node answers undefined until the head goes out
1999
- // — divergence: this surface is string-typed, the checker's shape).
2067
+ // Unset until the head is sent; then the assigned or default reason.
2000
2068
  const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
2001
- 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
+ }
2002
2091
  }
2003
2092
  if (recvKind === "http2Session" && lowerer.isStdlibMember(expr)) {
2004
2093
  const m = expr.name.text;
@@ -2389,13 +2478,33 @@ export function lowerHttpServerNew(lowerer, expr) {
2389
2478
  * (req, res), (req), or () — runtime adapters bridge each shape.
2390
2479
  * Everything else the module declares fences qualified. */
2391
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
+ }
2392
2501
  if (bi.member === "createServer" || bi.member === "Server") {
2393
2502
  return lowerHttpCreateServerForms(lowerer, expr, `http.${bi.member}`, loc);
2394
2503
  }
2395
2504
  if (bi.member === "request" || bi.member === "get") {
2396
2505
  return lowerHttpClientCall(lowerer, expr, bi.member, loc);
2397
2506
  }
2398
- 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));
2399
2508
  }
2400
2509
  /** The cert/key PEM option of tls.createServer / https.createServer: an
2401
2510
  * OBJECT LITERAL whose lowered `cert` and `key` entries are strings or
@@ -3664,6 +3773,35 @@ function lowerHttpClientMethodCall(lowerer, call, access) {
3664
3773
  const name = access.name.text;
3665
3774
  const loc = locOf(call);
3666
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
+ }
3667
3805
  if (name === "flushHeaders" || name === "cork" || name === "uncork") {
3668
3806
  requireStatementPosition(lowerer, call, `request.${name}()`);
3669
3807
  if (args.length !== 0)
@@ -3673,6 +3811,37 @@ function lowerHttpClientMethodCall(lowerer, call, access) {
3673
3811
  : name === "cork" ? "http.clientCork" : "http.clientUncork";
3674
3812
  return { kind: "libCall", fn, args: [receiver], type: VOID, loc };
3675
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
+ }
3676
3845
  if (name === "addTrailers") {
3677
3846
  requireStatementPosition(lowerer, call, "request.addTrailers(...)");
3678
3847
  if (args.length !== 1)
@@ -3707,13 +3876,13 @@ function lowerHttpClientMethodCall(lowerer, call, access) {
3707
3876
  }
3708
3877
  lowerer.noLowering(`${name} of '${lowerer.fmt(data.type)}' data`, args[0] ?? call, NARROW_DATA_HINT);
3709
3878
  }
3710
- if (name === "destroy") {
3711
- requireStatementPosition(lowerer, call, "request.destroy()");
3879
+ if (name === "destroy" || name === "abort") {
3880
+ requireStatementPosition(lowerer, call, `request.${name}()`);
3712
3881
  if (args.length !== 0) {
3713
- 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`);
3714
3883
  }
3715
3884
  const receiver = lowerer.lowerExpr(access.expression);
3716
- 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 };
3717
3886
  }
3718
3887
  if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
3719
3888
  requireStatementPosition(lowerer, call, `request.${name}(...)`);
@@ -3725,13 +3894,19 @@ function lowerHttpClientMethodCall(lowerer, call, access) {
3725
3894
  const { cb } = lowerCallbackArg(lowerer, args[1], "response listeners", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3726
3895
  return { kind: "libCall", fn: "http.clientOnResponse", args: [receiver, cb, once], type: VOID, loc };
3727
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
+ }
3728
3901
  if (event === "error") {
3729
3902
  const { cb } = lowerCallbackArg(lowerer, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
3730
3903
  return { kind: "libCall", fn: "http.clientOnError", args: [receiver, cb, once], type: VOID, loc };
3731
3904
  }
3732
- if (event === "timeout" || event === "close") {
3905
+ if (event === "timeout" || event === "close" || event === "finish" || event === "abort") {
3733
3906
  const { cb } = lowerCallbackArg(lowerer, args[1], `${event} listeners`, 0, () => false, "use ()", []);
3734
- 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";
3735
3910
  return { kind: "libCall", fn, args: [receiver, cb, once], type: VOID, loc };
3736
3911
  }
3737
3912
  if (event === "upgrade") {
@@ -3753,9 +3928,9 @@ function lowerHttpClientMethodCall(lowerer, call, access) {
3753
3928
  }
3754
3929
  return { kind: "libCall", fn: "http.clientOnUpgrade", args: [receiver, cb, once], type: VOID, loc };
3755
3930
  }
3756
- 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)');
3757
3932
  }
3758
- 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));
3759
3934
  }
3760
3935
  /** True when `node` is the h2-only stream/session CALL shape —
3761
3936
  * `req.stream.destroy()` / `req.session.m(...)` on an identifier
@@ -3849,6 +4024,17 @@ function lowerHttpReqMethodCall(lowerer, call, access) {
3849
4024
  const name = access.name.text;
3850
4025
  const loc = locOf(call);
3851
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
+ }
3852
4038
  if (name === "resume" || name === "destroy") {
3853
4039
  requireStatementPosition(lowerer, call, `req.${name}()`);
3854
4040
  if (args.length !== 0) {
@@ -3931,6 +4117,72 @@ function lowerHttpResMethodCall(lowerer, call, access) {
3931
4117
  const name = access.name.text;
3932
4118
  const loc = locOf(call);
3933
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
+ }
3934
4186
  if (name === "flushHeaders" || name === "cork" || name === "uncork") {
3935
4187
  requireStatementPosition(lowerer, call, `res.${name}()`);
3936
4188
  if (args.length !== 0)
@@ -4197,8 +4449,12 @@ function lowerHttpResMethodCall(lowerer, call, access) {
4197
4449
  const { cb } = lowerCallbackArg(lowerer, args[1], "close listeners", 0, () => false, "use ()", []);
4198
4450
  return { kind: "libCall", fn: "http.resOnClose", args: [receiver, cb, once], type: VOID, loc };
4199
4451
  }
4200
- 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)');
4201
4457
  }
4202
- 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));
4203
4459
  }
4204
4460
  //# sourceMappingURL=lower-server.js.map