@scriptc/compiler 0.0.29 → 0.0.30

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 (49) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +5 -13
  2. package/dist/backend/emission/emit-async.d.ts +1 -0
  3. package/dist/backend/emission/emit-async.js +27 -1
  4. package/dist/backend/emission/emit-async.js.map +1 -1
  5. package/dist/backend/emission/emit-exprs.js +109 -18
  6. package/dist/backend/emission/emit-exprs.js.map +1 -1
  7. package/dist/backend/emission/emitter.d.ts +1 -0
  8. package/dist/backend/emission/emitter.js +25 -3
  9. package/dist/backend/emission/emitter.js.map +1 -1
  10. package/dist/backend/llvm/emitter.js +152 -0
  11. package/dist/backend/llvm/emitter.js.map +1 -1
  12. package/dist/backend/mangle.d.ts +1 -0
  13. package/dist/backend/mangle.js +3 -0
  14. package/dist/backend/mangle.js.map +1 -1
  15. package/dist/diagnostics/diagnostic.d.ts +23 -1
  16. package/dist/diagnostics/diagnostic.js +34 -0
  17. package/dist/diagnostics/diagnostic.js.map +1 -1
  18. package/dist/frontend/lowering/lower-calls.d.ts +3 -1
  19. package/dist/frontend/lowering/lower-calls.js +196 -33
  20. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  21. package/dist/frontend/lowering/lower-containers.d.ts +6 -5
  22. package/dist/frontend/lowering/lower-containers.js +15 -11
  23. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  24. package/dist/frontend/lowering/lower-exprs.d.ts +11 -1
  25. package/dist/frontend/lowering/lower-exprs.js +366 -25
  26. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  27. package/dist/frontend/lowering/lower-server.d.ts +5 -0
  28. package/dist/frontend/lowering/lower-server.js +105 -55
  29. package/dist/frontend/lowering/lower-server.js.map +1 -1
  30. package/dist/frontend/lowering/lower-stmts.js +71 -9
  31. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  32. package/dist/frontend/lowering/lowerer.d.ts +24 -5
  33. package/dist/frontend/lowering/lowerer.js +28 -4
  34. package/dist/frontend/lowering/lowerer.js.map +1 -1
  35. package/dist/index.js +35 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/ir/nodes.d.ts +52 -19
  38. package/dist/ir/nodes.js +2 -2
  39. package/dist/ir/nodes.js.map +1 -1
  40. package/dist/ir/validate.js +67 -9
  41. package/dist/ir/validate.js.map +1 -1
  42. package/dist/library/profile.d.ts +33 -0
  43. package/dist/library/profile.js +161 -3
  44. package/dist/library/profile.js.map +1 -1
  45. package/dist/library/sidecar.d.ts +3 -2
  46. package/dist/library/sidecar.js +7 -3
  47. package/dist/library/sidecar.js.map +1 -1
  48. package/package.json +2 -2
  49. package/surface-manifest.json +1 -1
@@ -40,6 +40,11 @@ export declare function lowerHttpServerTimeoutAssignment(L: Lowerer, left: ts.Ex
40
40
  * entry in lower-calls.ts's intrinsic chain (the lowerChildMethodCall
41
41
  * slot). Null when the receiver is neither. */
42
42
  export declare function lowerServerMethodCall(L: Lowerer, call: ts.CallExpression, access: ts.PropertyAccessExpression): IrExpr | null;
