@alipay/alipay-aipay 0.1.1-beta.1

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.
Files changed (114) hide show
  1. package/README.md +1 -0
  2. package/bin/alipay-aipay.js +6 -0
  3. package/dist/commands/install.d.ts +10 -0
  4. package/dist/commands/install.d.ts.map +1 -0
  5. package/dist/commands/install.js +92 -0
  6. package/dist/commands/install.js.map +1 -0
  7. package/dist/commands/uninstall.d.ts +10 -0
  8. package/dist/commands/uninstall.d.ts.map +1 -0
  9. package/dist/commands/uninstall.js +82 -0
  10. package/dist/commands/uninstall.js.map +1 -0
  11. package/dist/commands/update.d.ts +10 -0
  12. package/dist/commands/update.d.ts.map +1 -0
  13. package/dist/commands/update.js +125 -0
  14. package/dist/commands/update.js.map +1 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +51 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/types.d.ts +43 -0
  20. package/dist/types.d.ts.map +1 -0
  21. package/dist/types.js +2 -0
  22. package/dist/types.js.map +1 -0
  23. package/dist/utils/alipay-cli.d.ts +15 -0
  24. package/dist/utils/alipay-cli.d.ts.map +1 -0
  25. package/dist/utils/alipay-cli.js +228 -0
  26. package/dist/utils/alipay-cli.js.map +1 -0
  27. package/dist/utils/config.d.ts +48 -0
  28. package/dist/utils/config.d.ts.map +1 -0
  29. package/dist/utils/config.js +207 -0
  30. package/dist/utils/config.js.map +1 -0
  31. package/dist/utils/file.d.ts +55 -0
  32. package/dist/utils/file.d.ts.map +1 -0
  33. package/dist/utils/file.js +154 -0
  34. package/dist/utils/file.js.map +1 -0
  35. package/dist/utils/gpg.d.ts +14 -0
  36. package/dist/utils/gpg.d.ts.map +1 -0
  37. package/dist/utils/gpg.js +247 -0
  38. package/dist/utils/gpg.js.map +1 -0
  39. package/dist/utils/jq.d.ts +14 -0
  40. package/dist/utils/jq.d.ts.map +1 -0
  41. package/dist/utils/jq.js +221 -0
  42. package/dist/utils/jq.js.map +1 -0
  43. package/dist/utils/npm.d.ts +17 -0
  44. package/dist/utils/npm.d.ts.map +1 -0
  45. package/dist/utils/npm.js +42 -0
  46. package/dist/utils/npm.js.map +1 -0
  47. package/dist/utils/shell.d.ts +11 -0
  48. package/dist/utils/shell.d.ts.map +1 -0
  49. package/dist/utils/shell.js +54 -0
  50. package/dist/utils/shell.js.map +1 -0
  51. package/package.json +53 -0
  52. package/skill/SKILL.md +118 -0
  53. package/skill/references/integration/flow.md +487 -0
  54. package/skill/references/integration/modules/alipay-sdk-reminder.md +256 -0
  55. package/skill/references/integration/modules/checklist.md +122 -0
  56. package/skill/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +68 -0
  57. package/skill/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +77 -0
  58. package/skill/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +74 -0
  59. package/skill/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +73 -0
  60. package/skill/references/integration/modules/code-examples/csharp/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +58 -0
  61. package/skill/references/integration/modules/code-examples/csharp/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +128 -0
  62. package/skill/references/integration/modules/code-examples/csharp/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.cs +500 -0
  63. package/skill/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +72 -0
  64. package/skill/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +80 -0
  65. package/skill/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +78 -0
  66. package/skill/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +77 -0
  67. package/skill/references/integration/modules/code-examples/java/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +66 -0
  68. package/skill/references/integration/modules/code-examples/java/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +135 -0
  69. package/skill/references/integration/modules/code-examples/java/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemoController.java +610 -0
  70. package/skill/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +51 -0
  71. package/skill/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +57 -0
  72. package/skill/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +55 -0
  73. package/skill/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +54 -0
  74. package/skill/references/integration/modules/code-examples/nodejs/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +77 -0
  75. package/skill/references/integration/modules/code-examples/nodejs/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +65 -0
  76. package/skill/references/integration/modules/code-examples/nodejs/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.js +461 -0
  77. package/skill/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +59 -0
  78. package/skill/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +67 -0
  79. package/skill/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +66 -0
  80. package/skill/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +65 -0
  81. package/skill/references/integration/modules/code-examples/php/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +56 -0
  82. package/skill/references/integration/modules/code-examples/php/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +107 -0
  83. package/skill/references/integration/modules/code-examples/php/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.php +444 -0
  84. package/skill/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +57 -0
  85. package/skill/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +65 -0
  86. package/skill/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +63 -0
  87. package/skill/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +62 -0
  88. package/skill/references/integration/modules/code-examples/python/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +48 -0
  89. package/skill/references/integration/modules/code-examples/python/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +43 -0
  90. package/skill/references/integration/modules/code-examples/python/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.py +465 -0
  91. package/skill/references/integration/modules/interface-guide.md +90 -0
  92. package/skill/references/integration/modules/product-decision.md +90 -0
  93. package/skill/references/integration/modules/sandbox/a2m-sandbox-test.md +270 -0
  94. package/skill/references/integration/modules/sandbox/alipay-sandbox-tool.md +133 -0
  95. package/skill/references/integration/modules/sandbox/sandbox-setup-guide.md +218 -0
  96. package/skill/references/integration/modules/scripts/local_402_sandbox_pay.py +659 -0
  97. package/skill/references/normal/alipay-cli-env.md +211 -0
  98. package/skill/references/normal/rejection-guide.md +37 -0
  99. package/skill/references/normal/scripts/common.sh +32 -0
  100. package/skill/references/normal/scripts/detect_dev_tool.sh +46 -0
  101. package/skill/references/onboarding/flow.md +571 -0
  102. package/skill/references/onboarding/modules/app-release.md +411 -0
  103. package/skill/references/onboarding/modules/authorization.md +269 -0
  104. package/skill/references/onboarding/modules/error-handling.md +247 -0
  105. package/skill/references/onboarding/modules/mcc-reference.md +209 -0
  106. package/skill/references/onboarding/modules/product-sign.md +304 -0
  107. package/skill/references/onboarding/modules/scripts/app.sh +705 -0
  108. package/skill/references/onboarding/modules/scripts/ar_sign_apply.sh +248 -0
  109. package/skill/references/onboarding/modules/scripts/auth.sh +505 -0
  110. package/skill/references/onboarding/modules/scripts/error_handler.sh +312 -0
  111. package/skill/references/onboarding/modules/scripts/query_sign_status.sh +146 -0
  112. package/skill/references/onboarding/modules/scripts/service.sh +267 -0
  113. package/skill/references/onboarding/modules/scripts/upload_screenshots.sh +152 -0
  114. package/skill/references/onboarding/modules/service-registration.md +294 -0
