@lazycatcloud/lzc-cli 1.2.55 → 1.2.57

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/changelog.md CHANGED
@@ -1,3 +1,14 @@
1
+ # 1.2.57
2
+
3
+ 1. 支持独立添加公钥到开发者工具中去 `lzc-cli box add-public-key`
4
+ 2. 支持选择使用公钥类型,不再优先使用 id_ed25519
5
+ 3. 添加 nodejs 版本检测, 要求最低版本 >=18
6
+ 4. 添加 dns 解析错误提示
7
+
8
+ # 1.2.56
9
+
10
+ 1. 修复没有写权限的lpk文件,不能通过 lzc-cli app install 安装
11
+
1
12
  # 1.2.55
2
13
 
3
14
  1. 添加 lzc-docker 命令
@@ -1,6 +1,20 @@
1
1
  import fs from "node:fs"
2
2
  import logger from "loglevel"
3
- import { api } from "../utils.js"
3
+ import axios from "axios"
4
+
5
+ // 创建 Axios 实例
6
+ const api = axios.create()
7
+
8
+ // 添加响应拦截器
9
+ api.interceptors.response.use(
10
+ (response) => response, // 直接返回响应
11
+ (error) => {
12
+ if (error.response && error.response.status === 304) {
13
+ return Promise.resolve(error.response) // 返回响应以便后续处理
14
+ }
15
+ return Promise.reject(error) // 其他错误继续抛出
16
+ }
17
+ )
4
18
 
5
19
  export async function triggerApk(id, name, iconPath) {
6
20
  if (!id) {
@@ -293,8 +293,17 @@ export class LpkBuild {
293
293
  return await curr(await prev, this.options)
294
294
  }, manifest)
295
295
  }
296
- logger.debug("manifest\n", manifest)
297
- dumpToYaml(manifest, path.join(tempDir, "manifest.yml"))
296
+
297
+ if (process.env.LZC_MANIFEST_TEMPLATE) {
298
+ logger.debug("copy origin manifest\n", this.manifestFilePath)
299
+ fs.copyFileSync(
300
+ this.manifestFilePath,
301
+ path.join(tempDir, "manifest.yml")
302
+ )
303
+ } else {
304
+ logger.debug("manifest\n", manifest)
305
+ dumpToYaml(manifest, path.join(tempDir, "manifest.yml"))
306
+ }
298
307
 
299
308
  // 打包 lpk
300
309
  if (this.beforeDumpLpkFn.length > 0) {
package/lib/box/index.js CHANGED
@@ -1,4 +1,6 @@
1
+ import logger from "loglevel"
1
2
  import shellapi from "../shellapi.js"
3
+ import { findSshPublicKey, selectSshPublicKey } from "../utils.js"
2
4
 
3
5
  export function boxCommand(box) {
4
6
  let subCommands = [
@@ -51,6 +53,22 @@ export function boxCommand(box) {
51
53
  })
52
54
  console.table(list)
53
55
  }
56
+ },
57
+ {
58
+ command: "add-public-key",
59
+ desc: "添加public-key到开发者工具中",
60
+ handler: async () => {
61
+ await shellapi.init()
62
+ const keys = await findSshPublicKey()
63
+ const sshInfo = await selectSshPublicKey(keys)
64
+ logger.debug("ssh public key info", sshInfo)
65
+ const pk = Buffer.from(sshInfo.content.trimLeft()).toString("base64")
66
+ logger.warn(
67
+ `请点击下面的连接,或者复制到浏览器中打开,点击申请完成添加
68
+ -> https://dev.${shellapi.boxname}.heiyu.space/auth?key=${pk}
69
+ `
70
+ )
71
+ }
54
72
  }
55
73
  ]
