@kdcloudjs/cli 0.0.1 → 0.0.2
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/README.MD +41 -0
- package/package.json +1 -1
- package/src/actions/debug/index.js +102 -0
- package/src/actions/debug/runner.js +38 -0
- package/src/actions/debug/utils.js +84 -0
- package/src/commands/debug.js +9 -0
- package/src/commands/env/index.js +2 -10
- package/src/index.js +1 -0
- package/src/actions/env/remote.js +0 -59
- package/src/commands/env/remote.js +0 -2
package/README.MD
CHANGED
|
@@ -19,4 +19,45 @@ kd project create kwcdemo --type kwc
|
|
|
19
19
|
#### 创建页面元数据
|
|
20
20
|
```
|
|
21
21
|
kd project create kwcdemo --type page
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
#### 环境配置
|
|
25
|
+
```
|
|
26
|
+
创建环境
|
|
27
|
+
kd env create dev --url https://dev.com
|
|
28
|
+
|
|
29
|
+
设置目标环境
|
|
30
|
+
kd env set target-env dev
|
|
31
|
+
|
|
32
|
+
当前环境信息
|
|
33
|
+
kd env info
|
|
34
|
+
|
|
35
|
+
环境列表
|
|
36
|
+
kd env list
|
|
37
|
+
|
|
38
|
+
删除环境
|
|
39
|
+
kd env delete dev
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
#### 认证授权
|
|
44
|
+
```
|
|
45
|
+
openapi认证
|
|
46
|
+
kd env auth openapi -e dev
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
#### 上传
|
|
51
|
+
```
|
|
52
|
+
kd project deploy
|
|
53
|
+
kd project deploy -e dev
|
|
54
|
+
kd project deploy -e dev -d app/kwc
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 调试
|
|
59
|
+
```
|
|
60
|
+
kd debug
|
|
61
|
+
kd debug -e dev
|
|
62
|
+
|
|
22
63
|
```
|
package/package.json
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const { findProjectRoot } = require('../project/deploy/projectRoot')
|
|
4
|
+
const { getEnvByName, loadDefaultEnv } = require('../env/config')
|
|
5
|
+
const { error, info } = require('../../utils/log')
|
|
6
|
+
const { safePrompts } = require('../../utils/prompts')
|
|
7
|
+
const { openBrowser, waitForPort, walk, getFormId } = require('./utils')
|
|
8
|
+
const { installDeps, runDebug } = require('./runner')
|
|
9
|
+
|
|
10
|
+
module.exports = async function debug(options = {}) {
|
|
11
|
+
const cwd = process.cwd()
|
|
12
|
+
const root = findProjectRoot(cwd)
|
|
13
|
+
|
|
14
|
+
if (!root) {
|
|
15
|
+
error('Current directory is not a KWC project')
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 1. Check and install dependencies
|
|
20
|
+
if (!fs.existsSync(path.join(root, 'node_modules'))) {
|
|
21
|
+
try {
|
|
22
|
+
await installDeps(root)
|
|
23
|
+
} catch (e) {
|
|
24
|
+
error(e.message)
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 2. Resolve Environment
|
|
30
|
+
let env
|
|
31
|
+
const envName = options.targetEnv
|
|
32
|
+
if (envName) {
|
|
33
|
+
env = getEnvByName(envName)
|
|
34
|
+
if (!env) {
|
|
35
|
+
error(`Environment "${envName}" not found`)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
env = loadDefaultEnv()
|
|
40
|
+
if (!env || !env.name) {
|
|
41
|
+
error('No environment specified and no default environment found')
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
info(`Using default environment: ${env.name}`)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!env.url) {
|
|
48
|
+
error(`Environment "${env.name}" has no URL configured`)
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 3. Get Form IDs
|
|
53
|
+
const pagesDir = path.join(root, 'app/pages')
|
|
54
|
+
const pageFiles = walk(pagesDir)
|
|
55
|
+
const forms = []
|
|
56
|
+
|
|
57
|
+
for (const file of pageFiles) {
|
|
58
|
+
const id = getFormId(file)
|
|
59
|
+
if (id) {
|
|
60
|
+
forms.push({
|
|
61
|
+
title: id,
|
|
62
|
+
value: id
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (forms.length === 0) {
|
|
68
|
+
error('No pages found in app/pages')
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 4. Select Form
|
|
73
|
+
const response = await safePrompts({
|
|
74
|
+
type: 'select',
|
|
75
|
+
name: 'formId',
|
|
76
|
+
message: 'Select a form to debug',
|
|
77
|
+
choices: forms
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
if (!response.formId) return
|
|
81
|
+
|
|
82
|
+
// 5. Construct URL
|
|
83
|
+
const targetUrl = new URL(env.url)
|
|
84
|
+
targetUrl.searchParams.append('formId', response.formId)
|
|
85
|
+
targetUrl.searchParams.append('kdkwc_cdn', 'http://localhost:3333')
|
|
86
|
+
const finalUrl = targetUrl.toString()
|
|
87
|
+
|
|
88
|
+
// 6. Open Browser & Start Debug
|
|
89
|
+
// Start server first
|
|
90
|
+
const { promise: serverPromise, child } = runDebug(root)
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
info('Waiting for debug server to be ready...')
|
|
94
|
+
await waitForPort(3333, child)
|
|
95
|
+
info(`Opening: ${finalUrl}`)
|
|
96
|
+
openBrowser(finalUrl)
|
|
97
|
+
} catch (e) {
|
|
98
|
+
error(`Server start failed: ${e.message}`)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
await serverPromise
|
|
102
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const { spawn } = require('child_process')
|
|
2
|
+
const { info } = require('../../utils/log')
|
|
3
|
+
|
|
4
|
+
function installDeps(root) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
info('Installing dependencies...')
|
|
7
|
+
const child = spawn('npm', ['install'], {
|
|
8
|
+
cwd: root,
|
|
9
|
+
stdio: 'inherit',
|
|
10
|
+
shell: true
|
|
11
|
+
})
|
|
12
|
+
child.on('close', (code) => {
|
|
13
|
+
if (code === 0) resolve()
|
|
14
|
+
else reject(new Error(`npm install failed with code ${code}`))
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function runDebug(root) {
|
|
20
|
+
info('Starting debug server...')
|
|
21
|
+
let childProcess
|
|
22
|
+
const promise = new Promise((resolve, reject) => {
|
|
23
|
+
const child = spawn('npm', ['run', 'debug'], {
|
|
24
|
+
cwd: root,
|
|
25
|
+
stdio: 'inherit',
|
|
26
|
+
shell: true
|
|
27
|
+
})
|
|
28
|
+
childProcess = child
|
|
29
|
+
child.on('close', resolve)
|
|
30
|
+
child.on('error', reject)
|
|
31
|
+
})
|
|
32
|
+
return { promise, child: childProcess }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
installDeps,
|
|
37
|
+
runDebug
|
|
38
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const net = require('net')
|
|
4
|
+
const { exec } = require('child_process')
|
|
5
|
+
|
|
6
|
+
function openBrowser(url) {
|
|
7
|
+
let cmd
|
|
8
|
+
if (process.platform === 'win32') {
|
|
9
|
+
cmd = `start "" "${url}"`
|
|
10
|
+
} else if (process.platform === 'darwin') {
|
|
11
|
+
cmd = `open "${url}"`
|
|
12
|
+
} else {
|
|
13
|
+
cmd = `xdg-open "${url}"`
|
|
14
|
+
}
|
|
15
|
+
exec(cmd)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function checkPort(port) {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const socket = new net.Socket()
|
|
21
|
+
socket.setTimeout(200)
|
|
22
|
+
socket.on('connect', () => {
|
|
23
|
+
socket.destroy()
|
|
24
|
+
resolve(true)
|
|
25
|
+
})
|
|
26
|
+
socket.on('timeout', () => {
|
|
27
|
+
socket.destroy()
|
|
28
|
+
reject(new Error('timeout'))
|
|
29
|
+
})
|
|
30
|
+
socket.on('error', (err) => {
|
|
31
|
+
socket.destroy()
|
|
32
|
+
reject(err)
|
|
33
|
+
})
|
|
34
|
+
socket.connect(port, '127.0.0.1')
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function waitForPort(port, child, retries = 60) {
|
|
39
|
+
for (let i = 0; i < retries; i++) {
|
|
40
|
+
if (child.exitCode !== null) {
|
|
41
|
+
throw new Error(`Server process exited with code ${child.exitCode}`)
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
await checkPort(port)
|
|
45
|
+
return true
|
|
46
|
+
} catch (e) {
|
|
47
|
+
await new Promise(r => setTimeout(r, 1000))
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`Timeout waiting for port ${port}`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function walk(dir, files = []) {
|
|
54
|
+
if (!fs.existsSync(dir)) return files
|
|
55
|
+
|
|
56
|
+
const items = fs.readdirSync(dir)
|
|
57
|
+
for (const item of items) {
|
|
58
|
+
const fullPath = path.join(dir, item)
|
|
59
|
+
const stat = fs.statSync(fullPath)
|
|
60
|
+
if (stat.isDirectory()) {
|
|
61
|
+
walk(fullPath, files)
|
|
62
|
+
} else if (item.endsWith('.page-meta.kwp')) {
|
|
63
|
+
files.push(fullPath)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return files
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getFormId(filePath) {
|
|
70
|
+
try {
|
|
71
|
+
const content = fs.readFileSync(filePath, 'utf-8')
|
|
72
|
+
const match = content.match(/<name>(.*?)<\/name>/)
|
|
73
|
+
return match ? match[1] : null
|
|
74
|
+
} catch (e) {
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
openBrowser,
|
|
81
|
+
waitForPort,
|
|
82
|
+
walk,
|
|
83
|
+
getFormId
|
|
84
|
+
}
|
|
@@ -41,14 +41,6 @@ module.exports = function registerEnv(program) {
|
|
|
41
41
|
require('./delete')(name)
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
-
env
|
|
45
|
-
.command('remote [envName]')
|
|
46
|
-
.description('Open remote environment page with local debug server')
|
|
47
|
-
.requiredOption('-f, --form-id <id>', 'Form ID')
|
|
48
|
-
.action((envName, options) =>
|
|
49
|
-
require('./remote')(envName, options)
|
|
50
|
-
)
|
|
51
|
-
|
|
52
44
|
const auth = env
|
|
53
45
|
.command('auth')
|
|
54
46
|
.description('Authenticate environment')
|
|
@@ -56,7 +48,7 @@ module.exports = function registerEnv(program) {
|
|
|
56
48
|
auth
|
|
57
49
|
.command('web')
|
|
58
50
|
.description('Authenticate via Web (username/password)')
|
|
59
|
-
.option('--env <name>', 'target environment name')
|
|
51
|
+
.option('-e --target-env <name>', 'target environment name')
|
|
60
52
|
.action((options) =>
|
|
61
53
|
require('./auth')('web', options)
|
|
62
54
|
)
|
|
@@ -64,7 +56,7 @@ module.exports = function registerEnv(program) {
|
|
|
64
56
|
auth
|
|
65
57
|
.command('openapi')
|
|
66
58
|
.description('Authenticate via OpenAPI (client credentials)')
|
|
67
|
-
.option('--env <name>', 'target environment name')
|
|
59
|
+
.option('-e --target-env <name>', 'target environment name')
|
|
68
60
|
.action((options) =>
|
|
69
61
|
require('./auth')('openapi', options)
|
|
70
62
|
)
|
package/src/index.js
CHANGED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
const { exec } = require('child_process')
|
|
2
|
-
const { getEnvByName, loadDefaultEnv } = require('./config')
|
|
3
|
-
const { error, info } = require('../../utils/log')
|
|
4
|
-
|
|
5
|
-
module.exports = async function remote(envName, options) {
|
|
6
|
-
const { formId } = options
|
|
7
|
-
|
|
8
|
-
if (!formId) {
|
|
9
|
-
error('Error: --form-id (-f) is required')
|
|
10
|
-
return
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
let env
|
|
14
|
-
if (envName) {
|
|
15
|
-
env = getEnvByName(envName)
|
|
16
|
-
if (!env) {
|
|
17
|
-
error(`Error: Environment "${envName}" not found`)
|
|
18
|
-
return
|
|
19
|
-
}
|
|
20
|
-
} else {
|
|
21
|
-
env = loadDefaultEnv()
|
|
22
|
-
if (!env || !env.name) {
|
|
23
|
-
error('Error: No environment specified and no default environment found')
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
info(`Using default environment: ${env.name}`)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!env.url) {
|
|
30
|
-
error(`Error: Environment "${env.name}" has no URL configured`)
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const targetUrl = new URL(env.url)
|
|
36
|
-
targetUrl.searchParams.append('formId', formId)
|
|
37
|
-
targetUrl.searchParams.append('kdkwc_cdn', 'http://localhost:3333')
|
|
38
|
-
|
|
39
|
-
const finalUrl = targetUrl.toString()
|
|
40
|
-
info(`Opening: ${finalUrl}`)
|
|
41
|
-
|
|
42
|
-
let cmd
|
|
43
|
-
if (process.platform === 'win32') {
|
|
44
|
-
cmd = `start "" "${finalUrl}"`
|
|
45
|
-
} else if (process.platform === 'darwin') {
|
|
46
|
-
cmd = `open "${finalUrl}"`
|
|
47
|
-
} else {
|
|
48
|
-
cmd = `xdg-open "${finalUrl}"`
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
exec(cmd, (err) => {
|
|
52
|
-
if (err) {
|
|
53
|
-
error(`Failed to open browser: ${err.message}`)
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
} catch (e) {
|
|
57
|
-
error(`Invalid Environment URL: ${env.url}`)
|
|
58
|
-
}
|
|
59
|
-
}
|