43
+ /** A compatibility request's `req.stream?.method(...)`: the static Node
44
+ * type omits the HTTP/1 undefined arm, so build the runtime guard explicitly.
45
+ * The body receives the narrowed backing stream directly, preserving lazy
46
+ * argument evaluation on the HTTP/1 arm. */
47
+ export declare function lowerCompatReqStreamOptionalCall(L: Lowerer, call: ts.CallExpression): IrExpr | null;
43
48
  /** The composed `server.address().port` read — the crypto
44
49
  * randomBytes(n).toString(enc) precedent: the AddressInfo record between
45
50
  * the two reads never materializes; the runtime answers the bound port
@@ -1086,13 +1086,10 @@ function lowerNetServerMethodCall(L, call, access) {
1086
1086
  // HTTP CONNECT — the tunneling handover: (req, socket, head), fired
1087
1087
  // INSTEAD of 'request' for CONNECT-method requests (the 'upgrade'
1088
1088
  // machinery's twin; no listener destroys the socket, Node's
1089
- // default). Under the allowHTTP1 lowering the h2 compat server's
1090
- // 'connect' only ever fires for HTTP/1.1 CONNECT, so the second
1091
- // argument is ALWAYS the raw socket — a listener typing it
1092
- // `Http2ServerResponse | net.Socket` (portless's RFC 8441 handler)
1093
- // takes the union with the socket wrapped at its arm; `instanceof
1094
- // net.Socket` narrows it (always true at runtime here, exactly like
1095
- // Node's allowHTTP1 HTTP/1.1 arm).
1089
+ // default). An allowHTTP1 server supplies a raw socket for HTTP/1.1
1090
+ // CONNECT and an Http2ServerResponse for valid traditional/extended
1091
+ // HTTP/2 CONNECT, so portless's union-typed listener selects the
1092
+ // protocol arm with `instanceof net.Socket`.
1096
1093
  const cb = L.lowerExpr(args[1]);
1097
1094
  if (cb.type.kind !== "func" || cb.type.params.length > 3) {
1098
1095
  L.unsupported("SC1090", args[1], "connect listeners with more than three parameters (use (req, socket, head))");
@@ -1138,17 +1135,16 @@ function lowerNetServerMethodCall(L, call, access) {
1138
1135
  return { kind: "libCall", fn: "http.serverOnUpgrade", args: [receiver, cb, once], type: VOID, loc };
1139
1136
  }
1140
1137
  if (event === "sessionError") {
1141
- // 'sessionError' is an HTTP/2 SESSION event — the allowHTTP1
1142
- // lowering serves every connection as HTTP/1.1, so no session ever
1143
- // exists and the event NEVER fires (SEMANTICS.md divergence 57).
1144
- // The registration is honest dead weight: the callback is built and
1145
- // released, never called — so its parameters need no checking
1146
- // beyond the closure shape.
1147
1138
  const cb = L.lowerExpr(args[1]);
1148
- if (cb.type.kind !== "func" || cb.type.ret.kind !== "void") {
1149
- L.unsupported("SC1090", args[1], "sessionError listeners returning a value (make the callback body a block)");
1139
+ if (cb.type.kind !== "func" || cb.type.ret.kind !== "void" || cb.type.params.length > 2) {
1140
+ L.unsupported("SC1090", args[1], "sessionError listeners with more than two parameters or returning a value");
1150
1141
  }
1151
- return { kind: "libCall", fn: "http2.serverOnSessionError", args: [receiver, cb], type: VOID, loc };
1142
+ const [err, session] = cb.type.params;
1143
+ if ((err !== undefined && !(err.kind === "object" && err.className === "%Error")) ||
1144
+ (session !== undefined && session.kind !== "http2Session")) {
1145
+ L.unsupported("SC1090", args[1], "sessionError listeners whose parameters are not (error: Error, session: ServerHttp2Session)");
1146
+ }
1147
+ return { kind: "libCall", fn: "http2.serverOnSessionError", args: [receiver, cb, once], type: VOID, loc };
1152
1148
  }
1153
1149
  L.noLowering(`server.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"connection", "request", "stream", "session", "upgrade", "connect", "error", "close", "listening", and "sessionError" are the supported server events (as literals)');
1154
1150
  }
@@ -1409,7 +1405,7 @@ function lowerNetSocketMethodCall(L, call, access) {
1409
1405
  * entry in lower-calls.ts's intrinsic chain (the lowerChildMethodCall
1410
1406
  * slot). Null when the receiver is neither. */
