@ranger1/dx 0.1.67 → 0.1.68

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.
@@ -40,7 +40,7 @@ export function parseTelegramWebhookFlags(argv = []) {
40
40
 
41
41
  const dryRun = args.includes('--webhook-dry-run') ? true : undefined
42
42
 
43
- // 默认值由下游根据 environment 决定,这里只负责覆盖
43
+ // 默认值由下游决定(当前为默认严格),这里仅处理显式覆盖
44
44
  const strict = args.includes('--strict-webhook')
45
45
  ? true
46
46
  : args.includes('--no-strict-webhook')
package/lib/cli/dx-cli.js CHANGED
@@ -295,6 +295,13 @@ class DxCli {
295
295
 
296
296
  this.validateInputs()
297
297
 
298
+ // Fail fast for unknown commands before dependency/env startup checks.
299
+ if (this.command && !this.commandHandlers[this.command]) {
300
+ logger.error(`未知命令: ${this.command}`)
301
+ showHelp()
302
+ process.exit(1)
303
+ }
304
+
298
305
  // Commands that should work without env/dependency checks.
299
306
  // - help: printing help should never require env vars.
300
307
  // - status: should be available even when env is incomplete.
@@ -344,11 +351,7 @@ class DxCli {
344
351
  }
345
352
 
346
353
  const handler = this.commandHandlers[command]
347
- if (!handler) {
348
- logger.error(`未知命令: ${command}`)
349
- showHelp()
350
- process.exit(1)
351
- }
354
+ if (!handler) return
352
355
 
353
356
  await handler(subArgs)
354
357
  }
package/lib/cli/help.js CHANGED
@@ -194,7 +194,7 @@ script 子命令:
194
194
  Telegram Webhook(仅 target=telegram-bot 生效):
195
195
  --webhook-path <path> 对外 webhook 路径(默认 /api/webhook)
196
196
  --webhook-dry-run 只打印将设置的 URL,不调用 Telegram API
197
- --strict-webhook 强制严格校验(Webhook 不生效则 deploy 失败)
197
+ --strict-webhook 显式开启严格校验(默认已严格)
198
198
  --no-strict-webhook 关闭严格校验(仅告警)
199
199
 
200
200
  常见示例:
@@ -203,7 +203,7 @@ script 子命令:
203
203
  dx deploy telegram-bot --staging # 部署 Telegram Bot + 自动配置 Webhook
204
204
  dx deploy telegram-bot --staging --webhook-path /webhook # 使用短路径(rewrite 到 /api/webhook)
205
205
  dx deploy telegram-bot --prod --webhook-dry-run # 仅打印,不实际调用 Telegram
206
- dx deploy telegram-bot --prod --no-strict-webhook # 生产环境也仅告警(不推荐)
206
+ dx deploy telegram-bot --dev --no-strict-webhook # 开发环境显式降级为仅告警
207
207
  dx deploy all --staging # 串行部署 front + admin
208
208
  `)
209
209
  return
@@ -17,11 +17,35 @@ function normalizeDeployUrl(raw) {
17
17
  }
18
18
 
19
19
  export function parseDeployUrlFromDeployOutput(output) {
20
- const s = String(output || '')
21
- const matches = [...s.matchAll(/(https?:\/\/)?([a-z0-9-]+\.vercel\.app)\b/gi)]
22
- if (matches.length === 0) return null
23
- const last = matches[matches.length - 1]
24
- return `https://${last[2]}`
20
+ const lines = String(output || '')
21
+ .split(/\r?\n/)
22
+ .map(line => String(line || '').trim())
23
+ .filter(Boolean)
24
+
25
+ const pickUrl = line => {
26
+ const m = line.match(/(https?:\/\/)?([a-z0-9-]+\.vercel\.app)\b/i)
27
+ return m ? `https://${m[2]}` : null
28
+ }
29
+
30
+ for (const line of lines) {
31
+ if (!/^production\s*:/i.test(line)) continue
32
+ const url = pickUrl(line)
33
+ if (url) return url
34
+ }
35
+
36
+ for (const line of lines) {
37
+ if (!/^preview\s*:/i.test(line)) continue
38
+ const url = pickUrl(line)
39
+ if (url) return url
40
+ }
41
+
42
+ for (const line of lines) {
43
+ if (/to deploy to production/i.test(line)) continue
44
+ const url = pickUrl(line)
45
+ if (url) return url
46
+ }
47
+
48
+ return null
25
49
  }
26
50
 
