@lazycatcloud/lzc-cli 1.2.28 → 1.2.30

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.
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs"
2
- import fetch from "node-fetch"
3
2
  import logger from "loglevel"
3
+ import { api } from "../utils.js"
4
4
 
5
5
  export async function triggerApk(id, name, iconPath) {
6
6
  if (!id) {
@@ -15,16 +15,11 @@ export async function triggerApk(id, name, iconPath) {
15
15
  if (iconPath) {
16
16
  form.append("app_icon", new Blob([fs.readFileSync(iconPath)]))
17
17
  }
18
- const resp = await fetch(
18
+ const resp = await api.post(
19
19
  "https://appstore.lazycat.cloud/api/trigger_latest_for_app",
20
- {
21
- method: "POST",
22
- body: form
23
- }
20
+ form
24
21
  )
25
22
  if (resp.status == 304) {
26
- // 没有修改
27
- logger.info(`APK构建任务已创建成功,如需使用安卓端,请耐心等待1分钟左右`)
28
23
  } else if (resp.status == 201) {
29
24
  logger.info(`APK构建任务已创建成功,如需使用安卓端,请耐心等待1分钟左右`)
30
25
  } else if (resp.status >= 400) {
package/lib/app/index.js CHANGED
@@ -2,7 +2,7 @@ import path from "node:path"
2
2
  import lpkCreate from "./lpk_create.js"
3
3
  import { LpkBuild } from "./lpk_build.js"
4
4
  import { AppDevShell } from "./lpk_devshell.js"
5
- import { LpkInstaller } from "./lpk_installer.js"
5
+ import { LpkInstaller, installConfig } from "./lpk_installer.js"
6
6
  import logger from "loglevel"
7
7
  import { sleep } from "../utils.js"
8
8
  import { DebugBridge } from "./lpk_debug_bridge.js"
@@ -14,8 +14,6 @@ export function lpkProjectCommand(program) {
14
14
  command: "create <name>",
15
15
  desc: "创建懒猫云应用",
16
16
  handler: async ({ name }) => {
17
- await shellApi.init()
18
-
19
17
  await lpkCreate(name)
20
18
  }
21
19
  },
@@ -68,10 +66,15 @@ export function lpkProjectCommand(program) {
68
66
  describe: "同时打包 lzc-build.yml 中指定的 contentdir 目录",
69
67
  type: "boolean"
70
68
  })
69
+ args.option("apk", {
70
+ describe: "是否生成APK(y/n)",
71
+ type: "string",
72
+ default: "y"
73
+ })
71
74
  },
72
- handler: async ({ context, force, config, contentdir }) => {
75
+ handler: async ({ context, force, config, contentdir, apk }) => {
73
76
  await shellApi.init()
74
-
77
+ installConfig.apk = apk == "y"
75
78
  const cwd = context ? path.resolve(context) : process.cwd()
76
79
  const lpkBuild = await new LpkBuild(cwd, config).init()
77
80
  lpkBuild.onBeforeBuildPackage(async (options) => {
@@ -107,8 +110,16 @@ export function lpkAppCommand(program) {
107
110
  {
108
111
  command: "install [pkgPath]",
109
112
  desc: "部署应用至设备, pkgPath 可以为路径,或者https://,http://请求地址, 如果不填写,将默认为当前目录下的lpk",
110
- handler: async ({ pkgPath }) => {
113
+ builder: (args) => {
114
+ args.option("apk", {
115
+ describe: "是否生成APK(y/n)",
116
+ type: "string",
117
+ default: "y"
118
+ })
119
+ },
120
+ handler: async ({ pkgPath, apk }) => {
111
121
  await shellApi.init()
122
+ installConfig.apk = apk == "y"
112
123
 
113
124
  pkgPath = pkgPath ?? process.cwd()
114
125
  const installer = new LpkInstaller()
@@ -144,6 +144,8 @@ export const TemplateConfig = {
144
144
  ⚙️ 进入应用容器后执行下面命令:
145
145
  npm install
146
146
  npm run dev
147
+ 🚀 启动应用:
148
+ 进入微服客户端启动器页面点击应用图标来测试应用
147
149
  `.trim()
148
150
  )
149
151
  )
@@ -2,7 +2,8 @@ import { spawn, spawnSync } from "child_process"
2
2
  import fs from "node:fs"
3
3
  import shellApi from "../shellapi.js"
4
4
  import inquirer from "inquirer"
5
- import { isDebugMode, resolveDomain } from "../utils.js"
5
+ import { isDebugMode, resolveDomain, sleep } from "../utils.js"
6
+ import logger from "loglevel"
6
7
 
7
8
  export class DebugBridge {
8
9
  constructor() {
@@ -18,7 +19,7 @@ export class DebugBridge {
18
19
  const ssh = spawnSync(sshCmd, args, {
19
20
  shell: true,
20
21
  encoding: "utf-8",
21
- stdio: ["pipe", "pipe", "inherit"]
22
+ stdio: ["pipe", "pipe", "pipe"]
22
23
  })
23
24
  return new Promise((resolve, reject) => {
24
25
  ssh.status == 0
@@ -31,6 +32,7 @@ export class DebugBridge {
31
32
 
32
33
  async install(lpkPath, pkgId) {
33
34
  if (!(await this.canPublicKey())) {
35
+ // 如果不能 ssh public key 登录则直接调用 ssh-copy-id 复制,否则后面可能会出现 rsync 询问密码的问题
34
36
  await this.sshCopyId()
35
37
  }
36
38
 
@@ -53,29 +55,13 @@ export class DebugBridge {
53
55
  }
54
56
 
55
57
  async canPublicKey() {
56
- try {
57
- await this.common(this.sshCmd, [`-o PasswordAuthentication=no`])
58
- return true
59
- } catch {
60
- return false
61
- }
58
+ // FIXME: 目前没有找到在允许空密码的情况下,检测是否只能通过 publickey 登录的方法。
59
+ return false
62
60
  }
63
61
 
64
62
  async sshCopyId() {
65
- const questions = [
66
- {
67
- name: "upload",
68
- type: "input",
69
- default: "y",
70
- message:
71
- "检测到你目前使用的密码帐号登录,是否使用 ssh-copy-id 上传密钥 (y/n): "
72
- }
73
- ]
74
- const answers = await inquirer.prompt(questions)
75
- if (answers.upload.toLowerCase() == "y") {
76
- const resolvedIp = await resolveDomain(this.domain)
77
- return this.common(`ssh-copy-id`, [`-f -p 22222 box@${resolvedIp}`])
78
- }
63
+ const resolvedIp = await resolveDomain(this.domain)
64
+ return this.common(`ssh-copy-id`, [`-f -p 22222 box@${resolvedIp}`])
79
65
  }
80
66
 
81
67
  async status(appId) {
@@ -100,6 +86,16 @@ export class DebugBridge {
100
86
 
101
87
  async devshell(appId, isUserApp, onconnect = null) {
102
88
  const resolvedIp = await resolveDomain(this.domain)
89
+ let waiting = true
90
+ while (waiting) {
91
+ if (await this.isDevshell(appId)) {
92
+ waiting = false
93
+ break
94
+ }
95
+ logger.debug("wait app container to running...")
96
+ await sleep(100)
97
+ }
98
+
103
99
  const stream = spawn(
104
100
  `ssh -p 22222 box@${resolvedIp}`,
105
101
  [
@@ -119,9 +115,9 @@ export class DebugBridge {
119
115
  stream.on("close", (code) => {
120
116
  code == 0 ? resolve() : reject()
121
117
  })
122
- if (onconnect) {
123
- stream.on("spawn", onconnect)
124
- }
118
+ // spawn 事件只是进程启动成功的事件,并不是ssh成功连接上的事件。所以这里使
119
+ // 用前面的一个 isDevshell 判断是否已经启动这个容器,再使用 spawn
120
+ stream.on("spawn", onconnect)
125
121
  })
126
122
  }
127
123
 
@@ -18,7 +18,8 @@ import {
18
18
  isUserApp,
19
19
  createTemplateFileCommon,
20
20
  isDebugMode,
21
- resolveDomain
21
+ resolveDomain,
22
+ sleep
22
23
  } from "../utils.js"
23
24
  import os from "node:os"
24
25
  import commandExists from "command-exists"
@@ -7,6 +7,7 @@ import { DebugBridge } from "./lpk_debug_bridge.js"
7
7
  import shellapi from "../shellapi.js"
8
8
  import { triggerApk } from "./apkshell.js"
9
9
 
10
+ export const installConfig = { apk: true }
10
11
  // 从一个目录中找出修改时间最新的包
11
12
  function findOnceLpkByDir(dir = process.cwd()) {
12
13
  const pkg = fs
@@ -95,11 +96,14 @@ export class LpkInstaller {
95
96
  try {
96
97
  spawnSync("unzip", ["-d", tempDir, pkgPath])
97
98
  manifest = loadFromYaml(path.join(tempDir, "manifest.yml"))
98
- await triggerApk(
99
- manifest["package"],
100
- manifest["name"],
101
- path.resolve(path.join(tempDir, "icon.png"))
102
- )
99
+ logger.debug("是否生成APK:", installConfig.apk)
100
+ if (installConfig.apk) {
101
+ await triggerApk(
102
+ manifest["package"],
103
+ manifest["name"],
104
+ path.resolve(path.join(tempDir, "icon.png"))
105
+ )
106
+ }
103
107
  logger.debug("lpk manifest", manifest)
104
108
  } finally {
105
109
  fs.rmSync(tempDir, { recursive: true })
@@ -113,5 +117,6 @@ export class LpkInstaller {
113
117
  logger.info(
114
118
  `👉 请在浏览器中访问 https://${manifest["application"]["subdomain"]}.${shellapi.boxname}.heiyu.space`
115
119
  )
120
+ logger.info(`👉 并使用微服的用户名和密码登录`)
116
121
  }
117
122
  }
@@ -3,7 +3,6 @@ import path from "path"
3
3
  import logger from "loglevel"
4
4
  import env from "../env.js"
5
5
  import inquirer from "inquirer"
6
- import FormData from "form-data"
7
6
 
8
7
  const accountServerUrl = "https://account.lazycat.cloud"
9
8
 
@@ -12,17 +11,13 @@ function join(...params) {
12
11
  return x
13
12
  }
14
13
 
15
- function login(username, password) {
16
- const form = new FormData()
17
- form.append("username", username)
18
- form.append("password", password)
19
-
14
+ async function login(username, password) {
20
15
  return fetch(join(accountServerUrl, "/api/login/signin"), {
21
16
  method: "POST",
22
- headers: {
23
- "content-type": `multipart/form-data; boundary=${form.getBoundary()}`
24
- },
25
- body: form
17
+ body: new URLSearchParams({
18
+ username: username,
19
+ password: password
20
+ })
26
21
  })
27
22
  .then(async (res) => {
28
23
  let bodyText = await res.text()
package/lib/shellapi.js CHANGED
@@ -32,6 +32,11 @@ class ShellApi {
32
32
  const { addr, cred } = this.readShellApiInfo()
33
33
  this.client = new pbShell.ShellCore(addr, grpc.credentials.createInsecure())
34
34
 
35
+ // 检查当前 shell 环境上下文是否配置 HTTP_PROXY
36
+ if (this.checkEnvProxy()) {
37
+ logger.warn(`WARN:: 当前终端环境已配置 HTTP_PROXY 代理,可能会导致访问懒猫微服失败,如果未影响功能可以忽略该警告`)
38
+ }
39
+
35
40
  const md = new grpc.Metadata()
36
41
  md.add("lzc-shellapi-cred", cred)
37
42
  this.metadata = md
@@ -115,6 +120,19 @@ class ShellApi {
115
120
  })
116
121
  }
117
122
 
123
+ checkEnvProxy() {
124
+ if(process.env.HTTPS_PROXY ||
125
+ process.env.HTTP_PROXY ||
126
+ process.env.ALL_PROXY ||
127
+ process.env.https_proxy ||
128
+ process.env.http_proxy ||
129
+ process.env.all_proxy
130
+ ){
131
+ return true
132
+ }
133
+ return false
134
+ }
135
+
118
136
  async setDefaultBox(boxname) {
119
137
  const boxes = await this.boxList()
120
138
  const box = boxes.find((b) => b.box_name === boxname)
package/lib/utils.js CHANGED
@@ -16,6 +16,21 @@ import { spawnSync } from "node:child_process"
16
16
  import logger from "loglevel"
17
17
  import * as tar from "tar"
18
18
  import dns from "node:dns/promises"
19
+ import axios from "axios"
20
+
21
+ // 创建 Axios 实例
22
+ export const api = axios.create()
23
+
24
+ // 添加响应拦截器
25
+ api.interceptors.response.use(
26
+ (response) => response, // 直接返回响应
27
+ (error) => {
28
+ if (error.response && error.response.status === 304) {
29
+ return Promise.resolve(error.response) // 返回响应以便后续处理
30
+ }
31
+ return Promise.reject(error) // 其他错误继续抛出
32
+ }
33
+ )
19
34
 
20
35
  export const envsubstr = async (templateContents, args) => {
21
36
  const parse = await importDefault("envsub/js/envsub-parser.js")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazycatcloud/lzc-cli",
3
- "version": "1.2.28",
3
+ "version": "1.2.30",
4
4
  "description": "lazycat cloud developer kit",
5
5
  "files": [
6
6
  "template",
@@ -21,6 +21,7 @@
21
21
  "@grpc/grpc-js": "^1.11.1",
22
22
  "@grpc/proto-loader": "^0.7.13",
23
23
  "archiver": "^7.0.1",
24
+ "axios": "^1.7.7",
24
25
  "chalk": "^5.3.0",
25
26
  "chokidar": "^3.6.0",
26
27
  "command-exists": "^1.2.9",