@cloudbase/manager-node 5.8.9-beta.1 → 5.9.0

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 (49) hide show
  1. package/.codebuddy/rules/error-code-contract.mdc +13 -0
  2. package/CHANGELOG.md +1 -0
  3. package/lib/agent/index.js +6 -5
  4. package/lib/aiModel/index.js +21 -9
  5. package/lib/cloudApp/index.js +4 -4
  6. package/lib/cloudrun/index.js +16 -15
  7. package/lib/common/index.js +1 -1
  8. package/lib/database/index.js +23 -23
  9. package/lib/deploy/DatabaseDeployer.js +19 -24
  10. package/lib/deploy/DeployOrchestrator.js +2 -2
  11. package/lib/deploy/FunctionDeployer.js +19 -1
  12. package/lib/deploy/GatewayDeployer.js +5 -5
  13. package/lib/deploy/StaticDeployer.js +2 -2
  14. package/lib/deploy/framework.js +2 -1
  15. package/lib/deploy/function/config-guard.js +23 -3
  16. package/lib/deploy/function/enterprise-tcr.js +18 -2
  17. package/lib/docs/index.js +4 -3
  18. package/lib/env/index.js +16 -16
  19. package/lib/environment.js +4 -4
  20. package/lib/environmentManager.js +5 -1
  21. package/lib/error-docs.js +385 -0
  22. package/lib/error-types.js +21 -0
  23. package/lib/error.js +239 -2
  24. package/lib/function/index.js +135 -41
  25. package/lib/function/packer.js +1 -1
  26. package/lib/hosting/index.js +1 -1
  27. package/lib/index.js +2 -1
  28. package/lib/integration/crypto.js +4 -3
  29. package/lib/integration/index.js +1 -1
  30. package/lib/integration/secretKey.js +4 -4
  31. package/lib/monitor/index.js +1 -1
  32. package/lib/mysql/index.js +2 -1
  33. package/lib/permission/index.js +56 -49
  34. package/lib/platform/index.js +2 -2
  35. package/lib/sandbox/index.js +68 -61
  36. package/lib/storage/index.js +164 -162
  37. package/lib/user/index.js +32 -31
  38. package/lib/utils/cloud-api-request.js +13 -5
  39. package/lib/utils/cloudbase-request.js +21 -0
  40. package/lib/utils/fs.js +3 -3
  41. package/lib/utils/http-request.js +2 -2
  42. package/lib/utils/index.js +4 -3
  43. package/lib/utils/storage-config.js +3 -3
  44. package/package.json +2 -2
  45. package/types/error-docs.d.ts +57 -0
  46. package/types/error-types.d.ts +32 -0
  47. package/types/error.d.ts +148 -2
  48. package/types/function/index.d.ts +14 -1
  49. package/types/utils/cloudbase-request.d.ts +22 -0
@@ -0,0 +1,13 @@
1
+ # 错误码契约(manager-node · 本仓指引)
2
+
3
+ **规则的唯一来源** → `cloudbase-cli/specs/error-rules.md`(**改规则只改那一处**;本文件只写**本仓差异**)。
4
+
5
+ ## 本仓差异
6
+
7
+ - **字段**:三仓应有项全有(含 `docs`、`meta`)+ **本仓专属 `meta.failures`**(多项失败明细登记,见 rules §5)
8
+ - **`docs`**:`this.docs = opts.docs ?? resolveErrorDoc(this.code, this.source)`(**类内派生**,依赖本仓 `src/error-docs.ts`)
9
+ > ⚠️ 映射表**只在本仓并不充分**:TB 侧错误拿不到 `docs` ⇒ 按判据 C 应走**单一来源**(文档站生成)或下沉共享基座;本仓不应成为映射表唯一归属点
10
+ - **机制**:有 `isCloudBaseError` / `isValidErrorCode` / 8 个 helper(含 `throwCredentialError`);**缺 `errorSourceOf`**(R3 前置,待对齐)
11
+ - **守卫**:`test/error.test.ts`(burn-down 平衡括号 + 码表)、`test/error-no-code-baseline.json`(`{}`)
12
+ - **本仓特殊约定**:错误对象是**对外 API**(CLI / MCP / 第三方 SDK 直接读 `.code` / `.docs` / `.meta`)⇒ 字段增删按 §3 冻结形状处理,不随基座版本漂移
13
+ - **新增自造码 ⇒ 必须同步文档站**:到 `cloudbase-docs` 跑 `node scripts/generate-sdk-error-code-pages.mjs`(分层登记页由生成器产出,**勿手工建页**、**勿加进 `basic.md`**;详见该仓 `.codebuddy/skills/error-code-manager`)
package/CHANGELOG.md CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  ## @cloudbase/manager-node v5.8.8 版本发布 🚀(2026-09-18)
2
3
 
3
4
  - 新增平台版套餐服务 PlatformService
@@ -13,6 +13,7 @@ exports.AgentService = void 0;
13
13
  const cloudrun_1 = require("../cloudrun");
14
14
  const type_1 = require("../cloudrun/type");
15
15
  const utils_1 = require("../utils");
16
+ const error_1 = require("../error");
16
17
  const path_1 = __importDefault(require("path"));
