diff --git a/packages/cli/script/build.ts b/packages/cli/script/build.ts index 1c272a39d6..c33e23bf37 100755 --- a/packages/cli/script/build.ts +++ b/packages/cli/script/build.ts @@ -27,6 +27,7 @@ const requestedTarget = process.argv.find((arg) => arg.startsWith("--target="))? const skipInstall = process.argv.includes("--skip-install") const skipWebUi = process.argv.includes("--skip-web-ui") const solidPlugin = createSolidTransformPlugin() +const releaseAssets = new Map>>() const allTargets: { os: string @@ -161,7 +162,13 @@ async function compileExecutable(item: (typeof allTargets)[number]) { if (!release) return const platform = item.os === "win32" ? "windows" : item.os - const name = ["bun", platform, item.arch, item.abi, item.avx2 === false ? "baseline" : undefined] + const name = [ + "bun", + platform, + item.arch === "arm64" ? "aarch64" : item.arch, + item.abi, + item.avx2 === false ? "baseline" : undefined, + ] .filter(Boolean) .join("-") const cache = path.join(outdir, ".bun", release) @@ -170,7 +177,13 @@ async function compileExecutable(item: (typeof allTargets)[number]) { await mkdir(cache, { recursive: true }) const archive = path.join(cache, `${name}.zip`) - const response = await fetch(`https://github.com/oven-sh/bun/releases/download/${release}/${name}.zip`) + const assets = await compileReleaseAssets(release) + const url = assets.get(`${name}.zip`) + if (!url) throw new Error(`Bun release ${release} does not include ${name}.zip`) + const token = process.env.GH_TOKEN ?? process.env.GITHUB_TOKEN + const response = await fetch(url, { + headers: { Accept: "application/octet-stream", ...(token ? { Authorization: `Bearer ${token}` } : {}) }, + }) if (!response.ok) throw new Error(`Failed to download ${name} from Bun release ${release}: ${response.status}`) await Bun.write(archive, response) await $`unzip -oq ${archive} -d ${cache}` @@ -178,6 +191,38 @@ async function compileExecutable(item: (typeof allTargets)[number]) { return executable } +function compileReleaseAssets(release: string) { + const existing = releaseAssets.get(release) + if (existing) return existing + const pending = fetch(`https://api.github.com/repos/oven-sh/bun/releases/tags/${release}?cache=${Date.now()}`) + .then(async (response) => { + if (!response.ok) throw new Error(`Failed to resolve Bun release ${release}: ${response.status}`) + const data: unknown = await response.json() + if (typeof data !== "object" || data === null || !("assets" in data) || !Array.isArray(data.assets)) { + throw new Error(`Bun release ${release} returned invalid metadata`) + } + return new Map( + data.assets + .filter( + (asset): asset is { name: string; url: string } => + typeof asset === "object" && + asset !== null && + "name" in asset && + typeof asset.name === "string" && + "url" in asset && + typeof asset.url === "string", + ) + .map((asset) => [asset.name, asset.url]), + ) + }) + .catch((error) => { + releaseAssets.delete(release) + throw error + }) + releaseAssets.set(release, pending) + return pending +} + function targetName(item: (typeof allTargets)[number]) { return [ binary,