@volcengine/cli 1.0.45 → 1.0.48

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
+ ca743cc6217a0dc724808a240b26ef74c7ba84e35b13ff486213cbc47852a203 volcengine-cli_1.0.48_darwin_amd64.tar.gz
2
+ 0d8eaf3cd1c237d81ccb88486d48ae14e205970c1493fd0ed8615131a00aeda5 volcengine-cli_1.0.48_darwin_amd64.zip
3
+ 709339417771879db9f97f94753167b6129f256592035614a5915ad2df782c67 volcengine-cli_1.0.48_darwin_arm64.tar.gz
4
+ fb58d460d29860045a4f58d9c57eb9f80c8bd903db8b1048be90b15ea3b30f83 volcengine-cli_1.0.48_darwin_arm64.zip
5
+ f543729800270414177d47b89d88f98c231b7ac4dbb37826f92a744a332e5e3b volcengine-cli_1.0.48_freebsd_386.tar.gz
6
+ a253024c9ccc42fc5030b2ed973c3470ae5d6ddd93dcc8b5c1b6bf943f8d1022 volcengine-cli_1.0.48_freebsd_386.zip
7
+ a2b4c12f8105efac99ce044ee3b534bbcd83f5e9c8d17a2d137fc1c92b9160f0 volcengine-cli_1.0.48_freebsd_amd64.tar.gz
8
+ 8f6829cdd9c89822087e909433b66f3d8989f35429acce3cfe8d9ac1bee43a6f volcengine-cli_1.0.48_freebsd_amd64.zip
9
+ f2a7eb0608d452d8fad20dd8f631993cb3e5293ae9756f70d35e5f0d5c51bce6 volcengine-cli_1.0.48_freebsd_arm.tar.gz
10
+ ff453e8b92d0689bbf87c7327d42e9f1217ca89792d2e81981eb6089e84ec8bf volcengine-cli_1.0.48_freebsd_arm.zip
11
+ d55214828b09f0cdb95486c861c8131a8b035a79b263930d97ddb60ec17994ea volcengine-cli_1.0.48_freebsd_arm64.tar.gz
12
+ 8463c983981048226d55c6f34c6463998e4fa7e86733d9a134e73b5a40a3eb2e volcengine-cli_1.0.48_freebsd_arm64.zip
13
+ 6bc811fb2d5b2e6e28b3d03d5f938babdc94967fe2665044d997652ed65aefb7 volcengine-cli_1.0.48_linux_386.tar.gz
14
+ 36964489dc205412dbc1a85e402637d3bc5e6229edf5197dca7af4d063721a6f volcengine-cli_1.0.48_linux_386.zip
15
+ 549fb8edc0a84378e150903b4e64eb410f33f799399a6d3bc02b36623651d847 volcengine-cli_1.0.48_linux_amd64.tar.gz
16
+ 532f551d1e4ed4bbcc34b2411754c7d48125a32600c7082355698ac28e51b0f8 volcengine-cli_1.0.48_linux_amd64.zip
17
+ c63dba17b147edeef0c8c8312626d0558054771fda4ce85a8d53b2799869316b volcengine-cli_1.0.48_linux_arm.tar.gz
18
+ 95c93f1301896f43458d08456d3613dd04b2e026e22f91b8a40883ccf2eefbb3 volcengine-cli_1.0.48_linux_arm.zip
19
+ ba660a381009fa0e7411f1899378ac9a4e94d9755539a764ca46a19b629cecc8 volcengine-cli_1.0.48_linux_arm64.tar.gz
20
+ 6b70a06b7cf51ea7406534a8442b1d163685ea866ce578805842bcefad0eeaea volcengine-cli_1.0.48_linux_arm64.zip
21
+ f60e09e7de6250c6437d8644e73d35903671db959d0e60e1b9e5ddd446c254cb volcengine-cli_1.0.48_windows_386.tar.gz
22
+ 3505c387bef5a846b88d641f51c7aa9cc43bf06012f8bbc705004e277c9610f6 volcengine-cli_1.0.48_windows_386.zip
23
+ 5fdefcf3d9f6d64d1403ae610955fccfda277b73ea8a570cdebbedf38f630384 volcengine-cli_1.0.48_windows_amd64.tar.gz
24
+ bbae0918b0d1fa2947e84166fa6f39f1e7599d670024ce2dcd256c942d5a4194 volcengine-cli_1.0.48_windows_amd64.zip
25
+ f7dfe472af3cfa3ad9e80fe0023d6f42689d3528fd0cc706505b8b27800fc813 volcengine-cli_1.0.48_windows_arm64.tar.gz
26
+ 43331270c6c56fb3835f59d1aa7920885dfb4a562eac2d44518f1916a4ca3d41 volcengine-cli_1.0.48_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.48",
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": [