@@ -0,0 +1,705 @@
1
+ #!/bin/bash
2
+ #=============================================================================
3
+ # 脚本名称: app.sh
4
+ # 功能描述: 应用发布全流程 - 查询/复用 + 创建 + 公钥设置 + 提交审核
5
+ # 调用位置: Step 5.3 应用发布
6
+ # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME
7
+ # list/create 可传 --application-type,未传时按 --product-type/--sales-code 或兼容环境变量推断
8
+ # 用法:
9
+ # app list [--product-type <type> --sales-code <code> --application-type <type>] - 查询已有应用并判断复用/新建
10
+ # app create [--product-type <type> --sales-code <code> --application-type <type>] [--mobile-platform IOS|ANDROID|ALL ...] - 创建新应用
11
+ # app key <appId> <publicKey> - 设置应用公钥
12
+ # app verify-key <appId> [publicKey] - 确认应用公钥已设置
13
+ # app audit <appId> - 提交应用审核
14
+ # app reuse <appId> - 复用已有应用(查询安全密钥)
15
+ # 返回值:
16
+ # list: FLOW:CREATE_NEW | FLOW:SELECT | FLOW:ERROR
17
+ # create: 输出 APP_ID=xxx
18
+ # key: 输出 confirmPageUrl
19
+ # audit: 输出审核结果
20
+ # reuse: FLOW:REUSE_SUCCESS | FLOW:REUSE_NO_KEY | FLOW:ERROR
21
+ #=============================================================================
22
+
23
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
24
+
25
+ # 一次性 source error_handler(含 unwrap_mcp)
26
+ if [ -f "${SCRIPT_DIR}/error_handler.sh" ]; then
27
+ source "${SCRIPT_DIR}/error_handler.sh"
28
+ else
29
+ echo "❌ 缺少错误处理脚本: ${SCRIPT_DIR}/error_handler.sh"
30
+ exit 1
31
+ fi
32
+
33
+ require_command jq || exit 1
34
+ require_command alipay-cli || exit 1
35
+
36
+ parse_app_context_args() {
37
+ while [[ $# -gt 0 ]]; do
38
+ case $1 in
39
+ --product-type)
40
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; return 1; }
41
+ PRODUCT_TYPE="$2"; shift 2 ;;
42
+ --sales-code)
43
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; return 1; }
44
+ SALES_CODE="$2"; shift 2 ;;
45
+ --application-type)
46
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; return 1; }
47
+ APPLICATION_TYPE="$2"; shift 2 ;;
48
+ --mobile-platform)
49
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; return 1; }
50
+ MOBILE_PLATFORM=$(printf '%s' "$2" | tr '[:lower:]' '[:upper:]'); shift 2 ;;
51
+ --bundle-id)
52
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; return 1; }
53
+ BUNDLE_ID="$2"; shift 2 ;;
54
+ --app-package)
55
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; return 1; }
56
+ APP_PACKAGE="$2"; shift 2 ;;
57
+ --app-sign)
58
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; return 1; }
59
+ APP_SIGN="$2"; shift 2 ;;
60
+ *)
61
+ echo "❌ 未知参数: $1"
62
+ return 1 ;;
63
+ esac
64
+ done
65
+ }
66
+
67
+ validate_mobile_platform_args() {
68
+ local APP_APPLICATION_TYPE="$1"
69
+
70
+ if [ -z "${MOBILE_PLATFORM:-}" ]; then
71
+ if [ -n "${BUNDLE_ID:-}" ] || [ -n "${APP_PACKAGE:-}" ] || [ -n "${APP_SIGN:-}" ]; then
72
+ echo "❌ bundleId/appPackage/appSign 必须与 --mobile-platform 一起传入" >&2
73
+ return 1
74
+ fi
75
+ if [ "$APP_APPLICATION_TYPE" = "MOBILEAPP" ]; then
76
+ echo "❌ 创建 MOBILEAPP 必须传 --mobile-platform IOS|ANDROID|ALL" >&2
77
+ echo "📋 IOS 需同时传 --bundle-id;ANDROID 需同时传 --app-package 和 --app-sign;ALL 需三项都传" >&2
78
+ return 1
79
+ fi
80
+ return 0
81
+ fi
82
+
83
+ if [ "$APP_APPLICATION_TYPE" != "MOBILEAPP" ]; then
84
+ echo "❌ --mobile-platform 仅支持 MOBILEAPP 创建场景" >&2
85
+ return 1
86
+ fi
87
+
88
+ case "$MOBILE_PLATFORM" in
89
+ IOS)
90
+ if [ -z "${BUNDLE_ID:-}" ]; then
91
+ echo "❌ mobilePlatform=IOS 时必须传 --bundle-id" >&2
92
+ return 1
93
+ fi
94
+ if [ -n "${APP_PACKAGE:-}" ] || [ -n "${APP_SIGN:-}" ]; then
95
+ echo "❌ mobilePlatform=IOS 时不应传 --app-package 或 --app-sign;如需同时支持 iOS 和 Android,请使用 --mobile-platform ALL" >&2
96
+ return 1
97
+ fi
98
+ ;;
99
+ ANDROID)
100
+ if [ -z "${APP_PACKAGE:-}" ] || [ -z "${APP_SIGN:-}" ]; then
101
+ echo "❌ mobilePlatform=ANDROID 时必须传 --app-package 和 --app-sign" >&2
102
+ return 1
103
+ fi
104
+ if [ -n "${BUNDLE_ID:-}" ]; then
105
+ echo "❌ mobilePlatform=ANDROID 时不应传 --bundle-id;如需同时支持 iOS 和 Android,请使用 --mobile-platform ALL" >&2
106
+ return 1
107
+ fi
108
+ ;;
109
+ ALL)
110
+ if [ -z "${BUNDLE_ID:-}" ] || [ -z "${APP_PACKAGE:-}" ] || [ -z "${APP_SIGN:-}" ]; then
111
+ echo "❌ mobilePlatform=ALL 时必须传 --bundle-id、--app-package 和 --app-sign" >&2
112
+ return 1
113
+ fi
114
+ ;;
115
+ *)
116
+ echo "❌ --mobile-platform 参数值无效: ${MOBILE_PLATFORM}(仅支持 IOS|ANDROID|ALL)" >&2
117
+ return 1
118
+ ;;
119
+ esac
120
+ }
121
+
122
+ build_create_application_request() {
123
+ local APP_APPLICATION_TYPE="$1"
124
+
125
+ if [ -z "${MOBILE_PLATFORM:-}" ]; then
126
+ jq -n --arg applicationType "$APP_APPLICATION_TYPE" \
127
+ '{request:{applicationType:$applicationType,createScene:"cli"}}'
128
+ return 0
129
+ fi
130
+
131
+ jq -n \
132
+ --arg applicationType "$APP_APPLICATION_TYPE" \
133
+ --arg mobilePlatform "$MOBILE_PLATFORM" \
134
+ --arg bundleId "${BUNDLE_ID:-}" \
135
+ --arg appPackage "${APP_PACKAGE:-}" \
136
+ --arg appSign "${APP_SIGN:-}" \
137
+ '{
138
+ request: (
139
+ {
140
+ applicationType:$applicationType,
141
+ createScene:"cli",
142
+ mobilePlatform:$mobilePlatform
143
+ }
144
+ + (if $bundleId != "" then {bundleId:$bundleId} else {} end)
145
+ + (if $appPackage != "" then {appPackage:$appPackage} else {} end)
146
+ + (if $appSign != "" then {appSign:$appSign} else {} end)
147
+ )
148
+ }'
149
+ }
150
+
151
+ validate_app_context() {
152
+ local EXPECTED_PRODUCT_TYPE=""
153
+ local EXPECTED_APPLICATION_TYPE=""
154
+
155
+ if [ -n "${PRODUCT_TYPE:-}" ] && [ "$PRODUCT_TYPE" != "aipay" ] && [ "$PRODUCT_TYPE" != "webpay" ] && [ "$PRODUCT_TYPE" != "apppay" ]; then
156
+ echo "❌ --product-type 参数值无效: ${PRODUCT_TYPE}(仅支持 aipay|webpay|apppay)" >&2
157
+ return 1
158
+ fi
159
+
160
+ case "${SALES_CODE:-}" in
161
+ "") ;;
162
+ "I1080300001000160457") EXPECTED_PRODUCT_TYPE="aipay" ;;
163
+ "I1080300001000041203") EXPECTED_PRODUCT_TYPE="webpay" ;;
164
+ "I1080300001000041313") EXPECTED_PRODUCT_TYPE="apppay" ;;
165
+ *) echo "❌ 未知 salesCode: ${SALES_CODE}" >&2; return 1 ;;
166
+ esac
167
+
168
+ if [ -n "$EXPECTED_PRODUCT_TYPE" ] && [ -n "${PRODUCT_TYPE:-}" ] && [ "$PRODUCT_TYPE" != "$EXPECTED_PRODUCT_TYPE" ]; then
169
+ echo "❌ --product-type 与 --sales-code 不匹配:--product-type=${PRODUCT_TYPE}, --sales-code=${SALES_CODE}" >&2
170
+ echo "📋 期望 --product-type=${EXPECTED_PRODUCT_TYPE}" >&2
171
+ return 1
172
+ fi
173
+
174
+ case "${PRODUCT_TYPE:-$EXPECTED_PRODUCT_TYPE}" in
175
+ apppay) EXPECTED_APPLICATION_TYPE="MOBILEAPP" ;;
176
+ aipay|webpay) EXPECTED_APPLICATION_TYPE="WEBAPP" ;;
177
+ esac
178
+
179
+ if [ -n "$EXPECTED_APPLICATION_TYPE" ] && [ -n "${APPLICATION_TYPE:-}" ] && [ "$APPLICATION_TYPE" != "$EXPECTED_APPLICATION_TYPE" ]; then
180
+ echo "❌ --application-type 与产品上下文不匹配:--application-type=${APPLICATION_TYPE}" >&2
181
+ echo "📋 期望 --application-type=${EXPECTED_APPLICATION_TYPE}" >&2
182
+ return 1
183
+ fi
184
+ }
185
+
186
+ resolve_application_type() {
187
+ validate_app_context || return 1
188
+
189
+ if [ -n "${APPLICATION_TYPE:-}" ]; then
190
+ case "$APPLICATION_TYPE" in
191
+ WEBAPP|MOBILEAPP) echo "$APPLICATION_TYPE" ;;
192
+ *) echo "❌ APPLICATION_TYPE 参数值无效: ${APPLICATION_TYPE}(仅支持 WEBAPP|MOBILEAPP)" >&2; return 1 ;;
193
+ esac
194
+ return 0
195
+ fi
196
+
197
+ if [ "${PRODUCT_TYPE:-}" = "apppay" ] || [ "${SALES_CODE:-}" = "I1080300001000041313" ]; then
198
+ echo "MOBILEAPP"
199
+ else
200
+ echo "WEBAPP"
201
+ fi
202
+ }
203
+
204
+ query_security_key() {
205
+ local APP_ID="$1"
206
+ local PUBLIC_KEY="${2:-}"
207
+
208
+ if [ -n "$PUBLIC_KEY" ]; then
209
+ REQUEST_JSON=$(jq -n \
210
+ --arg appId "$APP_ID" \
211
+ --arg publicKey "$PUBLIC_KEY" \
212
+ '{request:{appId:$appId,publicKey:$publicKey}}')
213
+ else
214
+ REQUEST_JSON=$(jq -n --arg appId "$APP_ID" '{request:{appId:$appId}}')
215
+ fi
216
+
217
+ RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call apprelease.queryApplicationSecurityKey \
218
+ -d "$REQUEST_JSON" \
219
+ --json 2>/dev/null)
220
+
221
+ if ! handle_error "$RESULT"; then
222
+ return 1
223
+ fi
224
+
225
+ SECURITY_BUSINESS=$(unwrap_mcp "$RESULT")
226
+ SUCCESS=$(echo "$SECURITY_BUSINESS" | jq -r '.success // false')
227
+
228
+ if [ "$SUCCESS" != "true" ]; then
229
+ ERROR_MSG=$(echo "$SECURITY_BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
230
+ echo "❌ 查询安全密钥失败: $ERROR_MSG"
231
+ return 1
232
+ fi
233
+ }
234
+
235
+ query_application_info() {
236
+ local APP_ID="$1"
237
+
238
+ REQUEST_JSON=$(jq -n --arg appId "$APP_ID" '{request:{appId:$appId}}')
239
+ RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call apprelease.queryApplicationInfo \
240
+ -d "$REQUEST_JSON" \
241
+ --json 2>/dev/null)
242
+
243
+ if ! handle_error "$RESULT"; then
244
+ return 1
245
+ fi
246
+
247
+ APPLICATION_INFO_BUSINESS=$(unwrap_mcp "$RESULT")
248
+ SUCCESS=$(echo "$APPLICATION_INFO_BUSINESS" | jq -r '.success // false')
249
+
250
+ if [ "$SUCCESS" != "true" ]; then
251
+ ERROR_MSG=$(echo "$APPLICATION_INFO_BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
252
+ echo "❌ 查询应用信息失败: $ERROR_MSG"
253
+ return 1
254
+ fi
255
+ }
256
+
257
+ extract_application_status() {
258
+ echo "$APPLICATION_INFO_BUSINESS" | jq -r '
259
+ .resultObj.status //
260
+ empty
261
+ '
262
+ }
263
+
264
+ extract_rsa2_key_info() {
265
+ echo "$SECURITY_BUSINESS" | jq -c '
266
+ (
267
+ (.resultObj.alipayKeyList // []) +
268
+ (.resultObj.securityKeys // []) +
269
+ (.data.alipayKeyList // []) +
270
+ (.data.securityKeys // [])
271
+ ) | map(select(.signType == "RSA2")) | .[0] // {}
272
+ '
273
+ }
274
+
275
+ extract_rsa2_security_config() {
276
+ echo "$SECURITY_BUSINESS" | jq -c '
277
+ (
278
+ (.resultObj.securityConfigList // []) +
279
+ (.data.securityConfigList // [])
280
+ ) | map(select(.signType == "RSA2")) | .[0] // {}
281
+ '
282
+ }
283
+
284
+ is_rsa2_application_key_ready() {
285
+ local RSA2_KEY_INFO="$1"
286
+ local RSA2_SECURITY_CONFIG="$2"
287
+
288
+ echo "$RSA2_KEY_INFO" | jq -e '
289
+ ((.certInfoDTO.publicKey // .publicKey // .alipayPublicKey // "") != "")
290
+ ' >/dev/null 2>&1 && return 0
291
+
292
+ echo "$RSA2_SECURITY_CONFIG" | jq -e '
293
+ ((.partnerPublicKey // "") != "") and (.invalid != true)
294
+ ' >/dev/null 2>&1
295
+ }
296
+
297
+ write_alipay_public_key() {
298
+ local APP_ID="$1"
299
+ local ALIPAY_PUBLIC_KEY="$2"
300
+
301
+ local KEY_FILE="${HOME}/.config/${APP_ID}-alipayPublicKey.keytext"
302
+ local ATTEMPT=1
303
+ local MAX_ATTEMPTS="${ALIPAY_PUBLIC_KEY_WRITE_RETRIES:-3}"
304
+
305
+ if ! [[ "$MAX_ATTEMPTS" =~ ^[1-9][0-9]*$ ]]; then
306
+ MAX_ATTEMPTS=3
307
+ fi
308
+
309
+ while [ "$ATTEMPT" -le "$MAX_ATTEMPTS" ]; do
310
+ if { mkdir -p "${HOME}/.config" && printf '%s\n' "$ALIPAY_PUBLIC_KEY" > "$KEY_FILE"; } 2>/dev/null; then
311
+ return 0
312
+ fi
313
+
314
+ if [ "$ATTEMPT" -lt "$MAX_ATTEMPTS" ]; then
315
+ echo "⚠️ 支付宝公钥文件写入失败,正在重试(${ATTEMPT}/${MAX_ATTEMPTS})..."
316
+ sleep 1
317
+ fi
318
+ ATTEMPT=$((ATTEMPT + 1))
319
+ done
320
+
321
+ echo "⚠️ 已获取到 RSA2 支付宝公钥,但本地文件写入失败: $KEY_FILE"
322
+ echo "📋 这不是公钥查询失败;当前流程会继续,但后续集成时需要手动配置支付宝公钥。"
323
+ echo "📋 可检查本地目录权限或设置 HOME 后重新执行导出。"
324
+ return 1
325
+ }
326
+
327
+ ensure_rsa2_application_key_ready() {
328
+ local APP_ID="$1"
329
+ local PUBLIC_KEY="${2:-}"
330
+ local ATTEMPT=1
331
+ local MAX_ATTEMPTS="${APP_KEY_VERIFY_RETRIES:-6}"
332
+ local INTERVAL_SECONDS="${APP_KEY_VERIFY_INTERVAL_SECONDS:-5}"
333
+
334
+ if ! [[ "$MAX_ATTEMPTS" =~ ^[1-9][0-9]*$ ]]; then
335
+ MAX_ATTEMPTS=6
336
+ fi
337
+
338
+ if ! [[ "$INTERVAL_SECONDS" =~ ^[0-9]+$ ]]; then
339
+ INTERVAL_SECONDS=5
340
+ fi
341
+
342
+ while [ "$ATTEMPT" -le "$MAX_ATTEMPTS" ]; do
343
+ query_security_key "$APP_ID" "$PUBLIC_KEY" || return 1
344
+
345
+ RSA2_KEY_INFO=$(extract_rsa2_key_info)
346
+ RSA2_SECURITY_CONFIG=$(extract_rsa2_security_config)
347
+
348
+ if is_rsa2_application_key_ready "$RSA2_KEY_INFO" "$RSA2_SECURITY_CONFIG"; then
349
+ return 0
350
+ fi
351
+
352
+ if [ "$ATTEMPT" -lt "$MAX_ATTEMPTS" ]; then
353
+ echo "⏳ 支付宝侧尚未确认到应用公钥生效,正在重试(${ATTEMPT}/${MAX_ATTEMPTS})..."
354
+ sleep "$INTERVAL_SECONDS"
355
+ fi
356
+
357
+ ATTEMPT=$((ATTEMPT + 1))
358
+ done
359
+
360
+ echo "❌ 应用公钥尚未确认,请先完成公钥设置确认"
361
+ return 1
362
+ }
363
+
364
+ ensure_alipay_public_key_exported() {
365
+ local APP_ID="$1"
366
+
367
+ query_security_key "$APP_ID" || return 1
368
+
369
+ RSA2_KEY_INFO=$(extract_rsa2_key_info)
370
+ RSA2_SECURITY_CONFIG=$(extract_rsa2_security_config)
371
+ ALIPAY_PUBLIC_KEY=$(echo "$RSA2_KEY_INFO" | jq -r '.alipayPublicKey // empty')
372
+
373
+ if ! is_rsa2_application_key_ready "$RSA2_KEY_INFO" "$RSA2_SECURITY_CONFIG"; then
374
+ echo "❌ 应用公钥尚未确认,禁止提交应用审核"
375
+ return 1
376
+ fi
377
+
378
+ if [ -z "$ALIPAY_PUBLIC_KEY" ]; then
379
+ echo "❌ 未获取到 RSA2 支付宝公钥,禁止提交应用审核"
380
+ return 1
381
+ fi
382
+
383
+ if write_alipay_public_key "$APP_ID" "$ALIPAY_PUBLIC_KEY"; then
384
+ echo "✅ 已确认应用公钥并导出支付宝公钥"
385
+ echo "支付宝公钥保存路径: ~/.config/${APP_ID}-alipayPublicKey.keytext"
386
+ echo "ALIPAY_PUBLIC_KEY_FILE=~/.config/${APP_ID}-alipayPublicKey.keytext"
387
+ fi
388
+ }
389
+
390
+ # ─── app list: 查询已有应用 ──────────────────────────────────────────────────
391
+ app_list() {
392
+ parse_app_context_args "$@" || {
393
+ echo "用法: bash app.sh list [--product-type aipay|webpay|apppay] [--sales-code <code>] [--application-type WEBAPP|MOBILEAPP]"
394
+ exit 1
395
+ }
396
+ APP_APPLICATION_TYPE=$(resolve_application_type) || exit 1
397
+ REQUEST_JSON=$(jq -n --arg applicationType "$APP_APPLICATION_TYPE" '{request:{appTypes:[$applicationType]}}')
398
+
399
+ RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call apprelease.queryApplicationList \
400
+ -d "$REQUEST_JSON" \
401
+ --json 2>/dev/null)
402
+
403
+ # 错误检测
404
+ if ! handle_error "$RESULT"; then
405
+ exit 1
406
+ fi
407
+
408
+ # 解包 MCP 信封后解析业务字段
409
+ BUSINESS=$(unwrap_mcp "$RESULT")
410
+ SUCCESS=$(echo "$BUSINESS" | jq -r '.success // false')
411
+
412
+ if [ "$SUCCESS" != "true" ]; then
413
+ ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
414
+ echo "❌ 查询应用列表失败: $ERROR_MSG"
415
+ echo "FLOW:ERROR"
416
+ exit 1
417
+ fi
418
+
419
+ APP_LIST=$(echo "$BUSINESS" | jq -c '
420
+ if (.resultObj | type) == "object" and (.resultObj.applicationList | type) == "array" then
421
+ .resultObj.applicationList
422
+ elif (.resultObj | type) == "array" then
423
+ .resultObj
424
+ else
425
+ []
426
+ end
427
+ ' 2>/dev/null)
428
+ if [ -z "$APP_LIST" ] || ! echo "$APP_LIST" | jq -e 'type == "array"' >/dev/null 2>&1; then
429
+ echo "❌ 应用列表返回结构异常,无法解析应用列表"
430
+ echo "FLOW:ERROR"
431
+ exit 1
432
+ fi
433
+ APP_COUNT=$(echo "$APP_LIST" | jq 'length')
434
+
435
+ if [ "$APP_COUNT" -eq 0 ]; then
436
+ echo "📋 暂无 ${APP_APPLICATION_TYPE} 应用,进入创建应用流程"
437
+ echo "FLOW:CREATE_NEW"
438
+ else
439
+ # 实际返回的状态字段值是 "ON_LINE"(带下划线)
440
+ ONLINE_APPS=$(echo "$APP_LIST" | jq -r '[.[] | select(.status == "ON_LINE")]')
441
+ ONLINE_COUNT=$(echo "$ONLINE_APPS" | jq 'length')
442
+ ONLINE_COUNT=${ONLINE_COUNT:-0}
443
+
444
+ if [ "$ONLINE_COUNT" -eq 0 ]; then
445
+ echo "📋 暂无上线 ${APP_APPLICATION_TYPE} 应用,进入创建应用流程"
446
+ echo "FLOW:CREATE_NEW"
447
+ else
448
+ echo "📋 发现您已有以下上线 ${APP_APPLICATION_TYPE} 应用:"
449
+ echo ""
450
+ echo "| 序号 | 应用ID | 应用名称 | 状态 |"
451
+ echo "|------|--------|----------|------|"
452
+
453
+ for i in $(seq 0 $((ONLINE_COUNT-1))); do
454
+ APP=$(echo "$ONLINE_APPS" | jq ".[$i]")
455
+ APP_ID=$(echo "$APP" | jq -r '.appId // "未知"')
456
+ APP_NAME=$(echo "$APP" | jq -r '.appName // "未知"')
457
+ echo "| $((i+1)) | $APP_ID | $APP_NAME | 已上线 |"
458
+ done
459
+
460
+ echo ""
461
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
462
+ echo " 请选择操作:"
463
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
464
+ echo ""
465
+ echo " 【复用】输入序号 (1-$ONLINE_COUNT) → 复用对应应用"
466
+ echo " 【新建】输入 \"新建\" → 创建新应用"
467
+ echo ""
468
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
469
+ echo "FLOW:SELECT"
470
+ fi
471
+ fi
472
+ }
473
+
474
+ # ─── app create: 创建新应用 ──────────────────────────────────────────────────
475
+ app_create() {
476
+ parse_app_context_args "$@" || {
477
+ echo "用法: bash app.sh create [--product-type aipay|webpay|apppay] [--sales-code <code>] [--application-type WEBAPP|MOBILEAPP] [--mobile-platform IOS|ANDROID|ALL --bundle-id <id> --app-package <pkg> --app-sign <sign>]"
478
+ exit 1
479
+ }
480
+ APP_APPLICATION_TYPE=$(resolve_application_type) || exit 1
481
+ validate_mobile_platform_args "$APP_APPLICATION_TYPE" || exit 1
482
+ REQUEST_JSON=$(build_create_application_request "$APP_APPLICATION_TYPE") || {
483
+ echo "❌ 创建应用请求参数组装失败"
484
+ exit 1
485
+ }
486
+
487
+ RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call apprelease.createApplication \
488
+ -d "$REQUEST_JSON" \
489
+ --json 2>/dev/null)
490
+
491
+ # 错误检测
492
+ if ! handle_error "$RESULT"; then
493
+ exit 1
494
+ fi
495
+
496
+ # 解包 MCP 信封
497
+ BUSINESS=$(unwrap_mcp "$RESULT")
498
+ SUCCESS=$(echo "$BUSINESS" | jq -r '.success // false')
499
+
500
+ if [ "$SUCCESS" = "true" ]; then
501
+ APP_ID=$(echo "$BUSINESS" | jq -r '.resultObj.appId // .data.appId // empty')
502
+ echo "✅ 应用创建成功"
503
+ echo "APPLICATION_TYPE=$APP_APPLICATION_TYPE"
504
+ echo "APP_ID=$APP_ID"
505
+ else
506
+ ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
507
+ echo "❌ 应用创建失败: $ERROR_MSG"
508
+ exit 1
509
+ fi
510
+ }
511
+
512
+ # ─── app key: 设置应用公钥 ───────────────────────────────────────────────────
513
+ app_key() {
514
+ APP_ID="$1"
515
+ PUBLIC_KEY="$2"
516
+
517
+ if [ -z "$APP_ID" ] || [ -z "$PUBLIC_KEY" ]; then
518
+ echo "❌ 请提供 appId 和 publicKey"
519
+ echo "用法: bash app.sh key <appId> <publicKey>"
520
+ exit 1
521
+ fi
522
+
523
+ REQUEST_JSON=$(jq -n \
524
+ --arg appId "$APP_ID" \
525
+ --arg publicKey "$PUBLIC_KEY" \
526
+ '{request:{appId:$appId,signType:"RSA2",publicKey:$publicKey}}')
527
+
528
+ RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call apprelease.createKeyConfirmPage \
529
+ -d "$REQUEST_JSON" \
530
+ --json 2>/dev/null)
531
+
532
+ # 错误检测
533
+ if ! handle_error "$RESULT"; then
534
+ exit 1
535
+ fi
536
+
537
+ # 解包 MCP 信封
538
+ BUSINESS=$(unwrap_mcp "$RESULT")
539
+ SUCCESS=$(echo "$BUSINESS" | jq -r '.success // false')
540
+
541
+ if [ "$SUCCESS" = "true" ]; then
542
+ CONFIRM_PAGE_URL=$(echo "$BUSINESS" | jq -r '.resultObj.confirmPageUrl // empty')
543
+
544
+ if [ -n "$CONFIRM_PAGE_URL" ]; then
545
+ echo "📋 应用公钥设置中..."
546
+ echo ""
547
+ echo "请点击以下链接确认公钥设置:"
548
+ echo ""
549
+ echo "[点击确认公钥设置]($CONFIRM_PAGE_URL)(无法跳链时,请复制链接到网页浏览器打开)"
550
+ echo ""
551
+ echo "链接有效期为10分钟。"
552
+ echo ""
553
+ echo "确认完成后,请告诉我\"好了\"继续后续流程。"
554
+ else
555
+ echo "❌ 未获取到确认页面链接,请重试"
556
+ exit 1
557
+ fi
558
+ else
559
+ ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
560
+ echo "❌ 公钥设置失败: $ERROR_MSG"
561
+ exit 1
562
+ fi
563
+ }
564
+
565
+ # ─── app audit: 提交应用审核 ─────────────────────────────────────────────────
566
+ app_audit() {
567
+ APP_ID="$1"
568
+
569
+ if [ -z "$APP_ID" ]; then
570
+ echo "❌ 请提供 appId"
571
+ echo "用法: bash app.sh audit <appId>"
572
+ exit 1
573
+ fi
574
+
575
+ ensure_alipay_public_key_exported "$APP_ID" || exit 1
576
+
577
+ REQUEST_JSON=$(jq -n --arg appId "$APP_ID" '{request:{appId:$appId}}')
578
+
579
+ RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call apprelease.submitApplicationAudit \
580
+ -d "$REQUEST_JSON" \
581
+ --json 2>/dev/null)
582
+
583
+ # 错误检测
584
+ if ! handle_error "$RESULT"; then
585
+ exit 1
586
+ fi
587
+
588
+ # 解包 MCP 信封
589
+ BUSINESS=$(unwrap_mcp "$RESULT")
590
+ SUCCESS=$(echo "$BUSINESS" | jq -r '.success // false')
591
+
592
+ if [ "$SUCCESS" = "true" ]; then
593
+ echo "✅ 应用审核提交成功"
594
+ echo "APP_ID=$APP_ID"
595
+ echo "FLOW:AUDIT_SUBMITTED"
596
+ else
597
+ ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
598
+ echo "❌ 提交审核失败: $ERROR_MSG"
599
+ exit 1
600
+ fi
601
+ }
602
+
603
+ # ─── app verify-key: 确认应用公钥已设置 ─────────────────────────────────────
604
+ app_verify_key() {
605
+ APP_ID="$1"
606
+ PUBLIC_KEY="${2:-}"
607
+
608
+ if [ -z "$APP_ID" ]; then
609
+ echo "❌ 请提供 appId"
610
+ echo "用法: bash app.sh verify-key <appId> [publicKey]"
611
+ exit 1
612
+ fi
613
+
614
+ if ensure_rsa2_application_key_ready "$APP_ID" "$PUBLIC_KEY"; then
615
+ echo "✅ 应用公钥已确认"
616
+ echo "APP_ID=$APP_ID"
617
+ echo "FLOW:KEY_CONFIRMED"
618
+ else
619
+ echo "FLOW:KEY_NOT_CONFIRMED"
620
+ exit 1
621
+ fi
622
+ }
623
+
624
+ # ─── app reuse: 复用已有应用(查询安全密钥) ──────────────────────────────────
625
+ app_reuse() {
626
+ APP_ID="$1"
627
+
628
+ if [ -z "$APP_ID" ]; then
629
+ echo "❌ 请提供 appId"
630
+ echo "用法: bash app.sh reuse <appId>"
631
+ exit 1
632
+ fi
633
+
634
+ if query_application_info "$APP_ID"; then
635
+ APP_STATUS=$(extract_application_status)
636
+ if [ "$APP_STATUS" != "ON_LINE" ]; then
637
+ echo "❌ 仅允许复用 ON_LINE(已上线)应用,当前应用状态: ${APP_STATUS:-未知}"
638
+ echo "FLOW:ERROR"
639
+ exit 1
640
+ fi
641
+ else
642
+ echo "FLOW:ERROR"
643
+ exit 1
644
+ fi
645
+
646
+ if query_security_key "$APP_ID"; then
647
+ RSA2_KEY_INFO=$(extract_rsa2_key_info)
648
+ ALIPAY_PUBLIC_KEY=$(echo "$RSA2_KEY_INFO" | jq -r '.alipayPublicKey // empty')
649
+
650
+ if [ -n "$ALIPAY_PUBLIC_KEY" ]; then
651
+ if write_alipay_public_key "$APP_ID" "$ALIPAY_PUBLIC_KEY"; then
652
+ echo "✅ 已获取支付宝公钥"
653
+ echo "支付宝公钥保存路径: ~/.config/${APP_ID}-alipayPublicKey.keytext"
654
+ echo "ALIPAY_PUBLIC_KEY_FILE=~/.config/${APP_ID}-alipayPublicKey.keytext"
655
+ fi
656
+ echo "APP_ID=$APP_ID"
657
+ echo "FLOW:REUSE_SUCCESS"
658
+ else
659
+ echo "⚠️ 未找到 RSA2 公钥,请先设置应用公钥"
660
+ echo "FLOW:REUSE_NO_KEY"
661
+ fi
662
+ else
663
+ echo "FLOW:ERROR"
664
+ exit 1
665
+ fi
666
+ }
667
+
668
+ # ─── 入口分发 ────────────────────────────────────────────────────────────────
669
+ case "${1:-}" in
670
+ list)
671
+ shift
672
+ app_list "$@"
673
+ ;;
674
+ create)
675
+ shift
676
+ app_create "$@"
677
+ ;;
678
+ key)
679
+ shift
680
+ app_key "$@"
681
+ ;;
682
+ verify-key)
683
+ shift
684
+ app_verify_key "$@"
685
+ ;;
686
+ audit)
687
+ shift
688
+ app_audit "$@"
689
+ ;;
690
+ reuse)
691
+ shift
692
+ app_reuse "$@"
693
+ ;;
694
+ *)
695
+ echo "用法: bash app.sh <list|create|key|verify-key|audit|reuse> [参数...]"
696
+ echo ""
697
+ echo " app list [--product-type <type> --sales-code <code> --application-type <type>] - 查询已有应用"
698
+ echo " app create [--product-type <type> --sales-code <code> --application-type <type>] [--mobile-platform IOS|ANDROID|ALL ...] - 创建新应用"
699
+ echo " app key <appId> <pubKey> - 设置公钥"
700
+ echo " app verify-key <appId> [pubKey] - 确认公钥设置结果"
701
+ echo " app audit <appId> - 提交审核"
702
+ echo " app reuse <appId> - 复用应用"
703
+ exit 1
704
+ ;;
705
+ esac