From 5f4fdab09732019120b2b0a0e6575bf5c1a01b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=20Kl=C3=A4rner?= Date: Thu, 26 Jun 2025 16:07:32 +0200 Subject: [PATCH 1/3] feat: download purely using octokit In my understanding octokit automatically uses authentication, but the real download was done using fetch directly, hence without authentication. This approach now uses octokit's getReleaseAsset() to download the asset, which should use proper authentication, hence allowing potentially higher rate limits. Closes: #419 --- src/index.ts | 4 ++-- src/release.ts | 27 +++++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/index.ts b/src/index.ts index f1fb0d2..e0aa231 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,9 +9,9 @@ import { downloadBinary, findRelease } from "./release" async function main() { if (!(await isReady())) { try { - const [name, assets] = await findRelease(VERSION) + const [name, asset_id, asset_filetype] = await findRelease(VERSION) console.info(`Downloading ${name}`) - await downloadBinary(assets.browser_download_url) + await downloadBinary(asset_id, asset_filetype) } catch (e) { console.error(`Failed to download binary:\n${e}`) await fs.rm(COMBINED_PATH, { recursive: true }) diff --git a/src/release.ts b/src/release.ts index 7dd7d65..febaf3b 100644 --- a/src/release.ts +++ b/src/release.ts @@ -1,7 +1,8 @@ -import { writeFile } from "node:fs/promises" import os from "node:os" import { Octokit } from "@octokit/rest" +import { createWriteStream } from "node:fs"; +import { pipeline } from "node:stream/promises"; import { getProxyForUrl } from "proxy-from-env" import { fetch, ProxyAgent } from "undici" import type { RequestInit } from "undici" @@ -24,15 +25,29 @@ export async function findRelease(version: string) { if (!matchedAsset) { throw new Error(`The binary '${releasePrefix}*' not found`) } - return [release.data.name, matchedAsset] as const + return [release.data.name, matchedAsset.id, matchedAsset.name.endsWith(".zip") ? "zip" : "tar" ] as const } -export async function downloadBinary(url: string) { - const response = await proxiedFetch(url) +export async function downloadBinary(asset_id: number, asset_filetype: string) { + // downloading the asset is copied from https://github.com/octokit/rest.js/issues/12#issuecomment-1916023479 + const asset = await octokit.repos.getReleaseAsset({ + owner: NAME, + repo: NAME, + asset_id: asset_id, + headers: { + accept: "application/octet-stream" + }, + request: { + parseSuccessResponseBody: false, // required to access response as stream + } + }); const tmpfile = await tmp.file() - await writeFile(tmpfile.path, Buffer.from(await response.arrayBuffer())) - if (url.endsWith(".zip")) { + const assetStream = asset.data as unknown as NodeJS.ReadableStream; + const outputFile = createWriteStream(tmpfile.path); + await pipeline(assetStream, outputFile); + + if (asset_filetype === ".zip") { const zip = new admzip(tmpfile.path) zip.extractAllTo(COMBINED_PATH, true) } else { From c74db2ecbe9ca80dc11e7a32ee905fe9db0175da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=20Kl=C3=A4rner?= Date: Thu, 26 Jun 2025 16:20:29 +0200 Subject: [PATCH 2/3] chore: run prettier --- src/release.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/release.ts b/src/release.ts index febaf3b..a6b4220 100644 --- a/src/release.ts +++ b/src/release.ts @@ -1,8 +1,8 @@ import os from "node:os" import { Octokit } from "@octokit/rest" -import { createWriteStream } from "node:fs"; -import { pipeline } from "node:stream/promises"; +import { createWriteStream } from "node:fs" +import { pipeline } from "node:stream/promises" import { getProxyForUrl } from "proxy-from-env" import { fetch, ProxyAgent } from "undici" import type { RequestInit } from "undici" @@ -25,7 +25,11 @@ export async function findRelease(version: string) { if (!matchedAsset) { throw new Error(`The binary '${releasePrefix}*' not found`) } - return [release.data.name, matchedAsset.id, matchedAsset.name.endsWith(".zip") ? "zip" : "tar" ] as const + return [ + release.data.name, + matchedAsset.id, + matchedAsset.name.endsWith(".zip") ? "zip" : "tar", + ] as const } export async function downloadBinary(asset_id: number, asset_filetype: string) { @@ -35,17 +39,17 @@ export async function downloadBinary(asset_id: number, asset_filetype: string) { repo: NAME, asset_id: asset_id, headers: { - accept: "application/octet-stream" + accept: "application/octet-stream", }, request: { parseSuccessResponseBody: false, // required to access response as stream - } - }); + }, + }) const tmpfile = await tmp.file() - const assetStream = asset.data as unknown as NodeJS.ReadableStream; - const outputFile = createWriteStream(tmpfile.path); - await pipeline(assetStream, outputFile); + const assetStream = asset.data as unknown as NodeJS.ReadableStream + const outputFile = createWriteStream(tmpfile.path) + await pipeline(assetStream, outputFile) if (asset_filetype === ".zip") { const zip = new admzip(tmpfile.path) From ed849572f5ecdaa9f03cbd6436d34e1d2bc64865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=20Kl=C3=A4rner?= Date: Thu, 26 Jun 2025 19:20:48 +0200 Subject: [PATCH 3/3] chore: use js-typical camelCase --- src/index.ts | 4 ++-- src/release.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index e0aa231..e057c19 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,9 +9,9 @@ import { downloadBinary, findRelease } from "./release" async function main() { if (!(await isReady())) { try { - const [name, asset_id, asset_filetype] = await findRelease(VERSION) + const [name, assetId, assetFiletype] = await findRelease(VERSION) console.info(`Downloading ${name}`) - await downloadBinary(asset_id, asset_filetype) + await downloadBinary(assetId, assetFiletype) } catch (e) { console.error(`Failed to download binary:\n${e}`) await fs.rm(COMBINED_PATH, { recursive: true }) diff --git a/src/release.ts b/src/release.ts index a6b4220..4e83b28 100644 --- a/src/release.ts +++ b/src/release.ts @@ -32,12 +32,12 @@ export async function findRelease(version: string) { ] as const } -export async function downloadBinary(asset_id: number, asset_filetype: string) { +export async function downloadBinary(assetId: number, assetFiletype: string) { // downloading the asset is copied from https://github.com/octokit/rest.js/issues/12#issuecomment-1916023479 const asset = await octokit.repos.getReleaseAsset({ owner: NAME, repo: NAME, - asset_id: asset_id, + asset_id: assetId, headers: { accept: "application/octet-stream", }, @@ -51,7 +51,7 @@ export async function downloadBinary(asset_id: number, asset_filetype: string) { const outputFile = createWriteStream(tmpfile.path) await pipeline(assetStream, outputFile) - if (asset_filetype === ".zip") { + if (assetFiletype === ".zip") { const zip = new admzip(tmpfile.path) zip.extractAllTo(COMBINED_PATH, true) } else {