git-userhub 3.0.2 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,18 +9,18 @@
9
9
  </p>
10
10
 
11
11
  <p>
12
- <a href="https://www.npmjs.com/package/git-userhub"><img src="https://img.shields.io/npm/v/git-userhub?style=flat-square&color=CB3837&logo=npm&logoColor=white" alt="npm version" /></a>
13
- <a href="https://www.npmjs.com/package/git-userhub"><img src="https://img.shields.io/npm/dt/git-userhub?style=flat-square&color=CB3837&logo=npm&logoColor=white&label=total%20downloads" alt="total downloads" /></a>
14
- <a href="https://github.com/divyo-argha/git-user/releases"><img src="https://img.shields.io/github/v/release/divyo-argha/git-user?style=flat-square&color=00FFAA&label=latest" alt="Latest Release" /></a>
15
- <a href="https://github.com/divyo-argha/git-user/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-22c55e?style=flat-square" alt="MIT" /></a>
12
+ <a href="https://www.npmjs.com/package/git-userhub"><img src="https://img.shields.io/npm/v/git-userhub?style=flat&color=CB3837&logo=npm&logoColor=white" alt="npm version" /></a>
13
+ <a href="https://www.npmjs.com/package/git-userhub"><img src="https://img.shields.io/npm/dt/git-userhub?style=flat&color=CB3837&logo=npm&logoColor=white&label=total%20downloads" alt="total downloads" /></a>
14
+ <a href="https://github.com/divyo-argha/git-user/releases"><img src="https://img.shields.io/github/v/release/divyo-argha/git-user?style=flat&color=00FFAA&label=latest" alt="Latest Release" /></a>
15
+ <a href="https://github.com/divyo-argha/git-user/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-22c55e?style=flat" alt="MIT" /></a>
16
16
  </p>
17
17
 
18
- <img src="https://img.shields.io/badge/GitHub-supported-181717?style=for-the-badge&logo=github&logoColor=white" alt="GitHub" />
19
- <img src="https://img.shields.io/badge/GitLab-supported-FC6D26?style=for-the-badge&logo=gitlab&logoColor=white" alt="GitLab" />
20
- <img src="https://img.shields.io/badge/Bitbucket-supported-0052CC?style=for-the-badge&logo=bitbucket&logoColor=white" alt="Bitbucket" />
21
- <img src="https://img.shields.io/badge/macOS-supported-000000?style=for-the-badge&logo=apple&logoColor=white" alt="macOS" />
22
- <img src="https://img.shields.io/badge/Linux-supported-FCC624?style=for-the-badge&logo=linux&logoColor=black" alt="Linux" />
23
- <img src="https://img.shields.io/badge/Windows-supported-0078D4?style=for-the-badge&logo=windows&logoColor=white" alt="Windows" />
18
+ <img src="https://img.shields.io/badge/GitHub-supported-181717?style=flat&logo=github&logoColor=white" alt="GitHub" />
19
+ <img src="https://img.shields.io/badge/GitLab-supported-FC6D26?style=flat&logo=gitlab&logoColor=white" alt="GitLab" />
20
+ <img src="https://img.shields.io/badge/Bitbucket-supported-0052CC?style=flat&logo=bitbucket&logoColor=white" alt="Bitbucket" />
21
+ <img src="https://img.shields.io/badge/macOS-supported-000000?style=flat&logo=apple&logoColor=white" alt="macOS" />
22
+ <img src="https://img.shields.io/badge/Linux-supported-FCC624?style=flat&logo=linux&logoColor=black" alt="Linux" />
23
+ <img src="https://img.shields.io/badge/Windows-supported-0078D4?style=flat&logo=windows&logoColor=white" alt="Windows" />
24
24
 
25
25
  <br /><br />
26
26
 
@@ -176,7 +176,7 @@ MIT
176
176
 
177
177
  <div align="center">
178
178
 
