@volcengine/cli 1.0.45 → 1.0.49

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.
Files changed (4) hide show
  1. package/bin/ve +3 -3
  2. package/checksum +26 -0
  3. package/install.js +203 -52
  4. package/package.json +6 -4
package/bin/ve CHANGED
@@ -1,3 +1,3 @@
1
- #!/bin/sh
2
- echo ve not installed. Run npm rebuild @volcengine/cli >&2
3
- exit 1
1
+ #!/usr/bin/env node
2
+ console.error("ve not installed. Run npm rebuild for this package");
3
+ process.exit(1);
package/checksum ADDED
@@ -0,0 +1,26 @@
1
+ 39930a55f0ee4492bca789d5c4198c790777f90d6080b9fdb49b89bae2430ac8 volcengine-cli_1.0.49_darwin_amd64.tar.gz
2
+ f241502edcfa7c1420c52f346b0405edd34243b30d0ef61db23ff5c9fed4e26e volcengine-cli_1.0.49_darwin_amd64.zip
3
+ 6bed2df8fd69d4f63470513a738dea0f012ddcc876a4c65fd5e7de0d2fe609a8 volcengine-cli_1.0.49_darwin_arm64.tar.gz
4
+ 7d7174921e0fbdc5b91a3d0226b8fe216256f49a100e74fe5b8a233a77f7109b volcengine-cli_1.0.49_darwin_arm64.zip
5
+ f03a972d6076dc6410dafefffef47b3674b3214fe16af36ee617fcc55ca47f61 volcengine-cli_1.0.49_freebsd_386.tar.gz
6
+ ebe53383090a82fb8360e2d36fac2ec4f43a1bc0f19523b302331314902b76b9 volcengine-cli_1.0.49_freebsd_386.zip
7
+ b251781435974315b27a940e7a0d33338a7ca370599fb481f9d13fe89c0a21bf volcengine-cli_1.0.49_freebsd_amd64.tar.gz
8
+ 032304a18d9004c675c11b1aa2c46dea3cba3a6acb9c0c26978f3f1f83eb210a volcengine-cli_1.0.49_freebsd_amd64.zip
9
+ 366439c1e0f84121f6675f7ad7d76781c1602a00cfbeef2372fd223afd20f3ce volcengine-cli_1.0.49_freebsd_arm.tar.gz
10
+ bb22059f9cb83ddfa0022a93c1e4a24294a61c0860ce83c7944518d967355922 volcengine-cli_1.0.49_freebsd_arm.zip
11
+ 6a07a13469827835981f348ea1d9b1bba1cd7e760a2a520702a14196a844d10d volcengine-cli_1.0.49_freebsd_arm64.tar.gz
12
+ 22280ab67b19dac6cc6a074ade099d374d98b4275f9e9cbd55ba4d8de0880ea4 volcengine-cli_1.0.49_freebsd_arm64.zip
13
+ 511267b42e9bac81546bdc478a61650942f9b344a1eb8c8d54466d1a9163e996 volcengine-cli_1.0.49_linux_386.tar.gz
14
+ 01787227513b7da9bd7fdf2b7874e9d87f6929c6de62e2312b1c4a39195ebe86 volcengine-cli_1.0.49_linux_386.zip
15
+ bf010a5e992de70bcc819877fc096c320d691119738cd17ffebfbaf7b4b72f47 volcengine-cli_1.0.49_linux_amd64.tar.gz
16
+ 833191edc890d4da54d64138c7df0385de7642c9ebd44e6db3ff083776d7bdac volcengine-cli_1.0.49_linux_amd64.zip
17
+ d933d94e8e85dd77d4c008383d5d29b273e1f429ffcc7dffdc32a3419636bef9 volcengine-cli_1.0.49_linux_arm.tar.gz
18
+ a3a94e926636fce4d0ad885249df9fb82f626c88d1d2270a7f5b40e365174e32 volcengine-cli_1.0.49_linux_arm.zip
19
+ 597b28a016d72061125d3301b0db60ccb1057be7b68b75b0e1649817e00686ae volcengine-cli_1.0.49_linux_arm64.tar.gz
20
+ 6b3d37128195c47d02c209ca7ad19d7178c79cc2f6e9dd7718892c5b635f757d volcengine-cli_1.0.49_linux_arm64.zip
21
+ b876af213c4ca8480c67a58e9300ef2cd9469b077284733e09876edd1cc10331 volcengine-cli_1.0.49_windows_386.tar.gz
22
+ b8a695a14c7eabf932204ffedd0f5ea3147295e63f8f7fc4d038669eba9271a3 volcengine-cli_1.0.49_windows_386.zip
23
+ 518be8bf0b6c96ccdbb0a02861dc6888392b17f394ea2141f72aff1f2937e2ff volcengine-cli_1.0.49_windows_amd64.tar.gz
24
+ ef596cad6c0e78f3feedc48d55ed0974956a01006154e57db099a577d530dba0 volcengine-cli_1.0.49_windows_amd64.zip
25
+ 9078b84b1ab79b41c9b16cddd41f8fa48e630e0de2a28f7ec9ce15d529646b09 volcengine-cli_1.0.49_windows_arm64.tar.gz
26
+ a52a85b91152c49507525fe862681ce771da66434b17f3e16e3fd4422a5726d8 volcengine-cli_1.0.49_windows_arm64.zip
package/install.js CHANGED
@@ -1,12 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const { execSync } = require("child_process");
4
+ const crypto = require("crypto");
4
5
  const https = require("https");