27
51
  export function parseDeployUrlFromVercelListOutput(output, projectNameHint) {
@@ -72,7 +96,7 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
72
96
  strict: strictOverride,
73
97
  } = options || {}
74
98
 
75
- const strictDefault = environment !== 'development'
99
+ const strictDefault = true
76
100
 
77
101
  const strictEnv = process.env.DX_TELEGRAM_WEBHOOK_STRICT != null
78
102
  ? !['0', 'false', 'no'].includes(String(process.env.DX_TELEGRAM_WEBHOOK_STRICT).toLowerCase())
@@ -103,12 +127,25 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
103
127
  logger.error(` - ${v}`)
104
128
  })
105
129
 
130
+ const message = 'Telegram Webhook 配置失败:缺少必需环境变量'
106
131
  if (strict) {
107
- throw new Error('Telegram Webhook 配置失败:缺少必需环境变量')
132
+ return {
133
+ status: 'failed',
134
+ reason: 'missing_env_vars',
135
+ strict,
136
+ message,
137
+ missingVars,
138
+ }
108
139
  }
109
140
 
110
141
  logger.warn('跳过 Webhook 配置,请手动设置')
111
- return
142
+ return {
143
+ status: 'warning',
144
+ reason: 'missing_env_vars',
145
+ strict,
146
+ message,
147
+ missingVars,
148
+ }
112
149
  }
113
150
 
114
151
  try {
@@ -122,12 +159,22 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
122
159
  projectNameHint,
123
160
  })
124
161
  if (!deploymentUrl) {
162
+ const message = '无法获取 Vercel 部署 URL'
125
163
  if (strict) {
126
- throw new Error('无法获取 Vercel 部署 URL')
164
+ return {
165
+ status: 'failed',
166
+ reason: 'missing_deploy_url',
167
+ strict,
168
+ message,
169
+ }
127
170
  }
128
-
129
171
  logger.error('无法获取 Vercel 部署 URL,跳过 Webhook 配置')
130
- return
172
+ return {
173
+ status: 'warning',
174
+ reason: 'missing_deploy_url',
175
+ strict,
176
+ message,
177
+ }
131
178
  }
132
179
 
133
180
  const webhookUrl = `${deploymentUrl}${webhookPath}`
@@ -135,7 +182,13 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
135
182
 
136
183
  if (dryRun) {
137
184
  logger.warn('DX_TELEGRAM_WEBHOOK_DRY_RUN=1,已跳过 setWebhook/getWebhookInfo 调用')
138
- return
185
+ return {
186
+ status: 'warning',
187
+ reason: 'dry_run',
188
+ strict,
189
+ message: 'DX_TELEGRAM_WEBHOOK_DRY_RUN=1',
190
+ webhookUrl,
191
+ }
139
192
  }
140
193
 
141
194
  // 3. 调用 Telegram API 设置 Webhook
@@ -163,15 +216,38 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
163
216
  logger.info(`Webhook URL: ${webhookUrl}`)
164
217
 
165
218
  // 4. 验证 Webhook 状态
166
- await verifyWebhook(botToken, webhookUrl, { strict })
219
+ const verifyResult = await verifyWebhook(botToken, webhookUrl, { strict })
220
+ if (verifyResult.status === 'success') {
221
+ return {
222
+ status: 'success',
223
+ reason: 'verified',
224
+ strict,
225
+ webhookUrl,
226
+ }
227
+ }
228
+
229
+ return {
230
+ status: strict ? 'failed' : 'warning',
231
+ reason: 'verify_failed',
232
+ strict,
233
+ message: verifyResult.message,
234
+ webhookUrl,
235
+ }
167
236
  }