1411
1407
  export function lowerServerMethodCall(L, call, access) {
1412
- if (call.questionDotToken || access.questionDotToken)
1408
+ if (call.questionDotToken || (access.questionDotToken && !L.chainHandled.has(access)))
1413
1409
  return null;
1414
1410
  return (lowerServerCloseBind(L, call, access) ??
1415
1411
  lowerNetServerMethodCall(L, call, access) ??
@@ -1647,15 +1643,18 @@ function lowerH2SessionMethodCall(L, call, access) {
1647
1643
  L.noLowering(`session.${name}`, call, "close/destroy/request and on(\"close\"|\"error\"|\"connect\"|\"stream\"|\"goaway\") are the lowered session members");
1648
1644
  }
1649
1645
  /** Method calls on ClientHttp2Stream / ServerHttp2Stream receivers. */
1650
- function lowerH2StreamMethodCall(L, call, access) {
1651
- if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "http2Stream")
1646
+ function lowerH2StreamMethodCall(L, call, access, receiverOverride) {
1647
+ const compatReqStream = ts.isPropertyAccessExpression(access.expression) &&
1648
+ access.expression.name.text === "stream" &&
1649
+ L.mapTypeOf(L.typeOf(access.expression.expression))?.kind === "httpReq";
1650
+ if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "http2Stream" && !compatReqStream)
1652
1651
  return null;
1653
- if (!L.isStdlibMember(access))
1652
+ if (!L.isStdlibMember(access) && !compatReqStream)
1654
1653
  return null;
1655
1654
  const name = access.name.text;
1656
1655
  const loc = locOf(call);
1657
1656
  const args = call.arguments;
1658
- const receiver = () => handleReceiver(L, access.expression, HTTP2STREAM_T);
1657
+ const receiver = () => receiverOverride ?? handleReceiver(L, access.expression, HTTP2STREAM_T);
1659
1658
  if (name === "respond") {
1660
1659
  requireStatementPosition(L, call, "stream.respond(...)");
1661
1660
  const headersArg = args.length >= 1
@@ -1745,6 +1744,32 @@ function lowerH2StreamMethodCall(L, call, access) {
1745
1744
  }
1746
1745
  L.noLowering(`stream.${name}`, call, "respond/write/end/close/destroy/setEncoding/resume/pause and on(...) are the lowered stream members");
1747
1746
  }
1747
+ /** A compatibility request's `req.stream?.method(...)`: the static Node
1748
+ * type omits the HTTP/1 undefined arm, so build the runtime guard explicitly.
1749
+ * The body receives the narrowed backing stream directly, preserving lazy
1750
+ * argument evaluation on the HTTP/1 arm. */
1751
+ export function lowerCompatReqStreamOptionalCall(L, call) {
1752
+ if (!ts.isPropertyAccessExpression(call.expression) || !call.expression.questionDotToken)
1753
+ return null;
1754
+ const stream = call.expression.expression;
1755
+ if (!ts.isPropertyAccessExpression(stream) || stream.name.text !== "stream" ||
1756
+ L.mapTypeOf(L.typeOf(stream.expression))?.kind !== "httpReq")
1757
+ return null;
1758
+ const loc = locOf(call);
1759
+ const unionT = { kind: "union", unionId: L.unions.intern([HTTP2STREAM_T, UNDEFINED_T]) };
1760
+ const guarded = {
1761
+ kind: "libCall",
1762
+ fn: "http.reqH2Stream",
1763
+ args: [handleReceiver(L, stream.expression, HTTPREQ_T)],
1764
+ type: unionT,
1765
+ loc,
1766
+ };
1767
+ const id = `chain.${L.chainCounter++}`;
1768
+ const body = lowerH2StreamMethodCall(L, call, call.expression, { kind: "chainRecv", id, type: HTTP2STREAM_T, loc });
1769
+ if (body === null)
1770
+ return null;
1771
+ return { kind: "optChain", id, receiver: guarded, body, type: VOID, loc };
1772
+ }
1748
1773
  /** The composed `server.address().port` read — the crypto
1749
1774
  * randomBytes(n).toString(enc) precedent: the AddressInfo record between
1750
1775
  * the two reads never materializes; the runtime answers the bound port
@@ -1810,14 +1835,33 @@ export function lowerServerProperty(L, expr) {
1810
1835
  const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1811
1836
  return { kind: "libCall", fn: "http.reqStatusMessage", args: [receiver], type: L.envValueType(), loc };
1812
1837
  }
1813
- if (name === "stream" || name === "session") {
1814
- // Http2ServerRequest's h2-only members. On the allowHTTP1 lowering
1815
- // every connection is HTTP/1.1, where Node answers undefined for
1816
- // both — the CALL forms lower in lower-calls.ts (guarded ?. no-ops,
1817
- // unguarded throws Node's exact TypeError); a bare read in any
1818
- // other position has no undefined-typed value form here, so the
1819
- // fence names the compiling shapes.
1820
- L.noLowering(`reading '${name}' (an HTTP/2-only member) from a request`, expr, "the allowHTTP1 lowering serves every connection as HTTP/1.1, where Node answers undefined — method calls compile (req.stream?.on(...) no-ops; unguarded req.stream.on(...) throws Node's TypeError); other reads have no lowering");
1838
+ if (name === "stream") {
1839
+ const parent = expr.parent;
1840
+ if (ts.isPropertyAccessExpression(parent) && parent.expression === expr &&
1841
+ ts.isCallExpression(parent.parent) && parent.parent.expression === parent) {
1842
+ const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1843
+ if (parent.questionDotToken) {
1844
+ const type = {
1845
+ kind: "union",
1846
+ unionId: L.unions.intern([HTTP2STREAM_T, UNDEFINED_T]),
1847
+ };
1848
+ return { kind: "libCall", fn: "http.reqH2Stream", args: [receiver], type, loc };
1849
+ }
1850
+ return {
1851
+ kind: "libCall",
1852
+ fn: "http.reqH2StreamOrThrow",
1853
+ args: [receiver, { kind: "strLit", value: parent.name.text, type: STRING, loc }],
1854
+ type: HTTP2STREAM_T,
1855
+ loc,
1856
+ };
1857
+ }
1858
+ L.noLowering("reading 'stream' from a request outside a method call", expr, "call req.stream methods directly; optional calls remain undefined on HTTP/1 and use the live stream on HTTP/2");
1859
+ }
1860
+ if (name === "session") {
1861
+ // Http2ServerRequest's h2-only members are not exposed through the
1862
+ // compatibility request handle yet. The call forms retain their
1863
+ // guarded-no-op / unguarded-TypeError stance; other reads fence.
1864
+ L.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");
1821
1865
  }
1822
1866
  if (name === "headers") {
1823
1867
  // `req.headers` as a VALUE — the `{ ...req.headers }` spread and
@@ -1835,7 +1879,7 @@ export function lowerServerProperty(L, expr) {
1835
1879
  }
1836
1880
  }
1837
1881
  if (recvKind === "httpRes" && L.isStdlibMember(expr) && expr.name.text === "stream") {
1838
- L.noLowering("reading 'stream' (an HTTP/2-only member) from a response", expr, "the allowHTTP1 lowering serves every connection as HTTP/1.1, where Node answers undefined — guard method calls with '?.' or drop the use");
1882
+ L.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");
1839
1883
  }
1840
1884
  if (recvKind === "netSocket" && expr.name.text === "encrypted") {
1841
1885
  // `boolean | undefined` — Node types `encrypted` on TLSSocket only
@@ -2782,12 +2826,10 @@ function lowerHttpsModuleCall(L, expr, bi, loc) {
2782
2826
  }
2783
2827
  L.noLowering(`https.${bi.member}`, expr, "createServer, request, and get are the lowered https module functions", L.resolveValueSymbol(expr.expression));
2784
2828
  }
2785
- /** The h2 SESSION-tuning options of http2.createSecureServer: knobs that
2786
- * configure HTTP/2 sessions, which the allowHTTP1 lowering never creates
2787
- * (every connection serves HTTP/1.1 — SEMANTICS.md divergence 57). They
2788
- * are accepted and IGNORED — Node before 22.11 ignores the streamReset
2789
- * pair the same way — but only with LITERAL values, so nothing observable
2790
- * (a call, a read) is silently skipped. */
2829
+ /** The h2 SESSION-tuning options of http2.createSecureServer. This slice
2830
+ * runs most at their defaults, so they are accepted and ignored only with
2831
+ * literal values; settings.enableConnectProtocol is parsed explicitly
2832
+ * below because it changes the wire protocol and CONNECT dispatch. */
2791
2833
  const HTTP2_IGNORED_TUNING_OPTIONS = new Set([
2792
2834
  "streamResetBurst",
2793
2835
  "streamResetRate",
@@ -2817,13 +2859,9 @@ function stripParensAndCasts(node) {
2817
2859
  return e;
2818
2860
  }
2819
2861
  }
2820
- /** Module-function calls on http2 import bindings. The ONE lowered member
2821
- * is createSecureServer with allowHTTP1: true — the honest HTTP/1.1
2822
- * fallback: the existing TLS server + HTTP/1.1 parser, ALPN advertising
2823
- * http/1.1 only (h2-capable clients negotiate down; h2-only clients fail
2824
- * the handshake — SEMANTICS.md divergence 57). The handler arrives later
2825
- * via server.on("request", ...); h2 sessions (connect, the h2c
2826
- * createServer) and h2-only servers keep their fences. */
2862
+ /** Module-function calls on http2 import bindings. createServer lowers h2c;
2863
+ * createSecureServer lowers h2 over TLS, with allowHTTP1 selecting one
2864
+ * dual-ALPN server whose request/connect listeners mirror across parsers. */
2827
2865
  function lowerHttp2ModuleCall(L, expr, bi, loc) {
2828
2866
  const args = expr.arguments;
2829
2867
  if (bi.member === "createServer") {
@@ -2990,6 +3028,7 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
2990
3028
  let key = null;
2991
3029
  let sni = null;
2992
3030
  let allowHttp1 = false;
3031
+ let enableConnectProtocol = false;
2993
3032
  // The SNICallback value shape: (servername: string, cb) => void where
2994
3033
  // cb is (err: Error | null, ctx?: SecureContext) => void — cb may
2995
3034
  // declare fewer params (the emitted answer thunk matches its ABI),
@@ -3079,14 +3118,13 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3079
3118
  }
3080
3119
  const k = prop.name.text;
3081
3120
  if (k === "allowHTTP1") {
3082
- // A literal true or false: true keeps the compatibility server
3083
- // (HTTP/1.1 only — divergence 57's remaining arm); false IS the
3084
- // absent default — the h2-only ALPN server below. A runtime
3121
+ // A literal true or false: true selects the dual h2/http1 server;
3122
+ // false IS the absent default — the h2-only ALPN server below. A runtime
3085
3123
  // value would pick a protocol stack dynamically — fence.
3086
3124
  if (initializer !== null && initializer.kind === ts.SyntaxKind.FalseKeyword)
3087
3125
  return;
3088
3126
  if (initializer === null || initializer.kind !== ts.SyntaxKind.TrueKeyword) {
3089
- L.noLowering("createSecureServer with a non-literal allowHTTP1 option", prop, "allowHTTP1 picks the protocol stack (true: the HTTP/1.1 compatibility server; false/absent: the ALPN=h2 server) — spell it as a literal");
3127
+ L.noLowering("createSecureServer with a non-literal allowHTTP1 option", prop, "allowHTTP1 picks the protocol stack (true: dual h2/http1; false/absent: ALPN=h2 only) — spell it as a literal");
3090
3128
  }
3091
3129
  allowHttp1 = true;
3092
3130
  return;
@@ -3125,11 +3163,23 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3125
3163
  e.kind === ts.SyntaxKind.TrueKeyword || e.kind === ts.SyntaxKind.FalseKeyword;
3126
3164
  const isLiteralObjectOfLiterals = (e) => ts.isObjectLiteralExpression(e) &&
3127
3165
  e.properties.every((p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && isScalarLiteral(p.initializer));
3166
+ if (k === "settings" && initializer !== null && ts.isObjectLiteralExpression(initializer)) {
3167
+ for (const setting of initializer.properties) {
3168
+ if (ts.isPropertyAssignment(setting) && ts.isIdentifier(setting.name) &&
3169
+ setting.name.text === "enableConnectProtocol") {
3170
+ if (setting.initializer.kind !== ts.SyntaxKind.TrueKeyword &&
3171
+ setting.initializer.kind !== ts.SyntaxKind.FalseKeyword) {
3172
+ L.noLowering("settings.enableConnectProtocol with a non-boolean literal", setting, "spell enableConnectProtocol as true or false");
3173
+ }
3174
+ enableConnectProtocol = setting.initializer.kind === ts.SyntaxKind.TrueKeyword;
3175
+ }
3176
+ }
3177
+ }
3128
3178
  if (initializer !== null &&
3129
3179
  (isScalarLiteral(initializer) || isLiteralObjectOfLiterals(initializer))) {
3130
3180
  return;
3131
3181
  }
3132
- L.noLowering(`createSecureServer option '${k}' with a non-literal value`, prop, "h2 session-tuning options are accepted with literal values (settings: a literal of literals) and ignored — the allowHTTP1 lowering serves HTTP/1.1 only, which has no h2 sessions to tune");
3182
+ L.noLowering(`createSecureServer option '${k}' with a non-literal value`, prop, "h2 session-tuning options are accepted with literal values but are not applied yet");
3133
3183
  }
3134
3184
  if (k === "SNICallback") {
3135
3185
  if (initializer === null) {
@@ -3156,25 +3206,25 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3156
3206
  // SNI callbacks are an https-path feature; the h2 stack serves one
3157
3207
  // cert/key pair.
3158
3208
  if (sni !== null) {
3159
- L.noLowering("createSecureServer with an SNICallback and no allowHTTP1", optsNode, "SNICallback lowers on the allowHTTP1 compatibility server — the ALPN=h2 server serves one cert/key pair");
3209
+ L.noLowering("createSecureServer with an SNICallback and no allowHTTP1", optsNode, "SNICallback lowers on the dual allowHTTP1 server — the h2-only server serves one cert/key pair");
3160
3210
  }
3161
3211
  if (handlerNode !== null) {
3162
3212
  const cb = lowerRequestHandlerArg(L, handlerNode);
3163
- return { kind: "libCall", fn: "http2.createSecureServerH2Req", args: [cert, key, cb], type: NETSERVER_T, loc };
3213
+ return { kind: "libCall", fn: "http2.createSecureServerH2Req", args: [cert, key, cb, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
3164
3214
  }
3165
- return { kind: "libCall", fn: "http2.createSecureServerH2", args: [cert, key], type: NETSERVER_T, loc };
3215
+ return { kind: "libCall", fn: "http2.createSecureServerH2", args: [cert, key, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
3166
3216
  }
3167
3217
  if (sni !== null) {
3168
- return { kind: "libCall", fn: "http2.createSecureServerSni", args: [cert, key, sni], type: NETSERVER_T, loc };
3218
+ return { kind: "libCall", fn: "http2.createSecureServerSni", args: [cert, key, sni, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
3169
3219
  }
3170
3220
  if (handlerNode !== null) {
3171
3221
  const cb = lowerRequestHandlerArg(L, handlerNode);
3172
- return { kind: "libCall", fn: "http2.createSecureServerReq", args: [cert, key, cb], type: NETSERVER_T, loc };
3222
+ return { kind: "libCall", fn: "http2.createSecureServerReq", args: [cert, key, cb, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
3173
3223
  }
3174
- return { kind: "libCall", fn: "http2.createSecureServer", args: [cert, key], type: NETSERVER_T, loc };
3224
+ return { kind: "libCall", fn: "http2.createSecureServer", args: [cert, key, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
3175
3225
  }
3176
3226
  L.noLowering(`http2.${bi.member}`, expr, builtinFenceHintOf("http2", bi.member) ??
3177
- "createSecureServer({ allowHTTP1: true, cert, key }) is the lowered http2 surface — it serves HTTP/1.1 only (ALPN never advertises h2); h2 sessions have no lowering", L.resolveValueSymbol(expr.expression));
3227
+ "createSecureServer({ allowHTTP1: true, cert, key }) and the h2-only form are lowered", L.resolveValueSymbol(expr.expression));
3178
3228
  }
3179
3229
  /** http.request(options[, cb]) / http.get(options[, cb]) — the client.
3180
3230
  * The options argument must be an OBJECT LITERAL; the lowered keys are