179
- [![GitHub](https://img.shields.io/badge/Star%20on%20GitHub-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/divyo-argha/git-user)
179
+ [![GitHub](https://img.shields.io/badge/Star%20on%20GitHub-181717?style=flat&logo=github&logoColor=white)](https://github.com/divyo-argha/git-user)
180
180
 
181
181
  <sub>If git-user saved you from a wrong-account commit, consider giving it a ⭐</sub>
182
182
 
Binary file
Binary file
Binary file
Binary file
package/bin/git-user.js CHANGED
@@ -1,233 +1,54 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const { spawn } = require('child_process');
4
- const https = require('https');
5
4
  const fs = require('fs');
6
5
  const path = require('path');
7
6
  const os = require('os');
8
- const crypto = require('crypto');
9
- const tar = require('tar');
10
- const pkg = require('../package.json');
11
-
12
- const REPO = pkg.config.repo;
13
- const BIN_DIR = path.join(__dirname, '..', 'bin');
14
7
 
15
8
  // Detect platform and architecture
16
- function getPlatform() {
17
- const platform = os.platform();
18
- const arch = os.arch();
19
-
20
- const platformMap = {
21
- 'darwin': 'darwin',
22
- 'linux': 'linux',
23
- 'win32': 'windows'
24
- };
25
-
26
- const archMap = {
27
- 'x64': 'amd64',
28
- 'arm64': 'arm64'
29
- };
30
-
31
- return {
32
- os: platformMap[platform],
33
- arch: archMap[arch],
34
- ext: platform === 'win32' ? '.exe' : ''
35
- };
9
+ const platform = os.platform();
10
+ const arch = os.arch();
11
+
12
+ const platformMap = {
13
+ 'darwin': 'darwin',
14
+ 'linux': 'linux',
15
+ 'win32': 'windows'
16
+ };
17
+
18
+ const archMap = {
19
+ 'x64': 'amd64',
20
+ 'arm64': 'arm64'
21
+ };
22
+
23
+ const osName = platformMap[platform];
24
+ const archName = archMap[arch];
25
+ const ext = platform === 'win32' ? '.exe' : '';
26
+
27
+ if (!osName || !archName) {
28
+ console.error(`❌ Unsupported platform: ${platform} ${arch}`);
29
+ process.exit(1);
36
30
  }
37
31
 
38
- // Download file to memory (for checksums.txt)
39
- function fetchText(url, redirectCount = 0) {
40
- return new Promise((resolve, reject) => {
41
- if (redirectCount > 3) return reject(new Error('Too many redirects'));
42
-
43
- const parsedUrl = new URL(url);
44
- if (parsedUrl.protocol !== 'https:') {
45
- return reject(new Error('Only HTTPS is allowed'));
46
- }
47
-
48
- https.get(url, { headers: { 'User-Agent': 'git-user-cli' } }, (res) => {
49
- if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
50
- return fetchText(res.headers.location, redirectCount + 1).then(resolve).catch(reject);
51
- }
52
- if (res.statusCode !== 200) {
53
- return reject(new Error(`Failed to fetch: ${res.statusCode} ${url}`));
54
- }
55
- let data = '';
56
- res.on('data', chunk => data += chunk);
57
- res.on('end', () => resolve(data));
58
- }).on('error', reject);
59
- });
60
- }
61
-
62
- // Download file from URL, and verify hash
63
- function downloadAndVerify(url, dest, expectedHash, redirectCount = 0) {
64
- return new Promise((resolve, reject) => {
65
- if (redirectCount > 3) return reject(new Error('Too many redirects'));
66
-
67
- const parsedUrl = new URL(url);
68
- if (parsedUrl.protocol !== 'https:') {
69
- return reject(new Error('Only HTTPS is allowed'));
70
- }
71
-
72
- const file = fs.createWriteStream(dest);
73
- const hash = crypto.createHash('sha256');
74
-
75
- https.get(url, { headers: { 'User-Agent': 'git-user-cli' } }, (response) => {
76
- if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
77
- file.close();
78
- fs.unlink(dest, () => {});
79
- return downloadAndVerify(response.headers.location, dest, expectedHash, redirectCount + 1)
80
- .then(resolve)
81
- .catch(reject);
82
- }
83
- if (response.statusCode !== 200) {
84
- file.close();
85
- fs.unlink(dest, () => {});
86
- return reject(new Error(`Failed to download: ${response.statusCode} ${url}`));
87
- }
88
-
89
- response.on('data', chunk => hash.update(chunk));
90
- response.pipe(file);
91
-
92
- file.on('finish', () => {
93
- file.close();
94
- const actualHash = hash.digest('hex');
95
- if (actualHash !== expectedHash) {
96
- fs.unlink(dest, () => {});
97
- return reject(new Error(`Checksum mismatch! Expected ${expectedHash}, got ${actualHash}`));
98
- }
99
- resolve();
100
- });
101
- }).on('error', (err) => {
102
- file.close();
103
- fs.unlink(dest, () => {});
104
- reject(err);
105
- });
106
- });
107
- }
32
+ const binaryName = `git-user-${osName}-${archName}${ext}`;
33
+ const binaryPath = path.join(__dirname, binaryName);
108
34
 
109
- // Get release info matching this npm package version.
110
- function getRelease() {
111
- return new Promise((resolve, reject) => {
112
- const options = {
113
- hostname: 'api.github.com',
114
- path: `/repos/${REPO}/releases/tags/v${pkg.version}`,
115
- headers: {
116
- 'User-Agent': 'git-user-cli'
117
- }
118
- };
119
-
120
- https.get(options, (res) => {
121
- if (res.statusCode !== 200) {
122
- return reject(new Error(`GitHub API returned ${res.statusCode} for release v${pkg.version}`));
123
- }
124
- let data = '';
125
- res.on('data', (chunk) => data += chunk);
126
- res.on('end', () => {
127
- try {
128
- resolve(JSON.parse(data));
129
- } catch (err) {
130
- reject(err);
131
- }
132
- });
133
- }).on('error', reject);
134
- });
35
+ if (!fs.existsSync(binaryPath)) {
36
+ console.error(`❌ git-user binary not found at ${binaryPath}`);
37
+ console.error(` Please ensure the package was correctly installed.`);
38
+ process.exit(1);
135
39
  }
136
40
 
137
- async function installAndRun() {
138
- const { os: osName, arch, ext } = getPlatform();
139
- const binaryPath = path.join(BIN_DIR, `git-user${ext}`);
140
-
141
- if (!fs.existsSync(binaryPath)) {
142
- console.log('📦 First run detected. Downloading git-user binary...');
143
-
144
- if (!osName || !arch) {
145
- console.error('❌ Unsupported platform:', os.platform(), os.arch());
146
- process.exit(1);
147
- }
148
-
149
- try {
150
- if (!fs.existsSync(BIN_DIR)) {
151
- fs.mkdirSync(BIN_DIR, { recursive: true });
152
- }
153
-
154
- console.log(`🔍 Fetching release v${pkg.version}...`);
155
- const release = await getRelease();
156
-
157
- const asset = release.assets?.find(a => {
158
- const name = a.name.toLowerCase();
159
- if (!name.includes(osName)) return false;
160
- if (arch === 'arm64') return name.includes('arm64');
161
- return name.includes('x86_64') || name.includes('amd64') || name.includes('x64');
162
- });
163
-
164
- if (!asset) {
165
- console.error('❌ No binary found for your platform');
166
- console.error(` Looking for a ${osName} binary matching architecture: ${arch}`);
167
- process.exit(1);
168
- }
169
-
170
- console.log('🔐 Fetching checksums...');
171
- // Fetch checksums.txt from the release assets or release tag
172
- // GitHub Releases typically attach checksums.txt if goreleaser is used
173
- const checksumAsset = release.assets?.find(a => a.name === 'checksums.txt');
174
- let checksumsUrl = '';
175
- if (checksumAsset) {
176
- checksumsUrl = checksumAsset.browser_download_url;
177
- } else {
178
- // Fallback pattern if asset list doesn't have it, try direct URL
179
- checksumsUrl = `https://github.com/${REPO}/releases/download/v${pkg.version}/checksums.txt`;
180
- }
181
-
182
- const checksumsText = await fetchText(checksumsUrl);
183
-
184
- // Parse checksums.txt to find the hash for our asset
185
- const expectedHashLine = checksumsText.split('\n').find(line => line.includes(asset.name));
186
- if (!expectedHashLine) {
187
- throw new Error(`Checksum for ${asset.name} not found in checksums.txt`);
188
- }
189
- const expectedHash = expectedHashLine.trim().split(/\s+/)[0];
190
-
191
- console.log(`⬇️ Downloading ${asset.name} (verifying SHA256 checksum)...`);
192
- const archivePath = path.join(BIN_DIR, asset.name);
193
- await downloadAndVerify(asset.browser_download_url, archivePath, expectedHash);
194
-
195
- console.log('📂 Extracting securely...');
196
- await tar.extract({
197
- file: archivePath,
198
- cwd: BIN_DIR,
199
- filter: (p) => p === `git-user${ext}` || p === `./git-user${ext}`
200
- });
201
-
202
- fs.unlinkSync(archivePath);
203
-
204
- if (fs.existsSync(binaryPath)) {
205
- fs.chmodSync(binaryPath, 0o755);
206
- console.log('✅ git-user installed successfully!\n');
207
- } else {
208
- console.error('❌ Binary not found after extraction');
209
- process.exit(1);
210
- }
211
- } catch (err) {
212
- console.error('❌ Installation failed:', err.message);
213
- process.exit(1);
214
- }
215
- }
41
+ // Forward all arguments to the bundled binary
42
+ const child = spawn(binaryPath, process.argv.slice(2), {
43
+ stdio: 'inherit',
44
+ shell: false
45
+ });
216
46
 
217
- // Forward all arguments to the binary
218
- const child = spawn(binaryPath, process.argv.slice(2), {
219
- stdio: 'inherit',
220
- shell: false
221
- });
222
-
223
- child.on('exit', (code) => {
224
- process.exit(code || 0);
225
- });
226
-
227
- child.on('error', (err) => {
228
- console.error('❌ Failed to start git-user:', err.message);
229
- process.exit(1);
230
- });
231
- }
47
+ child.on('exit', (code) => {
48
+ process.exit(code || 0);
49
+ });
232
50
 
233
- installAndRun();
51
+ child.on('error', (err) => {
52
+ console.error('❌ Failed to start git-user:', err.message);
53
+ process.exit(1);
54
+ });
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "git-userhub",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "description": "Switch Git accounts in one command. No config editing. No SSH key chaos.",
5
5
  "bin": {
6
6
  "git-user": "bin/git-user.js"
7
7
  },
8
8
  "scripts": {
9
- "test": "echo \"No tests yet\" && exit 0"
9
+ "test": "echo \"No tests yet\" && exit 0",
10
+ "prepublishOnly": "node scripts/download-binaries.js"
10
11
  },
11
- "dependencies": {
12
+ "devDependencies": {
12
13
  "tar": "^7.4.3"
13
14
  },
14
15
  "keywords": [
@@ -44,13 +45,6 @@
44
45
  "x64",
45
46
  "arm64"
46
47
  ],
47
- "socket": {
48
- "allowedNetworkHosts": [
49
- "api.github.com",
50
- "github.com",
51
- "objects.githubusercontent.com"
52
- ]
53
- },
54
48
  "config": {
55
49
  "repo": "divyo-argha/git-user"
56
50
  }