@skydiveai/git-cache 0.1.0-beta.3048 → 0.1.0-beta.3102
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/cli.mjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as isProtocolV2Request, c as parseAdvertisement, d as shouldBackfillAfterPassthrough, f as startServer, i as explainRejection, l as parseUpstream, n as classifyUploadRequest, o as metricsSnapshot, r as copyRequestHeaders, s as mirrorHasObjects, t as SidebandPackExtractor, u as recordColdBuildOutcome } from "./server-
|
|
1
|
+
import { a as isProtocolV2Request, c as parseAdvertisement, d as shouldBackfillAfterPassthrough, f as startServer, i as explainRejection, l as parseUpstream, n as classifyUploadRequest, o as metricsSnapshot, r as copyRequestHeaders, s as mirrorHasObjects, t as SidebandPackExtractor, u as recordColdBuildOutcome } from "./server-DjJs3KcN.mjs";
|
|
2
2
|
export { SidebandPackExtractor, classifyUploadRequest, copyRequestHeaders, explainRejection, isProtocolV2Request, metricsSnapshot, mirrorHasObjects, parseAdvertisement, parseUpstream, recordColdBuildOutcome, shouldBackfillAfterPassthrough, startServer };
|
|
@@ -78,6 +78,7 @@ const config = {
|
|
|
78
78
|
maxPackBytes: Number(process.env.GIT_CACHE_MAX_PACK_BYTES || 8 * 1024 * 1024 * 1024),
|
|
79
79
|
maxImporterQueueBytes: Number(process.env.GIT_CACHE_MAX_IMPORTER_QUEUE_BYTES || 256 * 1024 * 1024),
|
|
80
80
|
maxCacheBytes: Number(process.env.GIT_CACHE_MAX_CACHE_BYTES || 0),
|
|
81
|
+
upstreamTimeoutMs: Number(process.env.GIT_CACHE_UPSTREAM_TIMEOUT_MS || 3e4),
|
|
81
82
|
hostAllowlist: (process.env.GIT_CACHE_HOST_ALLOWLIST || "").split(",").map((h) => h.trim().toLowerCase()).filter(Boolean),
|
|
82
83
|
logLevel: process.env.GIT_CACHE_LOG_LEVEL || "info",
|
|
83
84
|
testOriginBase: (process.env.GIT_CACHE_TEST_ORIGIN_BASE || "").replace(/\/+$/, "")
|
|
@@ -94,7 +95,9 @@ const GIT_ENV = {
|
|
|
94
95
|
GIT_ASKPASS: "/bin/true",
|
|
95
96
|
SSH_ASKPASS: "/bin/true",
|
|
96
97
|
GCM_INTERACTIVE: "never",
|
|
97
|
-
GIT_CONFIG_NOSYSTEM: process.env.GIT_CONFIG_NOSYSTEM || "1"
|
|
98
|
+
GIT_CONFIG_NOSYSTEM: process.env.GIT_CONFIG_NOSYSTEM || "1",
|
|
99
|
+
GIT_HTTP_LOW_SPEED_LIMIT: "1024",
|
|
100
|
+
GIT_HTTP_LOW_SPEED_TIME: "60"
|
|
98
101
|
};
|
|
99
102
|
const activeLevel = LOG_LEVELS[config.logLevel] ?? LOG_LEVELS.info;
|
|
100
103
|
function log(level, event, fields = {}) {
|
|
@@ -676,12 +679,35 @@ function withCredential(headers, credHeader) {
|
|
|
676
679
|
function requestUpstream(target, options, callback) {
|
|
677
680
|
return (target.protocol === "http:" ? http : https).request(target, options, callback);
|
|
678
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Arm the idle-socket ceiling on an upstream request. Fires only when the
|
|
684
|
+
* socket is SILENT for config.upstreamTimeoutMs (any activity resets it), so a
|
|
685
|
+
* healthy transfer — even a slow one — is never interrupted. Must be armed on
|
|
686
|
+
* EVERY upstream request: a hung upstream surfaces as a fast error to the
|
|
687
|
+
* caller instead of a client `git fetch` that never returns.
|
|
688
|
+
*/
|
|
689
|
+
function armUpstreamIdleTimeout(up, onTimeout) {
|
|
690
|
+
up.setTimeout(config.upstreamTimeoutMs, () => {
|
|
691
|
+
log("error", "upstream_idle_timeout", { ms: config.upstreamTimeoutMs });
|
|
692
|
+
onTimeout();
|
|
693
|
+
});
|
|
694
|
+
}
|
|
679
695
|
function openUpstream(req, upstreamUrl, operation, callback, credHeader) {
|
|
680
|
-
const
|
|
696
|
+
const target = new URL(upstreamUrl + (operation === "info/refs" ? "/info/refs?service=git-upload-pack" : "/git-upload-pack"));
|
|
697
|
+
let settled = false;
|
|
698
|
+
const settle = (resOrNull, error) => {
|
|
699
|
+
if (settled) return;
|
|
700
|
+
settled = true;
|
|
701
|
+
callback(resOrNull, error);
|
|
702
|
+
};
|
|
703
|
+
const up = requestUpstream(target, {
|
|
681
704
|
method: req.method,
|
|
682
705
|
headers: withCredential(copyRequestHeaders(req.headers), credHeader)
|
|
683
|
-
}, (res) =>
|
|
684
|
-
up.on("error", (error) =>
|
|
706
|
+
}, (res) => settle(res, null));
|
|
707
|
+
up.on("error", (error) => settle(null, error));
|
|
708
|
+
armUpstreamIdleTimeout(up, () => {
|
|
709
|
+
up.destroy(/* @__PURE__ */ new Error(`upstream idle for ${config.upstreamTimeoutMs}ms`));
|
|
710
|
+
});
|
|
685
711
|
if (req.method === "POST") req.pipe(up);
|
|
686
712
|
else up.end();
|
|
687
713
|
return up;
|
|
@@ -1269,6 +1295,13 @@ function startColdStream(req, res, upstreamUrl, repo, requestBody, credHeader) {
|
|
|
1269
1295
|
});
|
|
1270
1296
|
});
|
|
1271
1297
|
up.on("error", (error) => settle.reject(error));
|
|
1298
|
+
armUpstreamIdleTimeout(up, () => {
|
|
1299
|
+
if (!res.headersSent) {
|
|
1300
|
+
res.writeHead(502, { "Content-Type": "text/plain" });
|
|
1301
|
+
res.end("unable to serve repository\n");
|
|
1302
|
+
}
|
|
1303
|
+
up.destroy(/* @__PURE__ */ new Error(`upstream idle for ${config.upstreamTimeoutMs}ms`));
|
|
1304
|
+
});
|
|
1272
1305
|
up.end(requestBody);
|
|
1273
1306
|
})().catch(settle.reject);
|
|
1274
1307
|
done.catch(async (error) => {
|
|
@@ -1488,6 +1521,9 @@ function proxyUploadPackWithBody(res, upstreamUrl, reqHeaders, body, credHeader)
|
|
|
1488
1521
|
if (!res.headersSent) res.writeHead(502);
|
|
1489
1522
|
res.end();
|
|
1490
1523
|
});
|
|
1524
|
+
armUpstreamIdleTimeout(up, () => {
|
|
1525
|
+
up.destroy(/* @__PURE__ */ new Error(`upstream idle for ${config.upstreamTimeoutMs}ms`));
|
|
1526
|
+
});
|
|
1491
1527
|
up.end(body);
|
|
1492
1528
|
}
|
|
1493
1529
|
function serveUploadPack(req, res, local, advertise, cacheState, body = null) {
|
|
@@ -1816,7 +1852,7 @@ async function handle(req, res) {
|
|
|
1816
1852
|
op: up.operation,
|
|
1817
1853
|
state: warm.cacheState
|
|
1818
1854
|
});
|
|
1819
|
-
return proxyInfoRefs(req, res, up.repo, up.upstreamUrl, host, clientCred);
|
|
1855
|
+
return await proxyInfoRefs(req, res, up.repo, up.upstreamUrl, host, clientCred);
|
|
1820
1856
|
}
|
|
1821
1857
|
if (up.operation === "git-upload-pack" && !await mirrorHasObjects(warm.local, uploadWants)) {
|
|
1822
1858
|
await refreshMirror(up.repo, warm.local, clientCred).catch((error) => {
|
|
@@ -1840,7 +1876,7 @@ async function handle(req, res) {
|
|
|
1840
1876
|
});
|
|
1841
1877
|
return serveUploadPack(req, res, warm.local, up.operation === "info/refs", warm.cacheState, uploadBody);
|
|
1842
1878
|
}
|
|
1843
|
-
if (up.operation === "info/refs") return proxyInfoRefs(req, res, up.repo, up.upstreamUrl, host, clientCred);
|
|
1879
|
+
if (up.operation === "info/refs") return await proxyInfoRefs(req, res, up.repo, up.upstreamUrl, host, clientCred);
|
|
1844
1880
|
const body = uploadBody ?? Buffer.alloc(0);
|
|
1845
1881
|
const credHeader = clientCred ?? await fetchCredentialHeader(host);
|
|
1846
1882
|
if (coldLeaders.has(up.repo)) return proxyColdFollowerWithBody(res, up.upstreamUrl, req.headers, body, up.repo, credHeader);
|
|
@@ -1868,6 +1904,9 @@ function proxyColdFollowerWithBody(res, upstreamUrl, reqHeaders, body, repo, cre
|
|
|
1868
1904
|
if (!res.headersSent) res.writeHead(502);
|
|
1869
1905
|
res.end();
|
|
1870
1906
|
});
|
|
1907
|
+
armUpstreamIdleTimeout(up, () => {
|
|
1908
|
+
up.destroy(/* @__PURE__ */ new Error(`upstream idle for ${config.upstreamTimeoutMs}ms`));
|
|
1909
|
+
});
|
|
1871
1910
|
up.end(body);
|
|
1872
1911
|
}
|
|
1873
1912
|
async function startServer(options = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skydiveai/git-cache",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.3102",
|
|
4
4
|
"description": "Sandbox-local Git smart-HTTP clone/fetch cache: a loopback daemon that transparently mirrors HTTPS git reads so repeated clone/fetch/ls-remote skip the origin round-trip. Runs inside an agent sandbox; pushes stay direct.",
|
|
5
5
|
"homepage": "https://skydive.com",
|
|
6
6
|
"license": "MIT",
|