@scriptc/compiler 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ambient/scriptc-node-fallback.d.ts +153 -24
- package/ambient/scriptc.d.ts +2 -2
- package/dist/backend/cc.d.ts +10 -2
- package/dist/backend/cc.js +12 -0
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-async.js +1 -1
- package/dist/backend/emission/emit-exprs.js +235 -64
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-island.js +1 -1
- package/dist/backend/emission/emit-shapes.js +1 -1
- package/dist/backend/emission/emit-walkers.d.ts +14 -14
- package/dist/backend/emission/emit-walkers.js +44 -44
- package/dist/backend/emission/emit-walkers.js.map +1 -1
- package/dist/backend/emission/emitter.d.ts +3 -3
- package/dist/backend/emission/emitter.js +8 -8
- package/dist/backend/emission/may-throw.js +1 -1
- package/dist/backend/llvm/dyn.d.ts +10 -10
- package/dist/backend/llvm/dyn.js +26 -26
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +140 -49
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/shapes.js +1 -1
- package/dist/backend/llvm/walkers.js +2 -2
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +1 -1
- package/dist/diagnostics/diagnostic.js +4 -3
- package/dist/diagnostics/diagnostic.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/lib-boundary.js +5 -5
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +12 -12
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +45 -27
- package/dist/frontend/lowering/lower-builtins.js +203 -70
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +4 -4
- package/dist/frontend/lowering/lower-calls.js +74 -66
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +41 -7
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +5 -5
- package/dist/frontend/lowering/lower-containers.js +19 -19
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-emitter.js +2 -2
- package/dist/frontend/lowering/lower-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +7 -7
- package/dist/frontend/lowering/lower-exprs.js +227 -119
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +5 -5
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +12 -3
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +17 -17
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +11 -1
- package/dist/frontend/lowering/lower-namespaces.js +41 -6
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +21 -0
- package/dist/frontend/lowering/lower-server.js +278 -23
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +1 -1
- package/dist/frontend/lowering/lower-stmts.js +195 -34
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +67 -23
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +31 -13
- package/dist/frontend/lowering/lowerer.js +99 -45
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +6 -0
- package/dist/frontend/lowering/surfaces.js +78 -2
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/program.js +1 -1
- package/dist/frontend/shared.js +7 -7
- package/dist/frontend/shared.js.map +1 -1
- package/dist/frontend/types.d.ts +2 -2
- package/dist/frontend/types.js +27 -15
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.js +44 -8
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +208 -106
- package/dist/ir/nodes.js +100 -22
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +96 -38
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/int-infer.js +13 -0
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/profile.d.ts +8 -6
- package/dist/library/profile.js.map +1 -1
- package/dist/library/sidecar-validate.js +1 -1
- package/dist/library/sidecar-validate.js.map +1 -1
- package/dist/library/sidecar.d.ts +1 -1
- package/dist/library/sidecar.js +20 -7
- package/dist/library/sidecar.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +289 -4
|
@@ -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
|
|
@@ -152,7 +152,7 @@ function lowerCallbackArg(L, node, what, maxParams, paramOk, paramHint, dynTuple
|
|
|
152
152
|
// hoisted `function onConn(socket)` — dyn params), or an
|
|
153
153
|
// arguments-reading rest function: box it and adapt through the
|
|
154
154
|
// dynCheck function boundary like the dyn flavor above — the event
|
|
155
|
-
// payloads box into the
|
|
155
|
+
// payloads box into the checked-dynamic tree (handles by reference) and the body's
|
|
156
156
|
// member uses dispatch at runtime.
|
|
157
157
|
const boxed = { kind: "dynFrom", value: cb, type: DYN, loc: locOf(node) };
|
|
158
158
|
const toT = funcOf([...dynTuple], VOID);
|
|
@@ -291,7 +291,7 @@ function h2HeadersCallbackAdapter(L, node, what, handleKind, withStatus, loc) {
|
|
|
291
291
|
// value or an arguments-reading rest function of dyn params): wrap it
|
|
292
292
|
// in a dynCheck to the CANONICAL event signature, then build the header
|
|
293
293
|
// record and invoke through that typed boundary (handles box by
|
|
294
|
-
// reference, the record boxes to a
|
|
294
|
+
// reference, the record boxes to a dyn object — the net server-callbacks
|
|
295
295
|
// precedent). The synthesized record IS the shape the adapter builds.
|
|
296
296
|
const handleT = handleKind === "http2Stream" ? HTTP2STREAM_T : null;
|
|
297
297
|
const isDynCb = cb.type.kind === "dyn" ||
|
|
@@ -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
|
|
@@ -1501,7 +1541,7 @@ function lowerH2SessionMethodCall(L, call, access) {
|
|
|
1501
1541
|
return { kind: "libCall", fn: "http2.sessionDestroy", args: [receiver()], type: VOID, loc };
|
|
1502
1542
|
}
|
|
1503
1543
|
if (name === "settings") {
|
|
1504
|
-
// session.settings(obj[, cb]): the settings record crosses as a
|
|
1544
|
+
// session.settings(obj[, cb]): the settings record crosses as a dyn
|
|
1505
1545
|
// value (the checked-dynamic boundary — object literals box); the
|
|
1506
1546
|
// callback fires on the peer's ACK ((err, settings, duration) in the
|
|
1507
1547
|
// dyn flavor, zero-arg in the typed one).
|
|
@@ -1515,7 +1555,7 @@ function lowerH2SessionMethodCall(L, call, access) {
|
|
|
1515
1555
|
const cbV = L.lowerExpr(args[1]);
|
|
1516
1556
|
if (cbV.type.kind === "dyn") {
|
|
1517
1557
|
// The dyn callback keeps Node's exact (err, settings, duration)
|
|
1518
|
-
// shape — the runtime fires it through the
|
|
1558
|
+
// shape — the runtime fires it through the checked-dynamic tree.
|
|
1519
1559
|
return { kind: "libCall", fn: "http2.sessionSettingsDynCb", args: [receiver(), settingsArg, cbV], type: VOID, loc };
|
|
1520
1560
|
}
|
|
1521
1561
|
const { cb } = lowerCallbackArg(L, args[1], "settings callbacks", 0, () => false, "use () — or a dynamic (mustCall-wrapped) callback for the (err, settings, duration) shape", []);
|
|
@@ -1529,7 +1569,7 @@ function lowerH2SessionMethodCall(L, call, access) {
|
|
|
1529
1569
|
const evT = L.typeOf(args[0]);
|
|
1530
1570
|
const event = evT.isStringLiteralType() ? evT.value : null;
|
|
1531
1571
|
if (event === "localSettings" || event === "remoteSettings") {
|
|
1532
|
-
// The settings payload crosses as a
|
|
1572
|
+
// The settings payload crosses as a dyn value: dyn (mustCall)
|
|
1533
1573
|
// listeners fire with the settings record; zero-arg typed
|
|
1534
1574
|
// listeners register plainly.
|
|
1535
1575
|
const local = boolLit(event === "localSettings", loc);
|
|
@@ -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
|
|
@@ -1845,7 +1896,7 @@ export function lowerServerProperty(L, expr) {
|
|
|
1845
1896
|
if (m === "pendingSettingsAck")
|
|
1846
1897
|
return { kind: "libCall", fn: "http2.sessionPendingSettingsAck", args: [recv()], type: BOOL, loc };
|
|
1847
1898
|
if (m === "localSettings" || m === "remoteSettings") {
|
|
1848
|
-
// The settings record crosses as a
|
|
1899
|
+
// The settings record crosses as a dyn value (the d.ts types it
|
|
1849
1900
|
// `any`): member reads ride the checked-dynamic keyed read.
|
|
1850
1901
|
return {
|
|
1851
1902
|
kind: "libCall", fn: "http2.sessionSettingsGet",
|
|
@@ -1900,7 +1951,7 @@ function lowerRequestHandlerArg(L, node) {
|
|
|
1900
1951
|
// A CHECKED-DYNAMIC handler (test/common's mustCall wrapper around
|
|
1901
1952
|
// the (req, res) listener — the canonical suite shape): adapt
|
|
1902
1953
|
// through the dynCheck function boundary. The adapter boxes req/res
|
|
1903
|
-
// as
|
|
1954
|
+
// as dyn HANDLE values (SCR_DYN_HANDLE — reference identity) and
|
|
1904
1955
|
// calls the wrapper through the checked-dynamic machinery; member
|
|
1905
1956
|
// uses inside the wrapped body dispatch back onto the same http
|
|
1906
1957
|
// entry points at runtime.
|
|
@@ -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) &&
|
|
@@ -2176,7 +2334,7 @@ function lowerTlsServerOptionsOrDyn(L, node, what) {
|
|
|
2176
2334
|
return { dyn: v };
|
|
2177
2335
|
// A typed options RECORD binding (`const options = { key, cert, ... };
|
|
2178
2336
|
// createServer(options)` — the Node-suite spelling): box it into the
|
|
2179
|
-
//
|
|
2337
|
+
// dyn and hand the whole record to the runtime walk (the divergence-66
|
|
2180
2338
|
// stance — members read at runtime, out-of-bounds ones throw the
|
|
2181
2339
|
// catchable fence, undefined/undocumented ones drop). canConvertToDyn
|
|
2182
2340
|
// now folds in the bytes-bearing option records the walker can box.
|
|
@@ -2246,7 +2404,7 @@ function lowerTlsConnectCall(L, expr, loc) {
|
|
|
2246
2404
|
}
|
|
2247
2405
|
}
|
|
2248
2406
|
// The options value rides whole to the runtime walk: dyn passes
|
|
2249
|
-
// directly; a typed record that converts boxes into the
|
|
2407
|
+
// directly; a typed record that converts boxes into the checked-dynamic tree.
|
|
2250
2408
|
let opts;
|
|
2251
2409
|
if (optsNode !== null) {
|
|
2252
2410
|
const o = L.lowerExpr(optsNode);
|
|
@@ -2265,7 +2423,7 @@ function lowerTlsConnectCall(L, expr, loc) {
|
|
|
2265
2423
|
L.noLowering("tls.connect without a port or options", expr, FORMS_HINT);
|
|
2266
2424
|
}
|
|
2267
2425
|
// No options: Node's defaults (rejectUnauthorized: true) — the
|
|
2268
|
-
// runtime walk reads an absent record (the
|
|
2426
|
+
// runtime walk reads an absent record (the dyn undefined).
|
|
2269
2427
|
opts = {
|
|
2270
2428
|
kind: "dynFrom",
|
|
2271
2429
|
value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc },
|
|
@@ -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);
|
|
@@ -2663,17 +2857,42 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
|
|
|
2663
2857
|
return { kind: "libCall", fn: "http2.connect", args: [auth, reject, ca], type: HTTP2SESSION_T, loc };
|
|
2664
2858
|
}
|
|
2665
2859
|
if (bi.member === "getDefaultSettings") {
|
|
2666
|
-
// The constant defaults record, as a
|
|
2860
|
+
// The constant defaults record, as a dyn value (the d.ts types it
|
|
2667
2861
|
// `any` — reads ride the checked-dynamic keyed read).
|
|
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) ??
|
|
@@ -2918,6 +3148,8 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
2918
3148
|
let connCb = null;
|
|
2919
3149
|
/** agent: false — inject Connection: close into the request head. */
|
|
2920
3150
|
let agentClose = null;
|
|
3151
|
+
/** agent: <Agent value> — the requestAgent rows thread the handle. */
|
|
3152
|
+
let agentVal = null;
|
|
2921
3153
|
for (const prop of optsNode.properties) {
|
|
2922
3154
|
// Shorthand entries ({ port } for { port: port }) are the natural
|
|
2923
3155
|
// spelling at these call sites — the shorthand's VALUE lowering
|
|
@@ -3055,8 +3287,11 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
3055
3287
|
// model, so it LOWERS (the header injects below). null/undefined
|
|
3056
3288
|
// pick the default agent, whose keep-alive request header the
|
|
3057
3289
|
// compiled client already sends (socket REUSE stays the
|
|
3058
|
-
// documented divergence either way). Agent
|
|
3059
|
-
//
|
|
3290
|
+
// documented divergence either way). An Agent VALUE (the lowered
|
|
3291
|
+
// `new http.Agent(...)` handle — a checked-dynamic value) threads
|
|
3292
|
+
// through the requestAgent rows: getName-keyed maxSockets
|
|
3293
|
+
// accounting over one-dial-per-request connections; a runtime
|
|
3294
|
+
// non-Agent value is Node's ERR_INVALID_ARG_TYPE.
|
|
3060
3295
|
const e = initializer !== null ? stripParensAndCasts(initializer) : null;
|
|
3061
3296
|
if (e !== null && e.kind === ts.SyntaxKind.FalseKeyword) {
|
|
3062
3297
|
agentClose = prop;
|
|
@@ -3067,9 +3302,14 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
3067
3302
|
(ts.isIdentifier(e) && e.text === "undefined"))) {
|
|
3068
3303
|
break; // the default agent: what the agent-free call compiles
|
|
3069
3304
|
}
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3305
|
+
const v = initializer !== null
|
|
3306
|
+
? L.lowerExpr(initializer)
|
|
3307
|
+
: L.lowerShorthandValue(prop);
|
|
3308
|
+
if (v.type.kind !== "dyn") {
|
|
3309
|
+
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 " +
|
|
3310
|
+
"(or false / null / undefined)");
|
|
3311
|
+
}
|
|
3312
|
+
agentVal = v;
|
|
3073
3313
|
break;
|
|
3074
3314
|
}
|
|
3075
3315
|
default:
|
|
@@ -3107,12 +3347,21 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
3107
3347
|
// exists — a silent half-use; set headers.host instead.
|
|
3108
3348
|
L.noLowering(`${member} mixing createConnection with hostname/host/port`, optsNode, "the dialer supplies the socket — set the Host header via headers: { host: ... } instead");
|
|
3109
3349
|
}
|
|
3350
|
+
if (agentVal !== null && connCb !== null) {
|
|
3351
|
+
L.noLowering(`${member} mixing an agent value with createConnection`, optsNode, "both own the dial — pass one or the other");
|
|
3352
|
+
}
|
|
3353
|
+
if (agentVal !== null && binding !== null) {
|
|
3354
|
+
L.noLowering(`${member} through a module-function binding with an agent value`, optsNode, "call http.request/https.request directly when passing an Agent");
|
|
3355
|
+
}
|
|
3110
3356
|
host ??= strLit("localhost");
|
|
3111
3357
|
// The binding mode's default port follows the runtime dial: 443 on the
|
|
3112
3358
|
// TLS arm, 80 on the plain one — exactly each client's own default.
|
|
3359
|
+
// With an AGENT the sentinel -1 says "no port option": the runtime
|
|
3360
|
+
// consults the agent's (settable) defaultPort first, Node's merge.
|
|
3113
3361
|
port ??= binding !== null
|
|
3114
3362
|
? { kind: "ternary", cond: secureExpr(), then: numLit(443), else_: numLit(80), type: F64, loc }
|
|
3115
|
-
:
|
|
3363
|
+
: agentVal !== null ? numLit(-1)
|
|
3364
|
+
: numLit(secure === true ? 443 : 80);
|
|
3116
3365
|
path ??= strLit("/");
|
|
3117
3366
|
method ??= strLit("GET");
|
|
3118
3367
|
timeout ??= numLit(0);
|
|
@@ -3132,14 +3381,20 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
|
|
|
3132
3381
|
ca ??= strLit(""); /* none: /etc/ssl/cert.pem stands in for Node's roots */
|
|
3133
3382
|
base.push(reject, ca);
|
|
3134
3383
|
}
|
|
3384
|
+
if (agentVal !== null)
|
|
3385
|
+
base.push(agentVal);
|
|
3135
3386
|
if (binding !== null)
|
|
3136
3387
|
base.unshift(secureExpr());
|
|
3137
3388
|
if (args.length === 1) {
|
|
3138
|
-
const fn = binding !== null ? "https.requestFn"
|
|
3389
|
+
const fn = binding !== null ? "https.requestFn"
|
|
3390
|
+
: secure === true ? (agentVal !== null ? "https.requestAgent" : "https.request")
|
|
3391
|
+
: agentVal !== null ? "http.requestAgent" : "http.request";
|
|
3139
3392
|
return { kind: "libCall", fn, args: base, type: HTTPCLIENTREQ_T, loc };
|
|
3140
3393
|
}
|
|
3141
3394
|
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"
|
|
3395
|
+
const fn = binding !== null ? "https.requestFnCb"
|
|
3396
|
+
: secure === true ? (agentVal !== null ? "https.requestAgentCb" : "https.requestCb")
|
|
3397
|
+
: agentVal !== null ? "http.requestAgentCb" : "http.requestCb";
|
|
3143
3398
|
return { kind: "libCall", fn, args: [...base, cb], type: HTTPCLIENTREQ_T, loc };
|
|
3144
3399
|
}
|
|
3145
3400
|
/** The headers option of http.request: an object literal with literal
|