@cloudbase/cli 2.0.3-alpha.1 → 2.0.3
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/.editorconfig +9 -9
- package/.eslintignore +7 -7
- package/.eslintrc +35 -35
- package/.prettierrc.js +29 -29
- package/.vscode/launch.json +16 -16
- package/.vscode/settings.json +3 -0
- package/LICENSE +5 -5
- package/README.md +35 -35
- package/bin/cloudbase.js +5 -5
- package/bin/tcb.js +0 -0
- package/changelog.md +6 -6
- package/jest.config.js +17 -17
- package/lib/commands/account/login.js +18 -18
- package/lib/commands/storage/storage.js +1 -1
- package/lib/env/login.js +7 -7
- package/lib/run/service/deployPackage.js +2 -2
- package/package.json +3 -3
- package/post-install.js +61 -61
- package/runtime/nodejs/bootstrap.js +255 -255
- package/runtime/nodejs/runtime.js +183 -183
- package/src/auth/index.ts +1 -1
- package/src/auth/login.ts +91 -91
- package/src/auth/logout.ts +7 -7
- package/src/commands/account/index.ts +2 -2
- package/src/commands/account/login.ts +192 -192
- package/src/commands/account/logout.ts +24 -24
- package/src/commands/env/base.ts +90 -90
- package/src/commands/env/create.ts +92 -92
- package/src/commands/env/domain.ts +186 -186
- package/src/commands/env/index.ts +4 -4
- package/src/commands/env/login.ts +235 -235
- package/src/commands/framework/index.ts +124 -124
- package/src/commands/functions/alias/getRoute.ts +76 -76
- package/src/commands/functions/alias/index.ts +2 -2
- package/src/commands/functions/alias/setRoute.ts +82 -82
- package/src/commands/functions/code-download.ts +100 -100
- package/src/commands/functions/code-update.ts +62 -62
- package/src/commands/functions/concurrency/delete.ts +45 -45
- package/src/commands/functions/concurrency/index.ts +2 -2
- package/src/commands/functions/concurrency/list.ts +58 -58
- package/src/commands/functions/concurrency/set.ts +47 -47
- package/src/commands/functions/config-update.ts +76 -76
- package/src/commands/functions/copy.ts +62 -62
- package/src/commands/functions/delete.ts +79 -79
- package/src/commands/functions/deploy.ts +293 -293
- package/src/commands/functions/detail.ts +138 -138
- package/src/commands/functions/index.ts +16 -16
- package/src/commands/functions/invoke.ts +121 -121
- package/src/commands/functions/layer/bind.ts +182 -182
- package/src/commands/functions/layer/common.ts +8 -8
- package/src/commands/functions/layer/create.ts +49 -49
- package/src/commands/functions/layer/delete.ts +73 -73
- package/src/commands/functions/layer/download.ts +92 -92
- package/src/commands/functions/layer/index.ts +7 -7
- package/src/commands/functions/layer/list.ts +94 -94
- package/src/commands/functions/layer/sort.ts +76 -76
- package/src/commands/functions/list.ts +68 -68
- package/src/commands/functions/log.ts +148 -148
- package/src/commands/functions/run.ts +249 -249
- package/src/commands/functions/trigger-create.ts +79 -79
- package/src/commands/functions/trigger-delete.ts +105 -105
- package/src/commands/functions/version/index.ts +1 -1
- package/src/commands/functions/version/list.ts +73 -73
- package/src/commands/functions/version/publish.ts +43 -43
- package/src/commands/gateway/create.ts +109 -109
- package/src/commands/gateway/delete.ts +81 -81
- package/src/commands/gateway/domain.ts +159 -159
- package/src/commands/gateway/index.ts +5 -5
- package/src/commands/gateway/list.ts +76 -76
- package/src/commands/gateway/switch.ts +107 -107
- package/src/commands/helpers/index.ts +2 -2
- package/src/commands/helpers/init.ts +431 -431
- package/src/commands/helpers/new.ts +117 -117
- package/src/commands/helpers/open.ts +67 -67
- package/src/commands/hosting/hosting.ts +360 -360
- package/src/commands/index.ts +13 -13
- package/src/commands/lowcode/app.ts +34 -34
- package/src/commands/lowcode/comps.ts +322 -322
- package/src/commands/lowcode/index.ts +1 -1
- package/src/commands/lowcode/utils.ts +24 -24
- package/src/commands/run/image/index.ts +4 -4
- package/src/commands/run/standalonegateway/common.ts +7 -7
- package/src/commands/run/standalonegateway/create.ts +85 -85
- package/src/commands/run/standalonegateway/destroy.ts +59 -59
- package/src/commands/run/standalonegateway/index.ts +4 -4
- package/src/commands/run/standalonegateway/list.ts +53 -53
- package/src/commands/run/standalonegateway/package.ts +62 -62
- package/src/commands/run/standalonegateway/turn.ts +63 -63
- package/src/commands/run/version/index.ts +4 -4
- package/src/commands/smart.ts +132 -132
- package/src/commands/storage/storage.ts +464 -464
- package/src/commands/third/thirdAttach.ts +49 -49
- package/src/completion/index.ts +13 -13
- package/src/decorators/captureError.ts +25 -25
- package/src/decorators/constants.ts +12 -12
- package/src/decorators/deprecate.ts +25 -25
- package/src/decorators/guard.ts +42 -42
- package/src/decorators/index.ts +7 -7
- package/src/decorators/injectParams.ts +54 -54
- package/src/decorators/params/common.ts +28 -28
- package/src/decorators/params/index.ts +35 -35
- package/src/env/domain.ts +33 -33
- package/src/env/index.ts +63 -63
- package/src/env/login.ts +80 -80
- package/src/error.ts +36 -36
- package/src/function/alias.ts +43 -43
- package/src/function/base.ts +253 -253
- package/src/function/code.ts +55 -55
- package/src/function/concurrency.ts +57 -57
- package/src/function/create.ts +78 -78
- package/src/function/delete.ts +42 -42
- package/src/function/index.ts +10 -10
- package/src/function/layer/attach.ts +68 -68
- package/src/function/layer/create.ts +63 -63
- package/src/function/layer/delete.ts +21 -21
- package/src/function/layer/download.ts +54 -54
- package/src/function/layer/index.ts +7 -7
- package/src/function/layer/list.ts +32 -32
- package/src/function/layer/sort.ts +24 -24
- package/src/function/trigger.ts +97 -97
- package/src/function/update.ts +35 -35
- package/src/function/version.ts +38 -38
- package/src/function/vpc.ts +22 -22
- package/src/gateway/index.ts +137 -137
- package/src/hosting.ts +212 -212
- package/src/index.ts +13 -13
- package/src/logger.ts +17 -17
- package/src/run/create.ts +23 -23
- package/src/run/delete.ts +15 -15
- package/src/run/image/build.ts +36 -36
- package/src/run/image/delete.ts +13 -13
- package/src/run/image/index.ts +3 -3
- package/src/run/image/info.ts +26 -26
- package/src/run/list.ts +29 -29
- package/src/run/repo.ts +24 -24
- package/src/run/service/deployPackage.ts +1 -1
- package/src/run/standalonegateway/create.ts +24 -24
- package/src/run/standalonegateway/destroy.ts +19 -19
- package/src/run/standalonegateway/index.ts +4 -4
- package/src/run/standalonegateway/list.ts +74 -74
- package/src/run/standalonegateway/package/list.ts +24 -24
- package/src/run/standalonegateway/turn/index.ts +1 -1
- package/src/run/standalonegateway/turn/off.ts +19 -19
- package/src/run/standalonegateway/turn/on.ts +19 -19
- package/src/run/version/create.ts +68 -68
- package/src/run/version/delete.ts +15 -15
- package/src/run/version/index.ts +5 -5
- package/src/run/version/list.ts +16 -16
- package/src/run/version/modify.ts +16 -16
- package/src/run/version/repo.ts +27 -27
- package/src/run/version/update.ts +58 -58
- package/src/storage.ts +114 -114
- package/src/third/index.ts +12 -12
- package/src/utils/auth.ts +15 -15
- package/src/utils/cli-table.ts +23 -23
- package/src/utils/config.ts +39 -39
- package/src/utils/env.ts +244 -244
- package/src/utils/fs/del.ts +5 -5
- package/src/utils/fs/index.ts +71 -71
- package/src/utils/function-packer.ts +97 -97
- package/src/utils/log.ts +81 -81
- package/src/utils/net/cloud-api-request.ts +62 -62
- package/src/utils/net/credential.ts +53 -53
- package/src/utils/net/index.ts +4 -4
- package/src/utils/net/manager-service.ts +36 -36
- package/src/utils/net/proxy.ts +6 -6
- package/src/utils/notice.ts +28 -28
- package/src/utils/output/highlight.ts +5 -5
- package/src/utils/output/index.ts +2 -2
- package/src/utils/output/link.ts +10 -10
- package/src/utils/output/loading.ts +82 -82
- package/src/utils/parallel.ts +82 -82
- package/src/utils/platform/index.ts +2 -2
- package/src/utils/platform/mac.ts +21 -21
- package/src/utils/platform/os.ts +64 -64
- package/src/utils/platform/port.ts +10 -10
- package/src/utils/progress-bar.ts +38 -38
- package/src/utils/prompt/select.ts +59 -59
- package/src/utils/reporter/agree.ts +20 -20
- package/src/utils/reporter/download.ts +26 -26
- package/src/utils/reporter/index.ts +3 -3
- package/src/utils/reporter/usage.ts +20 -20
- package/src/utils/store/auth.ts +49 -49
- package/src/utils/store/common.ts +8 -8
- package/src/utils/store/db.ts +68 -68
- package/src/utils/store/index.ts +4 -4
- package/src/utils/store/usage.ts +12 -12
- package/src/utils/template.ts +170 -170
- package/src/utils/tools/encoding.ts +8 -8
- package/src/utils/tools/index.ts +4 -4
- package/src/utils/tools/object.ts +33 -33
- package/src/utils/tools/time.ts +38 -38
- package/src/utils/tools/uid.ts +19 -19
- package/templates/html/loginFail.html +90 -90
- package/templates/html/loginSuccess.html +86 -86
- package/templates/server/node/_gitignore +54 -54
- package/templates/server/node/cloudbaserc.json +10 -10
- package/templates/server/node/index.js +5 -5
- package/templates/server/node/package.json +9 -9
- package/tsconfig.json +19 -19
- package/tsconfig.test.json +13 -13
|
@@ -1,249 +1,249 @@
|
|
|
1
|
-
import _ from 'lodash'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { spawn, SpawnOptionsWithoutStdio } from 'child_process'
|
|
4
|
-
import { Command, ICommand } from '../common'
|
|
5
|
-
import { CloudBaseError } from '../../error'
|
|
6
|
-
import { ICommandContext } from '../../types'
|
|
7
|
-
import { InjectParams, CmdContext } from '../../decorators'
|
|
8
|
-
import { checkFullAccess, isDirectory, checkAndGetCredential } from '../../utils'
|
|
9
|
-
|
|
10
|
-
// 启动文件
|
|
11
|
-
const bootstrapFilePath = path.join(__dirname, '../../../runtime/nodejs/bootstrap.js')
|
|
12
|
-
|
|
13
|
-
function checkJSON(data) {
|
|
14
|
-
try {
|
|
15
|
-
JSON.parse(data)
|
|
16
|
-
} catch (e) {
|
|
17
|
-
throw new CloudBaseError('非法的 JSON 字符串')
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function errorLog(msg: string, debug?: boolean) {
|
|
22
|
-
throw new CloudBaseError(msg, {
|
|
23
|
-
meta: { debug }
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function getDebugArgs(port = 9229) {
|
|
28
|
-
return [
|
|
29
|
-
`--inspect-brk=0.0.0.0:${port}`,
|
|
30
|
-
'--nolazy',
|
|
31
|
-
'--expose-gc',
|
|
32
|
-
'--max-semi-space-size=150',
|
|
33
|
-
'--max-old-space-size=2707'
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// 启动 Node 子进程执行
|
|
38
|
-
function spawnNodeProcess(args: string[], options: SpawnOptionsWithoutStdio) {
|
|
39
|
-
const commonOptions = {
|
|
40
|
-
cwd: path.dirname(bootstrapFilePath),
|
|
41
|
-
windowsHide: true
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const exec = spawn('node', args, {
|
|
45
|
-
...commonOptions,
|
|
46
|
-
...options
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
exec.on('error', (e) => {
|
|
50
|
-
console.log(`进程执行异常:${e.message}`)
|
|
51
|
-
setTimeout(() => {}, 100)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
exec.stdout.on('data', (data) => {
|
|
55
|
-
console.log(`${data}`)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
exec.stderr.on('data', (data) => {
|
|
59
|
-
console.log(`${data}`)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
exec.on('close', (code) => {
|
|
63
|
-
if (code !== 0) {
|
|
64
|
-
console.log(`\n云函数执行异常退出,错误码:${code}`)
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async function getSecret() {
|
|
70
|
-
const credential = await checkAndGetCredential()
|
|
71
|
-
if (_.isEmpty(credential)) {
|
|
72
|
-
console.log('未登录,无法直接调用 Node SDK')
|
|
73
|
-
return {}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const { secretId, secretKey, token } = credential
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
TENCENTCLOUD_SECRETID: secretId,
|
|
80
|
-
TENCENTCLOUD_SECRETKEY: secretKey,
|
|
81
|
-
TENCENTCLOUD_SESSIONTOKEN: token
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export async function debugFunctionByPath(functionPath: string, options: Record<string, any>) {
|
|
86
|
-
const { params, debug, port } = options
|
|
87
|
-
params && checkJSON(params)
|
|
88
|
-
|
|
89
|
-
// 检查路径是否存在
|
|
90
|
-
const filePath = path.resolve(functionPath)
|
|
91
|
-
checkFullAccess(filePath)
|
|
92
|
-
|
|
93
|
-
let debugDirname
|
|
94
|
-
const isDir = isDirectory(filePath)
|
|
95
|
-
|
|
96
|
-
if (isDir) {
|
|
97
|
-
const exists = checkFullAccess(path.join(filePath, 'index.js'))
|
|
98
|
-
if (!exists) {
|
|
99
|
-
errorLog('index.js 文件不存在!', debug)
|
|
100
|
-
}
|
|
101
|
-
debugDirname = filePath
|
|
102
|
-
} else {
|
|
103
|
-
const { base, dir } = path.parse(filePath)
|
|
104
|
-
if (base !== 'index.js') {
|
|
105
|
-
errorLog('index.js 文件不存在!', debug)
|
|
106
|
-
}
|
|
107
|
-
debugDirname = dir
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
// eslint-disable-next-line
|
|
112
|
-
const fileExports = require(path.join(debugDirname, 'index.js'))
|
|
113
|
-
if (!fileExports.main) {
|
|
114
|
-
errorLog('main 方法不存在!', debug)
|
|
115
|
-
}
|
|
116
|
-
} catch (e) {
|
|
117
|
-
errorLog(`导入云函数异常:${e.message}`, debug)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// 读取本地 secret 变量
|
|
121
|
-
const secret = await getSecret()
|
|
122
|
-
const debugArgs = getDebugArgs(port)
|
|
123
|
-
const args = debug ? [...debugArgs, bootstrapFilePath] : [bootstrapFilePath]
|
|
124
|
-
console.log('> 以默认配置启动 Node 云函数调试')
|
|
125
|
-
|
|
126
|
-
spawnNodeProcess(args, {
|
|
127
|
-
env: {
|
|
128
|
-
...process.env,
|
|
129
|
-
SCF_FUNCTION_HANDLER: 'index.main',
|
|
130
|
-
SCF_FUNCTION_NAME: 'main',
|
|
131
|
-
GLOBAL_USER_FILE_PATH: path.join(debugDirname, path.sep),
|
|
132
|
-
SCF_EVENT_BODY: params || '{}',
|
|
133
|
-
...secret
|
|
134
|
-
}
|
|
135
|
-
})
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export async function debugByConfig(ctx: ICommandContext, name: string) {
|
|
139
|
-
const { config, options, envId } = ctx
|
|
140
|
-
const { params, debug, port } = options
|
|
141
|
-
params && checkJSON(params)
|
|
142
|
-
|
|
143
|
-
// 检查路径是否存在
|
|
144
|
-
let functionPath = path.resolve(config.functionRoot, name)
|
|
145
|
-
const filePath = path.resolve(functionPath)
|
|
146
|
-
checkFullAccess(filePath, !debug)
|
|
147
|
-
|
|
148
|
-
let debugDirname
|
|
149
|
-
const funcConfig = config.functions.find((item) => item.name === name)
|
|
150
|
-
|
|
151
|
-
const handlers = (funcConfig?.handler || 'index.main').split('.')
|
|
152
|
-
const indexFileName = handlers[0]
|
|
153
|
-
const indexFile = `${indexFileName}.js`
|
|
154
|
-
const mainFunction = handlers[1]
|
|
155
|
-
|
|
156
|
-
const isDir = isDirectory(filePath)
|
|
157
|
-
|
|
158
|
-
if (isDir) {
|
|
159
|
-
const exists = checkFullAccess(path.join(filePath, indexFile))
|
|
160
|
-
if (!exists) {
|
|
161
|
-
errorLog(`${indexFile} 文件不存在!`, debug)
|
|
162
|
-
}
|
|
163
|
-
debugDirname = filePath
|
|
164
|
-
} else {
|
|
165
|
-
const { base, dir } = path.parse(filePath)
|
|
166
|
-
if (base !== indexFile) {
|
|
167
|
-
errorLog(`${indexFile} 文件不存在!`, debug)
|
|
168
|
-
}
|
|
169
|
-
debugDirname = dir
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
try {
|
|
173
|
-
// eslint-disable-next-line
|
|
174
|
-
const fileExports = require(path.join(debugDirname, indexFile))
|
|
175
|
-
if (!fileExports[mainFunction]) {
|
|
176
|
-
errorLog(`handler 中的 ${mainFunction} 方法不存在,请检查你的配置!`, debug)
|
|
177
|
-
}
|
|
178
|
-
} catch (e) {
|
|
179
|
-
errorLog(`导入云函数异常:${e.message}`, debug)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// 读取本地 secret
|
|
183
|
-
const secret = await getSecret()
|
|
184
|
-
const debugArgs = getDebugArgs(port)
|
|
185
|
-
const args = debug ? [...debugArgs, bootstrapFilePath] : [bootstrapFilePath]
|
|
186
|
-
|
|
187
|
-
spawnNodeProcess(args, {
|
|
188
|
-
env: {
|
|
189
|
-
...process.env,
|
|
190
|
-
SCF_NAMESPACE: envId,
|
|
191
|
-
SCF_FUNCTION_HANDLER: funcConfig?.handler || 'index.main',
|
|
192
|
-
SCF_FUNCTION_NAME: funcConfig?.name || 'main',
|
|
193
|
-
GLOBAL_USER_FILE_PATH: path.join(debugDirname, path.sep),
|
|
194
|
-
SCF_EVENT_BODY: params || JSON.stringify(funcConfig?.params || {}),
|
|
195
|
-
...funcConfig?.envVariables,
|
|
196
|
-
...secret
|
|
197
|
-
}
|
|
198
|
-
})
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
@ICommand()
|
|
202
|
-
export class FunctionDebug extends Command {
|
|
203
|
-
get options() {
|
|
204
|
-
return {
|
|
205
|
-
cmd: 'fn',
|
|
206
|
-
childCmd: 'run',
|
|
207
|
-
deprecateCmd: 'functions:run',
|
|
208
|
-
options: [
|
|
209
|
-
{
|
|
210
|
-
flags: '--path <path>',
|
|
211
|
-
desc: '云函数路径,使用默认配置直接调用云函数,无需配置文件'
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
flags: '--name <name>',
|
|
215
|
-
desc: '指定云函数的名称进行调用,需要配置文件'
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
flags: '--params <params>',
|
|
219
|
-
desc: '调用函数传入的参数,JSON 字符串格式'
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
flags: '--port <port>',
|
|
223
|
-
desc: '启动调试时监听的端口号,默认为 9229'
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
flags: '--debug',
|
|
227
|
-
desc: '启动调试模式'
|
|
228
|
-
}
|
|
229
|
-
],
|
|
230
|
-
desc: '本地运行云函数(当前仅支持 Node)'
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
@InjectParams()
|
|
235
|
-
async execute(@CmdContext() ctx) {
|
|
236
|
-
const { options } = ctx
|
|
237
|
-
const { path, name } = options
|
|
238
|
-
// 指定函数路径,以默认配置运行函数
|
|
239
|
-
if (path) {
|
|
240
|
-
await debugFunctionByPath(path, options)
|
|
241
|
-
} else if (typeof name === 'string') {
|
|
242
|
-
await debugByConfig(ctx, name)
|
|
243
|
-
} else {
|
|
244
|
-
throw new CloudBaseError(
|
|
245
|
-
'请指定运行函数的名称或函数的路径\n\n例如 cloudbase functions:run --name app'
|
|
246
|
-
)
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { spawn, SpawnOptionsWithoutStdio } from 'child_process'
|
|
4
|
+
import { Command, ICommand } from '../common'
|
|
5
|
+
import { CloudBaseError } from '../../error'
|
|
6
|
+
import { ICommandContext } from '../../types'
|
|
7
|
+
import { InjectParams, CmdContext } from '../../decorators'
|
|
8
|
+
import { checkFullAccess, isDirectory, checkAndGetCredential } from '../../utils'
|
|
9
|
+
|
|
10
|
+
// 启动文件
|
|
11
|
+
const bootstrapFilePath = path.join(__dirname, '../../../runtime/nodejs/bootstrap.js')
|
|
12
|
+
|
|
13
|
+
function checkJSON(data) {
|
|
14
|
+
try {
|
|
15
|
+
JSON.parse(data)
|
|
16
|
+
} catch (e) {
|
|
17
|
+
throw new CloudBaseError('非法的 JSON 字符串')
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function errorLog(msg: string, debug?: boolean) {
|
|
22
|
+
throw new CloudBaseError(msg, {
|
|
23
|
+
meta: { debug }
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getDebugArgs(port = 9229) {
|
|
28
|
+
return [
|
|
29
|
+
`--inspect-brk=0.0.0.0:${port}`,
|
|
30
|
+
'--nolazy',
|
|
31
|
+
'--expose-gc',
|
|
32
|
+
'--max-semi-space-size=150',
|
|
33
|
+
'--max-old-space-size=2707'
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 启动 Node 子进程执行
|
|
38
|
+
function spawnNodeProcess(args: string[], options: SpawnOptionsWithoutStdio) {
|
|
39
|
+
const commonOptions = {
|
|
40
|
+
cwd: path.dirname(bootstrapFilePath),
|
|
41
|
+
windowsHide: true
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const exec = spawn('node', args, {
|
|
45
|
+
...commonOptions,
|
|
46
|
+
...options
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
exec.on('error', (e) => {
|
|
50
|
+
console.log(`进程执行异常:${e.message}`)
|
|
51
|
+
setTimeout(() => {}, 100)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
exec.stdout.on('data', (data) => {
|
|
55
|
+
console.log(`${data}`)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
exec.stderr.on('data', (data) => {
|
|
59
|
+
console.log(`${data}`)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
exec.on('close', (code) => {
|
|
63
|
+
if (code !== 0) {
|
|
64
|
+
console.log(`\n云函数执行异常退出,错误码:${code}`)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function getSecret() {
|
|
70
|
+
const credential = await checkAndGetCredential()
|
|
71
|
+
if (_.isEmpty(credential)) {
|
|
72
|
+
console.log('未登录,无法直接调用 Node SDK')
|
|
73
|
+
return {}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const { secretId, secretKey, token } = credential
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
TENCENTCLOUD_SECRETID: secretId,
|
|
80
|
+
TENCENTCLOUD_SECRETKEY: secretKey,
|
|
81
|
+
TENCENTCLOUD_SESSIONTOKEN: token
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function debugFunctionByPath(functionPath: string, options: Record<string, any>) {
|
|
86
|
+
const { params, debug, port } = options
|
|
87
|
+
params && checkJSON(params)
|
|
88
|
+
|
|
89
|
+
// 检查路径是否存在
|
|
90
|
+
const filePath = path.resolve(functionPath)
|
|
91
|
+
checkFullAccess(filePath)
|
|
92
|
+
|
|
93
|
+
let debugDirname
|
|
94
|
+
const isDir = isDirectory(filePath)
|
|
95
|
+
|
|
96
|
+
if (isDir) {
|
|
97
|
+
const exists = checkFullAccess(path.join(filePath, 'index.js'))
|
|
98
|
+
if (!exists) {
|
|
99
|
+
errorLog('index.js 文件不存在!', debug)
|
|
100
|
+
}
|
|
101
|
+
debugDirname = filePath
|
|
102
|
+
} else {
|
|
103
|
+
const { base, dir } = path.parse(filePath)
|
|
104
|
+
if (base !== 'index.js') {
|
|
105
|
+
errorLog('index.js 文件不存在!', debug)
|
|
106
|
+
}
|
|
107
|
+
debugDirname = dir
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
// eslint-disable-next-line
|
|
112
|
+
const fileExports = require(path.join(debugDirname, 'index.js'))
|
|
113
|
+
if (!fileExports.main) {
|
|
114
|
+
errorLog('main 方法不存在!', debug)
|
|
115
|
+
}
|
|
116
|
+
} catch (e) {
|
|
117
|
+
errorLog(`导入云函数异常:${e.message}`, debug)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 读取本地 secret 变量
|
|
121
|
+
const secret = await getSecret()
|
|
122
|
+
const debugArgs = getDebugArgs(port)
|
|
123
|
+
const args = debug ? [...debugArgs, bootstrapFilePath] : [bootstrapFilePath]
|
|
124
|
+
console.log('> 以默认配置启动 Node 云函数调试')
|
|
125
|
+
|
|
126
|
+
spawnNodeProcess(args, {
|
|
127
|
+
env: {
|
|
128
|
+
...process.env,
|
|
129
|
+
SCF_FUNCTION_HANDLER: 'index.main',
|
|
130
|
+
SCF_FUNCTION_NAME: 'main',
|
|
131
|
+
GLOBAL_USER_FILE_PATH: path.join(debugDirname, path.sep),
|
|
132
|
+
SCF_EVENT_BODY: params || '{}',
|
|
133
|
+
...secret
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function debugByConfig(ctx: ICommandContext, name: string) {
|
|
139
|
+
const { config, options, envId } = ctx
|
|
140
|
+
const { params, debug, port } = options
|
|
141
|
+
params && checkJSON(params)
|
|
142
|
+
|
|
143
|
+
// 检查路径是否存在
|
|
144
|
+
let functionPath = path.resolve(config.functionRoot, name)
|
|
145
|
+
const filePath = path.resolve(functionPath)
|
|
146
|
+
checkFullAccess(filePath, !debug)
|
|
147
|
+
|
|
148
|
+
let debugDirname
|
|
149
|
+
const funcConfig = config.functions.find((item) => item.name === name)
|
|
150
|
+
|
|
151
|
+
const handlers = (funcConfig?.handler || 'index.main').split('.')
|
|
152
|
+
const indexFileName = handlers[0]
|
|
153
|
+
const indexFile = `${indexFileName}.js`
|
|
154
|
+
const mainFunction = handlers[1]
|
|
155
|
+
|
|
156
|
+
const isDir = isDirectory(filePath)
|
|
157
|
+
|
|
158
|
+
if (isDir) {
|
|
159
|
+
const exists = checkFullAccess(path.join(filePath, indexFile))
|
|
160
|
+
if (!exists) {
|
|
161
|
+
errorLog(`${indexFile} 文件不存在!`, debug)
|
|
162
|
+
}
|
|
163
|
+
debugDirname = filePath
|
|
164
|
+
} else {
|
|
165
|
+
const { base, dir } = path.parse(filePath)
|
|
166
|
+
if (base !== indexFile) {
|
|
167
|
+
errorLog(`${indexFile} 文件不存在!`, debug)
|
|
168
|
+
}
|
|
169
|
+
debugDirname = dir
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
// eslint-disable-next-line
|
|
174
|
+
const fileExports = require(path.join(debugDirname, indexFile))
|
|
175
|
+
if (!fileExports[mainFunction]) {
|
|
176
|
+
errorLog(`handler 中的 ${mainFunction} 方法不存在,请检查你的配置!`, debug)
|
|
177
|
+
}
|
|
178
|
+
} catch (e) {
|
|
179
|
+
errorLog(`导入云函数异常:${e.message}`, debug)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 读取本地 secret
|
|
183
|
+
const secret = await getSecret()
|
|
184
|
+
const debugArgs = getDebugArgs(port)
|
|
185
|
+
const args = debug ? [...debugArgs, bootstrapFilePath] : [bootstrapFilePath]
|
|
186
|
+
|
|
187
|
+
spawnNodeProcess(args, {
|
|
188
|
+
env: {
|
|
189
|
+
...process.env,
|
|
190
|
+
SCF_NAMESPACE: envId,
|
|
191
|
+
SCF_FUNCTION_HANDLER: funcConfig?.handler || 'index.main',
|
|
192
|
+
SCF_FUNCTION_NAME: funcConfig?.name || 'main',
|
|
193
|
+
GLOBAL_USER_FILE_PATH: path.join(debugDirname, path.sep),
|
|
194
|
+
SCF_EVENT_BODY: params || JSON.stringify(funcConfig?.params || {}),
|
|
195
|
+
...funcConfig?.envVariables,
|
|
196
|
+
...secret
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@ICommand()
|
|
202
|
+
export class FunctionDebug extends Command {
|
|
203
|
+
get options() {
|
|
204
|
+
return {
|
|
205
|
+
cmd: 'fn',
|
|
206
|
+
childCmd: 'run',
|
|
207
|
+
deprecateCmd: 'functions:run',
|
|
208
|
+
options: [
|
|
209
|
+
{
|
|
210
|
+
flags: '--path <path>',
|
|
211
|
+
desc: '云函数路径,使用默认配置直接调用云函数,无需配置文件'
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
flags: '--name <name>',
|
|
215
|
+
desc: '指定云函数的名称进行调用,需要配置文件'
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
flags: '--params <params>',
|
|
219
|
+
desc: '调用函数传入的参数,JSON 字符串格式'
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
flags: '--port <port>',
|
|
223
|
+
desc: '启动调试时监听的端口号,默认为 9229'
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
flags: '--debug',
|
|
227
|
+
desc: '启动调试模式'
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
desc: '本地运行云函数(当前仅支持 Node)'
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
@InjectParams()
|
|
235
|
+
async execute(@CmdContext() ctx) {
|
|
236
|
+
const { options } = ctx
|
|
237
|
+
const { path, name } = options
|
|
238
|
+
// 指定函数路径,以默认配置运行函数
|
|
239
|
+
if (path) {
|
|
240
|
+
await debugFunctionByPath(path, options)
|
|
241
|
+
} else if (typeof name === 'string') {
|
|
242
|
+
await debugByConfig(ctx, name)
|
|
243
|
+
} else {
|
|
244
|
+
throw new CloudBaseError(
|
|
245
|
+
'请指定运行函数的名称或函数的路径\n\n例如 cloudbase functions:run --name app'
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
import inquirer from 'inquirer'
|
|
2
|
-
import { Command, ICommand } from '../common'
|
|
3
|
-
import { successLog } from '../../logger'
|
|
4
|
-
import { CloudBaseError } from '../../error'
|
|
5
|
-
import { createFunctionTriggers, batchCreateTriggers } from '../../function'
|
|
6
|
-
import { InjectParams, CmdContext, ArgsParams } from '../../decorators'
|
|
7
|
-
|
|
8
|
-
@ICommand()
|
|
9
|
-
export class CreateTrigger extends Command {
|
|
10
|
-
get options() {
|
|
11
|
-
return {
|
|
12
|
-
cmd: 'fn',
|
|
13
|
-
childCmd: { cmd: 'trigger', desc: '函数触发器操作' },
|
|
14
|
-
childSubCmd: 'create [functionName]',
|
|
15
|
-
deprecateCmd: 'functions:trigger:create [functionName]',
|
|
16
|
-
options: [
|
|
17
|
-
{
|
|
18
|
-
flags: '-e, --envId <envId>',
|
|
19
|
-
desc: '环境 Id'
|
|
20
|
-
}
|
|
21
|
-
],
|
|
22
|
-
desc: '创建云函数触发器'
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
@InjectParams()
|
|
27
|
-
async execute(@CmdContext() ctx, @ArgsParams() params) {
|
|
28
|
-
const {
|
|
29
|
-
envId,
|
|
30
|
-
config: { functions }
|
|
31
|
-
} = ctx
|
|
32
|
-
|
|
33
|
-
const name = params?.[0]
|
|
34
|
-
|
|
35
|
-
let isBatchCreateTrigger = false
|
|
36
|
-
|
|
37
|
-
// 不指定云函数名称,创建配置文件中所有函数的所有触发器
|
|
38
|
-
if (!name) {
|
|
39
|
-
const { isBatch } = await inquirer.prompt({
|
|
40
|
-
type: 'confirm',
|
|
41
|
-
name: 'isBatch',
|
|
42
|
-
message: '无云函数名称,是否需要部署配置文件中的【全部云函数】的全部触发器?',
|
|
43
|
-
default: false
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
isBatchCreateTrigger = isBatch
|
|
47
|
-
|
|
48
|
-
if (!isBatchCreateTrigger) {
|
|
49
|
-
throw new CloudBaseError('请指定云函数名称!')
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (isBatchCreateTrigger) {
|
|
54
|
-
return batchCreateTriggers({
|
|
55
|
-
envId,
|
|
56
|
-
functions
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const functionItem = functions.find((item) => item.name === name)
|
|
61
|
-
|
|
62
|
-
if (!functionItem) {
|
|
63
|
-
throw new CloudBaseError('未找到相关函数配置,请检查函数名是否正确')
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const { triggers } = functionItem
|
|
67
|
-
|
|
68
|
-
if (!triggers || !triggers.length) {
|
|
69
|
-
throw new CloudBaseError('触发器配置不能为空')
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
await createFunctionTriggers({
|
|
73
|
-
envId,
|
|
74
|
-
functionName: name,
|
|
75
|
-
triggers
|
|
76
|
-
})
|
|
77
|
-
successLog(`[${name}] 创建云函数触发器成功!`)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
1
|
+
import inquirer from 'inquirer'
|
|
2
|
+
import { Command, ICommand } from '../common'
|
|
3
|
+
import { successLog } from '../../logger'
|
|
4
|
+
import { CloudBaseError } from '../../error'
|
|
5
|
+
import { createFunctionTriggers, batchCreateTriggers } from '../../function'
|
|
6
|
+
import { InjectParams, CmdContext, ArgsParams } from '../../decorators'
|
|
7
|
+
|
|
8
|
+
@ICommand()
|
|
9
|
+
export class CreateTrigger extends Command {
|
|
10
|
+
get options() {
|
|
11
|
+
return {
|
|
12
|
+
cmd: 'fn',
|
|
13
|
+
childCmd: { cmd: 'trigger', desc: '函数触发器操作' },
|
|
14
|
+
childSubCmd: 'create [functionName]',
|
|
15
|
+
deprecateCmd: 'functions:trigger:create [functionName]',
|
|
16
|
+
options: [
|
|
17
|
+
{
|
|
18
|
+
flags: '-e, --envId <envId>',
|
|
19
|
+
desc: '环境 Id'
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
desc: '创建云函数触发器'
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@InjectParams()
|
|
27
|
+
async execute(@CmdContext() ctx, @ArgsParams() params) {
|
|
28
|
+
const {
|
|
29
|
+
envId,
|
|
30
|
+
config: { functions }
|
|
31
|
+
} = ctx
|
|
32
|
+
|
|
33
|
+
const name = params?.[0]
|
|
34
|
+
|
|
35
|
+
let isBatchCreateTrigger = false
|
|
36
|
+
|
|
37
|
+
// 不指定云函数名称,创建配置文件中所有函数的所有触发器
|
|
38
|
+
if (!name) {
|
|
39
|
+
const { isBatch } = await inquirer.prompt({
|
|
40
|
+
type: 'confirm',
|
|
41
|
+
name: 'isBatch',
|
|
42
|
+
message: '无云函数名称,是否需要部署配置文件中的【全部云函数】的全部触发器?',
|
|
43
|
+
default: false
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
isBatchCreateTrigger = isBatch
|
|
47
|
+
|
|
48
|
+
if (!isBatchCreateTrigger) {
|
|
49
|
+
throw new CloudBaseError('请指定云函数名称!')
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (isBatchCreateTrigger) {
|
|
54
|
+
return batchCreateTriggers({
|
|
55
|
+
envId,
|
|
56
|
+
functions
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const functionItem = functions.find((item) => item.name === name)
|
|
61
|
+
|
|
62
|
+
if (!functionItem) {
|
|
63
|
+
throw new CloudBaseError('未找到相关函数配置,请检查函数名是否正确')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const { triggers } = functionItem
|
|
67
|
+
|
|
68
|
+
if (!triggers || !triggers.length) {
|
|
69
|
+
throw new CloudBaseError('触发器配置不能为空')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
await createFunctionTriggers({
|
|
73
|
+
envId,
|
|
74
|
+
functionName: name,
|
|
75
|
+
triggers
|
|
76
|
+
})
|
|
77
|
+
successLog(`[${name}] 创建云函数触发器成功!`)
|
|
78
|
+
}
|
|
79
|
+
}
|