Skip to content

Commit 766f21f

Browse files
committed
Add GitHub token support for private repo installs
1 parent 7abfb5a commit 766f21f

File tree

1 file changed

+78
-7
lines changed

1 file changed

+78
-7
lines changed

scripts/postinstall.js

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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,44 @@ 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+
64124
async 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+
if (token) {
132+
console.log(` (using GitHub token for authentication)`);
133+
}
72134

73135
try {
74-
const tarGz = await httpsGet(url);
136+
// Get the asset download URL from the API
137+
const assetUrl = await getAssetUrl(version, assetName, token);
138+
console.log(` ${assetUrl}`);
139+
140+
const tarGz = await httpsGet(assetUrl, token, true);
75141

76142
// Extract tar.gz
77143
const tar = zlib.gunzipSync(tarGz);
@@ -93,6 +159,11 @@ async function downloadBinary() {
93159
if (error.message.includes("404")) {
94160
console.error(`\nError: No prebuilt binary found for ${getPlatformKey()}`);
95161
console.error(`Release v${version} may not exist or may not have binaries yet.`);
162+
if (!token) {
163+
console.error(`\nThis is a private repo - you need to set GITHUB_TOKEN:`);
164+
console.error(` export GITHUB_TOKEN=ghp_your_token_here`);
165+
console.error(` pnpm install`);
166+
}
96167
console.error(`\nYou can build from source with: cargo build --release`);
97168
} else {
98169
console.error(`\nError downloading binary: ${error.message}`);

0 commit comments

Comments
 (0)