@eve-horizon/cli 0.2.44 → 0.2.45
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/index.js +63 -12
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -80594,17 +80594,27 @@ async function downloadBytes(url) {
|
|
|
80594
80594
|
return Buffer.from(arrayBuffer);
|
|
80595
80595
|
}
|
|
80596
80596
|
async function fetchText(url, headers) {
|
|
80597
|
-
const
|
|
80598
|
-
|
|
80599
|
-
|
|
80600
|
-
|
|
80601
|
-
|
|
80597
|
+
const maxRetries = 3;
|
|
80598
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
80599
|
+
const response = await fetch(url, {
|
|
80600
|
+
headers: {
|
|
80601
|
+
"User-Agent": "eve-cli-local-stack",
|
|
80602
|
+
Accept: "application/json,text/plain,*/*",
|
|
80603
|
+
...headers ?? {}
|
|
80604
|
+
}
|
|
80605
|
+
});
|
|
80606
|
+
if (response.status === 429 && attempt < maxRetries) {
|
|
80607
|
+
const retryAfter = parseInt(response.headers.get("retry-after") ?? "", 10);
|
|
80608
|
+
const delay = (retryAfter > 0 ? retryAfter : 2 ** attempt) * 1e3;
|
|
80609
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
80610
|
+
continue;
|
|
80602
80611
|
}
|
|
80603
|
-
|
|
80604
|
-
|
|
80605
|
-
|
|
80612
|
+
if (!response.ok) {
|
|
80613
|
+
throw new Error(`Request failed (${response.status}) for ${url}`);
|
|
80614
|
+
}
|
|
80615
|
+
return response.text();
|
|
80606
80616
|
}
|
|
80607
|
-
|
|
80617
|
+
throw new Error(`Request failed after ${maxRetries} retries for ${url}`);
|
|
80608
80618
|
}
|
|
80609
80619
|
function writeExecutable(destination, bytes) {
|
|
80610
80620
|
const tempPath = `${destination}.tmp-${Date.now()}-${process.pid}`;
|
|
@@ -80709,11 +80719,52 @@ async function fetchRegistryTags(imageRef) {
|
|
|
80709
80719
|
}
|
|
80710
80720
|
const registry2 = imageRef.slice(0, slashIndex);
|
|
80711
80721
|
const repository = imageRef.slice(slashIndex + 1);
|
|
80712
|
-
const
|
|
80713
|
-
|
|
80714
|
-
|
|
80722
|
+
const url = `https://${registry2}/v2/${repository}/tags/list?n=200`;
|
|
80723
|
+
const token = await fetchRegistryBearerToken(registry2, repository);
|
|
80724
|
+
const headers = token ? { Authorization: `Bearer ${token}` } : void 0;
|
|
80725
|
+
const tagsPayload = await fetchText(url, headers);
|
|
80715
80726
|
return JSON.parse(tagsPayload).tags ?? [];
|
|
80716
80727
|
}
|
|
80728
|
+
async function fetchRegistryBearerToken(registry2, repository) {
|
|
80729
|
+
const probeUrl = `https://${registry2}/v2/`;
|
|
80730
|
+
const probeResponse = await fetch(probeUrl, {
|
|
80731
|
+
headers: { "User-Agent": "eve-cli-local-stack" }
|
|
80732
|
+
});
|
|
80733
|
+
if (probeResponse.ok) {
|
|
80734
|
+
return void 0;
|
|
80735
|
+
}
|
|
80736
|
+
if (probeResponse.status !== 401) {
|
|
80737
|
+
throw new Error(`Registry probe failed (${probeResponse.status}) for ${probeUrl}`);
|
|
80738
|
+
}
|
|
80739
|
+
const wwwAuth = probeResponse.headers.get("www-authenticate") ?? "";
|
|
80740
|
+
const challenge = parseWwwAuthenticate(wwwAuth);
|
|
80741
|
+
if (!challenge.realm) {
|
|
80742
|
+
throw new Error(`Registry returned 401 without a Bearer realm in WWW-Authenticate header: ${wwwAuth}`);
|
|
80743
|
+
}
|
|
80744
|
+
const tokenUrl = new URL(challenge.realm);
|
|
80745
|
+
if (challenge.service) {
|
|
80746
|
+
tokenUrl.searchParams.set("service", challenge.service);
|
|
80747
|
+
}
|
|
80748
|
+
tokenUrl.searchParams.set("scope", `repository:${repository}:pull`);
|
|
80749
|
+
const tokenResponse = await fetch(tokenUrl.toString(), {
|
|
80750
|
+
headers: { "User-Agent": "eve-cli-local-stack" }
|
|
80751
|
+
});
|
|
80752
|
+
if (!tokenResponse.ok) {
|
|
80753
|
+
throw new Error(`Token exchange failed (${tokenResponse.status}) at ${tokenUrl.toString()}`);
|
|
80754
|
+
}
|
|
80755
|
+
const tokenData = await tokenResponse.json();
|
|
80756
|
+
return tokenData.token ?? tokenData.access_token;
|
|
80757
|
+
}
|
|
80758
|
+
function parseWwwAuthenticate(header) {
|
|
80759
|
+
const result = {};
|
|
80760
|
+
const body = header.replace(/^Bearer\s+/i, "");
|
|
80761
|
+
const pattern = /(\w+)="([^"]*)"/g;
|
|
80762
|
+
let match;
|
|
80763
|
+
while ((match = pattern.exec(body)) !== null) {
|
|
80764
|
+
result[match[1]] = match[2];
|
|
80765
|
+
}
|
|
80766
|
+
return result;
|
|
80767
|
+
}
|
|
80717
80768
|
function normalizeVersion(value) {
|
|
80718
80769
|
const trimmed = value.trim();
|
|
80719
80770
|
if (!trimmed) return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eve-horizon/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.45",
|
|
4
4
|
"description": "Eve Horizon CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -18,9 +18,6 @@
|
|
|
18
18
|
"assets",
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node22 --outfile=dist/index.js --format=cjs --external:yaml"
|
|
23
|
-
},
|
|
24
21
|
"publishConfig": {
|
|
25
22
|
"access": "public"
|
|
26
23
|
},
|
|
@@ -31,11 +28,14 @@
|
|
|
31
28
|
"yaml": "^2.5.1"
|
|
32
29
|
},
|
|
33
30
|
"devDependencies": {
|
|
34
|
-
"@eve/migrate": "workspace:*",
|
|
35
|
-
"@eve/shared": "workspace:*",
|
|
36
31
|
"@types/node": "^22.0.0",
|
|
37
32
|
"esbuild": "^0.27.3",
|
|
38
33
|
"postgres": "^3.4.0",
|
|
39
|
-
"typescript": "^5.7.0"
|
|
34
|
+
"typescript": "^5.7.0",
|
|
35
|
+
"@eve/migrate": "0.0.1",
|
|
36
|
+
"@eve/shared": "0.0.1"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node22 --outfile=dist/index.js --format=cjs --external:yaml"
|
|
40
40
|
}
|
|
41
|
-
}
|
|
41
|
+
}
|