168
237
  else {
169
238
  const desc = result.description || '未知错误'
239
+ const message = `Telegram Webhook 设置失败: ${desc}`
170
240
  if (strict) {
171
- throw new Error(`Telegram Webhook 设置失败: ${desc}`)
241
+ return {
242
+ status: 'failed',
243
+ reason: 'set_webhook_failed',
244
+ strict,
245
+ message,
246
+ webhookUrl,
247
+ }
172
248
  }
173
249
 
174
- logger.error(`Telegram Webhook 设置失败: ${desc}`)
250
+ logger.error(message)
175
251
  logger.info('请手动执行以下命令(不要把明文 token/secret 写进日志):')
176
252
  const manualPayload = JSON.stringify({
177
253
  url: webhookUrl,
@@ -181,15 +257,28 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
181
257
  logger.info(
182
258
  `curl -X POST "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook" -H "Content-Type: application/json" -d '${manualPayload}' --silent`,
183
259
  )
260
+ return {
261
+ status: 'warning',
262
+ reason: 'set_webhook_failed',
263
+ strict,
264
+ message,
265
+ webhookUrl,
266
+ }
184
267
  }
185
268
  }
186
269
  catch (error) {
187
270
  const message = error?.message || String(error)
188
271
  logger.error(`Webhook 配置失败: ${message}`)
189
272
 
190
- if (strict) throw error
191
-
192
- logger.warn('请手动设置 Webhook(参考 apps/telegram-bot/README.md)')
273
+ if (!strict) {
274
+ logger.warn('请手动设置 Webhook(参考 apps/telegram-bot/README.md)')
275
+ }
276
+ return {
277
+ status: strict ? 'failed' : 'warning',
278
+ reason: 'runtime_error',
279
+ strict,
280
+ message,
281
+ }
193
282
  }
194
283
  }
195
284
 
@@ -315,19 +404,28 @@ async function verifyWebhook(botToken, expectedWebhookUrl, options = {}) {
315
404
 
316
405
  if (expectedWebhookUrl && info.url !== expectedWebhookUrl) {
317
406
  const message = `Webhook 未生效:期望 ${expectedWebhookUrl},实际 ${info.url || '(empty)'}`
318
- if (strict) throw new Error(message)
407
+ if (strict) {
408
+ return { status: 'failed', message }
409
+ }
319
410
  logger.warn(message)
411
+ return { status: 'warning', message }
320
412
  }
413
+ return { status: 'success' }
321
414
  }
322
415
  else {
323
416
  const desc = result?.description || '未知错误'
324
417
  const message = `getWebhookInfo 失败: ${desc}`
325
- if (strict) throw new Error(message)
418
+ if (strict) {
419
+ return { status: 'failed', message }
420
+ }
326
421
  logger.warn(message)
422
+ return { status: 'warning', message }
327
423
  }
328
424
  }
329
425
  catch (error) {
330
- if (strict) throw error
426
+ const message = error?.message || String(error)
427
+ if (strict) return { status: 'failed', message }
331
428
  logger.warn('无法验证 Webhook 状态')
429
+ return { status: 'warning', message: '无法验证 Webhook 状态' }
332
430
  }
333
431
  }
@@ -260,6 +260,7 @@ export async function deployToVercel(target, options = {}) {
260
260
  const {
261
261
  environment = 'staging',
262
262
  telegramWebhook = null,
263
+ telegramWebhookHandler = null,
263
264
  strictContext = true,
264
265
  run = runVercel
265
266
  } = options
@@ -482,13 +483,26 @@ export async function deployToVercel(target, options = {}) {
482
483
 
483
484
  // Telegram Bot 部署成功后自动设置 Webhook(并做严格校验)
484
485
  if (t === 'telegram-bot') {
485
- const { handleTelegramBotDeploy } = await import('./telegram-webhook.js')
486
- await handleTelegramBotDeploy(environment, projectId, orgId, token, {
486
+ const resolvedWebhookHandler = telegramWebhookHandler
487
+ || (await import('./telegram-webhook.js')).handleTelegramBotDeploy
488
+ const webhookResult = await resolvedWebhookHandler(environment, projectId, orgId, token, {
487
489
  deployOutput,
488
490
  projectNameHint: 'telegram-bot',
489
491
  ...(telegramWebhook || {})
490
492
  })
491
- logger.success(`${t} 部署成功(Webhook 已校验)`)
493
+
494
+ if (webhookResult?.status === 'success') {
495
+ logger.success(`${t} 部署成功(Webhook 已校验)`)
496
+ } else if (webhookResult?.status === 'failed') {
497
+ const reason = webhookResult?.message || webhookResult?.reason || '未知原因'
498
+ logger.error(`${t} 部署成功,但 Webhook 配置失败: ${reason}`)
499
+ process.exitCode = 1
500
+ return
501
+ } else {
502
+ const reason = webhookResult?.message || webhookResult?.reason || '未严格校验'
503
+ logger.warn(`${t} 部署成功,但 Webhook 未完成校验: ${reason}`)
504
+ logger.success(`${t} 部署成功`)
505
+ }
492
506
  } else {
493
507
  logger.success(`${t} 部署成功`)
494
508
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ranger1/dx",
3
- "version": "0.1.67",
3
+ "version": "0.1.68",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {