@cloudbase/manager-node 5.8.9-beta.1 → 5.9.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.
- package/.codebuddy/rules/error-code-contract.mdc +13 -0
- package/.coding-ci-publish-beta.yaml +19 -12
- package/CHANGELOG.md +8 -0
- package/changelog_content_en.md +16 -0
- package/changelog_content_zh.md +16 -0
- package/lib/agent/index.js +6 -5
- package/lib/aiModel/index.js +21 -9
- package/lib/cloudApp/index.js +4 -4
- package/lib/cloudrun/index.js +16 -15
- package/lib/common/index.js +1 -1
- package/lib/database/index.js +23 -23
- package/lib/deploy/DatabaseDeployer.js +19 -24
- package/lib/deploy/DeployOrchestrator.js +2 -2
- package/lib/deploy/FunctionDeployer.js +19 -1
- package/lib/deploy/GatewayDeployer.js +5 -5
- package/lib/deploy/StaticDeployer.js +2 -2
- package/lib/deploy/framework.js +2 -1
- package/lib/deploy/function/config-guard.js +23 -3
- package/lib/deploy/function/enterprise-tcr.js +18 -2
- package/lib/docs/index.js +4 -3
- package/lib/env/index.js +16 -16
- package/lib/environment.js +4 -4
- package/lib/environmentManager.js +5 -1
- package/lib/error-docs.js +385 -0
- package/lib/error-types.js +21 -0
- package/lib/error.js +239 -2
- package/lib/function/index.js +454 -90
- package/lib/function/packer.js +1 -1
- package/lib/hosting/index.js +1 -1
- package/lib/index.js +2 -1
- package/lib/integration/crypto.js +4 -3
- package/lib/integration/index.js +1 -1
- package/lib/integration/secretKey.js +4 -4
- package/lib/monitor/index.js +1 -1
- package/lib/mysql/index.js +2 -1
- package/lib/permission/index.js +56 -49
- package/lib/platform/index.js +2 -2
- package/lib/sandbox/index.js +68 -61
- package/lib/storage/index.js +164 -162
- package/lib/user/index.js +32 -31
- package/lib/utils/cloud-api-request.js +13 -5
- package/lib/utils/cloudbase-request.js +21 -0
- package/lib/utils/fs.js +3 -3
- package/lib/utils/http-request.js +2 -2
- package/lib/utils/index.js +4 -3
- package/lib/utils/storage-config.js +3 -3
- package/package.json +2 -2
- package/types/error-docs.d.ts +57 -0
- package/types/error-types.d.ts +32 -0
- package/types/error.d.ts +148 -2
- package/types/function/index.d.ts +166 -8
- 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`)
|
|
@@ -138,7 +138,7 @@ stages:
|
|
|
138
138
|
- task: 生成并同步 changelog
|
|
139
139
|
cmds:
|
|
140
140
|
- plugin: ci_changelog
|
|
141
|
-
version:
|
|
141
|
+
version: 1.1.0
|
|
142
142
|
params:
|
|
143
143
|
to_ref: HEAD
|
|
144
144
|
tag_pattern: ^v(\d+\.\d+\.\d+(?:-[\w.]+)?)$
|
|
@@ -174,22 +174,22 @@ stages:
|
|
|
174
174
|
cmds:
|
|
175
175
|
- "bash -lc '\nset -e\nexport NVM_DIR=\"$HOME/.nvm\"\n[ -s \"$NVM_DIR/nvm.sh\"\
|
|
176
176
|
\ ] && . \"$NVM_DIR/nvm.sh\"\nnvm use 22.14.0\necho \"==========================================\"\
|
|
177
|
-
\necho \"\U0001F4E6 写回插件生成的 changelog 并打 tag v${MANAGER_NODE_VERSION}\"\
|
|
178
|
-
|
|
179
|
-
\ user.email \"cloudbase-ci-bot@tencent.com\"\ngit config --global
|
|
180
|
-
\ \"cloudbase-ci-bot\"\n# 切换到 release 分支\ngit fetch origin release/${MANAGER_NODE_VERSION}\n\
|
|
177
|
+
\necho \"\U0001F4E6 写回插件生成的 changelog 并打 tag v${MANAGER_NODE_VERSION}\"\n\
|
|
178
|
+
echo \"==========================================\"\n# 配置 git\ngit config\
|
|
179
|
+
\ --global user.email \"cloudbase-ci-bot@tencent.com\"\ngit config --global\
|
|
180
|
+
\ user.name \"cloudbase-ci-bot\"\n# 切换到 release 分支\ngit fetch origin release/${MANAGER_NODE_VERSION}\n\
|
|
181
181
|
git checkout release/${MANAGER_NODE_VERSION}\n# 1. 写回插件生成的 changelog(仅 latest\
|
|
182
|
-
\ 版本)\necho \"\"\necho \"\U0001F4DD Step 1: 写回插件产物到 CHANGELOG.md\"\nif [
|
|
183
|
-
\ = \"latest\" ]; then\n if [ ! -f \"${QCI_WORKSPACE}/changelog_content.md\"\
|
|
182
|
+
\ 版本)\necho \"\"\necho \"\U0001F4DD Step 1: 写回插件产物到 CHANGELOG.md\"\nif [\
|
|
183
|
+
\ \"$RELEASE_TYPE\" = \"latest\" ]; then\n if [ ! -f \"${QCI_WORKSPACE}/changelog_content.md\"\
|
|
184
184
|
\ ]; then\n echo \"❌ 插件产物 ${QCI_WORKSPACE}/changelog_content.md 不存在\"\
|
|
185
185
|
\n exit 1\n fi\n cat \"${QCI_WORKSPACE}/changelog_content.md\"\
|
|
186
186
|
\ CHANGELOG.md > CHANGELOG.md.new\n mv CHANGELOG.md.new CHANGELOG.md\n\
|
|
187
187
|
\ # 2. 提交 changelog\n echo \"\"\n echo \"\U0001F4DD Step 2: 提交变更\"\
|
|
188
188
|
\n git add CHANGELOG.md\n git commit -m \"docs(release): changelog\
|
|
189
|
-
\ for v${MANAGER_NODE_VERSION}\" || echo \"没有需要提交的变更\"\nelse\n echo\
|
|
190
|
-
|
|
191
|
-
\
|
|
192
|
-
\
|
|
189
|
+
\ for v${MANAGER_NODE_VERSION}\" || echo \"没有需要提交的变更\"\nelse\n echo \"\
|
|
190
|
+
⏭️ RELEASE_TYPE !== latest,跳过 CHANGELOG.md 写回\"\nfi\n# 3. 打 tag\necho \"\
|
|
191
|
+
\"\necho \"\U0001F3F7️ Step 3: 创建 tag v${MANAGER_NODE_VERSION}\"\ngit tag\
|
|
192
|
+
\ -a \"v${MANAGER_NODE_VERSION}\" -m \"Release v${MANAGER_NODE_VERSION}\"\
|
|
193
193
|
\n# 4. 推送分支和 tag\necho \"\"\necho \"\U0001F680 Step 4: 推送到远程\"\ngit push\
|
|
194
194
|
\ origin release/${MANAGER_NODE_VERSION}\ngit push origin \"v${MANAGER_NODE_VERSION}\"\
|
|
195
195
|
\necho \"\"\necho \"✅ 完成!\"\necho \" - changelog.md: 已更新\"\necho \" \
|
|
@@ -237,12 +237,19 @@ stages:
|
|
|
237
237
|
tasks:
|
|
238
238
|
- task: 企微群通知
|
|
239
239
|
cmds:
|
|
240
|
+
- plugin: cmds
|
|
241
|
+
params:
|
|
242
|
+
cmds:
|
|
243
|
+
- echo "📦 @cloudbase/manager-node v${MANAGER_NODE_VERSION} 发布成功" > ${QCI_WORKSPACE}/wework_message.md
|
|
244
|
+
- echo "" >> ${QCI_WORKSPACE}/wework_message.md
|
|
245
|
+
- cat ${QCI_WORKSPACE}/changelog_content.md >> ${QCI_WORKSPACE}/wework_message.md
|
|
246
|
+
- cat ${QCI_WORKSPACE}/wework_message.md
|
|
240
247
|
- plugin: message_wework_group
|
|
241
248
|
params:
|
|
242
249
|
c_type: text
|
|
243
250
|
env_variable: _WEWORK_GROUP_ID
|
|
244
251
|
mentioned: lucyqzhang;nenneyu
|
|
245
|
-
content_path: ${QCI_WORKSPACE}/
|
|
252
|
+
content_path: ${QCI_WORKSPACE}/wework_message.md
|
|
246
253
|
group_id: ww150005365489083
|
|
247
254
|
if: $RELEASE_TYPE = latest
|
|
248
255
|
version: '2.0'
|
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## [5.9.0] 2026-09-28
|
|
2
|
+
|
|
3
|
+
- [Added] Add `ERROR_TYPES` standard error type table (6 entries) and support `type` option in `CloudBaseError` constructor (decides `code` / `source` with priority and cannot be overridden by caller); helpers now reference `ERROR_TYPES`
|
|
4
|
+
- [Added] error-docs: locate self-made codes by layer registry page (returns `/error-code/<layer>#<lowercase-code>` anchor when `source` is `cli` / `toolbox` / `manager-node`); manager-node soft-fallback whitelist collapsed to layer registry page (`ready: true`)
|
|
5
|
+
- [Added] Unify error object contract and clear no-`code` throws: add `CloudBaseError.toJSON()`, `ErrorSource` union type (with `'toolbox'`), `isCloudBaseError` / `isValidErrorCode`; converge 171 raw `throw new Error` to unified helpers, storage batch delete now carries `code` + `source` + `details`
|
|
6
|
+
- [Added] Upgrade `@cloudbase/toolbox` to `~0.9.0`
|
|
7
|
+
- [Added] Update cloud function and cloud run integration tests: replace fixed sleep with polling wait, unify jest timeout to 10 minutes, add `waitUntil` / `waitForSandboxToolSettled` helpers with fast-fail diagnostics on failed states
|
|
8
|
+
- [Fixed] Fix `function` regression where throw-helper was misused in value position (`reject(throwNetError(...))`) causing Promise to never settle; now construct `new CloudBaseError(msg, { type: ERROR_TYPES.netError })` in value position
|
|
9
|
+
- [Fixed] `error`: `toJSON()` normalizes numeric codes to strings (e.g. `876` ⇒ `"876"`) at output layer while `code` on object stays faithful; `NaN` / `±Infinity` fall back to `ERROR`
|
|
10
|
+
- [Fixed] `error`: add ES5 prototype fallback (`Object.setPrototypeOf(this, CloudBaseError.prototype)`) to avoid lost prototype chain under third-party downlevel compilation
|
|
11
|
+
- [Fixed] Address code review fixes: extract `MODEL_STATUS` constant in `aiModel`; fix `authoration` → `authorization` spelling in `environment` / `cloud-api-request`; use truthy checks in `user` validation; change `error: any` → `unknown` in `function` and use `WeakMap` for idempotency marker; use truthy checks for `customConfiguration` / `DNSConfig` in `sandbox` to avoid null pointer
|
|
12
|
+
- [Fixed] `review`: fix empty `failures[0].id` null pointer when deploy report is inconsistent; narrow `description` with `typeof === 'string'` in `permission`; remove `as any` and tighten `isRetryableError` retry logic in `function`
|
|
13
|
+
- [Fixed] `deploy`: downgrade image `latest` tag from block (`fail`) to hint (`warn`) since platform allows `latest` as suboptimal not mandatory failure
|
|
14
|
+
- [Fixed] `error`: change enterprise image guidance idempotency from `message` text dependency to marker flag to avoid duplicate append after text mutation
|
|
15
|
+
- [Fixed] `error`: governance D14/D15/D16/D22 — pass through TCR permission errors; only retry retryable errors in trigger creation; `waitFunctionActive` tolerates creation-phase `NOT_FOUND`; `toJSON()` emits `stack`
|
|
16
|
+
- [Refactor] `error`: rename throw helpers to `throwXxx` form (e.g. `invalidParam` → `throwInvalidParam`) so call sites signal interruption, 494 sites / 35 files
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## [5.9.0] 2026-09-28
|
|
2
|
+
|
|
3
|
+
- [Added] 新增 `ERROR_TYPES` 标准错误类型表(6 条),`CloudBaseError` 构造器支持 `type` 选项(优先决定 `code` / `source` 且不可被调用方覆盖),helper 改引 `ERROR_TYPES`
|
|
4
|
+
- [Added] error-docs:自造码按层登记页定位(`source` 为 `cli` / `toolbox` / `manager-node` 时返回 `/error-code/<layer>#<小写码名>` 锚点),manager-node 软降级白名单收敛为层级登记页(`ready: true`)
|
|
5
|
+
- [Added] 错误对象契约统一与无 `code` 抛错清零:新增 `CloudBaseError.toJSON()`、`ErrorSource` 联合类型(含 `'toolbox'`)、`isCloudBaseError` / `isValidErrorCode` 识别;171 处原生 `throw new Error` 收敛为统一辅助函数,storage 批量删除补 `code` + `source` + `details`
|
|
6
|
+
- [Added] 升级 `@cloudbase/toolbox` 至 `~0.9.0`
|
|
7
|
+
- [Added] 更新云函数与云托管集成测试:轮询等待替代固定 sleep,jest 超时统一抬至 10 分钟,新增 `waitUntil` / `waitForSandboxToolSettled` 等辅助函数并补充失败态快速失败诊断
|
|
8
|
+
- [Fixed] 修复 `function` 模块必抛 helper 误用于值位置(`reject(throwNetError(...))`)导致 Promise 永不 settle 的回归,改为值位置构造 `new CloudBaseError(msg, { type: ERROR_TYPES.netError })`
|
|
9
|
+
- [Fixed] `error`: `toJSON()` 输出层将数值码归一化为字符串(如 `876` ⇒ `"876"`),对象上 `code` 保持保真;`NaN` / `±Infinity` 兜底为 `ERROR`
|
|
10
|
+
- [Fixed] `error`: 补 ES5 原型兜底(`Object.setPrototypeOf(this, CloudBaseError.prototype)`),避免第三方降级编译时丢失原型链
|
|
11
|
+
- [Fixed] 按代码评审修复多处问题:`aiModel` 抽 `MODEL_STATUS` 常量;`environment` / `cloud-api-request` 拼写 `authoration` → `authorization`;`user` 校验改真值判断;`function` 的 `error: any` → `unknown` 并改用 `WeakMap` 缓存幂等标记;`sandbox` 的 `customConfiguration` / `DNSConfig` 改真值判断避免空指针
|
|
12
|
+
- [Fixed] `review`: 响应评审修复 `deploy` 报告不自洽时 `failures[0].id` 空指针;`permission` 的 `description` 改用 `typeof === 'string'` 收窄;`function` 去掉 `as any` 断言并收紧 `isRetryableError` 重试判定
|
|
13
|
+
- [Fixed] `deploy`: 镜像 `latest` 标签由拦截(`fail`)降级为提示(`warn`),平台允许 `latest` 属次优而非必然失败
|
|
14
|
+
- [Fixed] `error`: 企业版镜像排查指引幂等判断由依赖 `message` 文本改为标记位,避免文本被改动后重复追加
|
|
15
|
+
- [Fixed] `error`: 治理 D14/D15/D16/D22 — TCR 权限错误透传上游;触发器创建仅重试可重试错误;`waitFunctionActive` 容忍创建期 `NOT_FOUND`;`toJSON()` 输出 `stack`
|
|
16
|
+
- [Refactor] `error`: 抛错 helper 统一改名为 `throwXxx` 形态(如 `invalidParam` → `throwInvalidParam`),调用点即知会中断,共 494 处 / 35 文件
|
package/lib/agent/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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('-');
|
package/lib/aiModel/index.js
CHANGED
|
@@ -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
|
-
|
|
31
|
+
(0, error_1.throwInvalidParam)('groupName is required');
|
|
24
32
|
}
|
|
25
33
|
if (groupName.toLowerCase().startsWith('cloudbase')) {
|
|
26
|
-
|
|
34
|
+
(0, error_1.throwInvalidParam)('groupName cannot start with cloudbase');
|
|
27
35
|
}
|
|
28
|
-
if (status !== undefined &&
|
|
29
|
-
|
|
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
|
-
|
|
50
|
+
(0, error_1.throwInvalidParam)('groupName is required');
|
|
41
51
|
}
|
|
42
|
-
if (status !== undefined &&
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
+
(0, error_1.throwInvalidParam)('groupNames contains invalid item');
|
|
59
71
|
}
|
|
60
72
|
return this.tcbService.request('DeleteAIModel', {
|
|
61
73
|
EnvId: envId || EnvId,
|
package/lib/cloudApp/index.js
CHANGED
|
@@ -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
|
-
|
|
136
|
+
(0, error_1.throwNotFound)(`本地路径不存在: ${localPath}`);
|
|
137
137
|
}
|
|
138
138
|
const stat = fs_1.default.statSync(localPath);
|
|
139
139
|
if (!stat.isDirectory()) {
|
|
140
|
-
|
|
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
|
-
|
|
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
|
-
|
|
229
|
+
(0, error_1.throwInvalidParam)(`${field} 是必填参数`);
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
}
|
package/lib/cloudrun/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
246
|
+
(0, error_1.throwInvalidParam)('Missing required parameters: ServerName');
|
|
246
247
|
}
|
|
247
248
|
if (!currentVersionName) {
|
|
248
|
-
|
|
249
|
+
(0, error_1.throwInvalidParam)('Missing required parameters: CurrentVersionName');
|
|
249
250
|
}
|
|
250
251
|
if (!rollbackVersionName) {
|
|
251
|
-
|
|
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
|
-
|
|
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
|
-
|
|
273
|
+
(0, error_1.throwInvalidParam)(`Invalid SimpleVersions[${index}].ServerName`);
|
|
273
274
|
}
|
|
274
275
|
if (!versionName) {
|
|
275
|
-
|
|
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
|
-
|
|
298
|
+
(0, error_1.throwInvalidParam)('Missing required parameters: ServerName');
|
|
298
299
|
}
|
|
299
300
|
if (!versionName) {
|
|
300
|
-
|
|
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
|
-
|
|
363
|
+
(0, error_1.throwInvalidParam)('Missing required parameters: serviceName');
|
|
363
364
|
}
|
|
364
365
|
// 获取当前环境配置(包含EnvId)
|
|
365
366
|
const envConfig = this.environment.lazyEnvironmentConfig;
|
package/lib/common/index.js
CHANGED
|
@@ -30,7 +30,7 @@ class CommonService {
|
|
|
30
30
|
async call(options) {
|
|
31
31
|
const { Action, Param = {} } = options;
|
|
32
32
|
if (!Action) {
|
|
33
|
-
|
|
33
|
+
(0, error_1.throwInvalidParam)('缺少必填参数 Action');
|
|
34
34
|
}
|
|
35
35
|
const res = await this.commonService.request(Action, Object.assign({}, Param));
|
|
36
36
|
return res;
|
package/lib/database/index.js
CHANGED
|
@@ -201,7 +201,7 @@ class DatabaseService {
|
|
|
201
201
|
fileType = path_1.default.extname(filePath).substring(1);
|
|
202
202
|
}
|
|
203
203
|
else {
|
|
204
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
341
|
+
(0, error_1.throwInvalidParam)('Migration.Version 必须是 14 位数字');
|
|
342
342
|
}
|
|
343
343
|
if (!/^[a-z_]+$/.test(migration.Name)) {
|
|
344
|
-
|
|
344
|
+
(0, error_1.throwInvalidParam)('Migration.Name 只允许小写字母和下划线');
|
|
345
345
|
}
|
|
346
346
|
if (!((_a = migration.Query) === null || _a === void 0 ? void 0 : _a.trim())) {
|
|
347
|
-
|
|
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
|
-
|
|
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
|
-
|
|
365
|
+
(0, error_1.throwInvalidParam)('Migration.Version 必须是 14 位数字');
|
|
366
366
|
}
|
|
367
367
|
if (!/^[a-z_]+$/.test(migration.Name)) {
|
|
368
|
-
|
|
368
|
+
(0, error_1.throwInvalidParam)('Migration.Name 只允许小写字母和下划线');
|
|
369
369
|
}
|
|
370
370
|
if (!((_a = migration.Query) === null || _a === void 0 ? void 0 : _a.trim())) {
|
|
371
|
-
|
|
371
|
+
(0, error_1.throwInvalidParam)('Migration.Query 不能为空');
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
374
|
if (LockTimeoutMs !== undefined && LockTimeoutMs < 0) {
|
|
375
|
-
|
|
375
|
+
(0, error_1.throwInvalidParam)('LockTimeoutMs 不能小于 0');
|
|
376
376
|
}
|
|
377
377
|
if (StatementTimeoutMs !== undefined && StatementTimeoutMs < 0) {
|
|
378
|
-
|
|
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
|
-
|
|
390
|
+
(0, error_1.throwInvalidParam)('MigrationVersion 必须是 14 位数字');
|
|
391
391
|
}
|
|
392
392
|
if (!/^[a-z_]+$/.test(Name)) {
|
|
393
|
-
|
|
393
|
+
(0, error_1.throwInvalidParam)('Name 只允许小写字母和下划线');
|
|
394
394
|
}
|
|
395
395
|
if (Status !== 'applied' && Status !== 'reverted') {
|
|
396
|
-
|
|
396
|
+
(0, error_1.throwInvalidParam)('Status 只允许 applied 或 reverted');
|
|
397
397
|
}
|
|
398
398
|
if (!(Reason === null || Reason === void 0 ? void 0 : Reason.trim())) {
|
|
399
|
-
|
|
399
|
+
(0, error_1.throwInvalidParam)('Reason 不能为空');
|
|
400
400
|
}
|
|
401
401
|
if (Status === 'applied' && !(Query === null || Query === void 0 ? void 0 : Query.trim())) {
|
|
402
|
-
|
|
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
|
-
|
|
424
|
+
(0, error_1.throwInvalidParam)('Limit 取值范围为 [1, 500]');
|
|
425
425
|
}
|
|
426
426
|
if (Offset !== undefined && Offset < 0) {
|
|
427
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
504
|
+
(0, error_1.throwApiError)('当前环境未开通文档型数据库');
|
|
505
505
|
}
|
|
506
506
|
return instanceId;
|
|
507
507
|
}
|