@promigence/sdk 0.1.0-beta.13 → 0.1.0-beta.15
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/dist/cjs/client.d.ts +84 -14
- package/dist/cjs/client.js +126 -34
- package/dist/cjs/core.d.ts +1 -1
- package/dist/cjs/core.js +3 -1
- package/dist/cjs/http2.d.ts +1 -0
- package/dist/cjs/http2.js +194 -22
- package/dist/cjs/models.gen.d.ts +599 -36
- package/dist/cjs/pty.d.ts +11 -14
- package/dist/cjs/pty.js +15 -12
- package/dist/cjs/trace.d.ts +2 -0
- package/dist/cjs/trace.js +17 -0
- package/dist/cjs/transport-worker.js +72 -12
- package/dist/client.d.ts +84 -14
- package/dist/client.js +125 -33
- package/dist/core.d.ts +1 -1
- package/dist/core.js +3 -1
- package/dist/http2.d.ts +1 -0
- package/dist/http2.js +195 -23
- package/dist/models.gen.d.ts +599 -36
- package/dist/pty.d.ts +11 -14
- package/dist/pty.js +13 -11
- package/dist/trace.d.ts +2 -0
- package/dist/trace.js +16 -0
- package/dist/transport-worker.js +72 -12
- package/package.json +1 -1
package/dist/cjs/http2.js
CHANGED
|
@@ -21,6 +21,7 @@ const MAX_SESSIONS = 4;
|
|
|
21
21
|
const FIRST_SESSIONS = 2;
|
|
22
22
|
const BURST_MIN = 8;
|
|
23
23
|
const HOLD_MS = 10;
|
|
24
|
+
const STANDBY_AFTER_MS = 300;
|
|
24
25
|
const LOAD_FIRST_USE_MS = 120_000;
|
|
25
26
|
const CONNECT_TIMEOUT_MS = 10_000;
|
|
26
27
|
const IDLE_CLOSE_MS = 10_000;
|
|
@@ -572,6 +573,7 @@ exports.tuning = {
|
|
|
572
573
|
holdMs: HOLD_MS,
|
|
573
574
|
burstMin: BURST_MIN,
|
|
574
575
|
loadFirstUseMs: LOAD_FIRST_USE_MS,
|
|
576
|
+
standbyAfterMs: STANDBY_AFTER_MS,
|
|
575
577
|
earlyPlatform: undefined,
|
|
576
578
|
earlyServers: undefined,
|
|
577
579
|
earlyHostsFile: undefined,
|
|
@@ -855,7 +857,9 @@ function apiLookup(asked, observe, ipv4First = v4First(), earlyOk = true) {
|
|
|
855
857
|
const earlies = new Map();
|
|
856
858
|
const MAX_EARLIES = 4;
|
|
857
859
|
const EARLY_MAX_AGE_MS = 60_000;
|
|
858
|
-
const
|
|
860
|
+
const LOOKUP_FIRST_MS = 150;
|
|
861
|
+
const LOOKUP_TRIES = 3;
|
|
862
|
+
const LOOKUP_AT_MS = [0, 100, 250];
|
|
859
863
|
const DNS_AT_LOAD = (() => {
|
|
860
864
|
try {
|
|
861
865
|
return nodeDns();
|
|
@@ -876,8 +880,8 @@ function lookupReplaced() {
|
|
|
876
880
|
const EARLY_WORKER = `
|
|
877
881
|
const { workerData } = require("node:worker_threads");
|
|
878
882
|
const { isIPv4 } = require("node:net");
|
|
879
|
-
const { port, host, timeoutMs, servers, hostsFile } = workerData;
|
|
880
|
-
const done = (m) => { try { port.postMessage(m); } catch {} try { port.close(); } catch {} };
|
|
883
|
+
const { port, host, timeoutMs, tries, atMs, servers, hostsFile } = workerData;
|
|
884
|
+
const done = (m) => { m.hr = Number(process.hrtime.bigint()) / 1e6; try { port.postMessage(m); } catch {} try { port.close(); } catch {} };
|
|
881
885
|
try {
|
|
882
886
|
let named = false;
|
|
883
887
|
const v4 = [];
|
|
@@ -891,12 +895,28 @@ try {
|
|
|
891
895
|
} catch {}
|
|
892
896
|
if (named) done(v4.length > 0 ? { host, addrs: v4, ttl: 60, at: Date.now() } : { host, none: "hosts" });
|
|
893
897
|
else {
|
|
894
|
-
const
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
});
|
|
898
|
+
const { Resolver } = require("node:dns");
|
|
899
|
+
const rs = [];
|
|
900
|
+
const timers = [];
|
|
901
|
+
let fin = false, asked = 0, failed = 0;
|
|
902
|
+
const finish = (m) => { if (fin) return; fin = true; for (const t of timers) clearTimeout(t); for (const r of rs) { try { r.cancel(); } catch {} } done(m); };
|
|
903
|
+
const gaveUp = (why) => { if (++failed < asked) return; if (asked < atMs.length) ask(); else finish({ host, none: why }); };
|
|
904
|
+
const ask = () => {
|
|
905
|
+
if (fin || asked >= atMs.length) return;
|
|
906
|
+
const k = asked++;
|
|
907
|
+
try {
|
|
908
|
+
const r = new Resolver({ timeout: timeoutMs, tries });
|
|
909
|
+
const list = Array.isArray(servers) && servers.length > 0 ? servers : r.getServers();
|
|
910
|
+
if (list.length > 0) r.setServers(list.map((_, i) => list[(i + k) % list.length]));
|
|
911
|
+
rs.push(r);
|
|
912
|
+
r.resolve4(host, { ttl: true }, (err, recs) => {
|
|
913
|
+
if (fin) return;
|
|
914
|
+
if (!err && Array.isArray(recs) && recs.length > 0) return finish({ host, addrs: recs.map((x) => x.address), ttl: Math.min(...recs.map((x) => x.ttl)), at: Date.now() });
|
|
915
|
+
gaveUp((err && err.code) || "empty");
|
|
916
|
+
});
|
|
917
|
+
} catch { gaveUp("error"); }
|
|
918
|
+
};
|
|
919
|
+
for (const ms of atMs) { if (ms <= 0) ask(); else timers.push(setTimeout(ask, ms)); }
|
|
900
920
|
}
|
|
901
921
|
} catch { done({ host, none: "error" }); }
|
|
902
922
|
`;
|
|
@@ -927,7 +947,7 @@ function earlyLookupFor(host) {
|
|
|
927
947
|
const worker = new node_worker_threads_1.Worker(EARLY_WORKER, {
|
|
928
948
|
eval: true,
|
|
929
949
|
workerData: {
|
|
930
|
-
port: port2, host, timeoutMs:
|
|
950
|
+
port: port2, host, timeoutMs: LOOKUP_FIRST_MS, tries: LOOKUP_TRIES, atMs: LOOKUP_AT_MS,
|
|
931
951
|
servers: exports.tuning.earlyServers ?? (Array.isArray(earlySeam().servers) ? earlySeam().servers : undefined),
|
|
932
952
|
hostsFile: exports.tuning.earlyHostsFile ?? (typeof earlySeam().hostsFile === "string" ? earlySeam().hostsFile : undefined),
|
|
933
953
|
},
|
|
@@ -975,6 +995,10 @@ function settleEarly(e, message) {
|
|
|
975
995
|
else {
|
|
976
996
|
e.state = "none";
|
|
977
997
|
}
|
|
998
|
+
if (trace_js_1.TRACE_ON) {
|
|
999
|
+
const at = typeof m?.hr === "number" ? m.hr - (Number(process.hrtime.bigint()) / 1e6 - performance.now()) : performance.now();
|
|
1000
|
+
(0, trace_js_1.traceEventAt)(e.state === "answered" ? `dns:early-answer ${addrs.length}` : `dns:early-none ${typeof m?.none === "string" ? m.none : "gone"}`, at);
|
|
1001
|
+
}
|
|
978
1002
|
safely(() => { e.port.close(); });
|
|
979
1003
|
const waiters = e.waiters.splice(0);
|
|
980
1004
|
for (const w of waiters)
|
|
@@ -1338,6 +1362,8 @@ class TransportThread {
|
|
|
1338
1362
|
everReady = false;
|
|
1339
1363
|
closedReason = "";
|
|
1340
1364
|
onFail;
|
|
1365
|
+
startedAt = performance.now();
|
|
1366
|
+
startWaiters = [];
|
|
1341
1367
|
inflight = new Map();
|
|
1342
1368
|
nextId = 1;
|
|
1343
1369
|
listening = false;
|
|
@@ -1377,10 +1403,41 @@ class TransportThread {
|
|
|
1377
1403
|
}
|
|
1378
1404
|
}
|
|
1379
1405
|
ready() {
|
|
1380
|
-
if (!this.listening && this.state !== "closed")
|
|
1406
|
+
if ((!this.listening || this.state === "starting") && this.state !== "closed")
|
|
1381
1407
|
this.poll();
|
|
1382
1408
|
return this.state === "ready" && this.sessions > 0 && this.inflight.size < this.sessions * this.limit && this.freeMarks.length > 0;
|
|
1383
1409
|
}
|
|
1410
|
+
starting() {
|
|
1411
|
+
if (this.state === "starting")
|
|
1412
|
+
this.poll();
|
|
1413
|
+
return this.state === "starting";
|
|
1414
|
+
}
|
|
1415
|
+
whenStarted(cb) {
|
|
1416
|
+
if (!this.starting()) {
|
|
1417
|
+
queueMicrotask(cb);
|
|
1418
|
+
return () => { };
|
|
1419
|
+
}
|
|
1420
|
+
this.startWaiters.push(cb);
|
|
1421
|
+
this.listen();
|
|
1422
|
+
return () => {
|
|
1423
|
+
const i = this.startWaiters.indexOf(cb);
|
|
1424
|
+
if (i >= 0)
|
|
1425
|
+
this.startWaiters.splice(i, 1);
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
started() {
|
|
1429
|
+
for (const cb of this.startWaiters.splice(0))
|
|
1430
|
+
safely(cb);
|
|
1431
|
+
}
|
|
1432
|
+
listen() {
|
|
1433
|
+
if (this.listening)
|
|
1434
|
+
return;
|
|
1435
|
+
this.listening = true;
|
|
1436
|
+
this.poll();
|
|
1437
|
+
this.port.on("message", (m) => { this.onMessage(m); });
|
|
1438
|
+
if (!this.refd)
|
|
1439
|
+
safely(() => { this.port.unref(); });
|
|
1440
|
+
}
|
|
1384
1441
|
onMessage(m) {
|
|
1385
1442
|
const msg = m;
|
|
1386
1443
|
this.messages++;
|
|
@@ -1403,8 +1460,16 @@ class TransportThread {
|
|
|
1403
1460
|
if (typeof c.index === "number" && typeof c.addr === "string" && typeof c.localPort === "number")
|
|
1404
1461
|
(0, trace_js_1.traceEventAt)(`thread:conn${c.index} ${c.addr} ${c.localPort}`, t);
|
|
1405
1462
|
}
|
|
1463
|
+
if (first)
|
|
1464
|
+
this.started();
|
|
1406
1465
|
}
|
|
1407
1466
|
return;
|
|
1467
|
+
case "ev": {
|
|
1468
|
+
const e = msg;
|
|
1469
|
+
if (typeof e.n === "string" && typeof e.hr === "number")
|
|
1470
|
+
(0, trace_js_1.traceEventAt)(`thread:w-${e.n}`, e.hr - this.hrOffset);
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1408
1473
|
case "sessions":
|
|
1409
1474
|
if (typeof msg.sessions === "number")
|
|
1410
1475
|
this.sessions = msg.sessions;
|
|
@@ -1415,6 +1480,7 @@ class TransportThread {
|
|
|
1415
1480
|
if (this.closedReason === "")
|
|
1416
1481
|
this.closedReason = msg.reason ?? "draining";
|
|
1417
1482
|
(0, trace_js_1.traceEvent)("thread:draining");
|
|
1483
|
+
this.started();
|
|
1418
1484
|
}
|
|
1419
1485
|
return;
|
|
1420
1486
|
case "closed":
|
|
@@ -1495,6 +1561,7 @@ class TransportThread {
|
|
|
1495
1561
|
this.port.postMessage({ t: "drain" });
|
|
1496
1562
|
}
|
|
1497
1563
|
catch { }
|
|
1564
|
+
this.started();
|
|
1498
1565
|
}
|
|
1499
1566
|
close(reason) {
|
|
1500
1567
|
if (this.state === "closed")
|
|
@@ -1503,6 +1570,7 @@ class TransportThread {
|
|
|
1503
1570
|
if (this.closedReason === "")
|
|
1504
1571
|
this.closedReason = reason;
|
|
1505
1572
|
(0, trace_js_1.traceEvent)("thread:closed");
|
|
1573
|
+
this.started();
|
|
1506
1574
|
this.outbox = [];
|
|
1507
1575
|
for (const [id, p] of [...this.inflight]) {
|
|
1508
1576
|
const sent = this.acked(p);
|
|
@@ -1525,11 +1593,7 @@ class TransportThread {
|
|
|
1525
1593
|
}
|
|
1526
1594
|
}
|
|
1527
1595
|
ref() {
|
|
1528
|
-
|
|
1529
|
-
this.listening = true;
|
|
1530
|
-
this.poll();
|
|
1531
|
-
this.port.on("message", (m) => { this.onMessage(m); });
|
|
1532
|
-
}
|
|
1596
|
+
this.listen();
|
|
1533
1597
|
if (this.refd)
|
|
1534
1598
|
return;
|
|
1535
1599
|
this.refd = true;
|
|
@@ -1670,6 +1734,55 @@ function threadFor(origin) {
|
|
|
1670
1734
|
return undefined;
|
|
1671
1735
|
return t.ready() && !lookupReplaced() ? t : undefined;
|
|
1672
1736
|
}
|
|
1737
|
+
function startingThread(origin) {
|
|
1738
|
+
const t = transportThread;
|
|
1739
|
+
if (t === undefined || t.origin !== origin || lookupReplaced())
|
|
1740
|
+
return undefined;
|
|
1741
|
+
return t.starting() ? t : undefined;
|
|
1742
|
+
}
|
|
1743
|
+
let raceTraced = false;
|
|
1744
|
+
function firstUp(t, pool, deadline, signal) {
|
|
1745
|
+
const first = !raceTraced;
|
|
1746
|
+
if (first) {
|
|
1747
|
+
raceTraced = true;
|
|
1748
|
+
(0, trace_js_1.traceEvent)("h2:race");
|
|
1749
|
+
}
|
|
1750
|
+
const stop = new AbortController();
|
|
1751
|
+
const both = signal === undefined ? stop.signal : AbortSignal.any([signal, stop.signal]);
|
|
1752
|
+
return new Promise((resolve, reject) => {
|
|
1753
|
+
let done = false;
|
|
1754
|
+
const forget = t.whenStarted(() => {
|
|
1755
|
+
if (done)
|
|
1756
|
+
return;
|
|
1757
|
+
const ready = threadFor(t.origin);
|
|
1758
|
+
if (ready === undefined)
|
|
1759
|
+
return;
|
|
1760
|
+
done = true;
|
|
1761
|
+
if (first)
|
|
1762
|
+
(0, trace_js_1.traceEvent)("h2:race-thread");
|
|
1763
|
+
stop.abort();
|
|
1764
|
+
resolve({ thread: ready });
|
|
1765
|
+
});
|
|
1766
|
+
pool.acquire(deadline, both).then((entry) => {
|
|
1767
|
+
if (done) {
|
|
1768
|
+
if (entry !== null)
|
|
1769
|
+
pool.end(entry);
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
done = true;
|
|
1773
|
+
forget();
|
|
1774
|
+
if (first)
|
|
1775
|
+
(0, trace_js_1.traceEvent)("h2:race-pool");
|
|
1776
|
+
resolve({ entry });
|
|
1777
|
+
}, (err) => {
|
|
1778
|
+
if (done)
|
|
1779
|
+
return;
|
|
1780
|
+
done = true;
|
|
1781
|
+
forget();
|
|
1782
|
+
reject(err);
|
|
1783
|
+
});
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1673
1786
|
function ownFile() {
|
|
1674
1787
|
const frame = (new Error().stack ?? "").split("\n")[1] ?? "";
|
|
1675
1788
|
const m = /\((.*):\d+:\d+\)\s*$/.exec(frame) ?? /at (.*):\d+:\d+\s*$/.exec(frame);
|
|
@@ -1712,7 +1825,7 @@ function startTransportThread(origin, onFail) {
|
|
|
1712
1825
|
workerData: {
|
|
1713
1826
|
promigenceTransport: true, port: port2, acks, origin: origin.origin, sessions: knobs.sessions, gapUs: knobs.gapUs,
|
|
1714
1827
|
firstUseMs: exports.tuning.loadFirstUseMs, idleMs: IDLE_CLOSE_MS, connectTimeoutMs: CONNECT_TIMEOUT_MS,
|
|
1715
|
-
lookupTimeoutMs:
|
|
1828
|
+
lookupTimeoutMs: LOOKUP_FIRST_MS, lookupTries: LOOKUP_TRIES, lookupAtMs: LOOKUP_AT_MS, trace: trace_js_1.TRACE_ON,
|
|
1716
1829
|
servers: exports.tuning.earlyServers ?? (Array.isArray(seam.servers) ? seam.servers : undefined),
|
|
1717
1830
|
hostsFile: exports.tuning.earlyHostsFile ?? (typeof seam.hostsFile === "string" ? seam.hostsFile : undefined),
|
|
1718
1831
|
distrustedForTest: ca_guard_js_1.__caGuardInternals.testHashes(),
|
|
@@ -1730,6 +1843,11 @@ function startTransportThread(origin, onFail) {
|
|
|
1730
1843
|
worker.on("exit", () => { t.poll(); t.close("exit"); });
|
|
1731
1844
|
transportThread = t;
|
|
1732
1845
|
(0, trace_js_1.traceEvent)("thread:start");
|
|
1846
|
+
(0, trace_js_1.onTraceFlush)(() => {
|
|
1847
|
+
t.poll();
|
|
1848
|
+
for (const e of earlies.values())
|
|
1849
|
+
pollEarly(e);
|
|
1850
|
+
});
|
|
1733
1851
|
}
|
|
1734
1852
|
catch {
|
|
1735
1853
|
transportThread = undefined;
|
|
@@ -1816,8 +1934,34 @@ class Http2Transport {
|
|
|
1816
1934
|
const pool = poolFor(target.origin);
|
|
1817
1935
|
if (!pool.usable())
|
|
1818
1936
|
return this.viaFetch(url, init, deadline);
|
|
1937
|
+
let raced = false;
|
|
1819
1938
|
for (;;) {
|
|
1820
|
-
|
|
1939
|
+
let entry = pool.tryAcquire();
|
|
1940
|
+
if (entry === undefined) {
|
|
1941
|
+
const starting = raced || resends > 0 || replays > 0 ? undefined : startingThread(target.origin);
|
|
1942
|
+
if (starting !== undefined) {
|
|
1943
|
+
raced = true;
|
|
1944
|
+
const won = await firstUp(starting, pool, deadline, init.signal);
|
|
1945
|
+
if (won.thread !== undefined) {
|
|
1946
|
+
if (tr !== undefined)
|
|
1947
|
+
(0, trace_js_1.mark)(tr, "race");
|
|
1948
|
+
const out = await won.thread.send(target, init, replayable, deadline);
|
|
1949
|
+
if (out === VIA_FETCH)
|
|
1950
|
+
return this.viaFetch(url, init, deadline);
|
|
1951
|
+
if (!(out instanceof HandBack))
|
|
1952
|
+
return out;
|
|
1953
|
+
resends = out.resends;
|
|
1954
|
+
replays = out.replays;
|
|
1955
|
+
if (tr !== undefined)
|
|
1956
|
+
delete tr.via;
|
|
1957
|
+
continue;
|
|
1958
|
+
}
|
|
1959
|
+
entry = won.entry;
|
|
1960
|
+
}
|
|
1961
|
+
else {
|
|
1962
|
+
entry = await pool.acquire(deadline, init.signal);
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1821
1965
|
if (tr !== undefined)
|
|
1822
1966
|
(0, trace_js_1.mark)(tr, "acq");
|
|
1823
1967
|
if (entry === null)
|
|
@@ -1917,7 +2061,7 @@ exports.__http2Internals = {
|
|
|
1917
2061
|
if (t === undefined)
|
|
1918
2062
|
return undefined;
|
|
1919
2063
|
t.poll();
|
|
1920
|
-
return { state: t.state, sessions: t.sessions, limit: t.limit, answered: t.answered, everReady: t.everReady, closedReason: t.closedReason, messages: t.messages, posts: t.posts };
|
|
2064
|
+
return { state: t.state, sessions: t.sessions, limit: t.limit, answered: t.answered, everReady: t.everReady, closedReason: t.closedReason, messages: t.messages, posts: t.posts, startedAt: t.startedAt };
|
|
1921
2065
|
},
|
|
1922
2066
|
threadKnobs(env) {
|
|
1923
2067
|
return threadKnobs(env);
|
|
@@ -1966,6 +2110,15 @@ function isMainThread() {
|
|
|
1966
2110
|
return false;
|
|
1967
2111
|
}
|
|
1968
2112
|
}
|
|
2113
|
+
function standby(url) {
|
|
2114
|
+
try {
|
|
2115
|
+
(0, trace_js_1.traceEvent)("h2:standby");
|
|
2116
|
+
warmTls();
|
|
2117
|
+
poolFor(url.origin).warm(exports.tuning.loadFirstUseMs);
|
|
2118
|
+
}
|
|
2119
|
+
catch {
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
1969
2122
|
function connectAtLoad() {
|
|
1970
2123
|
try {
|
|
1971
2124
|
if (!isNode() || Number(process.versions.node.split(".")[0]) < 22)
|
|
@@ -1986,6 +2139,8 @@ function connectAtLoad() {
|
|
|
1986
2139
|
if (url.protocol === "https:" && !(0, dispatcher_js_1.customDispatcher)() && earlyPlatform() && v4First() && !threadOff && earlySeam().transportThread !== false) {
|
|
1987
2140
|
startTransportThread(url, () => { if (loadTurnRan)
|
|
1988
2141
|
warmAtLoad(); });
|
|
2142
|
+
if ((0, node_net_1.isIP)(host) === 0)
|
|
2143
|
+
earlyLookupFor(host);
|
|
1989
2144
|
}
|
|
1990
2145
|
else if (url.protocol === "https:" && !(0, dispatcher_js_1.customDispatcher)() && (0, node_net_1.isIP)(host) === 0 && earlyPlatform() && v4First())
|
|
1991
2146
|
earlyLookupFor(host);
|
|
@@ -2004,10 +2159,27 @@ function connectAtLoad() {
|
|
|
2004
2159
|
const url = new URL(raw ? raw : core_js_1.DEFAULT_API_URL);
|
|
2005
2160
|
if (url.protocol !== "https:" || (0, dispatcher_js_1.customDispatcher)())
|
|
2006
2161
|
return;
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2162
|
+
const t = transportThread;
|
|
2163
|
+
if (t !== undefined && t.origin === url.origin) {
|
|
2164
|
+
t.poll();
|
|
2165
|
+
if (t.everReady)
|
|
2166
|
+
return;
|
|
2167
|
+
if (t.state !== "closed") {
|
|
2168
|
+
const check = () => {
|
|
2169
|
+
t.poll();
|
|
2170
|
+
if (t.everReady || t.state === "closed")
|
|
2171
|
+
return;
|
|
2172
|
+
const wait = t.startedAt + exports.tuning.standbyAfterMs - performance.now();
|
|
2173
|
+
if (wait > 0) {
|
|
2174
|
+
const timer = setTimeout(check, wait);
|
|
2175
|
+
timer.unref?.();
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
standby(url);
|
|
2179
|
+
};
|
|
2180
|
+
check();
|
|
2010
2181
|
return;
|
|
2182
|
+
}
|
|
2011
2183
|
}
|
|
2012
2184
|
warmTls();
|
|
2013
2185
|
poolFor(url.origin).warm(exports.tuning.loadFirstUseMs);
|