node-nim 10.9.71 → 10.9.72

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-nim",
3
- "version": "10.9.71",
3
+ "version": "10.9.72",
4
4
  "description": "NetEase IM nodejs wrapper based on NetEase IM C++ SDK",
5
5
  "main": "dist/node-nim.js",
6
6
  "bin": {
@@ -20,8 +20,8 @@
20
20
  "build_ts": "rimraf ./dist && rimraf ./types && tsc",
21
21
  "build_html_doc": "typedoc --plugin typedoc-github-theme",
22
22
  "prepublishOnly": "npm run build_ts",
23
- "install": "npm run download_sdk",
24
- "download_sdk": "node -e \"require('./script/download-sdk.js').downloadSDK()\"",
23
+ "postinstall": "node script/download-sdk.js",
24
+ "download_sdk": "node script/download-sdk.js",
25
25
  "publish_to_netease_npm": "node script/publish-to-netease-npm.js http://npm.netease.im/",
26
26
  "publish_to_npmjs": "node script/publish-to-netease-npm.js https://registry.npmjs.org",
27
27
  "test": "npx cross-env BABEL_ENV=test mocha"
@@ -33,10 +33,10 @@
33
33
  ]
34
34
  },
35
35
  "dependencies": {
36
+ "axios": "^1.6.2",
36
37
  "compare-versions": "^4.1.4",
37
- "download": "^8.0.0",
38
- "eventemitter3": "^4.0.7",
39
- "node-fetch": "^2.6.9"
38
+ "decompress": "^4.2.1",
39
+ "eventemitter3": "^4.0.7"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@babel/preset-env": "^7.24.0",
@@ -1,8 +1,8 @@
1
- const fetch = require('node-fetch')
1
+ const axios = require('axios')
2
2
  const fs = require('fs')
3
3
  const path = require('path')
4
4
  const compareVersions = require('compare-versions')
5
- const download = require('download')
5
+ const decompress = require('decompress')
6
6
 
7
7
  // Global variables
8
8
  const default_arch = 'universal'
@@ -14,94 +14,490 @@ const product = 'nim'
14
14
  const savePath = path.join(__dirname, '..', 'temporary')
15
15
 
16
16
  if (process.env.npm_config_ignoredownloadsdk) {
17
- console.log('ignore download product')
17
+ console.log('[node-nim] Ignore download product')
18
18
  process.exit(0)
19
19
  }
20
20
  let version
21
- let downloadUrl = process.env.npm_config_nimsdkurl
22
21
  if (process.env.npm_package_version) {
23
22
  version = process.env.npm_package_version.split('-')[0]
24
23
  }
25
24
  if (process.env.npm_config_nimsdkversion) {
26
25
  version = process.env.npm_config_nimsdkversion
27
26
  }
28
- async function downloadSDK(custom_sdk_url) {
29
- if (custom_sdk_url) {
30
- downloadUrl = custom_sdk_url
27
+
28
+ // Simple logger that works with npm postinstall
29
+ // Use console.error to ensure output is visible when installed as dependency
30
+ // npm captures stdout but is less aggressive with stderr
31
+ function log(message) {
32
+ console.error(message)
33
+ }
34
+
35
+ // Progress bar utility - real-time progress bar
36
+ function createProgressBar(total) {
37
+ let lastUpdate = 0
38
+ const updateInterval = 100 // Update every 100ms
39
+ return (loaded) => {
40
+ const now = Date.now()
41
+ const percent = Math.floor((loaded * 100) / total)
42
+ // Update based on time interval or when complete
43
+ if (now - lastUpdate < updateInterval && loaded < total) {
44
+ return
45
+ }
46
+ lastUpdate = now
47
+ const size = formatBytes(loaded)
48
+ const totalSize = formatBytes(total)
49
+ // Create progress bar
50
+ const barLength = 30
51
+ const filledLength = Math.floor((barLength * loaded) / total)
52
+ const bar = '█'.repeat(filledLength) + '░'.repeat(barLength - filledLength)
53
+ // Use \r to overwrite the same line
54
+ process.stderr.write(`\r[node-nim] ⬇ ${bar} ${percent}% (${size}/${totalSize})`)
55
+ // Print newline when complete
56
+ if (loaded >= total) {
57
+ process.stderr.write('\n')
58
+ log(` ✅ Download complete`)
59
+ }
31
60
  }
32
- // fetch publish list
33
- const res = await fetch('https://admin.netease.im/public-service/free/publish/list')
34
- const publish_json = await res.json()
35
- // get sdk list
36
- if (!downloadUrl) {
37
- let latestVersion = '0.0.0'
38
- let latestDownloadUrl = ''
39
- Object.keys(publish_json.data[channel]).forEach((temp) => {
40
- if (compareVersions.compare(latestVersion, temp, '<')) {
41
- publish_json.data[channel][temp].forEach((member) => {
42
- if (member.filename.includes(product) && member.filename.includes(platform) && member.filename.includes(arch)) {
43
- latestVersion = temp
44
- latestDownloadUrl = member.cdnlink
61
+ }
62
+
63
+ // Format bytes to human readable format
64
+ function formatBytes(bytes) {
65
+ if (bytes === 0) return '0 B'
66
+ const k = 1024
67
+ const sizes = ['B', 'KB', 'MB', 'GB']
68
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
69
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]
70
+ }
71
+
72
+ // Compatibility function for removing directories (supports older Node.js versions)
73
+ function removeDirectory(dirPath) {
74
+ if (!fs.existsSync(dirPath)) {
75
+ return
76
+ }
77
+
78
+ // Use rmSync if available (Node.js >= 14.14.0)
79
+ if (fs.rmSync) {
80
+ fs.rmSync(dirPath, { recursive: true, force: true })
81
+ return
82
+ }
83
+
84
+ // Fallback for older Node.js versions using rimraf-like logic
85
+ const rimraf = (path) => {
86
+ const stat = fs.lstatSync(path)
87
+
88
+ if (stat.isDirectory()) {
89
+ // Read directory contents
90
+ const files = fs.readdirSync(path)
91
+
92
+ // Recursively remove all contents
93
+ files.forEach(file => {
94
+ const fullPath = require('path').join(path, file)
95
+ rimraf(fullPath)
96
+ })
97
+
98
+ // Remove the empty directory
99
+ fs.rmdirSync(path)
100
+ } else {
101
+ // Remove file
102
+ // Handle readonly files on Windows
103
+ try {
104
+ fs.unlinkSync(path)
105
+ } catch (err) {
106
+ if (err.code === 'EBUSY' || err.code === 'ENOTEMPTY' || err.code === 'EPERM') {
107
+ // Try to change permissions and retry
108
+ try {
109
+ fs.chmodSync(path, 0o666)
110
+ fs.unlinkSync(path)
111
+ } catch (retryErr) {
112
+ // If still fails, just log and continue
113
+ console.warn(`Warning: Could not remove file ${path}: ${retryErr.message}`)
45
114
  }
46
- })
115
+ } else {
116
+ throw err
117
+ }
47
118
  }
48
- if (version === temp) {
49
- publish_json.data[channel][temp].forEach((member) => {
50
- if (member.filename.includes(product) && member.filename.includes(platform) && member.filename.includes(arch)) {
51
- downloadUrl = member.cdnlink
52
- }
53
- })
119
+ }
120
+ }
121
+
122
+ try {
123
+ rimraf(dirPath)
124
+ } catch (err) {
125
+ // If rmSync and rimraf both fail, try the legacy recursive option
126
+ if (fs.rmdirSync && typeof fs.rmdirSync === 'function') {
127
+ try {
128
+ fs.rmdirSync(dirPath, { recursive: true })
129
+ } catch (legacyErr) {
130
+ console.warn(`Warning: Could not remove directory ${dirPath}: ${legacyErr.message}`)
131
+ }
132
+ } else {
133
+ console.warn(`Warning: Could not remove directory ${dirPath}: ${err.message}`)
134
+ }
135
+ }
136
+ }
137
+
138
+ // Download and extract function using axios + decompress
139
+ async function downloadAndExtract(url, destination) {
140
+ if (!fs.existsSync(destination)) {
141
+ fs.mkdirSync(destination, { recursive: true })
142
+ }
143
+ // Determine archive file name from URL
144
+ const urlPath = new URL(url).pathname
145
+ const fileName = path.basename(urlPath) || 'temp-archive'
146
+ const archivePath = path.join(destination, fileName)
147
+ log(` 📥 Starting download...`)
148
+ try {
149
+ // Download with progress tracking
150
+ const response = await axios({
151
+ method: 'GET',
152
+ url: url,
153
+ responseType: 'stream',
154
+ timeout: 300000, // 5 minutes timeout
155
+ onDownloadProgress: (progressEvent) => {
156
+ if (progressEvent.total) {
157
+ const progressBar = createProgressBar(progressEvent.total)
158
+ progressBar(progressEvent.loaded)
159
+ }
54
160
  }
55
161
  })
56
- if (!downloadUrl || downloadUrl.length === 0) {
57
- console.log(`[node-nim] Product [${product}] version ${version} not found, use latest version ${latestVersion}`)
58
- downloadUrl = latestDownloadUrl
162
+ // Save the downloaded file
163
+ const writeStream = fs.createWriteStream(archivePath)
164
+ response.data.pipe(writeStream)
165
+ // Wait for download to complete
166
+ await new Promise((resolve, reject) => {
167
+ writeStream.on('finish', resolve)
168
+ writeStream.on('error', reject)
169
+ response.data.on('error', reject)
170
+ })
171
+ log(` 📦 Extracting archive...`)
172
+ // Extract using decompress (auto-detects format)
173
+ await decompress(archivePath, destination, {
174
+ filter: (file) => {
175
+ // Filter out macOS hidden files (._files) and __MACOSX folders
176
+ const filePath = file.path
177
+ return !filePath.includes('._') &&
178
+ !filePath.includes('__MACOSX') &&
179
+ !filePath.startsWith('._')
180
+ },
181
+ // Remove the map function to preserve original directory structure
182
+ // This keeps the complete directory hierarchy from the archive
183
+ })
184
+ log(` ✅ Extraction complete`)
185
+ // Clean up the temporary archive file
186
+ fs.unlinkSync(archivePath)
187
+ } catch (error) {
188
+ // Clean up on error
189
+ if (fs.existsSync(archivePath)) {
190
+ fs.unlinkSync(archivePath)
59
191
  }
60
- console.log(`[node-nim] Downloading product: ${product}, platform: ${platform}, arch: ${arch}`)
192
+ throw error
61
193
  }
194
+ }
195
+ async function downloadSDK(customPackageUrl) {
196
+ // Use custom URL if provided, otherwise fetch from official server
197
+ let downloadUrl = customPackageUrl
62
198
  if (!downloadUrl) {
63
- console.error(`[node-nim] Downloading product: ${product}, platform: ${platform}, arch: ${arch} not found`)
64
- return
199
+ // Fetch package list from official server
200
+ const res = await axios.get('https://admin.netease.im/public-service/free/publish/list')
201
+ const publishData = res.data.data[channel]
202
+ // Find package URL for specified version or latest
203
+ downloadUrl = findPackageUrl(publishData, version, platform, arch, product)
204
+ if (!downloadUrl) {
205
+ log(` ❌ ERROR: Package not found for ${platform} (${arch})`)
206
+ return
207
+ }
208
+ log(` 🚀 Preparing to download package for ${platform} (${arch})`)
65
209
  }
66
- console.info(`[node-nim] Downloading prebuilt SDK from ${downloadUrl} to ${savePath}`)
67
210
  // remove temporary download folder and target folder
68
211
  const target = path.join(__dirname, '..', 'build', 'Release')
69
- if (fs.existsSync(savePath)) {
70
- fs.rmSync(savePath, { recursive: true })
71
- }
72
- if (fs.existsSync(target)) {
73
- fs.rmSync(target, { recursive: true })
74
- }
212
+ removeDirectory(savePath)
213
+ removeDirectory(target)
75
214
  // download sdk
76
215
  try {
77
- await download(downloadUrl, savePath, {
78
- extract: true,
79
- filter: (file) => {
80
- return !file.path.includes('._')
81
- }
82
- })
216
+ await downloadAndExtract(downloadUrl, savePath)
83
217
  // create build/Release folder
84
218
  if (!fs.existsSync(target)) {
85
219
  fs.mkdirSync(target, { recursive: true })
86
220
  }
87
- // move sdk/* files to build/Release
88
- const from = path.join(savePath, platform === 'win32' ? 'bin' : 'lib')
89
- const files = fs.readdirSync(from)
221
+ // Debug: List all extracted contents
222
+ log(` 🔍 Extracted contents in ${savePath}:`)
223
+ const extractedItems = fs.readdirSync(savePath)
224
+ extractedItems.forEach(item => {
225
+ const itemPath = path.join(savePath, item)
226
+ const isDir = fs.statSync(itemPath).isDirectory()
227
+ log(` ${isDir ? '📁' : '📄'} ${item}`)
228
+ })
229
+
230
+ // Find the package directory (should be the first directory that contains bin/lib)
231
+ const expectedSubDir = platform === 'win32' ? 'bin' : 'lib'
232
+ let packageDir = null
233
+ let libraryDir = null
234
+
235
+ // Look for the main package directory
236
+ for (const item of extractedItems) {
237
+ const itemPath = path.join(savePath, item)
238
+ if (fs.statSync(itemPath).isDirectory()) {
239
+ const subDirPath = path.join(itemPath, expectedSubDir)
240
+ if (fs.existsSync(subDirPath)) {
241
+ packageDir = itemPath
242
+ libraryDir = subDirPath
243
+ log(` ✅ Found package directory: ${item}`)
244
+ log(` ✅ Found library directory: ${item}/${expectedSubDir}`)
245
+ break
246
+ }
247
+ }
248
+ }
249
+
250
+ // Fallback: look for library files in any subdirectory
251
+ if (!libraryDir) {
252
+ log(` ⚠️ Standard package structure not found, searching for library files...`)
253
+
254
+ const searchForLibraryFiles = (searchPath, relativePath = '') => {
255
+ const items = fs.readdirSync(searchPath)
256
+ for (const item of items) {
257
+ const fullPath = path.join(searchPath, item)
258
+ const stat = fs.statSync(fullPath)
259
+
260
+ if (stat.isDirectory()) {
261
+ // Recursively search subdirectories
262
+ const found = searchForLibraryFiles(fullPath, path.join(relativePath, item))
263
+ if (found) return found
264
+ } else {
265
+ // Check if this directory contains library files
266
+ if (item.endsWith('.node')) {
267
+ return searchPath
268
+ }
269
+ }
270
+ }
271
+ return null
272
+ }
273
+
274
+ libraryDir = searchForLibraryFiles(savePath)
275
+ if (libraryDir) {
276
+ log(` ✅ Found library files in: ${path.relative(savePath, libraryDir)}`)
277
+ }
278
+ }
279
+
280
+ if (!libraryDir) {
281
+ throw new Error(`No library files found in extracted archive. Expected structure: packageDir/${expectedSubDir}/`)
282
+ }
283
+
284
+ // Install files from the found directory
285
+ const files = fs.readdirSync(libraryDir)
90
286
  files.forEach((file) => {
91
- console.info(`[node-nim] move ${file} to ${target}`)
92
- fs.renameSync(path.join(from, file), path.join(target, file))
287
+ const filePath = path.join(libraryDir, file)
288
+ if (fs.statSync(filePath).isFile()) {
289
+ log(` 📁 Installing ${file}`)
290
+ fs.renameSync(filePath, path.join(target, file))
291
+ }
93
292
  })
94
293
  // remove temporary download folder
95
- fs.rmSync(savePath, { recursive: true })
96
- console.info(`[node-nim] Downloading prebuilt SDK complete`)
294
+ removeDirectory(savePath)
295
+ log(` Package installation complete!`)
97
296
  } catch (err) {
98
- console.error(`[node-nim] Failed to download, error: ${err}`)
297
+ log(` ERROR: ${err.message}`)
298
+ throw err
299
+ }
300
+ }
301
+ // Helper function to find package download URL from publish data
302
+ function findPackageUrl(publishData, targetVersion, platform, arch, product) {
303
+ let latestVersion = '0.0.0'
304
+ let latestDownloadUrl = ''
305
+ let targetDownloadUrl = ''
306
+ // Check if package matches current platform/arch
307
+ const isMatchingPackage = (member) => {
308
+ const basicMatch = member.filename.includes(product) &&
309
+ member.filename.includes(platform) &&
310
+ member.filename.includes(arch)
311
+ // For win32 platform, also require 'multi-threaded' keyword
312
+ if (platform === 'win32') {
313
+ return basicMatch && member.filename.includes('multi-threaded')
314
+ }
315
+ return basicMatch
316
+ }
317
+ // Iterate through all versions
318
+ Object.keys(publishData).forEach((versionKey) => {
319
+ const versionSDKs = publishData[versionKey]
320
+ // Track latest version
321
+ if (compareVersions.compare(latestVersion, versionKey, '<')) {
322
+ const latestPackage = versionSDKs.find(isMatchingPackage)
323
+ if (latestPackage) {
324
+ latestVersion = versionKey
325
+ latestDownloadUrl = latestPackage.cdnlink
326
+ }
327
+ }
328
+ // Find target version
329
+ if (targetVersion === versionKey) {
330
+ const targetPackage = versionSDKs.find(isMatchingPackage)
331
+ if (targetPackage) {
332
+ targetDownloadUrl = targetPackage.cdnlink
333
+ }
334
+ }
335
+ })
336
+ // Use target version if found, otherwise fallback to latest
337
+ if (targetDownloadUrl) {
338
+ return targetDownloadUrl
339
+ }
340
+ if (latestDownloadUrl) {
341
+ log(` ⚠️ Version ${targetVersion} not found, using latest version ${latestVersion}`)
342
+ return latestDownloadUrl
343
+ }
344
+ return null
345
+ }
346
+
347
+ // Parse directory listing from HTTP server
348
+ async function parseDirectoryListing(url) {
349
+ try {
350
+ const response = await axios.get(url)
351
+ const html = response.data
352
+ // Extract directory/file names from href attributes
353
+ // Matches patterns like: href="dirname/" or href="filename.tar.gz"
354
+ const hrefRegex = /href="([^"]+)"/g
355
+ const items = []
356
+ let match
357
+ while ((match = hrefRegex.exec(html)) !== null) {
358
+ const item = match[1]
359
+ // Skip parent directory and absolute URLs
360
+ if (item !== '../' && !item.startsWith('http') && !item.startsWith('/')) {
361
+ items.push(item)
362
+ }
363
+ }
364
+ return items
365
+ } catch (error) {
366
+ throw new Error(`Failed to parse directory listing from ${url}: ${error.message}`)
367
+ }
368
+ }
369
+
370
+ // Find latest build number from directory listing
371
+ async function findLatestBuild(baseUrl, branch) {
372
+ const branchUrl = `${baseUrl}/${branch}/`
373
+ log(` 🔍 Searching for latest build in ${branchUrl}`)
374
+ const items = await parseDirectoryListing(branchUrl)
375
+ // Filter directories (end with /) and extract build numbers
376
+ const buildNumbers = items
377
+ .filter(item => item.endsWith('/'))
378
+ .map(item => parseInt(item.replace('/', '')))
379
+ .filter(num => !isNaN(num))
380
+ .sort((a, b) => b - a) // Sort in descending order
381
+
382
+ if (buildNumbers.length === 0) {
383
+ throw new Error(`No build directories found in ${branchUrl}`)
384
+ }
385
+ // Return all build numbers sorted by latest first
386
+ return buildNumbers
387
+ }
388
+
389
+ // Find latest build that contains the requested platform package
390
+ async function findLatestBuildWithPackage(baseUrl, branch, nodePlatform, nodeArch) {
391
+ const buildNumbers = await findLatestBuild(baseUrl, branch)
392
+
393
+ // Try builds from latest to oldest
394
+ for (const buildNumber of buildNumbers) {
395
+ try {
396
+ const buildUrl = `${baseUrl}/${branch}/${buildNumber}/`
397
+ log(` 🔍 Checking build ${buildNumber} for ${nodePlatform}-${nodeArch} package...`)
398
+
399
+ // Try to find package in this build
400
+ const packageUrl = await findPackage(buildUrl, nodePlatform, nodeArch)
401
+ log(` ✅ Found package in build ${buildNumber}`)
402
+ return { buildNumber, packageUrl }
403
+ } catch (error) {
404
+ log(` ⚠️ Build ${buildNumber} does not contain ${nodePlatform}-${nodeArch} package, trying previous build...`)
405
+ // Continue to next build
406
+ }
407
+ }
408
+
409
+ throw new Error(`No build found with ${nodePlatform}-${nodeArch} package for branch ${branch}`)
410
+ }
411
+
412
+ // Map Node.js platform/arch to SDK directory format
413
+ function getPlatformArchDir(nodePlatform, nodeArch) {
414
+ // Normalize arch - default to x64 if not arm64
415
+ const arch = nodeArch === 'arm64' ? 'arm64' : (nodeArch === 'ia32' ? 'ia32' : 'x64')
416
+ // For win32, include multi-threaded suffix
417
+ if (nodePlatform === 'win32') {
418
+ return `win32-${arch}-multi-threaded/`
419
+ }
420
+ // For other platforms (darwin, linux)
421
+ return `${nodePlatform}-${arch}/`
422
+ }
423
+
424
+ // Find package from directory listing
425
+ async function findPackage(buildUrl, nodePlatform, nodeArch) {
426
+ const platformArchDir = getPlatformArchDir(nodePlatform, nodeArch)
427
+ const fullUrl = `${buildUrl}${platformArchDir}`
428
+ log(` 🔍 Searching for package in ${fullUrl}`)
429
+ const items = await parseDirectoryListing(fullUrl)
430
+ // Filter tar.gz files and exclude symbol files
431
+ const packageFiles = items.filter(item => {
432
+ if (!item.endsWith('.tar.gz') && !item.endsWith('.zip')) {
433
+ return false
434
+ }
435
+ // Exclude symbol files based on platform
436
+ if (nodePlatform === 'darwin' && item.includes('-dSYM')) {
437
+ return false
438
+ }
439
+ if (nodePlatform === 'win32' && item.includes('-PDB')) {
440
+ return false
441
+ }
442
+ if (nodePlatform === 'linux' && item.includes('-with-symbol')) {
443
+ return false
444
+ }
445
+ // Must start with nim- prefix
446
+ return item.startsWith('nim-')
447
+ })
448
+ if (packageFiles.length === 0) {
449
+ throw new Error(`No package found in ${fullUrl}`)
99
450
  }
451
+ // If multiple files, prefer the first one (they should be the same package, just different compression)
452
+ const packageFile = packageFiles[0]
453
+ log(` ✅ Found package: ${packageFile}`)
454
+ return `${fullUrl}${packageFile}`
100
455
  }
456
+
457
+ // Build package URL from branch name
458
+ async function buildPackageUrlFromBranch(branch, nodePlatform, nodeArch) {
459
+ // Base64 encoded internal server URL (decode when needed)
460
+ const encodedBaseUrl = 'aHR0cDovLzEwLjIxOS4yNS4xMjc6ODgvSU0tTmF0aXZlL0Rlc2t0b3A='
461
+ const baseUrl = Buffer.from(encodedBaseUrl, 'base64').toString('utf-8')
462
+ log(` 🌿 Resolving package URL for branch: ${branch}`)
463
+
464
+ // Find latest build that contains the requested platform package
465
+ // This will automatically fallback to previous builds if the latest doesn't have the package
466
+ const { buildNumber, packageUrl } = await findLatestBuildWithPackage(baseUrl, branch, nodePlatform, nodeArch)
467
+
468
+ return packageUrl
469
+ }
470
+
101
471
  if (require.main === module) {
102
472
  const args = process.argv
103
- const downloadUrlIndex = args.indexOf('--nimSdkUrl');
104
- const url = downloadUrlIndex !== -1 ? args[downloadUrlIndex + 1] : '';
105
- downloadSDK(url)
473
+ const urlIndex = args.indexOf('--nimSdkUrl')
474
+ const branchIndex = args.indexOf('--branch')
475
+ ;(async () => {
476
+ try {
477
+ let url
478
+ let downloadUrl = process.env.npm_config_nimsdkurl
479
+ let branch = process.env.npm_config_branch
480
+
481
+ // 优先使用环境变量,然后才是命令行参数
482
+ if (branch || (branchIndex !== -1 && args[branchIndex + 1])) {
483
+ // Build URL from branch name
484
+ branch = branch || args[branchIndex + 1]
485
+ url = await buildPackageUrlFromBranch(branch, platform, process.arch)
486
+ } else if (downloadUrl || (urlIndex !== -1 && args[urlIndex + 1])) {
487
+ // Use provided URL directly
488
+ url = downloadUrl || args[urlIndex + 1]
489
+ // If URL is a directory path (ends with /), find the package
490
+ if (url.endsWith('/')) {
491
+ url = await findPackage(url, platform, arch)
492
+ }
493
+ }
494
+ // Pass undefined to downloadSDK when no custom URL is provided
495
+ // This allows it to fetch the latest package from admin.netease.im
496
+ await downloadSDK(url)
497
+ } catch (error) {
498
+ log(` ❌ ERROR: ${error.message}`)
499
+ process.exit(1)
500
+ }
501
+ })()
106
502
  }
107
503
  exports.downloadSDK = downloadSDK