11/**
2- * @fileoverview GitHub release download utilities for Socket projects.
3- *
4- * Provides unified utilities for downloading release assets from any GitHub repository.
5- * Supports version caching, retry logic, and follows the socket-cli/socket-btm pattern.
6- *
7- * Features:
8- * - Generic `downloadGitHubRelease` for any GitHub repo
9- * - Specialized `downloadSocketBtmRelease` for socket-btm releases
10- * - Download release assets with automatic retry and redirect handling
11- * - Cache downloaded binaries with version tracking (.version files)
12- * - Support for latest release tag lookup by tool prefix
13- * - Configurable working directory and download destination
14- * - macOS quarantine attribute removal for downloaded executables
15- *
16- * Directory Structure:
17- * ```
18- * {downloadDir}/{toolName}/{platformArch}/
19- * ├── {binaryName}
20- * └── .version
21- * ```
22- *
23- * @example
24- * ```ts
25- * // Generic: Download from any GitHub repo
26- * const binaryPath = await downloadGitHubRelease({
27- * owner: 'nodejs',
28- * repo: 'node',
29- * tag: 'v20.10.0',
30- * assetName: 'node-v20.10.0-linux-x64.tar.gz',
31- * binaryName: 'node',
32- * toolName: 'node',
33- * platformArch: 'linux-x64'
34- * })
35- *
36- * // Specialized: Download from socket-btm
37- * const nodePath = await downloadSocketBtmRelease({
38- * toolPrefix: 'node-smol-',
39- * assetName: 'node-linux-x64-musl',
40- * binaryName: 'node',
41- * toolName: 'node-smol',
42- * platformArch: 'linux-x64-musl'
43- * })
44- * ```
2+ * @fileoverview GitHub release download utilities.
453 */
464
475import { chmodSync , existsSync } from 'fs'
@@ -94,19 +52,11 @@ export interface RepoConfig {
9452
9553/**
9654 * Get GitHub authentication headers if token is available.
97- *
98- * Environment Variables:
99- * - GH_TOKEN: GitHub Personal Access Token (preferred).
100- * - GITHUB_TOKEN: Alternative token environment variable.
101- *
102- * Rate Limits (per hour):
103- * - Unauthenticated: 60 requests.
104- * - Authenticated (personal token): 5,000 requests.
105- * - Authenticated (GitHub Actions): 1,000 requests.
55+ * Checks GH_TOKEN or GITHUB_TOKEN environment variables.
10656 *
10757 * @returns Headers object with Authorization header if token exists.
10858 */
109- function getAuthHeaders ( ) : Record < string , string > {
59+ export function getAuthHeaders ( ) : Record < string , string > {
11060 const token = process . env [ 'GH_TOKEN' ] || process . env [ 'GITHUB_TOKEN' ]
11161 const headers : Record < string , string > = {
11262 Accept : 'application/vnd.github+json' ,
@@ -121,23 +71,10 @@ function getAuthHeaders(): Record<string, string> {
12171/**
12272 * Get latest release tag matching a tool prefix.
12373 *
124- * Searches recent releases for the first tag matching the given prefix.
125- * Useful for finding latest versions of tools with date-based tags like
126- * `node-smol-20260105-c47753c` or `binject-20260106-1df5745`.
127- *
128- * @param toolPrefix - Tool name prefix to search for (e.g., 'node-smol-', 'binject-')
74+ * @param toolPrefix - Tool name prefix to search for (e.g., 'node-smol-')
12975 * @param repoConfig - Repository configuration (owner/repo)
13076 * @param options - Additional options
13177 * @returns Latest release tag or null if not found
132- *
133- * @example
134- * ```ts
135- * const tag = await getLatestRelease('node-smol-', {
136- * owner: 'SocketDev',
137- * repo: 'socket-btm'
138- * })
139- * // Returns: 'node-smol-20260105-c47753c'
140- * ```
14178 */
14279export async function getLatestRelease (
14380 toolPrefix : string ,
@@ -200,20 +137,11 @@ export async function getLatestRelease(
200137/**
201138 * Get download URL for a specific release asset.
202139 *
203- * @param tag - Release tag name (e.g., 'node-smol-20260105-c47753c')
204- * @param assetName - Asset name to download (e.g., 'node-linux-x64-musl')
140+ * @param tag - Release tag name
141+ * @param assetName - Asset name to download
205142 * @param repoConfig - Repository configuration (owner/repo)
206143 * @param options - Additional options
207144 * @returns Browser download URL for the asset
208- *
209- * @example
210- * ```ts
211- * const url = await getReleaseAssetUrl(
212- * 'node-smol-20260105-c47753c',
213- * 'node-linux-x64-musl',
214- * { owner: 'SocketDev', repo: 'socket-btm' }
215- * )
216- * ```
217145 */
218146export async function getReleaseAssetUrl (
219147 tag : string ,
@@ -274,24 +202,11 @@ export async function getReleaseAssetUrl(
274202/**
275203 * Download a specific release asset.
276204 *
277- * Uses browser_download_url to avoid consuming GitHub API quota.
278- * Automatically follows redirects and retries on failure.
279- *
280205 * @param tag - Release tag name
281206 * @param assetName - Asset name to download
282207 * @param outputPath - Path to write the downloaded file
283208 * @param repoConfig - Repository configuration (owner/repo)
284209 * @param options - Additional options
285- *
286- * @example
287- * ```ts
288- * await downloadReleaseAsset(
289- * 'node-smol-20260105-c47753c',
290- * 'node-linux-x64-musl',
291- * '/path/to/output/node',
292- * { owner: 'SocketDev', repo: 'socket-btm' }
293- * )
294- * ```
295210 */
296211export async function downloadReleaseAsset (
297212 tag : string ,
@@ -331,90 +246,37 @@ export async function downloadReleaseAsset(
331246 * Configuration for downloading a GitHub release.
332247 */
333248export interface DownloadGitHubReleaseConfig {
334- /**
335- * GitHub repository owner/organization.
336- */
249+ /** GitHub repository owner/organization. */
337250 owner : string
338- /**
339- * GitHub repository name.
340- */
251+ /** GitHub repository name. */
341252 repo : string
342- /**
343- * Working directory (defaults to process.cwd()).
344- * Used to resolve relative paths in downloadDir.
345- */
253+ /** Working directory (defaults to process.cwd()). */
346254 cwd ?: string
347- /**
348- * Download destination directory.
349- * Can be absolute or relative to cwd.
350- * @default 'build/downloaded' (relative to cwd)
351- */
255+ /** Download destination directory. @default 'build/downloaded' */
352256 downloadDir ?: string
353- /**
354- * Tool name for directory structure (e.g., 'node-smol', 'binject', 'lief').
355- * Creates subdirectory: {downloadDir}/{toolName}/{platformArch}/
356- */
257+ /** Tool name for directory structure. */
357258 toolName : string
358- /**
359- * Platform-arch identifier (e.g., 'linux-x64-musl', 'darwin-arm64').
360- * Used for the download directory path.
361- */
259+ /** Platform-arch identifier (e.g., 'linux-x64-musl'). */
362260 platformArch : string
363- /**
364- * Binary filename (e.g., 'node', 'binject', 'lief', 'node.exe').
365- */
261+ /** Binary filename (e.g., 'node', 'binject'). */
366262 binaryName : string
367- /**
368- * Asset name on GitHub (e.g., 'node-linux-x64-musl', 'binject-darwin-arm64').
369- */
263+ /** Asset name on GitHub. */
370264 assetName : string
371- /**
372- * Tool prefix for finding latest release (e.g., 'node-smol-', 'binject-').
373- * Either this or `tag` must be provided.
374- */
265+ /** Tool prefix for finding latest release. */
375266 toolPrefix ?: string
376- /**
377- * Specific release tag to download (e.g., 'node-smol-20260105-c47753c').
378- * If not provided, uses `toolPrefix` to find the latest release.
379- */
267+ /** Specific release tag to download. */
380268 tag ?: string
381- /**
382- * Suppress log messages.
383- * @default false
384- */
269+ /** Suppress log messages. @default false */
385270 quiet ?: boolean
386- /**
387- * Remove macOS quarantine attribute after download.
388- * Only applies when downloading on macOS for macOS binaries.
389- * @default true
390- */
271+ /** Remove macOS quarantine attribute after download. @default true */
391272 removeMacOSQuarantine ?: boolean
392273}
393274
394275/**
395276 * Download a binary from any GitHub repository with version caching.
396277 *
397- * Downloads to: `{downloadDir}/{toolName}/{platformArch}/{binaryName}`
398- * Caches version in: `{downloadDir}/{toolName}/{platformArch}/.version`
399- *
400278 * @param config - Download configuration
401279 * @returns Path to the downloaded binary
402- *
403- * @example
404- * ```ts
405- * // Download from any GitHub repo
406- * const nodePath = await downloadGitHubRelease({
407- * owner: 'nodejs',
408- * repo: 'node',
409- * cwd: process.cwd(),
410- * downloadDir: 'build/downloaded', // relative to cwd
411- * toolName: 'node',
412- * platformArch: 'linux-x64',
413- * binaryName: 'node',
414- * assetName: 'node-v20.10.0-linux-x64.tar.gz',
415- * tag: 'v20.10.0'
416- * })
417- * ```
418280 */
419281export async function downloadGitHubRelease (
420282 config : DownloadGitHubReleaseConfig ,
0 commit comments