56
74
  box.command({
@@ -7,6 +7,7 @@ import {
7
7
  resolveDomain,
8
8
  sleep,
9
9
  findSshPublicKey,
10
+ selectSshPublicKey,
10
11
  isWindows,
11
12
  contextDirname,
12
13
  compareVersions
@@ -91,13 +92,18 @@ export class DebugBridge {
91
92
  try {
92
93
  await this.common(sshBinary(), [...sshCmdArgs(`box@${this.domain}`)])
93
94
  return true
94
- } catch {
95
+ } catch (err) {
96
+ logger.debug("canPublicKey error: ", err)
95
97
  return false
96
98
  }
97
99
  }
98
100
 
99
101
  async sshApplyGrant() {
100
- const sshInfo = await findSshPublicKey()
102
+ const keys = await findSshPublicKey()
103
+ logger.info(
104
+ "检测到您当前的环境还没有添加 ssh 公钥到 ‘懒猫开发者工具’ 中,请选择您需要添加的公钥类型"
105
+ )
106
+ const sshInfo = await selectSshPublicKey(keys)
101
107
  logger.debug("ssh public key info", sshInfo)
102
108
 
103
109
  const pk = Buffer.from(sshInfo.content.trimLeft()).toString("base64")
package/lib/utils.js CHANGED
@@ -15,11 +15,12 @@ import process from "node:process"
15
15
  import spawn from "cross-spawn"
16
16
  import logger from "loglevel"
17
17
  import * as tar from "tar"
18
- import dns from "node:dns/promises"
19
- import axios from "axios"
18
+ import dns from "node:dns"
20
19
  import AdmZip from "adm-zip"
21
20
  import commandExists from "command-exists"
22
21
  import fetch from "node-fetch"
22
+ import semver from "semver"
23
+ import inquirer from "inquirer"
23
24
 
24
25
  // lzc-cli 包的 pkgInfo 信息
25
26
  export const pkgInfo = JSON.parse(
@@ -28,6 +29,24 @@ export const pkgInfo = JSON.parse(
28
29
  )
29
30
  )
30
31
 
32
+ export function checkNodejsVersion() {
33
+ const requiredVersion = pkgInfo.engines.node
34
+ if (!semver.satisfies(process.version, requiredVersion)) {
35
+ logger.error(
36
+ `检测到您当前的 nodejs 版本 ${process.version} 不匹配,lzc-cli 最低要求 nodejs 版本为 ${requiredVersion}, 请升级`
37
+ )
38
+ process.exit(1)
39
+ }
40
+
41
+ // 如果版本小于 21.0.0 且大于等于 16.15.0,禁用 Fetch API 实验性警告
42
+ if (
43
+ semver.lt(process.version, "21.0.0") &&
44
+ semver.gte(process.version, "16.15.0")
45
+ ) {
46
+ process.removeAllListeners("warning")
47
+ }
48
+ }
49
+
31
50
  export async function getLatestVersion(controller, pkgName = pkgInfo.name) {
32
51
  const url = `https://data.jsdelivr.com/v1/package/npm/${pkgName}`
33
52
  try {
@@ -49,20 +68,6 @@ export async function getLatestVersion(controller, pkgName = pkgInfo.name) {
49
68
  }
50
69
  }
51
70
 
52
- // 创建 Axios 实例
53
- export const api = axios.create()
54
-
55
- // 添加响应拦截器
56
- api.interceptors.response.use(
57
- (response) => response, // 直接返回响应
58
- (error) => {
59
- if (error.response && error.response.status === 304) {
60
- return Promise.resolve(error.response) // 返回响应以便后续处理
61
- }
62
- return Promise.reject(error) // 其他错误继续抛出
63
- }
64
- )
65
-
66
71
  export const isMacOs = process.platform == "darwin"
67
72
  export const isLinux = process.platform == "linux"
68
73
  export const isWindows = process.platform == "win32"
@@ -282,12 +287,10 @@ export function isDirExist(path) {
282
287
 
283
288
  export function isFileExist(path) {
284
289
  try {
285
- fs.accessSync(
286
- path,
287
- fs.constants.W_OK | fs.constants.R_OK | fs.constants.F_OK
288
- )
290
+ fs.accessSync(path, fs.constants.R_OK | fs.constants.F_OK)
289
291
  return true
290
- } catch {
292
+ } catch (err) {
293
+ logger.debug(`access ${path} error: ${err}`)
291
294
  return false
292
295
  }
293
296
  }
@@ -458,31 +461,45 @@ export function isTraceMode() {
458
461
  return logger.getLevel() <= logger.levels.TRACE
459
462
  }
460
463
 
464
+ // 没有直接使用 dns/promise,因为这个 dns/promise 是在 15.0.0 后加入,如果低版本
465
+ // 会直接报错,连版本检测都到不了(包导入的太前面了)
466
+ async function __resolveDomain(domain, ipv6 = false) {
467
+ return new Promise((resolve, reject) => {
468
+ const callback = function (err, addresses) {
469
+ if (addresses && addresses.length > 0) {
470
+ resolve(addresses[0])
471
+ } else {
472
+ logger.trace("dns resolve error: ", err)
473
+ reject(err)
474
+ }
475
+ }
476
+ if (ipv6) {
477
+ dns.resolve6(domain, callback)
478
+ } else {
479
+ dns.resolve4(domain, callback)
480
+ }
481
+ })
482
+ }
483
+
461
484
  export async function resolveDomain(domain) {
462
485
  try {
463
486
  // Set machine's dns server as defalut dns server
464
487
  dns.setServers(["[fc03:1136:3800::1]"])
488
+
465
489
  const [ipv6Addresses, ipv4Addresses] = await Promise.allSettled([
466
- dns.resolve6(domain),
467
- dns.resolve4(domain)
490
+ __resolveDomain(domain, true),
491
+ __resolveDomain(domain, false)
468
492
  ])
469
- let resolvedAddress
470
- if (
471
- ipv6Addresses.status === "fulfilled" &&
472
- ipv6Addresses.value.length > 0
473
- ) {
474
- resolvedAddress = ipv6Addresses.value[0]
475
- } else if (
476
- ipv4Addresses.status === "fulfilled" &&
477
- ipv4Addresses.value.length > 0
478
- ) {
479
- resolvedAddress = ipv4Addresses.value[0]
493
+ if (ipv6Addresses.status == "fulfilled") {
494
+ return ipv6Addresses.value
495
+ } else if (ipv4Addresses.status != "fulfilled") {
496
+ return ipv4Addresses.value
480
497
  } else {
481
- throw new Error(`无法解析域名 ${domain}`)
498
+ throw `无法解析域名 ${domain}`
482
499
  }
483
- return resolvedAddress
484
500
  } catch (error) {
485
- throw new Error(`无法解析域名 ${domain}: ${error.message}`)
501
+ logger.error("resolve domain: ", error)
502
+ throw `无法解析域名 ${domain}: ${error}`
486
503
  }
487
504
  }
488
505
 
@@ -510,6 +527,24 @@ export function unzipSync(zipPath, destPath, entries = []) {
510
527
  }
511
528
  }
512
529
 
530
+ export async function selectSshPublicKey(avaiableKeys) {
531
+ const keyNames = avaiableKeys.map((k) => k.path)
532
+ const selected = (
533
+ await inquirer.prompt([
534
+ {
535
+ name: "type",
536
+ message: "选择使用的公钥",
537
+ type: "list",
538
+ choices: keyNames
539
+ }
540
+ ])
541
+ )["type"]
542
+ return {
543
+ path: selected,
544
+ content: fs.readFileSync(selected, "utf8")
545
+ }
546
+ }
547
+
513
548
  export function findSshPublicKey() {
514
549
  // 获取用户 HOME 目录
515
550
  let homeDir
@@ -554,6 +589,7 @@ export function findSshPublicKey() {
554
589
  "id_dsa.pub"
555
590
  ]
556
591
 
592
+ let avaiableKeys = []
557
593
  try {
558
594
  // 获取 .ssh 目录下所有文件
559
595
  const files = fs.readdirSync(sshDir)
@@ -565,10 +601,10 @@ export function findSshPublicKey() {
565
601
  // 验证文件是否可读
566
602
  try {
567
603
  fs.accessSync(keyPath, fs.constants.R_OK)
568
- return {
569
- path: keyPath,
570
- content: fs.readFileSync(keyPath, "utf8")
571
- }
604
+ avaiableKeys.push({
605
+ keyName,
606
+ path: keyPath
607
+ })
572
608
  } catch (error) {
573
609
  console.warn(`Found ${keyName} but cannot read it:`, error.message)
574
610
  continue
@@ -576,23 +612,13 @@ export function findSshPublicKey() {
576
612
  }
577
613
  }
578
614
 
579
- // 如果没找到优先级列表中的公钥,查找任何 .pub 结尾的文件
580
- const pubKey = files.find((file) => file.endsWith(".pub"))
581
- if (pubKey) {
582
- const keyPath = path.join(sshDir, pubKey)
583
- try {
584
- fs.accessSync(keyPath, fs.constants.R_OK)
585
- return {
586
- path: keyPath,
587
- content: fs.readFileSync(keyPath, "utf8")
588
- }
589
- } catch (error) {
590
- throw new Error(`Found ${pubKey} but cannot read it: ${error.message}`)
591
- }
615
+ if (avaiableKeys.length == 0) {
616
+ throw new Error(
617
+ ".ssh 目录没有没有找到任何 .pub 公钥. 请使用 ssh-keygen 生成"
618
+ )
619
+ } else {
620
+ return avaiableKeys
592
621
  }
593
- throw new Error(
594
- ".ssh 目录没有没有找到任何 .pub 公钥. 请使用 ssh-keygen 生成"
595
- )
596
622
  } catch (error) {
597
623
  if (error.code === "ENOENT") {
598
624
  throw new Error("不能查询 .ssh 目录")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazycatcloud/lzc-cli",
3
- "version": "1.2.55",
3
+ "version": "1.2.57",
4
4
  "description": "lazycat cloud developer kit",
5
5
  "scripts": {
6
6
  "prepublishOnly": "node check-changelog.js"
@@ -11,6 +11,9 @@
11
11
  "lib",
12
12
  "changelog.md"
13
13
  ],
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
14
17
  "bin": {
15
18
  "lzc-cli": "scripts/cli.js",
16
19
  "lzc-docker": "scripts/lzc-docker.js",
@@ -47,6 +50,7 @@
47
50
  "lodash.mergewith": "^4.6.2",
48
51
  "loglevel": "^1.9.1",
49
52
  "node-fetch": "^3.3.2",
53
+ "semver": "^7.6.3",
50
54
  "tar": "^7.4.3",
51
55
  "yargs": "^17.7.2"
52
56
  },
package/scripts/cli.js CHANGED
@@ -7,7 +7,12 @@ import yargs from "yargs"
7
7
  import { hideBin } from "yargs/helpers"
8
8
  import "../lib/log.js" // init logger
9
9
 
10
- import { contextDirname, pkgInfo, getLatestVersion } from "../lib/utils.js"
10
+ import {
11
+ contextDirname,
12
+ pkgInfo,
13
+ getLatestVersion,
14
+ checkNodejsVersion
15
+ } from "../lib/utils.js"
11
16
  import { boxCommand } from "../lib/box/index.js"
12
17
  import { appstoreCommand } from "../lib/appstore/index.js"
13
18
  import { lpkAppCommand, lpkProjectCommand } from "../lib/app/index.js"
@@ -56,8 +61,9 @@ lzcDockerCommand(program)
56
61
 
57
62
  // 当没有参数的时候,默认显示帮助。
58
63
  ;(async () => {
59
- const controller = new AbortController()
64
+ checkNodejsVersion()
60
65
 
66
+ const controller = new AbortController()
61
67
  const parser = program
62
68
  .strict()
63
69
  .showHelpOnFail(false, "使用 lzc-cli help 查看更多帮助")