17
18
  /**
18
19
  * Agent 管理类
@@ -254,7 +255,7 @@ class AgentService {
254
255
  // 1. 查询 Agent 获取类型
255
256
  const agentListRes = await this.describeAgentList({ AgentId });
256
257
  if (!agentListRes.AgentList || agentListRes.AgentList.length === 0) {
257
- throw new Error(`Agent ${AgentId} 不存在`);
258
+ (0, error_1.throwNotFound)(`Agent ${AgentId} 不存在`);
258
259
  }
259
260
  const agentInfo = agentListRes.AgentList[0];
260
261
  const agentType = agentInfo.AgentType;
@@ -273,7 +274,7 @@ class AgentService {
273
274
  });
274
275
  }
275
276
  else {
276
- throw new Error(`不支持的 Agent 类型: ${agentType}`);
277
+ (0, error_1.throwInvalidParam)(`不支持的 Agent 类型: ${agentType}`);
277
278
  }
278
279
  }
279
280
  /**
@@ -333,7 +334,7 @@ class AgentService {
333
334
  // 1. 查询 Agent 获取类型
334
335
  const agentListRes = await this.describeAgentList({ AgentId });
335
336
  if (!agentListRes.AgentList || agentListRes.AgentList.length === 0) {
336
- throw new Error(`Agent ${AgentId} 不存在`);
337
+ (0, error_1.throwNotFound)(`Agent ${AgentId} 不存在`);
337
338
  }
338
339
  const agentInfo = agentListRes.AgentList[0];
339
340
  const agentType = agentInfo.AgentType;
@@ -368,7 +369,7 @@ class AgentService {
368
369
  });
369
370
  }
370
371
  else {
371
- throw new Error(`不支持的 Agent 类型: ${agentType}`);
372
+ (0, error_1.throwInvalidParam)(`不支持的 Agent 类型: ${agentType}`);
372
373
  }
373
374
  }
374
375
  // ==================== TCBR 云托管(内部方法,暂不对外暴露) ====================
@@ -592,7 +593,7 @@ class AgentService {
592
593
  const envConfig = this.environment.lazyEnvironmentConfig;
593
594
  // 判断 params.BotId 的数据格式是否为 ibot-xxx-xxx 的格式
594
595
  if (!/^ibot-[a-z0-9_]+-[a-z0-9_]+$/.test(BotId)) {
595
- throw new Error('BotId格式应为"ibot-xxx-xxx",其中 xxx 仅支持小写字母、数字或下划线');
596
+ (0, error_1.throwInvalidParam)('BotId格式应为"ibot-xxx-xxx",其中 xxx 仅支持小写字母、数字或下划线');
596
597
  }
597
598
  // 获取函数型云托管服务的名称:ibot-xxx-xxx 中的 ibot-xxx
598
599
  const serverName = BotId.split('-').slice(0, 2).join('-');
@@ -8,6 +8,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.AiModelService = void 0;
10
10
  const utils_1 = require("../utils");
11
+ const error_1 = require("../error");
12
+ /** AI 模型分组状态(CreateAIModel / UpdateAIModel 协议值) */
13
+ const MODEL_STATUS = {
14
+ /** 启用 */
15
+ enabled: 1,
16
+ /** 禁用 */
17
+ disabled: 2
18
+ };
11
19
  class AiModelService {
12
20
  constructor(environment) {
13
21
  this.environment = environment;
@@ -20,13 +28,15 @@ class AiModelService {
20
28
  const { EnvId } = this.environment.lazyEnvironmentConfig;
21
29
  const { envId, groupName, baseUrl, models, remark, status, secret } = options;
22
30
  if (!groupName || groupName.trim().length === 0) {
23
- throw new Error('groupName is required');
31
+ (0, error_1.throwInvalidParam)('groupName is required');
24
32
  }
25
33
  if (groupName.toLowerCase().startsWith('cloudbase')) {
26
- throw new Error('groupName cannot start with cloudbase');
34
+ (0, error_1.throwInvalidParam)('groupName cannot start with cloudbase');
27
35
  }
28
- if (status !== undefined && status !== 1 && status !== 2) {
29
- throw new Error('status must be 1 or 2');
36
+ if (status !== undefined &&
37
+ status !== MODEL_STATUS.enabled &&
38
+ status !== MODEL_STATUS.disabled) {
39
+ (0, error_1.throwInvalidParam)(`status must be ${MODEL_STATUS.enabled} or ${MODEL_STATUS.disabled}`);
30
40
  }
31
41
  return this.tcbService.request('CreateAIModel', Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ EnvId: envId || EnvId, GroupName: groupName }, (baseUrl !== undefined ? { BaseUrl: baseUrl } : {})), (models !== undefined ? { Models: models } : {})), (remark !== undefined ? { Remark: remark } : {})), (status !== undefined ? { Status: status } : {})), (secret !== undefined ? { Secret: secret } : {})));
32
42
  }
@@ -37,10 +47,12 @@ class AiModelService {
37
47
  const { EnvId } = this.environment.lazyEnvironmentConfig;
38
48
  const { envId, groupName, baseUrl, models, remark, status, secret } = options;
39
49
  if (!groupName || groupName.trim().length === 0) {
40
- throw new Error('groupName is required');
50
+ (0, error_1.throwInvalidParam)('groupName is required');
41
51
  }
42
- if (status !== undefined && status !== 1 && status !== 2) {
43
- throw new Error('status must be 1 or 2');
52
+ if (status !== undefined &&
53
+ status !== MODEL_STATUS.enabled &&
54
+ status !== MODEL_STATUS.disabled) {
55
+ (0, error_1.throwInvalidParam)(`status must be ${MODEL_STATUS.enabled} or ${MODEL_STATUS.disabled}`);
44
56
  }
45
57
  return this.tcbService.request('UpdateAIModel', Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ EnvId: envId || EnvId, GroupName: groupName }, (baseUrl !== undefined ? { BaseUrl: baseUrl } : {})), (models !== undefined ? { Models: models } : {})), (remark !== undefined ? { Remark: remark } : {})), (status !== undefined ? { Status: status } : {})), (secret !== undefined ? { Secret: secret } : {})));
