import { createWriteStream, existsSync, mkdirSync, rmSync } from "node:fs"; import { basename, join } from "node:path"; import { pipeline } from "node:stream/promises"; import { spawnSync } from "node:child_process"; import { tmpdir } from "node:os"; const versionInput = process.env.NETBIRD_VERSION || "latest"; const release = await getRelease(versionInput); const version = release.tag_name.replace(/^v/, ""); const tmpDir = tmpdir(); const targets = [ { label: "macOS arm64", assetName: `netbird_${version}_darwin_arm64.tar.gz`, outputDir: join(import.meta.dirname, "..", "resources"), files: [{ source: "netbird", destination: "netbird" }] }, { label: "Windows amd64", assetName: `netbird_${version}_windows_amd64_signed.tar.gz`, outputDir: join(import.meta.dirname, "..", "resources"), files: [ { source: "netbird.exe", destination: "netbird.exe" }, { source: "wintun.dll", destination: "wintun.dll" } ] } ]; for (const target of targets) { const asset = release.assets.find((candidate) => candidate.name === target.assetName); if (!asset) { throw new Error(`Could not find ${target.assetName} in NetBird ${release.tag_name}.`); } const archivePath = join(tmpDir, asset.name); await download(asset.browser_download_url, archivePath); const extractDir = join(tmpDir, basename(asset.name, ".tar.gz")); mkdirSync(extractDir, { recursive: true }); run("tar", ["-xzf", archivePath, "-C", extractDir]); mkdirSync(target.outputDir, { recursive: true }); for (const file of target.files) { run("cp", [join(extractDir, file.source), join(target.outputDir, file.destination)]); } console.log(`Installed ${target.label} NetBird ${release.tag_name} assets.`); } rmSync(tmpDir, { recursive: true, force: true }); async function getRelease(versionSelector) { const url = versionSelector === "latest" ? "https://api.github.com/repos/netbirdio/netbird/releases/latest" : `https://api.github.com/repos/netbirdio/netbird/releases/tags/${versionSelector.startsWith("v") ? versionSelector : `v${versionSelector}`}`; const response = await fetch(url, { headers: { "User-Agent": "vynte-connect-build" } }); if (!response.ok) { throw new Error(`NetBird release lookup failed: ${response.status} ${response.statusText}`); } return response.json(); } async function download(url, destination) { const response = await fetch(url, { headers: { "User-Agent": "vynte-connect-build" } }); if (!response.ok || !response.body) { throw new Error(`Download failed for ${url}: ${response.status} ${response.statusText}`); } await pipeline(response.body, createWriteStream(destination)); } function run(command, args) { const result = spawnSync(command, args, { stdio: "inherit" }); if (result.status !== 0) { throw new Error(`${command} ${args.join(" ")} failed with exit code ${result.status}`); } }