@@ -40,13 +40,52 @@ function getVersion() {
4040 return pkg . version ;
4141}
4242
43- function httpsGet ( url ) {
43+ function getGitHubToken ( ) {
44+ // Check environment variables first
45+ if ( process . env . GITHUB_TOKEN ) return process . env . GITHUB_TOKEN ;
46+ if ( process . env . GH_TOKEN ) return process . env . GH_TOKEN ;
47+
48+ // Try gh CLI (GitHub's official CLI)
49+ try {
50+ const token = execSync ( "gh auth token" , {
51+ encoding : "utf8" ,
52+ stdio : [ "pipe" , "pipe" , "pipe" ] ,
53+ } ) . trim ( ) ;
54+ if ( token && token . startsWith ( "gh" ) ) {
55+ return token ;
56+ }
57+ } catch {
58+ // gh CLI not installed or not logged in
59+ }
60+
61+ return null ;
62+ }
63+
64+ function httpsGet ( url , token = null , isBinaryDownload = false ) {
4465 return new Promise ( ( resolve , reject ) => {
66+ const headers = { "User-Agent" : "relay-dedup-installer" } ;
67+
68+ // Add auth header for private repos
69+ if ( token ) {
70+ headers [ "Authorization" ] = `token ${ token } ` ;
71+ }
72+
73+ // For downloading binary assets from API URL
74+ if ( isBinaryDownload ) {
75+ headers [ "Accept" ] = "application/octet-stream" ;
76+ }
77+
4578 https
46- . get ( url , { headers : { "User-Agent" : "relay-dedup-installer" } } , ( res ) => {
47- // Follow redirects
79+ . get ( url , { headers } , ( res ) => {
80+ // Follow redirects (don't pass token to external domains like S3)
4881 if ( res . statusCode === 301 || res . statusCode === 302 ) {
49- return httpsGet ( res . headers . location ) . then ( resolve ) . catch ( reject ) ;
82+ const redirectUrl = res . headers . location ;
83+ const sameOrigin =
84+ redirectUrl . includes ( "github.com" ) ||
85+ redirectUrl . includes ( "api.github.com" ) ;
86+ return httpsGet ( redirectUrl , sameOrigin ? token : null , isBinaryDownload )
87+ . then ( resolve )
88+ . catch ( reject ) ;
5089 }
5190 if ( res . statusCode !== 200 ) {
5291 reject ( new Error ( `HTTP ${ res . statusCode } : ${ url } ` ) ) ;
@@ -61,17 +100,52 @@ function httpsGet(url) {
61100 } ) ;
62101}
63102
103+ async function getAssetUrl ( version , assetName , token ) {
104+ // For private repos, we need to use the API to get the asset download URL
105+ const apiUrl = `https://api.github.com/repos/${ REPO } /releases/tags/v${ version } ` ;
106+
107+ const response = await httpsGet ( apiUrl , token ) ;
108+ const release = JSON . parse ( response . toString ( ) ) ;
109+
110+ if ( ! release . assets ) {
111+ throw new Error ( `No assets found in release v${ version } ` ) ;
112+ }
113+
114+ const asset = release . assets . find ( ( a ) => a . name === assetName ) ;
115+ if ( ! asset ) {
116+ const available = release . assets . map ( ( a ) => a . name ) . join ( ", " ) ;
117+ throw new Error ( `Asset ${ assetName } not found. Available: ${ available } ` ) ;
118+ }
119+
120+ // Return the API URL for downloading (works for private repos)
121+ return asset . url ;
122+ }
123+
64124async function downloadBinary ( ) {
65125 const target = getTarget ( ) ;
66126 const version = getVersion ( ) ;
127+ const token = getGitHubToken ( ) ;
67128 const assetName = `${ BINARY_NAME } -${ target } .tar.gz` ;
68- const url = `https://github.com/${ REPO } /releases/download/v${ version } /${ assetName } ` ;
69129
70130 console . log ( `Downloading ${ BINARY_NAME } v${ version } for ${ getPlatformKey ( ) } ...` ) ;
71- console . log ( ` ${ url } ` ) ;
131+
132+ if ( ! token ) {
133+ console . error ( `\nError: No GitHub token found.` ) ;
134+ console . error ( `\nThis is a private repo. You need either:` ) ;
135+ console . error ( ` 1. GitHub CLI: Install and run 'gh auth login'` ) ;
136+ console . error ( ` 2. Environment variable: export GITHUB_TOKEN=ghp_your_token` ) ;
137+ console . error ( `\nThen reinstall: pnpm install` ) ;
138+ process . exit ( 1 ) ;
139+ }
140+
141+ console . log ( ` (using GitHub token for authentication)` ) ;
72142
73143 try {
74- const tarGz = await httpsGet ( url ) ;
144+ // Get the asset download URL from the API
145+ const assetUrl = await getAssetUrl ( version , assetName , token ) ;
146+ console . log ( ` ${ assetUrl } ` ) ;
147+
148+ const tarGz = await httpsGet ( assetUrl , token , true ) ;
75149
76150 // Extract tar.gz
77151 const tar = zlib . gunzipSync ( tarGz ) ;
@@ -90,13 +164,12 @@ async function downloadBinary() {
90164
91165 console . log ( `✓ Installed ${ BINARY_NAME } to ${ binaryPath } ` ) ;
92166 } catch ( error ) {
167+ console . error ( `\nError: Failed to download binary for ${ getPlatformKey ( ) } ` ) ;
168+ console . error ( ` ${ error . message } ` ) ;
93169 if ( error . message . includes ( "404" ) ) {
94- console . error ( `\nError: No prebuilt binary found for ${ getPlatformKey ( ) } ` ) ;
95- console . error ( `Release v${ version } may not exist or may not have binaries yet.` ) ;
96- console . error ( `\nYou can build from source with: cargo build --release` ) ;
97- } else {
98- console . error ( `\nError downloading binary: ${ error . message } ` ) ;
170+ console . error ( `\nRelease v${ version } may not exist or may not have binaries for your platform.` ) ;
99171 }
172+ console . error ( `\nYou can build from source with: cargo build --release` ) ;
100173 process . exit ( 1 ) ;
101174 }
102175}
0 commit comments