5
6
  const fs = require("fs");
6
7
  const path = require("path");
7
8
 
8
- const VERSION = "1.0.45";
9
- const BASE_URL = `https://github.com/volcengine/volcengine-cli/releases/download/v${VERSION}`;
9
+ const VERSION = require("./package.json").version;
10
+ const DEFAULT_DOWNLOAD_BASE_URL = "https://cloudcache.volccdn.com/ve";
11
+ const CHECKSUM_PATH = path.join(__dirname, "checksum");
12
+ const OFFICIAL_RELEASES_URL = "https://github.com/volcengine/volcengine-cli/releases";
13
+ const DOWNLOAD_BASE_URL = normalizeBaseURL(
14
+ process.env.VOLCENGINE_CLI_DOWNLOAD_BASE_URL || DEFAULT_DOWNLOAD_BASE_URL
15
+ );
10
16
 
11
17
  const PLATFORM_MAP = {
12
18
  darwin: "darwin",
@@ -22,58 +28,189 @@ const ARCH_MAP = {
22
28
  arm: "arm",
23
29
  };
24
30
 
25
- const platform = PLATFORM_MAP[process.platform];
26
- const arch = ARCH_MAP[process.arch];
31
+ const SUPPORTED_TARGETS = {
32
+ darwin: ["amd64", "arm64"],
33
+ linux: ["amd64", "386", "arm", "arm64"],
34
+ freebsd: ["amd64", "386", "arm", "arm64"],
35
+ windows: ["amd64", "386", "arm64"],
36
+ };
27
37
 
28
- if (!platform || !arch) {
29
- console.error(`Unsupported platform: ${process.platform} ${process.arch}`);
30
- process.exit(1);
38
+ function normalizeBaseURL(url) {
39
+ return String(url || "").replace(/\/+$/, "");
40
+ }
41
+
42
+ function binaryNameForPlatform(platform) {
43
+ return platform === "win32" ? "ve.exe" : "ve";
44
+ }
45
+
46
+ function targetForPlatform(platform, arch) {
47
+ const targetPlatform = PLATFORM_MAP[platform];
48
+ const targetArch = ARCH_MAP[arch];
49
+
50
+ if (!targetPlatform || !targetArch) {
51
+ return null;
52
+ }
53
+
54
+ const supportedArchs = SUPPORTED_TARGETS[targetPlatform] || [];
55
+ if (supportedArchs.indexOf(targetArch) === -1) {
56
+ return null;
57
+ }
58
+
59
+ return {
60
+ platform: targetPlatform,
61
+ arch: targetArch,
62
+ };
63
+ }
64
+
65
+ function archiveNameForTarget(target, version) {
66
+ return `volcengine-cli_${version}_${target.platform}_${target.arch}.zip`;
31
67
  }
32
68
 
33
- const zipName = `volcengine-cli_${VERSION}_${platform}_${arch}.zip`;
34
- const url = `${BASE_URL}/${zipName}`;
69
+ function archiveURLForTarget(target, version, downloadBaseURL) {
70
+ const baseURL = normalizeBaseURL(downloadBaseURL);
71
+ return `${baseURL}/v${version}/${archiveNameForTarget(target, version)}`;
72
+ }
35
73
 
36
- const binDir = path.join(__dirname, "bin");
37
- fs.mkdirSync(binDir, { recursive: true });
74
+ function sha256(data) {
75
+ return crypto.createHash("sha256").update(data).digest("hex");
76
+ }
38
77
 
39
- const isWindows = process.platform === "win32";
40
- const binaryName = isWindows ? "ve.exe" : "ve";
41
- const binPath = path.join(binDir, binaryName);
78
+ function archiveBasename(filename) {
79
+ return String(filename || "").split(/[\\/]/).pop();
80
+ }
81
+
82
+ function parseChecksum(content) {
83
+ const entries = [];
84
+ String(content || "")
85
+ .split(/\r?\n/)
86
+ .forEach((line, index) => {
87
+ const trimmed = line.trim();
88
+ if (!trimmed) {
89
+ return;
90
+ }
91
+
92
+ const match = trimmed.match(/^([a-fA-F0-9]{64})\s+\*?(.+)$/);
93
+ if (!match) {
94
+ throw new Error(`Invalid checksum line ${index + 1}`);
95
+ }
96
+
97
+ entries.push({
98
+ hash: match[1].toLowerCase(),
99
+ filename: match[2],
100
+ });
101
+ });
102
+ return entries;
103
+ }
104
+
105
+ function checksumForArchive(content, archiveName) {
106
+ const match = parseChecksum(content).find(
107
+ (entry) => entry.filename === archiveName || archiveBasename(entry.filename) === archiveName
108
+ );
109
+
110
+ if (!match) {
111
+ throw new Error(`Checksum entry not found for ${archiveName}`);
112
+ }
113
+
114
+ return match.hash;
115
+ }
116
+
117
+ function verifyArchiveChecksum(data, archiveName, checksumPath = CHECKSUM_PATH) {
118
+ let checksumContent;
119
+ try {
120
+ checksumContent = fs.readFileSync(checksumPath, "utf8");
121
+ } catch (err) {
122
+ if (err && err.code === "ENOENT") {
123
+ throw new Error(`Checksum file not found: ${checksumPath}`);
124
+ }
125
+ throw err;
126
+ }
127
+
128
+ const expected = checksumForArchive(checksumContent, archiveName);
129
+ const actual = sha256(data);
130
+
131
+ if (actual !== expected) {
132
+ throw new Error(
133
+ `Checksum mismatch for ${archiveName}: expected ${expected}, got ${actual}. ` +
134
+ `The downloaded archive may have been tampered with. ` +
135
+ `Please download Volcengine CLI from the official releases page: ${OFFICIAL_RELEASES_URL}`
136
+ );
137
+ }
138
+
139
+ return actual;
140
+ }
141
+
142
+ function downloadErrorMessage(statusCode, url) {
143
+ return (
144
+ `Download failed: HTTP ${statusCode} for ${url}. ` +
145
+ `\nPlease download Volcengine CLI from the official releases page: ${OFFICIAL_RELEASES_URL}`
146
+ );
147
+ }
148
+
149
+ function createWindowsVeShim(binDir) {
150
+ const shimPath = path.join(binDir, "ve");
151
+ const shim = `#!/usr/bin/env node
152
+
153
+ const { spawnSync } = require("child_process");
154
+ const path = require("path");
155
+
156
+ const exePath = path.join(__dirname, "ve.exe");
157
+ const result = spawnSync(exePath, process.argv.slice(2), { stdio: "inherit" });
158
+
159
+ if (result.error) {
160
+ console.error(result.error.message);
161
+ process.exit(1);
162
+ }
163
+
164
+ process.exit(result.status === null ? 1 : result.status);
165
+ `;
166
+
167
+ fs.writeFileSync(shimPath, shim);
168
+ fs.chmodSync(shimPath, 0o755);
169
+ }
42
170
 
43
171
  function download(url) {
44
172
  return new Promise((resolve, reject) => {
45
173
  const follow = (url) => {
46
- https
47
- .get(url, (res) => {
48
- if (
49
- res.statusCode >= 300 &&
50
- res.statusCode < 400 &&
51
- res.headers.location
52
- ) {
53
- follow(res.headers.location);
54
- return;
55
- }
56
- if (res.statusCode !== 200) {
57
- reject(
58
- new Error(`Download failed: HTTP ${res.statusCode} for ${url}`),
59
- );
60
- return;
61
- }
62
- const chunks = [];
63
- res.on("data", (chunk) => chunks.push(chunk));
64
- res.on("end", () => resolve(Buffer.concat(chunks)));
65
- res.on("error", reject);
66
- })
67
- .on("error", reject);
174
+ https.get(url, (res) => {
175
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
176
+ follow(res.headers.location);
177
+ return;
178
+ }
179
+ if (res.statusCode !== 200) {
180
+ reject(new Error(downloadErrorMessage(res.statusCode, url)));
181
+ return;
182
+ }
183
+ const chunks = [];
184
+ res.on("data", (chunk) => chunks.push(chunk));
185
+ res.on("end", () => resolve(Buffer.concat(chunks)));
186
+ res.on("error", reject);
187
+ }).on("error", reject);
68
188
  };
69
189
  follow(url);
70
190
  });
71
191
  }
72
192
 
73
193
  async function install() {
194
+ const target = targetForPlatform(process.platform, process.arch);
195
+
196
+ if (!target) {
197
+ console.error(`Unsupported platform: ${process.platform} ${process.arch}`);
198
+ process.exit(1);
199
+ }
200
+
201
+ const zipName = archiveNameForTarget(target, VERSION);
202
+ const url = archiveURLForTarget(target, VERSION, DOWNLOAD_BASE_URL);
203
+ const binDir = path.join(__dirname, "bin");
204
+ const isWindows = process.platform === "win32";
205
+ const binaryName = binaryNameForPlatform(process.platform);
206
+ const binPath = path.join(binDir, binaryName);
207
+
208
+ fs.mkdirSync(binDir, { recursive: true });
74
209
  console.log(`Downloading ${zipName}...`);
75
210
 
76
211
  const data = await download(url);
212
+ verifyArchiveChecksum(data, zipName);
213
+
77
214
  const tmpDir = path.join(__dirname, ".tmp");
78
215
  const zipPath = path.join(tmpDir, zipName);
79
216
 
@@ -84,7 +221,7 @@ async function install() {
84
221
  if (isWindows) {
85
222
  execSync(
86
223
  `powershell -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${tmpDir}' -Force"`,
87
- { stdio: "pipe" },
224
+ { stdio: "pipe" }
88
225
  );
89
226
  } else {
90
227
  execSync(`unzip -o -q "${zipPath}" -d "${tmpDir}"`, { stdio: "pipe" });
@@ -94,37 +231,51 @@ async function install() {
94
231
  const veBinary = extracted.find((f) => f === "ve" || f === "ve.exe");
95
232
 
96
233
  if (!veBinary) {
97
- console.error(
98
- "Could not find 've' binary in zip archive. Found:",
99
- extracted,
100
- );
234
+ console.error("Could not find 've' binary in zip archive. Found:", extracted);
101
235
  process.exit(1);
102
236
  }
103
237
 
104
238
  fs.copyFileSync(path.join(tmpDir, veBinary), binPath);
105
239
 
106
- if (!isWindows) {
240
+ if (isWindows) {
241
+ createWindowsVeShim(binDir);
242
+ } else {
107
243
  fs.chmodSync(binPath, 0o755);
108
244
  }
109
245
 
110
- // macOS: remove quarantine attribute to avoid Gatekeeper blocking
111
246
  if (process.platform === "darwin") {
112
247
  try {
113
- execSync(`xattr -d com.apple.quarantine "${binPath}"`, {
114
- stdio: "pipe",
115
- });
248
+ execSync(`xattr -d com.apple.quarantine "${binPath}"`, { stdio: "pipe" });
116
249
  } catch (_) {
117
- // Attribute may not exist, ignore
250
+ // Attribute may not exist, ignore.
118
251
  }
119
252
  }
120
253
 
121
- console.log(`Volcengine CLI v${VERSION} installed for ${platform}/${arch}`);
254
+ console.log(`Volcengine CLI v${VERSION} installed for ${target.platform}/${target.arch}`);
122
255
  } finally {
123
256
  fs.rmSync(tmpDir, { recursive: true, force: true });
124
257
  }
125
258
  }
126
259
 
127
- install().catch((err) => {
128
- console.error("Installation failed:", err.message);
129
- process.exit(1);
130
- });
260
+ if (require.main === module) {
261
+ install().catch((err) => {
262
+ console.error("Installation failed:", err.message);
263
+ process.exit(1);
264
+ });
265
+ }
266
+
267
+ module.exports = {
268
+ archiveNameForTarget,
269
+ archiveURLForTarget,
270
+ binaryNameForPlatform,
271
+ checksumForArchive,
272
+ createWindowsVeShim,
273
+ defaultDownloadBaseURL: DEFAULT_DOWNLOAD_BASE_URL,
274
+ downloadErrorMessage,
275
+ normalizeBaseURL,
276
+ parseChecksum,
277
+ sha256,
278
+ targetForPlatform,
279
+ verifyArchiveChecksum,
280
+ version: VERSION,
281
+ };
package/package.json CHANGED
@@ -1,16 +1,18 @@
1
1
  {
2
2
  "name": "@volcengine/cli",
3
- "version": "1.0.45",
4
- "description": "Volcengine CLI - 火山引擎命令行工具",
3
+ "version": "1.0.49",
4
+ "description": "Volcengine CLI npm installer",
5
5
  "bin": {
6
6
  "ve": "bin/ve"
7
7
  },
8
8
  "scripts": {
9
- "prepack": "node -e \"require('fs').writeFileSync('bin/ve','#!/bin/sh\\necho ve not installed. Run npm rebuild @volcengine/cli >&2\\nexit 1\\n');require('fs').chmodSync('bin/ve',0o755)\"",
10
- "postinstall": "node install.js"
9
+ "prepack": "node -e \"const fs=require('fs');fs.mkdirSync('bin',{recursive:true});fs.writeFileSync('bin/ve','#!/usr/bin/env node\\nconsole.error(\\\"ve not installed. Run npm rebuild for this package\\\");\\nprocess.exit(1);\\n');fs.chmodSync('bin/ve',0o755)\"",
10
+ "postinstall": "node install.js",
11
+ "test": "node install_test.js"
11
12
  },
12
13
  "files": [
13
14
  "bin/",
15
+ "checksum",
14
16
  "install.js"
15
17
  ],
16
18
  "keywords": [