46
58
  }
@@ -51,11 +63,11 @@ class AiModelService {
51
63
  const { EnvId } = this.environment.lazyEnvironmentConfig;
52
64
  const { envId, groupNames } = options;
53
65
  if (!Array.isArray(groupNames) || groupNames.length === 0) {
54
- throw new Error('groupNames is required');
66
+ (0, error_1.throwInvalidParam)('groupNames is required');
55
67
  }
56
68
  const invalidGroupName = groupNames.find(item => typeof item !== 'string' || item.trim().length === 0);
57
69
  if (invalidGroupName !== undefined) {
58
- throw new Error('groupNames contains invalid item');
70
+ (0, error_1.throwInvalidParam)('groupNames contains invalid item');
59
71
  }
60
72
  return this.tcbService.request('DeleteAIModel', {
61
73
  EnvId: envId || EnvId,
@@ -133,11 +133,11 @@ class CloudAppService {
133
133
  const { serviceName, localPath, ignore = [], excludeNodeModules = true, onPhase } = params;
134
134
  // 1. 验证本地路径
135
135
  if (!fs_1.default.existsSync(localPath)) {
136
- throw new error_1.CloudBaseError(`本地路径不存在: ${localPath}`);
136
+ (0, error_1.throwNotFound)(`本地路径不存在: ${localPath}`);
137
137
  }
138
138
  const stat = fs_1.default.statSync(localPath);
139
139
  if (!stat.isDirectory()) {
140
- throw new error_1.CloudBaseError(`localPath 必须是目录: ${localPath}`);
140
+ (0, error_1.throwInvalidParam)(`localPath 必须是目录: ${localPath}`);
141
141
  }
142
142
  // 2. 打包本地文件为 ZIP(node_modules 按场景决定是否排除)
143
143
  const tmpZipPath = path_1.default.join(os_1.default.tmpdir(), `cloudapp-${Date.now()}-${Math.random().toString(36).slice(2)}.zip`);
@@ -193,7 +193,7 @@ class CloudAppService {
193
193
  catch (_a) {
194
194
  // 解析失败时 errorDetail 保持空串,不影响主错误抛出
195
195
  }
196
- throw new error_1.CloudBaseError(`上传失败: ${response.status} ${response.statusText}${errorDetail}`);
196
+ (0, error_1.throwApiError)(`上传失败: ${response.status} ${response.statusText}${errorDetail}`);
197
197
  }
198
198
  onPhase === null || onPhase === void 0 ? void 0 : onPhase({ phase: 'upload', durationMs: Date.now() - putStart, bytes: zipBuffer.length });
199
199
  // 7. 返回结果(返回 cosTimestamp,用于创建应用)
@@ -226,7 +226,7 @@ class CloudAppService {
226
226
  validateRequiredParams(params, fields) {
227
227
  for (const field of fields) {
228
228
  if (!params[field]) {
229
- throw new error_1.CloudBaseError(`${field} 是必填参数`);
229
+ (0, error_1.throwInvalidParam)(`${field} 是必填参数`);
230
230
  }
231
231
  }
232
232
  }
@@ -15,6 +15,7 @@ exports.parseObjectToDiffConfigItem = parseObjectToDiffConfigItem;
15
15
  const archiver_1 = __importDefault(require("archiver"));
16
16
  const fs_extra_1 = require("fs-extra");
17
17
  const path_1 = __importDefault(require("path"));
18
+ const error_1 = require("../error");
18
19
  const utils_1 = require("../utils");
19
20
  const type_1 = require("./type");
20
21
  /**
@@ -46,7 +47,7 @@ class CloudRunService {
46
47
  const templates = await this.getTemplates();
47
48
  const templateData = templates.find(item => item.identifier === template);
48
49
  if (!templateData || !templateData.zipFileStore) {
49
- throw new Error(`未找到匹配的模板: ${template}`);
50
+ (0, error_1.throwNotFound)(`未找到匹配的模板: ${template}`);
50
51
  }
51
52
  // 2. 下载并解压模板到目标目录
52
53
  const downloadUrl = templateData.zipFileStore;
@@ -75,7 +76,7 @@ class CloudRunService {
75
76
  const cloudRunServerDetailRes = await this.detail({ serverName });
76
77
  const version = (_b = (_a = cloudRunServerDetailRes.OnlineVersionInfos) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.VersionName;
77
78
  if (!version) {
78
- throw new Error('未找到云托管服务版本');
79
+ (0, error_1.throwNotFound)('未找到云托管服务版本');
79
80
  }
80
81
  /**
81
82
  * 获取下载地址
@@ -89,7 +90,7 @@ class CloudRunService {
89
90
  await (0, utils_1.downloadAndExtractRemoteZip)(cloudBaseBuildServiceRes === null || cloudBaseBuildServiceRes === void 0 ? void 0 : cloudBaseBuildServiceRes.DownloadUrl, path_1.default.resolve(targetPath));
90
91
  }
91
92
  else {
92
- throw new Error(`云托管代码下载地址为空(请求ID: ${cloudBaseBuildServiceRes.RequestId})`);
93
+ (0, error_1.throwApiError)(`云托管代码下载地址为空(请求ID: ${cloudBaseBuildServiceRes.RequestId})`);
93
94
  }
94
95
  }
95
96
  /**
@@ -116,7 +117,7 @@ class CloudRunService {
116
117
  const serverName = (_a = params === null || params === void 0 ? void 0 : params.ServerName) === null || _a === void 0 ? void 0 : _a.trim();
117
118
  const status = (_b = params === null || params === void 0 ? void 0 : params.Status) === null || _b === void 0 ? void 0 : _b.trim();
118
119
  if (!serverName) {
119
- throw new Error('Missing required parameters: ServerName');
120
+ (0, error_1.throwInvalidParam)('Missing required parameters: ServerName');
120
121
  }
121
122
  return this.tcbrService.request('DescribeReleaseOrder', Object.assign({ EnvId: envConfig.EnvId, ServerName: serverName }, (status ? { Status: status } : {})));
122
123
  }
@@ -148,7 +149,7 @@ class CloudRunService {
148
149
  async setTraffic(serverName, stablePercent, canaryPercent) {
149
150
  // 校验比例之和是否为100%
150
151
  if (stablePercent + canaryPercent !== 100) {
151
- throw new Error('稳定版本流量比例和灰度版本流量比例之和必须等于 100');
152
+ (0, error_1.throwInvalidParam)('稳定版本流量比例和灰度版本流量比例之和必须等于 100');
152
153
  }
153
154
  const envConfig = this.environment.lazyEnvironmentConfig;
154
155
  const { Task } = await this.tcbrService.request('DescribeServerManageTask', {
@@ -159,7 +160,7 @@ class CloudRunService {
159
160
  // 判断是否存在灰度版本
160
161
  const isGary = (Task === null || Task === void 0 ? void 0 : Task.ReleaseType) === type_1.ReleaseTypeEnum.GRAY && (Task === null || Task === void 0 ? void 0 : Task.Status) === 'running';
161
162
  if (!isGary) {
162
- throw new Error('不存在灰度中的版本或灰度版本部署未完成');
163
+ (0, error_1.throwApiError)('不存在灰度中的版本或灰度版本部署未完成');
163
164
  }
164
165
  // 获取当前版本和灰度版本
165
166
  const { ReleaseOrderInfo } = await this.tcbrService.request('DescribeReleaseOrder', {
@@ -242,13 +243,13 @@ class CloudRunService {
242
243
  const rollbackVersionName = (_c = params === null || params === void 0 ? void 0 : params.RollbackVersionName) === null || _c === void 0 ? void 0 : _c.trim();
243
244
  const operatorRemark = (_d = params === null || params === void 0 ? void 0 : params.OperatorRemark) === null || _d === void 0 ? void 0 : _d.trim();
244
245
  if (!serverName) {
245
- throw new Error('Missing required parameters: ServerName');
246
+ (0, error_1.throwInvalidParam)('Missing required parameters: ServerName');
246
247
  }
247
248
  if (!currentVersionName) {
248
- throw new Error('Missing required parameters: CurrentVersionName');
249
+ (0, error_1.throwInvalidParam)('Missing required parameters: CurrentVersionName');
249
250
  }
250
251
  if (!rollbackVersionName) {
251
- throw new Error('Missing required parameters: RollbackVersionName');
252
+ (0, error_1.throwInvalidParam)('Missing required parameters: RollbackVersionName');
252
253
  }
253
254
  return this.tcbrService.request('SubmitServerRollback', Object.assign({ EnvId: envConfig.EnvId, ServerName: serverName, CurrentVersionName: currentVersionName, RollbackVersionName: rollbackVersionName }, (operatorRemark ? { OperatorRemark: operatorRemark } : {})));
254
255
  }
@@ -262,17 +263,17 @@ class CloudRunService {
262
263
  const envConfig = this.environment.lazyEnvironmentConfig;
263
264
  const operatorRemark = (_a = params === null || params === void 0 ? void 0 : params.OperatorRemark) === null || _a === void 0 ? void 0 : _a.trim();
264
265
  if (!Array.isArray(params === null || params === void 0 ? void 0 : params.SimpleVersions) || params.SimpleVersions.length === 0) {
265
- throw new Error('Missing required parameters: SimpleVersions');
266
+ (0, error_1.throwInvalidParam)('Missing required parameters: SimpleVersions');
266
267
  }
267
268
  const simpleVersions = params.SimpleVersions.map((item, index) => {
268
269
  var _a, _b, _c;
269
270
  const serverName = (_a = item === null || item === void 0 ? void 0 : item.ServerName) === null || _a === void 0 ? void 0 : _a.trim();
270
271
  const versionName = (_b = item === null || item === void 0 ? void 0 : item.VersionName) === null || _b === void 0 ? void 0 : _b.trim();
271
272
  if (!serverName) {
272
- throw new Error(`Invalid SimpleVersions[${index}].ServerName`);
273
+ (0, error_1.throwInvalidParam)(`Invalid SimpleVersions[${index}].ServerName`);
273
274
  }
274
275
  if (!versionName) {
275
- throw new Error(`Invalid SimpleVersions[${index}].VersionName`);
276
+ (0, error_1.throwInvalidParam)(`Invalid SimpleVersions[${index}].VersionName`);
276
277
  }
277
278
  return {
278
279
  EnvId: ((_c = item === null || item === void 0 ? void 0 : item.EnvId) === null || _c === void 0 ? void 0 : _c.trim()) || envConfig.EnvId,
@@ -294,10 +295,10 @@ class CloudRunService {
294
295
  const versionName = (_b = params === null || params === void 0 ? void 0 : params.VersionName) === null || _b === void 0 ? void 0 : _b.trim();
295
296
  const channel = (_c = params === null || params === void 0 ? void 0 : params.Channel) === null || _c === void 0 ? void 0 : _c.trim();
296
297
  if (!serverName) {
297
- throw new Error('Missing required parameters: ServerName');
298
+ (0, error_1.throwInvalidParam)('Missing required parameters: ServerName');
298
299
  }
299
300
  if (!versionName) {
300
- throw new Error('Missing required parameters: VersionName');
301
+ (0, error_1.throwInvalidParam)('Missing required parameters: VersionName');
301
302
  }
302
303
  return this.tcbrService.request('DescribeVersionDetail', Object.assign({ EnvId: envConfig.EnvId, ServerName: serverName, VersionName: versionName }, (channel ? { Channel: channel } : {})));
303
304
  }
@@ -359,7 +360,7 @@ class CloudRunService {
359
360
  * 参数校验和默认值设置
360
361
  */
361
362
  if (!serverName) {
362
- throw new Error('Missing required parameters: serviceName');
363
+ (0, error_1.throwInvalidParam)('Missing required parameters: serviceName');
363
364
  }
364
365
  // 获取当前环境配置(包含EnvId)
365
366
  const envConfig = this.environment.lazyEnvironmentConfig;
@@ -30,7 +30,7 @@ class CommonService {
30
30
  async call(options) {
31
31
  const { Action, Param = {} } = options;
32
32
  if (!Action) {
33
- throw new error_1.CloudBaseError('缺少必填参数 Action');
33
+ (0, error_1.throwInvalidParam)('缺少必填参数 Action');
34
34
  }
35
35
  const res = await this.commonService.request(Action, Object.assign({}, Param));
36
36
  return res;
@@ -201,7 +201,7 @@ class DatabaseService {
201
201
  fileType = path_1.default.extname(filePath).substring(1);
202
202
  }
203
203
  else {
204
- throw new error_1.CloudBaseError('Miss file.filePath or file.objectKey');
204
+ (0, error_1.throwInvalidParam)('Miss file.filePath or file.objectKey');
205
205
  }
206
206
  if (file['FileType']) {
207
207
  fileType = file['FileType'];
@@ -217,7 +217,7 @@ class DatabaseService {
217
217
  fileType = path_1.default.extname(filePath).substring(1);
218
218
  }
219
219
  else {
220
- throw new error_1.CloudBaseError('Miss file.filePath or file.objectKey');
220
+ (0, error_1.throwInvalidParam)('Miss file.filePath or file.objectKey');
221
221
  }
222
222
  if (file['FileType']) {
223
223
  fileType = file['FileType'];
@@ -334,17 +334,17 @@ class DatabaseService {
334
334
  var _a;
335
335
  const { EnvId, Migrations, IncludeAll } = options;
336
336
  if (!Array.isArray(Migrations) || Migrations.length === 0) {
337
- throw new error_1.CloudBaseError('Migrations 至少需要 1 条');
337
+ (0, error_1.throwInvalidParam)('Migrations 至少需要 1 条');
338
338
  }
339
339
  for (const migration of Migrations) {
340
340
  if (!/^\d{14}$/.test(migration.Version)) {
341
- throw new error_1.CloudBaseError('Migration.Version 必须是 14 位数字');
341
+ (0, error_1.throwInvalidParam)('Migration.Version 必须是 14 位数字');
342
342
  }
343
343
  if (!/^[a-z_]+$/.test(migration.Name)) {
344
- throw new error_1.CloudBaseError('Migration.Name 只允许小写字母和下划线');
344
+ (0, error_1.throwInvalidParam)('Migration.Name 只允许小写字母和下划线');
345
345
  }
346
346
  if (!((_a = migration.Query) === null || _a === void 0 ? void 0 : _a.trim())) {
347
- throw new error_1.CloudBaseError('Migration.Query 不能为空');
347
+ (0, error_1.throwInvalidParam)('Migration.Query 不能为空');
348
348
  }
349
349
  }
350
350
  return this.dbOpService.request('PreviewPGUserMigrations', Object.assign({ EnvId: EnvId || this.envId, Migrations }, (IncludeAll !== undefined ? { IncludeAll } : {})));
@@ -358,24 +358,24 @@ class DatabaseService {
358
358
  var _a;
359
359
  const { EnvId, Migrations, LockTimeoutMs, StatementTimeoutMs, IncludeAll } = options;
360
360
  if (!Array.isArray(Migrations) || Migrations.length === 0) {
361
- throw new error_1.CloudBaseError('Migrations 至少需要 1 条');
361
+ (0, error_1.throwInvalidParam)('Migrations 至少需要 1 条');
362
362
  }
363
363
  for (const migration of Migrations) {
364
364
  if (!/^\d{14}$/.test(migration.Version)) {
365
- throw new error_1.CloudBaseError('Migration.Version 必须是 14 位数字');
365
+ (0, error_1.throwInvalidParam)('Migration.Version 必须是 14 位数字');
366
366
  }
367
367
  if (!/^[a-z_]+$/.test(migration.Name)) {
368
- throw new error_1.CloudBaseError('Migration.Name 只允许小写字母和下划线');
368
+ (0, error_1.throwInvalidParam)('Migration.Name 只允许小写字母和下划线');
369
369
  }
370
370
  if (!((_a = migration.Query) === null || _a === void 0 ? void 0 : _a.trim())) {
371
- throw new error_1.CloudBaseError('Migration.Query 不能为空');
371
+ (0, error_1.throwInvalidParam)('Migration.Query 不能为空');
372
372
  }
373
373
  }
374
374
  if (LockTimeoutMs !== undefined && LockTimeoutMs < 0) {
375
- throw new error_1.CloudBaseError('LockTimeoutMs 不能小于 0');
375
+ (0, error_1.throwInvalidParam)('LockTimeoutMs 不能小于 0');
376
376
  }
377
377
  if (StatementTimeoutMs !== undefined && StatementTimeoutMs < 0) {
378
- throw new error_1.CloudBaseError('StatementTimeoutMs 不能小于 0');
378
+ (0, error_1.throwInvalidParam)('StatementTimeoutMs 不能小于 0');
379
379
  }
380
380
  return this.dbOpService.request('PushPGUserMigrations', Object.assign(Object.assign(Object.assign({ EnvId: EnvId || this.envId, Migrations }, (LockTimeoutMs !== undefined ? { LockTimeoutMs } : {})), (StatementTimeoutMs !== undefined ? { StatementTimeoutMs } : {})), (IncludeAll !== undefined ? { IncludeAll } : {})));
381
381
  }
@@ -387,19 +387,19 @@ class DatabaseService {
387
387
  async repairPGUserMigrationHistory(options) {
388
388
  const { EnvId, MigrationVersion, Name, Status, Reason, Query } = options;
389
389
  if (!/^\d{14}$/.test(MigrationVersion)) {
390
- throw new error_1.CloudBaseError('MigrationVersion 必须是 14 位数字');
390
+ (0, error_1.throwInvalidParam)('MigrationVersion 必须是 14 位数字');
391
391
  }
392
392
  if (!/^[a-z_]+$/.test(Name)) {
393
- throw new error_1.CloudBaseError('Name 只允许小写字母和下划线');
393
+ (0, error_1.throwInvalidParam)('Name 只允许小写字母和下划线');
394
394
  }
395
395
  if (Status !== 'applied' && Status !== 'reverted') {
396
- throw new error_1.CloudBaseError('Status 只允许 applied 或 reverted');
396
+ (0, error_1.throwInvalidParam)('Status 只允许 applied 或 reverted');
397
397
  }
398
398
  if (!(Reason === null || Reason === void 0 ? void 0 : Reason.trim())) {
399
- throw new error_1.CloudBaseError('Reason 不能为空');
399
+ (0, error_1.throwInvalidParam)('Reason 不能为空');
400
400
  }
401
401
  if (Status === 'applied' && !(Query === null || Query === void 0 ? void 0 : Query.trim())) {
402
- throw new error_1.CloudBaseError('Status=applied 时 Query 不能为空');
402
+ (0, error_1.throwInvalidParam)('Status=applied 时 Query 不能为空');
403
403
  }
404
404
  const params = {
405
405
  EnvId: EnvId || this.envId,
@@ -421,10 +421,10 @@ class DatabaseService {
421
421
  async listPGUserMigrations(options = {}) {
422
422
  const { EnvId, Limit, Offset } = options;
423
423
  if (Limit !== undefined && (Limit < 1 || Limit > 500)) {
424
- throw new error_1.CloudBaseError('Limit 取值范围为 [1, 500]');
424
+ (0, error_1.throwInvalidParam)('Limit 取值范围为 [1, 500]');
425
425
  }
426
426
  if (Offset !== undefined && Offset < 0) {
427
- throw new error_1.CloudBaseError('Offset 不能小于 0');
427
+ (0, error_1.throwInvalidParam)('Offset 不能小于 0');
428
428
  }
429
429
  return this.dbOpService.request('ListPGUserMigrations', Object.assign(Object.assign({ EnvId: EnvId || this.envId }, (Limit !== undefined ? { Limit } : {})), (Offset !== undefined ? { Offset } : {})));
430
430
  }
@@ -436,7 +436,7 @@ class DatabaseService {
436
436
  async listAllPGUserMigrations(options = {}) {
437
437
  const { EnvId, PageSize = 500 } = options;
438
438
  if (PageSize < 1 || PageSize > 500) {
439
- throw new error_1.CloudBaseError('PageSize 取值范围为 [1, 500]');
439
+ (0, error_1.throwInvalidParam)('PageSize 取值范围为 [1, 500]');
440
440
  }
441
441
  const migrations = [];
442
442
  let offset = 0;
@@ -474,7 +474,7 @@ class DatabaseService {
474
474
  async describePGUserMigration(options) {
475
475
  const { EnvId, MigrationVersion } = options;
476
476
  if (!/^\d{14}$/.test(MigrationVersion)) {
477
- throw new error_1.CloudBaseError('MigrationVersion 必须是 14 位数字');
477
+ (0, error_1.throwInvalidParam)('MigrationVersion 必须是 14 位数字');
478
478
  }
479
479
  return this.dbOpService.request('DescribePGUserMigration', {
480
480
  EnvId: EnvId || this.envId,
@@ -489,7 +489,7 @@ class DatabaseService {
489
489
  async describeTaskResult(options) {
490
490
  const { EnvId, TaskId } = options;
491
491
  if (!(TaskId === null || TaskId === void 0 ? void 0 : TaskId.trim())) {
492
- throw new error_1.CloudBaseError('TaskId 不能为空');
492
+ (0, error_1.throwInvalidParam)('TaskId 不能为空');
493
493
  }
494
494
  return this.dbOpService.request('DescribeTaskResult', {
495
495
  EnvId: EnvId || this.envId,
@@ -501,7 +501,7 @@ class DatabaseService {
501
501
  const currEnv = this.environment;
502
502
  const instanceId = (_c = (_b = (_a = currEnv.lazyEnvironmentConfig) === null || _a === void 0 ? void 0 : _a.Databases) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.InstanceId;
503
503
  if (!instanceId) {
504
- throw new error_1.CloudBaseError('当前环境未开通文档型数据库');
504
+ (0, error_1.throwApiError)('当前环境未开通文档型数据库');
505
505
  }
506
506
  return instanceId;
507
507
  }
@@ -27,7 +27,7 @@ class DatabaseDeployer {
27
27
  */
28
28
  parseMigrationFiles(migrationsDir) {
29
29
  if (!fs_1.default.existsSync(migrationsDir)) {
30
- throw new error_1.CloudBaseError(`数据库迁移目录不存在: ${migrationsDir}`);
30
+ (0, error_1.throwNotFound)(`数据库迁移目录不存在: ${migrationsDir}`);
31
31
  }
32
32
  const files = fs_1.default.readdirSync(migrationsDir)
33
33
  .filter(f => f.endsWith('.sql'))
@@ -36,13 +36,13 @@ class DatabaseDeployer {
36
36
  for (const file of files) {
37
37
  const match = file.match(MIGRATION_FILE_PATTERN);
38
38
  if (!match) {
39
- throw new error_1.CloudBaseError(`migration 文件名格式错误: ${file},应为 {14位时间戳}_{小写下划线名称}.sql`);
39
+ (0, error_1.throwInvalidParam)(`migration 文件名格式错误: ${file},应为 {14位时间戳}_{小写下划线名称}.sql`);
40
40
  }
41
41
  const [, version, name] = match;
42
42
  const filePath = path_1.default.join(migrationsDir, file);
43
43
  const query = fs_1.default.readFileSync(filePath, 'utf-8');
44
44
  if (!query.trim()) {
45
- throw new error_1.CloudBaseError(`migration 文件内容为空: ${file}`);
45
+ (0, error_1.throwInvalidParam)(`migration 文件内容为空: ${file}`);
46
46
  }
47
47
  migrations.push({ Version: version, Name: name, Query: query });
48
48
  }
@@ -71,10 +71,9 @@ class DatabaseDeployer {
71
71
  }
72
72
  catch (error) {
73
73
  const err = error;
74
- throw new error_1.CloudBaseError(`数据库迁移预览失败 [EnvId=${envId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
74
+ throw new error_1.CloudBaseError(`数据库迁移预览失败 [EnvId=${envId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, { code: 'API_ERROR', source: 'manager-node',
75
75
  requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
76
- original: err instanceof Error ? err : undefined
77
- });
76
+ original: err instanceof Error ? err : undefined });
78
77
  }
79
78
  const items = [];
80
79
  // pending:将要执行的
@@ -124,16 +123,15 @@ class DatabaseDeployer {
124
123
  }
125
124
  catch (error) {
126
125
  const err = error;
127
- throw new error_1.CloudBaseError(`数据库迁移预览失败 [EnvId=${envId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
126
+ throw new error_1.CloudBaseError(`数据库迁移预览失败 [EnvId=${envId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, { code: 'API_ERROR', source: 'manager-node',
128
127
  requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
129
- original: err instanceof Error ? err : undefined
130
- });
128
+ original: err instanceof Error ? err : undefined });
131
129
  }
132
130
  if (!preview.Executable) {
133
131
  const conflictDetails = (preview.Conflicts || [])
134
132
  .map((c) => ` - ${c.Version}_${c.Name || '?'}: ${c.Reason || c.Message || 'unknown'}`)
135
133
  .join('\n');
136
- throw new error_1.CloudBaseError(`数据库迁移存在冲突,中断部署。请先解决以下冲突:\n${conflictDetails}`, {
134
+ throw new error_1.CloudBaseError(`数据库迁移存在冲突,中断部署。请先解决以下冲突:\n${conflictDetails}`, { code: 'API_ERROR', source: 'manager-node',
137
135
  requestId: preview.RequestId
138
136
  });
139
137
  }
@@ -151,24 +149,22 @@ class DatabaseDeployer {
151
149
  }
152
150
  catch (error) {
153
151
  const err = error;
154
- throw new error_1.CloudBaseError(`数据库迁移提交失败 [EnvId=${envId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
152
+ throw new error_1.CloudBaseError(`数据库迁移提交失败 [EnvId=${envId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, { code: 'API_ERROR', source: 'manager-node',
155
153
  requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
156
- original: err instanceof Error ? err : undefined
157
- });
154
+ original: err instanceof Error ? err : undefined });
158
155
  }
159
156
  // 4. 轮询等待完成
160
157
  try {
161
158
  await this.waitForTask(envId, result.TaskId, DEFAULT_TIMEOUT_MS);
162
159
  }
163
160
  catch (error) {
164
- if (error instanceof error_1.CloudBaseError) {
161
+ if ((0, error_1.isCloudBaseError)(error)) {
165
162
  throw error;
166
163
  }
167
164
  const err = error;
168
- throw new error_1.CloudBaseError(`数据库迁移任务等待失败 [TaskId=${result.TaskId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
165
+ throw new error_1.CloudBaseError(`数据库迁移任务等待失败 [TaskId=${result.TaskId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, { code: 'API_ERROR', source: 'manager-node',
169
166
  requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
170
- original: err instanceof Error ? err : undefined
171
- });
167
+ original: err instanceof Error ? err : undefined });
172
168
  }
173
169
  return { taskId: result.TaskId };
174
170
  }
@@ -180,7 +176,7 @@ class DatabaseDeployer {
180
176
  resolveMigrationsDir(cwd, migrations) {
181
177
  const raw = migrations || './cloudbase/migrations';
182
178
  if (path_1.default.isAbsolute(raw) || raw.startsWith('/')) {
183
- throw new error_1.CloudBaseError('database.migrations 仅支持相对路径(例如 ./cloudbase/migrations)');
179
+ (0, error_1.throwInvalidParam)('database.migrations 仅支持相对路径(例如 ./cloudbase/migrations)');
184
180
  }
185
181
  return path_1.default.resolve(cwd, raw);
186
182
  }
@@ -189,7 +185,7 @@ class DatabaseDeployer {
189
185
  */
190
186
  assertDatabaseType(config) {
191
187
  if (config.type !== 'postgresql') {
192
- throw new error_1.CloudBaseError(`database.type 仅支持 postgresql,当前为: ${String(config.type)}`);
188
+ (0, error_1.throwInvalidParam)(`database.type 仅支持 postgresql,当前为: ${String(config.type)}`);
193
189
  }
194
190
  }
195
191
  /**
@@ -206,10 +202,9 @@ class DatabaseDeployer {
206
202
  catch (error) {
207
203
  if (Date.now() - startTime > timeoutMs) {
208
204
  const err = error;
209
- throw new error_1.CloudBaseError(`数据库迁移任务状态查询超时(${timeoutMs / 1000}s),TaskId: ${taskId},最后错误:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
205
+ throw new error_1.CloudBaseError(`数据库迁移任务状态查询超时(${timeoutMs / 1000}s),TaskId: ${taskId},最后错误:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, { code: 'NETWORK_ERROR', source: 'manager-node',
210
206
  requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
211
- original: err instanceof Error ? err : undefined
212
- });
207
+ original: err instanceof Error ? err : undefined });
213
208
  }
214
209
  await new Promise(resolve => {
215
210
  setTimeout(resolve, POLL_INTERVAL_MS);
@@ -220,12 +215,12 @@ class DatabaseDeployer {
220
215
  return;
221
216
  }
222
217
  if (task.Status === 'Failed') {
223
- throw new error_1.CloudBaseError(`数据库迁移任务失败 [TaskId=${taskId}]: ${task.Reason || '未知原因'}`, {
218
+ throw new error_1.CloudBaseError(`数据库迁移任务失败 [TaskId=${taskId}]: ${task.Reason || '未知原因'}`, { code: 'API_ERROR', source: 'manager-node',
224
219
  requestId: task.RequestId
225
220
  });
226
221
  }
227
222
  if (Date.now() - startTime > timeoutMs) {
228
- throw new error_1.CloudBaseError(`数据库迁移任务超时(${timeoutMs / 1000}s),TaskId: ${taskId},当前状态: ${task.Status}/${task.Phase}`, {
223
+ throw new error_1.CloudBaseError(`数据库迁移任务超时(${timeoutMs / 1000}s),TaskId: ${taskId},当前状态: ${task.Status}/${task.Phase}`, { code: 'NETWORK_ERROR', source: 'manager-node',
229
224
  requestId: task.RequestId
230
225
  });
231
226
  }
@@ -531,10 +531,10 @@ class DeployOrchestrator {
531
531
  */
532
532
  guardConfig(config) {
533
533
  if (!config || typeof config !== 'object') {
534
- throw new error_1.CloudBaseError('无效的配置:config 必须为对象');
534
+ (0, error_1.throwInvalidParam)('无效的配置:config 必须为对象');
535
535
  }
536
536
  if (!config.envId) {
537
- throw new error_1.CloudBaseError('无效的配置:缺少 envId');
537
+ (0, error_1.throwInvalidParam)('无效的配置:缺少 envId');
538
538
  }
539
539
  }
540
540
  }
@@ -447,6 +447,16 @@ class FunctionDeployer {
447
447
  return;
448
448
  }
449
449
  const failures = report.checks.filter(item => item.status === 'fail');
450
+ // ⚠️ `report.ready === false` 但没有任何 `status === 'fail'` 的检查项(报告不自洽)时,
451
+ // `failures` 是空数组,直接取 `failures[0].id` 会先抛 TypeError、把真正的校验失败盖掉
452
+ // (代码评审:边界条件)。这里合成一条兜底失败项,保证 code / message / meta.failures 都有取值。
453
+ if (failures.length === 0) {
454
+ failures.push({
455
+ id: 'CHECK_REPORT_INCONSISTENT',
456
+ status: 'fail',
457
+ summary: '部署前检查未通过,但未给出具体失败项,请重试或用 --debug 查看完整报告'
458
+ });
459
+ }
450
460
  const message = failures
451
461
  .map(item => {
452
462
  const remediation = item.remediation ? `,${item.remediation}` : '';
@@ -454,7 +464,15 @@ class FunctionDeployer {
454
464
  })
455
465
  .join('\n');
456
466
  throw new error_1.CloudBaseError(`部署前检查未通过:\n${message}`, {
457
- code: failures[0].id
467
+ code: failures[0].id,
468
+ // code 只能承载第一个失败项,meta.failures 保留全量(埋点才能统计真实分布)
469
+ meta: {
470
+ failures: failures.map(item => ({
471
+ code: item.id,
472
+ summary: item.summary,
473
+ remediation: item.remediation
474
+ }))
475
+ }
458
476
  });
459
477
  }
460
478
  /**