@scriptc/compiler 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ambient/scriptc-node-fallback.d.ts +162 -19
- package/dist/backend/cc.d.ts +8 -0
- package/dist/backend/cc.js +12 -0
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-exprs.js +146 -16
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/llvm/emitter.js +54 -7
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/frontend/lowering/crypto-tables.d.ts +7 -0
- package/dist/frontend/lowering/crypto-tables.js +139 -0
- package/dist/frontend/lowering/crypto-tables.js.map +1 -0
- package/dist/frontend/lowering/lower-builtins.d.ts +38 -20
- package/dist/frontend/lowering/lower-builtins.js +111 -39
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +8 -0
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +10 -2
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +69 -7
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +1 -1
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +21 -0
- package/dist/frontend/lowering/lower-server.js +294 -23
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +4 -4
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +1 -1
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +21 -3
- package/dist/frontend/lowering/lowerer.js +48 -8
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +6 -0
- package/dist/frontend/lowering/surfaces.js +76 -0
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/types.js +12 -0
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +103 -9
- package/dist/ir/nodes.js +56 -1
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +55 -4
- package/dist/ir/validate.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +286 -1
|
@@ -12,7 +12,7 @@ import * as ts from "../ts7/adapter.js";
|
|
|
12
12
|
import { ladderFenceExpr, nodeThrowExpr } from "./lowerer.js";
|
|
13
13
|
import { isJsSourceFile, locOf } from "../program.js";
|
|
14
14
|
import { arrayOf, BOOL, BYTES_U8, canBoxFuncIntoDyn, canConvertToDyn, DYN, DYN_HANDLE_KINDS, F64, funcOf, HTTP2SESSION_T, HTTP2STREAM_T, HTTPCLIENTREQ_T, HTTPREQ_T, HTTPRES_T, NETSERVER_T, NETSOCKET_T, NULL_T, SECURECTX_T, STRING, UNDEFINED_T, typeKey, VOID } from "../../ir/nodes.js";
|
|
15
|
-
import { builtinFenceHintOf, builtinModuleFnOf, fenceOrDropOptionKey, HTTP_CLIENT_DOCUMENTED_OPTIONS, HTTP_SERVER_DOCUMENTED_OPTIONS, HTTP2_SECURE_SERVER_DOCUMENTED_OPTIONS, HTTPS_CLIENT_DOCUMENTED_OPTIONS, sideEffectFreeOptionValue, TLS_SERVER_DOCUMENTED_OPTIONS, } from "./surfaces.js";
|
|
15
|
+
import { AGENT_DOCUMENTED_OPTIONS, builtinFenceHintOf, builtinModuleFnOf, fenceOrDropOptionKey, HTTP_CLIENT_DOCUMENTED_OPTIONS, HTTP_SERVER_DOCUMENTED_OPTIONS, HTTP2_SECURE_SERVER_DOCUMENTED_OPTIONS, HTTPS_CLIENT_DOCUMENTED_OPTIONS, sideEffectFreeOptionValue, TLS_SERVER_DOCUMENTED_OPTIONS, } from "./surfaces.js";
|
|
16
16
|
import { conditionalSpreadOf } from "./lower-exprs.js";
|
|
17
17
|
/** The lowered value members of the net module — the surfaces.ts table's
|
|
18
18
|
* spoke-side twin (the call SHAPES are all special-cased here, so the
|
|
@@ -1244,6 +1244,40 @@ function lowerNetSocketMethodCall(L, call, access) {
|
|
|
1244
1244
|
const ms = L.lowerExprExpecting(args[0], F64);
|
|
1245
1245
|
return { kind: "libCall", fn: "net.sockSetTimeout", args: [receiver, ms], type: VOID, loc };
|
|
1246
1246
|
}
|
|
1247
|
+
if (name === "pause" || name === "resume") {
|
|
1248
|
+
// Flow control (the struct's flag comments in scr_net.c): pause holds
|
|
1249
|
+
// reads off — kernel/TCP backpressure is the buffer; resume flows
|
|
1250
|
+
// (and discards sans listeners, so 'end' is reachable). Both answer
|
|
1251
|
+
// the socket, Node's chaining.
|
|
1252
|
+
if (args.length !== 0) {
|
|
1253
|
+
L.noLowering(`${name} with ${args.length} arguments`, call, `the form is ${name}()`);
|
|
1254
|
+
}
|
|
1255
|
+
const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
|
|
1256
|
+
const fn = name === "pause" ? "net.sockPause" : "net.sockResume";
|
|
1257
|
+
return { kind: "libCall", fn, args: [receiver], type: NETSOCKET_T, loc };
|
|
1258
|
+
}
|
|
1259
|
+
if (name === "setNoDelay") {
|
|
1260
|
+
// TCP_NODELAY on the live fd; missing/undefined means true (Node).
|
|
1261
|
+
// Answers the socket, Node's chaining.
|
|
1262
|
+
if (args.length > 1) {
|
|
1263
|
+
L.noLowering(`setNoDelay with ${args.length} arguments`, call, "the form is setNoDelay(noDelay?)");
|
|
1264
|
+
}
|
|
1265
|
+
const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
|
|
1266
|
+
const enable = args.length === 1
|
|
1267
|
+
? L.lowerExprExpecting(args[0], BOOL)
|
|
1268
|
+
: boolLit(true, loc);
|
|
1269
|
+
return { kind: "libCall", fn: "net.sockSetNoDelay", args: [receiver, enable], type: NETSOCKET_T, loc };
|
|
1270
|
+
}
|
|
1271
|
+
if (name === "destroySoon") {
|
|
1272
|
+
// end() now, destroy once the FIN actually flushed — Node's
|
|
1273
|
+
// 'finish'-then-destroy.
|
|
1274
|
+
requireStatementPosition(L, call, "socket.destroySoon()");
|
|
1275
|
+
if (args.length !== 0) {
|
|
1276
|
+
L.noLowering(`destroySoon with ${args.length} arguments`, call, "the form is destroySoon()");
|
|
1277
|
+
}
|
|
1278
|
+
const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
|
|
1279
|
+
return { kind: "libCall", fn: "net.sockDestroySoon", args: [receiver], type: VOID, loc };
|
|
1280
|
+
}
|
|
1247
1281
|
if (name === "read") {
|
|
1248
1282
|
// socket.read(n?) — the demux peek. Answers the interned
|
|
1249
1283
|
// `Buffer | null` union: exactly n buffered bytes, or null (Node's
|
|
@@ -1311,6 +1345,12 @@ function lowerNetSocketMethodCall(L, call, access) {
|
|
|
1311
1345
|
: "net.sockOnConnect";
|
|
1312
1346
|
return { kind: "libCall", fn, args: [receiver, cb, once], type: VOID, loc };
|
|
1313
1347
|
}
|
|
1348
|
+
if (event === "finish") {
|
|
1349
|
+
// Fires once when the FIN goes out — once either way (the event
|
|
1350
|
+
// happens at most once per socket).
|
|
1351
|
+
const { cb } = lowerCallbackArg(L, args[1], "finish listeners", 0, () => false, "use ()", []);
|
|
1352
|
+
return { kind: "libCall", fn: "net.sockOnFinish", args: [receiver, cb], type: VOID, loc };
|
|
1353
|
+
}
|
|
1314
1354
|
if (event === "secureConnect") {
|
|
1315
1355
|
// The TLS client's post-handshake event: on a TLS socket the
|
|
1316
1356
|
// 'connect' list already fires at establishment (scr_net.c's
|
|
@@ -1794,6 +1834,17 @@ export function lowerServerProperty(L, expr) {
|
|
|
1794
1834
|
const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
|
|
1795
1835
|
return { kind: "libCall", fn: "net.sockWritable", args: [receiver], type: BOOL, loc };
|
|
1796
1836
|
}
|
|
1837
|
+
if (recvKind === "netSocket" && L.isStdlibMember(expr) && expr.name.text === "bytesWritten") {
|
|
1838
|
+
// Every byte the write paths accepted (buffered included — Node
|
|
1839
|
+
// counts those too; plaintext on TLS sockets).
|
|
1840
|
+
const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
|
|
1841
|
+
return { kind: "libCall", fn: "net.sockBytesWritten", args: [receiver], type: F64, loc };
|
|
1842
|
+
}
|
|
1843
|
+
if (recvKind === "netSocket" && L.isStdlibMember(expr) && expr.name.text === "readable") {
|
|
1844
|
+
// true until the read half is done (peer FIN / destroy).
|
|
1845
|
+
const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
|
|
1846
|
+
return { kind: "libCall", fn: "net.sockReadable", args: [receiver], type: BOOL, loc };
|
|
1847
|
+
}
|
|
1797
1848
|
if (recvKind === "netSocket" && L.isStdlibMember(expr) && expr.name.text === "remoteAddress") {
|
|
1798
1849
|
// `string | undefined` — Node's read-time caching: a value read while
|
|
1799
1850
|
// connected survives destroy; never-read sockets answer undefined
|
|
@@ -2037,6 +2088,113 @@ function lowerHttpCreateServerForms(L, expr, what, loc) {
|
|
|
2037
2088
|
* createServer (Node's Server class IS the factory's product); called
|
|
2038
2089
|
* from lowerNew ahead of the stdlib-constructor fence. Null when the
|
|
2039
2090
|
* callee is not the http module's Server. */
|
|
2091
|
+
/** `new http.Agent(opts?)` / `new https.Agent(opts?)` (property access or
|
|
2092
|
+
* named import): the Agent lowers to a checked-dynamic HANDLE —
|
|
2093
|
+
* getName/destroy and the sockets/requests/freeSockets counters dispatch
|
|
2094
|
+
* through the dyn handle ops, and the request path threads it (the
|
|
2095
|
+
* requestAgent rows). Options parse at the LITERAL construction site:
|
|
2096
|
+
* keepAlive (a boolean value — TRUE throws the runtime's named pooling
|
|
2097
|
+
* fence: this client dials one connection per request), keepAliveMsecs /
|
|
2098
|
+
* maxSockets / maxFreeSockets / timeout / port as numbers, scheduling
|
|
2099
|
+
* DROPS (no free pool exists, so selection order cannot observe), other
|
|
2100
|
+
* documented keys fence by name, and undocumented keys drop like Node
|
|
2101
|
+
* drops them. Null when the callee isn't the http/https Agent. */
|
|
2102
|
+
export function lowerHttpAgentNew(L, expr) {
|
|
2103
|
+
const callee = expr.expression;
|
|
2104
|
+
const bi = ts.isPropertyAccessExpression(callee) && callee.name.text === "Agent"
|
|
2105
|
+
? L.builtinMemberOf(callee)
|
|
2106
|
+
: ts.isIdentifier(callee)
|
|
2107
|
+
? L.builtinImportOf(callee)
|
|
2108
|
+
: null;
|
|
2109
|
+
if (!bi || bi.member !== "Agent" || (bi.module !== "http" && bi.module !== "https"))
|
|
2110
|
+
return null;
|
|
2111
|
+
const loc = locOf(expr);
|
|
2112
|
+
const api = `new ${bi.module}.Agent`;
|
|
2113
|
+
const numLit = (value) => ({ kind: "numLit", value, type: F64, loc });
|
|
2114
|
+
const boolAt = (value) => ({ kind: "boolLit", value, type: BOOL, loc });
|
|
2115
|
+
let keepAlive = boolAt(false);
|
|
2116
|
+
let kaMsecs = numLit(-1);
|
|
2117
|
+
let maxSockets = numLit(-1);
|
|
2118
|
+
let maxFree = numLit(-1);
|
|
2119
|
+
let timeout = numLit(-1);
|
|
2120
|
+
let port = numLit(-1);
|
|
2121
|
+
const args = expr.arguments ?? [];
|
|
2122
|
+
if (args.length > 1) {
|
|
2123
|
+
L.noLowering(`${api} with ${args.length} arguments`, expr, "the supported form is new Agent(options?)");
|
|
2124
|
+
}
|
|
2125
|
+
if (args.length === 1) {
|
|
2126
|
+
const optsNode = stripParensAndCasts(args[0]);
|
|
2127
|
+
if (!ts.isObjectLiteralExpression(optsNode)) {
|
|
2128
|
+
L.noLowering(`${api} with a non-literal options value`, args[0], "spell the options as an object literal at the construction site");
|
|
2129
|
+
}
|
|
2130
|
+
for (const prop of optsNode.properties) {
|
|
2131
|
+
if (ts.isSpreadAssignment(prop)) {
|
|
2132
|
+
L.noLowering(`${api} with an options spread`, prop, "write each option inline");
|
|
2133
|
+
}
|
|
2134
|
+
let initializer;
|
|
2135
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
2136
|
+
(ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name))) {
|
|
2137
|
+
initializer = prop.initializer;
|
|
2138
|
+
}
|
|
2139
|
+
else if (ts.isShorthandPropertyAssignment(prop)) {
|
|
2140
|
+
initializer = null;
|
|
2141
|
+
}
|
|
2142
|
+
else {
|
|
2143
|
+
L.noLowering(`${api} options with computed keys`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
|
|
2144
|
+
}
|
|
2145
|
+
const key = prop.name.text;
|
|
2146
|
+
const lowerVal = (want) => {
|
|
2147
|
+
const v = initializer !== null
|
|
2148
|
+
? L.lowerExpr(initializer)
|
|
2149
|
+
: L.lowerShorthandValue(prop);
|
|
2150
|
+
if (v.type.kind === "dyn") {
|
|
2151
|
+
return { kind: "dynCheck", value: v, type: want === "bool" ? BOOL : F64, loc: locOf(prop) };
|
|
2152
|
+
}
|
|
2153
|
+
if (v.type.kind !== want) {
|
|
2154
|
+
L.noLowering(`a ${api} '${key}' option of '${L.fmt(v.type)}' values`, prop, want === "bool" ? "the option value must be a boolean" : "the option value must be a number");
|
|
2155
|
+
}
|
|
2156
|
+
return v;
|
|
2157
|
+
};
|
|
2158
|
+
switch (key) {
|
|
2159
|
+
case "keepAlive":
|
|
2160
|
+
keepAlive = lowerVal("bool");
|
|
2161
|
+
break;
|
|
2162
|
+
case "keepAliveMsecs":
|
|
2163
|
+
kaMsecs = lowerVal("f64");
|
|
2164
|
+
break;
|
|
2165
|
+
case "maxSockets":
|
|
2166
|
+
maxSockets = lowerVal("f64");
|
|
2167
|
+
break;
|
|
2168
|
+
case "maxFreeSockets":
|
|
2169
|
+
maxFree = lowerVal("f64");
|
|
2170
|
+
break;
|
|
2171
|
+
case "timeout":
|
|
2172
|
+
timeout = lowerVal("f64");
|
|
2173
|
+
break;
|
|
2174
|
+
case "port":
|
|
2175
|
+
// Node merges agent options under portless request options —
|
|
2176
|
+
// the settable defaultPort carries this one.
|
|
2177
|
+
port = lowerVal("f64");
|
|
2178
|
+
break;
|
|
2179
|
+
case "scheduling":
|
|
2180
|
+
// Free-socket selection order: no free pool exists here (no
|
|
2181
|
+
// keep-alive reuse), so the choice cannot observe — dropped.
|
|
2182
|
+
if (initializer !== null)
|
|
2183
|
+
L.lowerExpr(initializer); // evaluate, like Node
|
|
2184
|
+
break;
|
|
2185
|
+
default:
|
|
2186
|
+
fenceOrDropOptionKey(L, prop, key, api, AGENT_DOCUMENTED_OPTIONS, "keepAlive, keepAliveMsecs, maxSockets, maxFreeSockets, timeout, port, and scheduling are the supported options");
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
return {
|
|
2191
|
+
kind: "libCall",
|
|
2192
|
+
fn: "http.agentNew",
|
|
2193
|
+
args: [boolAt(bi.module === "https"), keepAlive, kaMsecs, maxSockets, maxFree, timeout, port],
|
|
2194
|
+
type: DYN,
|
|
2195
|
+
loc,
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2040
2198
|
export function lowerHttpServerNew(L, expr) {
|
|
2041
2199
|
const callee = expr.expression;
|
|
2042
2200
|
const isHttpServer = (ts.isPropertyAccessExpression(callee) &&
|
|
@@ -2341,9 +2499,45 @@ function lowerTlsModuleCall(L, expr, bi, loc) {
|
|
|
2341
2499
|
}
|
|
2342
2500
|
return { kind: "libCall", fn: "tls.createSecureContext", args: [opts.cert, opts.key], type: SECURECTX_T, loc };
|
|
2343
2501
|
}
|
|
2502
|
+
// The CA-store introspection pair (scr_tls_ca.c — its own link gate, no
|
|
2503
|
+
// mbedTLS): getCACertificates(type?) answers the per-type cached PEM
|
|
2504
|
+
// string array (an omitted type completes to "default", Node's own
|
|
2505
|
+
// default; unknown strings throw Node's ERR_INVALID_ARG_VALUE at
|
|
2506
|
+
// runtime), and setDefaultCACertificates(certs) replaces the default
|
|
2507
|
+
// set and the client trust anchors. rootCertificates is a VALUE read —
|
|
2508
|
+
// lowerTlsRootCertificates below.
|
|
2509
|
+
if (bi.member === "getCACertificates") {
|
|
2510
|
+
if (args.length > 1) {
|
|
2511
|
+
L.noLowering(`getCACertificates with ${args.length} arguments`, expr);
|
|
2512
|
+
}
|
|
2513
|
+
const typeArg = args.length === 1
|
|
2514
|
+
? L.lowerExprExpecting(args[0], STRING)
|
|
2515
|
+
: { kind: "strLit", value: "default", type: STRING, loc };
|
|
2516
|
+
return { kind: "libCall", fn: "tlsca.get", args: [typeArg], type: arrayOf(STRING), loc };
|
|
2517
|
+
}
|
|
2518
|
+
if (bi.member === "setDefaultCACertificates") {
|
|
2519
|
+
if (args.length !== 1) {
|
|
2520
|
+
L.noLowering(`setDefaultCACertificates with ${args.length} arguments`, expr);
|
|
2521
|
+
}
|
|
2522
|
+
const certs = L.lowerExpr(args[0]);
|
|
2523
|
+
if (certs.type.kind !== "array" || certs.type.elem.kind !== "string") {
|
|
2524
|
+
L.noLowering(`setDefaultCACertificates of a '${L.fmt(certs.type)}' value`, args[0], "a string[] of PEM certificates is the lowered shape — decode Buffer/typed-array entries to strings first");
|
|
2525
|
+
}
|
|
2526
|
+
return { kind: "libCall", fn: "tlsca.set", args: [certs], type: VOID, loc };
|
|
2527
|
+
}
|
|
2344
2528
|
L.noLowering(`tls.${bi.member}`, expr, builtinFenceHintOf("tls", bi.member) ??
|
|
2345
2529
|
"createServer({ cert, key }, handler) and createSecureContext({ cert, key }) are the lowered tls module functions", L.resolveValueSymbol(expr.expression));
|
|
2346
2530
|
}
|
|
2531
|
+
/** The tls.rootCertificates VALUE read (any import spelling): the same
|
|
2532
|
+
* cached array getCACertificates("bundled") answers — Node's own
|
|
2533
|
+
* equality (test-tls-get-ca-certificates-bundled pins certs ===
|
|
2534
|
+
* rootCertificates). Null for other members (the property chains keep
|
|
2535
|
+
* trying). */
|
|
2536
|
+
export function lowerTlsRootCertificates(L, bi, loc) {
|
|
2537
|
+
if (bi.module !== "tls" || bi.member !== "rootCertificates")
|
|
2538
|
+
return null;
|
|
2539
|
+
return { kind: "libCall", fn: "tlsca.root", args: [], type: arrayOf(STRING), loc };
|
|
2540
|
+
}
|
|
2347
2541
|
const httpClientFnBindings = new WeakMap();
|
|
2348
2542
|
export function httpClientFnBindingOf(L, sym) {
|
|
2349
2543
|
return httpClientFnBindings.get(L)?.get(sym);
|
|
@@ -2668,12 +2862,37 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
|
|
|
2668
2862
|
return { kind: "libCall", fn: "http2.getDefaultSettings", args: [], type: DYN, loc };
|
|
2669
2863
|
}
|
|
2670
2864
|
if (bi.member === "createSecureServer") {
|
|
2671
|
-
if (args.length
|
|
2672
|
-
L.noLowering(`createSecureServer with ${args.length} arguments`, expr, "the supported
|
|
2865
|
+
if (args.length < 1 || args.length > 2) {
|
|
2866
|
+
L.noLowering(`createSecureServer with ${args.length} arguments`, expr, "the supported forms are createSecureServer(options[, onRequestHandler]) with options { allowHTTP1?, cert, key }");
|
|
2673
2867
|
}
|
|
2674
2868
|
const optsNode = args[0];
|
|
2869
|
+
// The eager (req, res) handler — Node routes it as the first
|
|
2870
|
+
// 'request' listener; both flavors' compat layers serve it (the
|
|
2871
|
+
// allowHTTP1 server's HTTP/1.1 handles, the h2 server's compat
|
|
2872
|
+
// handles over streams).
|
|
2873
|
+
const handlerNode = args.length === 2 ? args[1] : null;
|
|
2675
2874
|
if (!ts.isObjectLiteralExpression(optsNode)) {
|
|
2676
|
-
|
|
2875
|
+
// The RUNTIME options record (the divergence-66 stance, the
|
|
2876
|
+
// tls/https.createServerDyn precedent): allowHTTP1/cert/key read
|
|
2877
|
+
// at runtime, out-of-bounds TLS members throw the catchable
|
|
2878
|
+
// runtime fence, h2 session-tuning keys drop exactly like the
|
|
2879
|
+
// literal walk ignores them.
|
|
2880
|
+
const v = L.lowerExpr(optsNode);
|
|
2881
|
+
let dynOpts;
|
|
2882
|
+
if (v.type.kind === "dyn") {
|
|
2883
|
+
dynOpts = v;
|
|
2884
|
+
}
|
|
2885
|
+
else if (canConvertToDyn(v.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
|
|
2886
|
+
dynOpts = { kind: "dynFrom", value: v, type: DYN, loc: locOf(optsNode) };
|
|
2887
|
+
}
|
|
2888
|
+
else {
|
|
2889
|
+
L.noLowering("createSecureServer with a non-literal options argument", optsNode, "pass the options as an object literal ({ allowHTTP1: true, cert, key }) or a runtime record of those members");
|
|
2890
|
+
}
|
|
2891
|
+
if (handlerNode === null) {
|
|
2892
|
+
return { kind: "libCall", fn: "http2.createSecureServerDyn", args: [dynOpts], type: NETSERVER_T, loc };
|
|
2893
|
+
}
|
|
2894
|
+
const cb = lowerRequestHandlerArg(L, handlerNode);
|
|
2895
|
+
return { kind: "libCall", fn: "http2.createSecureServerDynCb", args: [dynOpts, cb], type: NETSERVER_T, loc };
|
|
2677
2896
|
}
|
|
2678
2897
|
let cert = null;
|
|
2679
2898
|
let key = null;
|
|
@@ -2835,6 +3054,9 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
|
|
|
2835
3054
|
if (cert === null || key === null) {
|
|
2836
3055
|
L.noLowering("createSecureServer without both cert and key", optsNode, "the supported options object is { allowHTTP1?, cert, key } (PEM strings or Buffers)");
|
|
2837
3056
|
}
|
|
3057
|
+
if (sni !== null && handlerNode !== null) {
|
|
3058
|
+
L.noLowering("createSecureServer with both an SNICallback and an eager handler", expr, "register the handler separately: server.on(\"request\", (req, res) => ...)");
|
|
3059
|
+
}
|
|
2838
3060
|
if (!allowHttp1) {
|
|
2839
3061
|
// The REAL h2-over-TLS server (scr_http2.c + scr_tls.c): ALPN
|
|
2840
3062
|
// advertises h2 alone and the h2 session attaches at establishment
|
|
@@ -2844,11 +3066,19 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
|
|
|
2844
3066
|
if (sni !== null) {
|
|
2845
3067
|
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");
|
|
2846
3068
|
}
|
|
3069
|
+
if (handlerNode !== null) {
|
|
3070
|
+
const cb = lowerRequestHandlerArg(L, handlerNode);
|
|
3071
|
+
return { kind: "libCall", fn: "http2.createSecureServerH2Req", args: [cert, key, cb], type: NETSERVER_T, loc };
|
|
3072
|
+
}
|
|
2847
3073
|
return { kind: "libCall", fn: "http2.createSecureServerH2", args: [cert, key], type: NETSERVER_T, loc };
|
|
2848
3074
|
}
|
|
2849
3075
|
if (sni !== null) {
|
|
2850
3076
|
return { kind: "libCall", fn: "http2.createSecureServerSni", args: [cert, key, sni], type: NETSERVER_T, loc };
|
|
2851
3077
|
}
|
|
3078
|
+
if (handlerNode !== null) {
|
|
3079
|
+
const cb = lowerRequestHandlerArg(L, handlerNode);
|
|
3080
|
+
return { kind: "libCall", fn: "http2.createSecureServerReq", args: [cert, key, cb], type: NETSERVER_T, loc };
|
|
3081
|
+
}
|
|
2852
3082
|
return { kind: "libCall", fn: "http2.createSecureServer", args: [cert, key], type: NETSERVER_T, loc };
|
|
2853
3083
|
}
|
|
2854
3084
|
L.noLowering(`http2.${bi.member}`, expr, builtinFenceHintOf("http2", bi.member) ??
|
|
@@ -2860,8 +3090,8 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
|
|
|
2860
3090
|
* object literal with string values, or any Record whose values are
|
|
2861
3091
|
* strings / `string | undefined` — the env.pairs shape). Every other key
|
|
2862
3092
|
* fences by name. The callback registers as once('response'); get() is
|
|
2863
|
-
* request() plus the eager end().
|
|
2864
|
-
*
|
|
3093
|
+
* request() plus the eager end(). A URL-STRING first argument takes the
|
|
3094
|
+
* requestUrl row instead (both schemes; see below). `secure` is the https
|
|
2865
3095
|
* spelling: port defaults to 443 and the rejectUnauthorized (boolean)
|
|
2866
3096
|
* and ca (PEM string/Buffer) options join the lowered set. A
|
|
2867
3097
|
* HttpClientFnBinding as `secure` is the requestFn-binding mode: whether
|
|
@@ -2890,22 +3120,38 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
2890
3120
|
const optsNode = args[0];
|
|
2891
3121
|
if (!ts.isObjectLiteralExpression(optsNode)) {
|
|
2892
3122
|
const t = L.mapTypeOf(L.typeOf(optsNode));
|
|
2893
|
-
if (t?.kind === "string" &&
|
|
2894
|
-
// The URL-string form — http.get(`http://127.0.0.1:${port}/x`[, cb])
|
|
2895
|
-
// the runtime parses through the WHATWG unit
|
|
2896
|
-
// inputs and
|
|
2897
|
-
|
|
3123
|
+
if ((t?.kind === "string" || t?.kind === "url") && binding === null) {
|
|
3124
|
+
// The URL-string form — http.get(`http://127.0.0.1:${port}/x`[, cb])
|
|
3125
|
+
// and its https spelling: the runtime parses through the WHATWG unit
|
|
3126
|
+
// and dials; unparsable inputs and a scheme that is not the calling
|
|
3127
|
+
// module's throw catchably (may-throw seed). No options means Node's
|
|
3128
|
+
// defaults, which for https is verification against the default
|
|
3129
|
+
// trust anchors. The requestFn binding has no URL row — whether the
|
|
3130
|
+
// dial is TLS is only known at runtime there, and the two schemes
|
|
3131
|
+
// reject each other's URLs.
|
|
3132
|
+
// A URL OBJECT is its href through the same parse — Node's own
|
|
3133
|
+
// reading of the argument, and the serialization round-trips.
|
|
3134
|
+
const url = t.kind === "url"
|
|
3135
|
+
? { kind: "libCall", fn: "url.href", args: [L.lowerExpr(optsNode)], type: STRING, loc }
|
|
3136
|
+
: L.lowerExprExpecting(optsNode, STRING);
|
|
2898
3137
|
const methodLit = { kind: "strLit", value: "GET", type: STRING, loc };
|
|
2899
3138
|
const autoEnd = boolLit(member === "get", loc);
|
|
3139
|
+
const isTls = secure === true;
|
|
2900
3140
|
if (args.length === 1) {
|
|
2901
|
-
|
|
3141
|
+
const fn = isTls ? "https.requestUrl" : "http.requestUrl";
|
|
3142
|
+
return { kind: "libCall", fn, args: [url, methodLit, autoEnd], type: HTTPCLIENTREQ_T, loc };
|
|
2902
3143
|
}
|
|
2903
3144
|
const { cb } = lowerCallbackArg(L, args[1], "response callbacks", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
|
|
2904
|
-
|
|
3145
|
+
const fn = isTls ? "https.requestUrlCb" : "http.requestUrlCb";
|
|
3146
|
+
return { kind: "libCall", fn, args: [url, methodLit, autoEnd, cb], type: HTTPCLIENTREQ_T, loc };
|
|
2905
3147
|
}
|
|
2906
3148
|
L.noLowering(t?.kind === "string"
|
|
2907
|
-
?
|
|
2908
|
-
: `${member} with a non-literal options argument`, optsNode,
|
|
3149
|
+
? `a URL-string first argument through a request-function binding`
|
|
3150
|
+
: `${member} with a non-literal options argument`, optsNode, t?.kind === "string"
|
|
3151
|
+
// Only the binding mode reaches here now: the scheme would have to
|
|
3152
|
+
// agree with a dial chosen at runtime.
|
|
3153
|
+
? "call http.request / https.request directly for the URL-string form, or pass the options as an object literal"
|
|
3154
|
+
: "pass the options as an object literal: { hostname, port, path, method, timeout?, headers? }");
|
|
2909
3155
|
}
|
|
2910
3156
|
let host = null;
|
|
2911
3157
|
let port = null;
|
|
@@ -2918,6 +3164,8 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
2918
3164
|
let connCb = null;
|
|
2919
3165
|
/** agent: false — inject Connection: close into the request head. */
|
|
2920
3166
|
let agentClose = null;
|
|
3167
|
+
/** agent: <Agent value> — the requestAgent rows thread the handle. */
|
|
3168
|
+
let agentVal = null;
|
|
2921
3169
|
for (const prop of optsNode.properties) {
|
|
2922
3170
|
// Shorthand entries ({ port } for { port: port }) are the natural
|
|
2923
3171
|
// spelling at these call sites — the shorthand's VALUE lowering
|
|
@@ -3055,8 +3303,11 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
3055
3303
|
// model, so it LOWERS (the header injects below). null/undefined
|
|
3056
3304
|
// pick the default agent, whose keep-alive request header the
|
|
3057
3305
|
// compiled client already sends (socket REUSE stays the
|
|
3058
|
-
// documented divergence either way). Agent
|
|
3059
|
-
//
|
|
3306
|
+
// documented divergence either way). An Agent VALUE (the lowered
|
|
3307
|
+
// `new http.Agent(...)` handle — a checked-dynamic value) threads
|
|
3308
|
+
// through the requestAgent rows: getName-keyed maxSockets
|
|
3309
|
+
// accounting over one-dial-per-request connections; a runtime
|
|
3310
|
+
// non-Agent value is Node's ERR_INVALID_ARG_TYPE.
|
|
3060
3311
|
const e = initializer !== null ? stripParensAndCasts(initializer) : null;
|
|
3061
3312
|
if (e !== null && e.kind === ts.SyntaxKind.FalseKeyword) {
|
|
3062
3313
|
agentClose = prop;
|
|
@@ -3067,9 +3318,14 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
3067
3318
|
(ts.isIdentifier(e) && e.text === "undefined"))) {
|
|
3068
3319
|
break; // the default agent: what the agent-free call compiles
|
|
3069
3320
|
}
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3321
|
+
const v = initializer !== null
|
|
3322
|
+
? L.lowerExpr(initializer)
|
|
3323
|
+
: L.lowerShorthandValue(prop);
|
|
3324
|
+
if (v.type.kind !== "dyn") {
|
|
3325
|
+
L.noLowering(`a ${member} 'agent' option of '${L.fmt(v.type)}' values`, prop, "the agent is the checked-dynamic Agent handle new http.Agent(...) answers " +
|
|
3326
|
+
"(or false / null / undefined)");
|
|
3327
|
+
}
|
|
3328
|
+
agentVal = v;
|
|
3073
3329
|
break;
|
|
3074
3330
|
}
|
|
3075
3331
|
default:
|
|
@@ -3107,12 +3363,21 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
3107
3363
|
// exists — a silent half-use; set headers.host instead.
|
|
3108
3364
|
L.noLowering(`${member} mixing createConnection with hostname/host/port`, optsNode, "the dialer supplies the socket — set the Host header via headers: { host: ... } instead");
|
|
3109
3365
|
}
|
|
3366
|
+
if (agentVal !== null && connCb !== null) {
|
|
3367
|
+
L.noLowering(`${member} mixing an agent value with createConnection`, optsNode, "both own the dial — pass one or the other");
|
|
3368
|
+
}
|
|
3369
|
+
if (agentVal !== null && binding !== null) {
|
|
3370
|
+
L.noLowering(`${member} through a module-function binding with an agent value`, optsNode, "call http.request/https.request directly when passing an Agent");
|
|
3371
|
+
}
|
|
3110
3372
|
host ??= strLit("localhost");
|
|
3111
3373
|
// The binding mode's default port follows the runtime dial: 443 on the
|
|
3112
3374
|
// TLS arm, 80 on the plain one — exactly each client's own default.
|
|
3375
|
+
// With an AGENT the sentinel -1 says "no port option": the runtime
|
|
3376
|
+
// consults the agent's (settable) defaultPort first, Node's merge.
|
|
3113
3377
|
port ??= binding !== null
|
|
3114
3378
|
? { kind: "ternary", cond: secureExpr(), then: numLit(443), else_: numLit(80), type: F64, loc }
|
|
3115
|
-
:
|
|
3379
|
+
: agentVal !== null ? numLit(-1)
|
|
3380
|
+
: numLit(secure === true ? 443 : 80);
|
|
3116
3381
|
path ??= strLit("/");
|
|
3117
3382
|
method ??= strLit("GET");
|
|
3118
3383
|
timeout ??= numLit(0);
|
|
@@ -3132,14 +3397,20 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
3132
3397
|
ca ??= strLit(""); /* none: /etc/ssl/cert.pem stands in for Node's roots */
|
|
3133
3398
|
base.push(reject, ca);
|
|
3134
3399
|
}
|
|
3400
|
+
if (agentVal !== null)
|
|
3401
|
+
base.push(agentVal);
|
|
3135
3402
|
if (binding !== null)
|
|
3136
3403
|
base.unshift(secureExpr());
|
|
3137
3404
|
if (args.length === 1) {
|
|
3138
|
-
const fn = binding !== null ? "https.requestFn"
|
|
3405
|
+
const fn = binding !== null ? "https.requestFn"
|
|
3406
|
+
: secure === true ? (agentVal !== null ? "https.requestAgent" : "https.request")
|
|
3407
|
+
: agentVal !== null ? "http.requestAgent" : "http.request";
|
|
3139
3408
|
return { kind: "libCall", fn, args: base, type: HTTPCLIENTREQ_T, loc };
|
|
3140
3409
|
}
|
|
3141
3410
|
const { cb } = lowerCallbackArg(L, args[1], "response callbacks", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
|
|
3142
|
-
const fn = binding !== null ? "https.requestFnCb"
|
|
3411
|
+
const fn = binding !== null ? "https.requestFnCb"
|
|
3412
|
+
: secure === true ? (agentVal !== null ? "https.requestAgentCb" : "https.requestCb")
|
|
3413
|
+
: agentVal !== null ? "http.requestAgentCb" : "http.requestCb";
|
|
3143
3414
|
return { kind: "libCall", fn, args: [...base, cb], type: HTTPCLIENTREQ_T, loc };
|
|
3144
3415
|
}
|
|
3145
3416
|
/** The headers option of http.request: an object literal with literal
|