@cloudbase/manager-node 5.9.0 → 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.
@@ -138,7 +138,7 @@ stages:
138
138
  - task: 生成并同步 changelog
139
139
  cmds:
140
140
  - plugin: ci_changelog
141
- version: 0.12.0
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
- \necho \"==========================================\"\n# 配置 git\ngit config --global\
179
- \ user.email \"cloudbase-ci-bot@tencent.com\"\ngit config --global user.name\
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 [ \"$RELEASE_TYPE\"\
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
- \ \"⏭️ RELEASE_TYPE !== latest,跳过 CHANGELOG.md 写回\"\nfi\n# 3. 打 tag\necho\
191
- \ \"\"\necho \"\U0001F3F7️ Step 3: 创建 tag v${MANAGER_NODE_VERSION}\"\
192
- \ngit tag -a \"v${MANAGER_NODE_VERSION}\" -m \"Release v${MANAGER_NODE_VERSION}\"\
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}/changelog_content.md
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
@@ -1,3 +1,10 @@
1
+ ## @cloudbase/manager-node v5.9.0 版本发布 🚀(2026-09-28)
2
+
3
+ - 新增 错误对象契约统一与无 code 抛错清零 + 自造码文档锚点(D5)
4
+ - 新增发布流水线配置
5
+
6
+ ---
7
+
1
8
 
2
9
  ## @cloudbase/manager-node v5.8.8 版本发布 🚀(2026-09-18)
3
10
 
@@ -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 文件
@@ -20,6 +20,14 @@ const error_1 = require("../error");
20
20
  const error_types_1 = require("../error-types");
21
21
  const utils_1 = require("../utils");
22
22
  const constant_1 = require("../constant");
23
+ /**
24
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境支持的运行环境。
25
+ *
26
+ * 服务端目前仅提供 Node.js 24.11;SDK 在 CBF 环境下也以它作为 `createFunction` 的默认 runtime。
27
+ *
28
+ * 仅供 SDK 内部使用:CBF 的字段支持范围仍在联调中,暂不作为公开 API 导出。
29
+ */
30
+ const CBF_ALLOWED_RUNTIMES = ['Nodejs24.11'];
23
31
  /**
24
32
  * 解析环境变量为布尔值
25
33
  * 视 'true'/'1'/'yes'/'on'(大小写不敏感)为 true,
@@ -161,7 +169,7 @@ function formatImageDeploymentErrorMessage(error, imageConfig) {
161
169
  // 解析函数配置,换成请求参数(用于 CreateFunction)
162
170
  function configToParams(options) {
163
171
  var _a, _b, _c;
164
- const { func, codeSecret, baseParams = {} } = options;
172
+ const { func, codeSecret, baseParams = {}, isCbf = false } = options;
165
173
  // 白名单:只有这些字段会被透传到 API(大小写不敏感)
166
174
  // 参考 SCF API 文档:https://cloud.tencent.com/document/product/583/18586
167
175
  // key: 小写用于匹配,value: PascalCase 用于输出
@@ -202,10 +210,12 @@ function configToParams(options) {
202
210
  params.InstallDependency = toBooleanString(func.installDependency);
203
211
  }
204
212
  // 2. L5 配置 - 当不存在时不修改,否则根据 true/false 进行修改
213
+ // CBF 不接受 SDK 注入的兜底字段:未显式配置时不提交;
214
+ // 用户显式配置的仍原样下发,由服务端校验并透传报错
205
215
  if (func.l5 !== undefined) {
206
216
  params.L5Enable = toBooleanString(func.l5);
207
217
  }
208
- else {
218
+ else if (!isCbf) {
209
219
  params.L5Enable = null;
210
220
  }
211
221
  // 3. 需要 'TRUE'/'FALSE' 字符串的布尔字段统一处理(大小写不敏感)
@@ -397,6 +407,14 @@ class FunctionService {
397
407
  }
398
408
  /**
399
409
  * 创建云函数
410
+ *
411
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境差异:
412
+ * - 默认 runtime 为 `Nodejs24.11`(见 `CBF_ALLOWED_RUNTIMES`)
413
+ * - 不再注入 `Stamp` / `ClsTopicId` / `ClsLogsetId` 与默认 `Role`
414
+ * - 不支持定时触发器,内部跳过触发器创建
415
+ *
416
+ * 用户显式配置的字段一律原样下发,不支持的字段由服务端报错透传。
417
+ *
400
418
  * @param {ICreateFunctionParam} funcParam
401
419
  * @returns {(Promise<IResponseInfo | ICreateFunctionRes>)}
402
420
  */
@@ -405,25 +423,34 @@ class FunctionService {
405
423
  const { namespace, backend } = this.getFunctionConfig();
406
424
  const { func, functionRootPath, force = false, base64Code, codeSecret, functionPath, deployMode, code } = funcParam;
407
425
  const funcName = func.name;
408
- const { TopicId, LogsetId } = this.getClsServiceConfig();
426
+ const isCbf = backend === 'cbf';
427
+ // EnvId 为两端共用;Stamp / ClsTopicId / ClsLogsetId 与默认 Role 都是 SDK 侧注入的字段,
428
+ // CBF(云开发云函数)不接受这些参数,一旦下发 CreateFunction 会直接失败(CBF does not
429
+ // support parameter xxx),故 CBF 下不再注入。用户显式配置的 role 等字段仍经
430
+ // configToParams 的字段映射原样下发,由服务端校验并透传报错。
409
431
  const baseParams = {
410
- EnvId: namespace,
411
- Stamp: 'MINI_QCBASE',
412
- ClsTopicId: TopicId,
413
- ClsLogsetId: LogsetId
432
+ EnvId: namespace
414
433
  };
415
- // 默认注入 TCB_QcsRole,DISABLE_DEFAULT_TCB_ROLE 为真时跳过(由 func.role 决定或留空)
416
- if (!parseEnvBoolean(process.env.DISABLE_DEFAULT_TCB_ROLE)) {
417
- baseParams.Role = 'TCB_QcsRole';
434
+ if (!isCbf) {
435
+ const { TopicId, LogsetId } = this.getClsServiceConfig();
436
+ baseParams.Stamp = 'MINI_QCBASE';
437
+ baseParams.ClsTopicId = TopicId;
438
+ baseParams.ClsLogsetId = LogsetId;
439
+ // 默认注入 TCB_QcsRole,DISABLE_DEFAULT_TCB_ROLE 为真时跳过(由 func.role 决定或留空)
440
+ if (!parseEnvBoolean(process.env.DISABLE_DEFAULT_TCB_ROLE)) {
441
+ baseParams.Role = 'TCB_QcsRole';
442
+ }
418
443
  }
419
444
  const params = configToParams({
420
445
  func,
421
446
  codeSecret,
422
- baseParams
447
+ baseParams,
448
+ isCbf
423
449
  });
424
450
  // 统一走 tcb;默认 runtime 按环境函数后端类型设置
451
+ // CBF(云开发云函数)目前仅提供 Nodejs24.11(见 CBF_ALLOWED_RUNTIMES)
425
452
  if (!func.runtime) {
426
- params.Runtime = backend === 'tcb' ? 'Nodejs24.14' : 'Nodejs20.19';
453
+ params.Runtime = isCbf ? CBF_ALLOWED_RUNTIMES[0] : 'Nodejs20.19';
427
454
  }
428
455
  const customCode = code;
429
456
  const customImageCode = customCode === null || customCode === void 0 ? void 0 : customCode.ImageConfig;
@@ -466,8 +493,10 @@ class FunctionService {
466
493
  const res = await this.tcbService.request('CreateFunction', params);
467
494
  // 等待函数状态正常
468
495
  await this.waitFunctionActive(funcName, codeSecret);
469
- // 创建函数触发器、失败自动重试
470
- await this.retryCreateTrigger(funcName, func.triggers);
496
+ // 创建函数触发器、失败自动重试(CBF 不支持定时触发器,跳过)
497
+ if (!isCbf) {
498
+ await this.retryCreateTrigger(funcName, func.triggers);
499
+ }
471
500
  // 设置路径,创建云接入路径
472
501
  if (func.path) {
473
502
  await this.createAccessPath(funcName, func.path);
@@ -514,8 +543,10 @@ class FunctionService {
514
543
  const configRes = await this.updateFunctionConfig(func);
515
544
  // 等待函数状态正常
516
545
  await this.waitFunctionActive(funcName, codeSecret);
517
- // 3. 创建函数触发器
518
- const triggerRes = await this.retryCreateTrigger(funcName, func.triggers);
546
+ // 3. 创建函数触发器(CBF 不支持定时触发器,跳过)
547
+ const triggerRes = isCbf
548
+ ? null
549
+ : await this.retryCreateTrigger(funcName, func.triggers);
519
550
  // 设置路径,创建云接入路径
520
551
  if (func.path) {
521
552
  await this.createAccessPath(funcName, func.path);
@@ -690,18 +721,32 @@ class FunctionService {
690
721
  }
691
722
  /**
692
723
  * 获取云函数详细信息
724
+ *
725
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境差异:
726
+ * - 不再注入 `ShowCode`(CBF 不接受该参数),因此也拿不到函数代码内容,
727
+ * 需要代码请使用 `downloadFunction`
728
+ * - 不转发 `codeSecret`:CBF 不支持代码保护,若在此下发会掩盖
729
+ * `CreateFunction` / `UpdateFunctionCode` 的真实报错
730
+ *
693
731
  * @param {string} name 云函数名称
694
732
  * @returns {Promise<Record<string, string>>}
695
733
  */
696
734
  async getFunctionDetail(name, codeSecret) {
697
- const { namespace } = this.getFunctionConfig();
735
+ const { namespace, backend } = this.getFunctionConfig();
736
+ const isCbf = backend === 'cbf';
737
+ // GetFunction 只传 EnvId 即可(SCF 与 CBF 均实测支持),Namespace 属冗余参数,不再下发
698
738
  const params = {
699
739
  FunctionName: name,
700
- ShowCode: 'TRUE',
701
- EnvId: namespace,
702
- Namespace: namespace
740
+ EnvId: namespace
703
741
  };
704
- if (codeSecret) {
742
+ // ShowCode 是 SDK 侧注入的字段:CBF(云开发云函数)不接受该参数,故 CBF 下不再注入
743
+ if (!isCbf) {
744
+ params.ShowCode = 'TRUE';
745
+ }
746
+ // CodeSecret(代码保护)在 CBF 下不被支持。该参数由调用方透传进来,
747
+ // 若在这里下发,用户会先看到指向 GetFunction 的报错,掩盖真正不支持代码保护的
748
+ // CreateFunction / UpdateFunctionCode,故 CBF 下不转发
749
+ if (codeSecret && !isCbf) {
705
750
  params.CodeSecret = codeSecret;
706
751
  }
707
752
  const data = await this.tcbService.request('GetFunction', params);
@@ -812,12 +857,21 @@ class FunctionService {
812
857
  }
813
858
  /**
814
859
  * 更新云函数配置
860
+ *
861
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境差异:
862
+ * - 不再注入 `ClsTopicId` / `ClsLogsetId`,也不转发 `InstallDependency`
863
+ * - 环境变量:不传不接受 Key 为空的占位项,清空需提交空数组(传 `envVariables: {}` 即清空)
864
+ * - 不支持定时触发器:配置里的 `triggers` 会被跳过
865
+ *
866
+ * 用户显式配置的字段一律原样下发,不支持的字段由服务端报错透传。
867
+ *
815
868
  * @param {ICloudFunction} func 云函数配置
816
869
  * @returns {Promise<IResponseInfo>}
817
870
  */
818
871
  async updateFunctionConfig(func) {
819
872
  var _a, _b, _c;
820
- const { namespace } = this.getFunctionConfig();
873
+ const { namespace, backend } = this.getFunctionConfig();
874
+ const isCbf = backend === 'cbf';
821
875
  // UpdateFunctionConfiguration API 白名单(大小写不敏感)
822
876
  // 参考:https://cloud.tencent.com/document/product/583/18580
823
877
  // 注意:Runtime, Handler, Code, Type, ProtocolType 只能在 CreateFunction 时指定
@@ -840,14 +894,19 @@ class FunctionService {
840
894
  // 注意:dnsCache 需要 'TRUE'/'FALSE' 字符串,在特殊处理阶段处理
841
895
  intranetconfig: 'IntranetConfig'
842
896
  };
843
- const { TopicId, LogsetId } = this.getClsServiceConfig();
844
897
  // 构建参数
898
+ // ClsTopicId / ClsLogsetId 为 SDK 侧注入的字段:CBF(云开发云函数)不接受这两个参数,
899
+ // 且 UpdateFunctionConfiguration 按请求 JSON 中出现过的 key 生成 FieldMask,
900
+ // 一旦下发会直接报 FieldMask contains an unsupported field,故 CBF 下不再注入。
845
901
  const params = {
846
902
  EnvId: namespace,
847
- FunctionName: func.name,
848
- ClsTopicId: TopicId,
849
- ClsLogsetId: LogsetId
903
+ FunctionName: func.name
850
904
  };
905
+ if (!isCbf) {
906
+ const { TopicId, LogsetId } = this.getClsServiceConfig();
907
+ params.ClsTopicId = TopicId;
908
+ params.ClsLogsetId = LogsetId;
909
+ }
851
910
  // 白名单字段自动转换(大小写不敏感,统一输出 PascalCase)
852
911
  for (const key of Object.keys(func)) {
853
912
  const lowerKey = key.toLowerCase();
@@ -857,7 +916,11 @@ class FunctionService {
857
916
  params[pascalKey] = toPascalCaseKeys(func[key]);
858
917
  }
859
918
  // 特殊处理:安装依赖标志(仅透传用户显式指定的值)
860
- if (func.installDependency !== undefined) {
919
+ // CBF(云开发云函数)的 UpdateFunctionConfiguration 不接受该参数
920
+ // (CBF does not support parameter InstallDependency)。它属于「创建 / 更新代码」语义:
921
+ // SDK 在 createFunction(force=true) 覆盖部署时会把整个 func 透传给本接口,
922
+ // 若原样下发会让常规覆盖部署直接失败,故 CBF 下不下发
923
+ if (func.installDependency !== undefined && !isCbf) {
861
924
  params.InstallDependency = toBooleanString(func.installDependency);
862
925
  }
863
926
  // 特殊处理:L5 配置(支持 boolean | string)
@@ -877,13 +940,25 @@ class FunctionService {
877
940
  params.Publish = toBooleanString(publishValue);
878
941
  }
879
942
  // 特殊处理:环境变量
880
- if (func.envVariables && Object.keys(func.envVariables).length > 0) {
881
- params.Environment = {
882
- Variables: Object.keys(func.envVariables).map(key => ({
883
- Key: key,
884
- Value: func.envVariables[key]
885
- }))
886
- };
943
+ // - 有变量:原样下发
944
+ // - 未传 envVariables:不提交,保持云端现有变量不变
945
+ // - 显式传空对象:CBF(云开发云函数)清空环境变量需提交空数组
946
+ // (CBF 不接受 SCF 那套 Key 为空的占位项,会报 Invalid environment variable)
947
+ if (func.envVariables) {
948
+ const envKeys = Object.keys(func.envVariables);
949
+ if (envKeys.length > 0) {
950
+ params.Environment = {
951
+ Variables: envKeys.map(key => ({
952
+ Key: key,
953
+ Value: func.envVariables[key]
954
+ }))
955
+ };
956
+ }
957
+ else if (isCbf) {
958
+ params.Environment = {
959
+ Variables: []
960
+ };
961
+ }
887
962
  }
888
963
  // 特殊处理:VPC 配置
889
964
  if (((_a = func === null || func === void 0 ? void 0 : func.vpc) === null || _a === void 0 ? void 0 : _a.subnetId) !== undefined && ((_b = func === null || func === void 0 ? void 0 : func.vpc) === null || _b === void 0 ? void 0 : _b.vpcId) !== undefined) {
@@ -928,7 +1003,8 @@ class FunctionService {
928
1003
  }
929
1004
  try {
930
1005
  // 如果函数配置中包含触发器,则更新触发器
931
- if (func.triggers && func.triggers.length > 0) {
1006
+ // CBF(云开发云函数)不支持定时触发器,内部静默跳过(避免无意义的失败告警)
1007
+ if (func.triggers && func.triggers.length > 0 && !isCbf) {
932
1008
  try {
933
1009
  await this.createFunctionTriggers(func.name, func.triggers);
934
1010
  }
@@ -947,6 +1023,11 @@ class FunctionService {
947
1023
  }
948
1024
  }
949
1025
  /**
1026
+ * 更新云函数代码
1027
+ *
1028
+ * `UpdateFunctionCode` 只传 `EnvId` 即可(SCF 与 CBF 均实测支持),不再下发冗余的 `Namespace`。
1029
+ *
1030
+ * 注意:CBF(云开发云函数)不支持 `codeSecret`(代码保护),传入后会由服务端报错。
950
1031
  *
951
1032
  * @param {IUpdateFunctionCodeParam} funcParam
952
1033
  * @returns {Promise<IResponseInfo>}
@@ -961,7 +1042,6 @@ class FunctionService {
961
1042
  const params = {
962
1043
  FunctionName: funcName,
963
1044
  EnvId: namespace,
964
- Namespace: namespace,
965
1045
  Code: {
966
1046
  ImageConfig: buildImageConfig(func.imageConfig)
967
1047
  }
@@ -1009,7 +1089,6 @@ class FunctionService {
1009
1089
  const params = {
1010
1090
  FunctionName: funcName,
1011
1091
  EnvId: namespace,
1012
- Namespace: namespace,
1013
1092
  Handler: func.handler || 'index.main',
1014
1093
  InstallDependency: installDependency,
1015
1094
  Code: codeParams
@@ -1156,6 +1235,11 @@ class FunctionService {
1156
1235
  }
1157
1236
  /**
1158
1237
  * 创建云函数触发器
1238
+ *
1239
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境不支持定时触发器,
1240
+ * 且该接口走 SCF 后端,对 CBF 的函数会返回「未找到指定的函数」这类误导性报错,
1241
+ * 故 CBF 下直接抛错。内部调用点(`createFunction` / `updateFunctionConfig`)会跳过本方法。
1242
+ *
1159
1243
  * @param {string} name 云函数名称
1160
1244
  * @param {ICloudFunctionTrigger[]} triggers 云函数触发器配置
1161
1245
  * @returns {Promise<IResponseInfo>}
@@ -1163,7 +1247,12 @@ class FunctionService {
1163
1247
  async createFunctionTriggers(name, triggers = []) {
1164
1248
  if (!triggers || !triggers.length)
1165
1249
  return null;
1166
- const { namespace } = this.getFunctionConfig();
1250
+ const { namespace, backend } = this.getFunctionConfig();
1251
+ // CBF(云开发云函数)不支持定时触发器:不下发到 SCF 后端
1252
+ // (否则会报「未找到指定的函数」,误导用户以为是函数不存在)
1253
+ if (backend === 'cbf') {
1254
+ (0, error_1.throwInvalidParam)(`[${name}] CBF(云开发云函数)环境不支持定时触发器`);
1255
+ }
1167
1256
  const parsedTriggers = triggers.map(item => {
1168
1257
  if (item.type !== 'timer') {
1169
1258
  (0, error_1.throwInvalidParam)(`不支持的触发器类型 [${item.type}],目前仅支持定时触发器(timer)!`);
@@ -1206,12 +1295,22 @@ class FunctionService {
1206
1295
  }
1207
1296
  /**
1208
1297
  * 删除云函数触发器
1298
+ *
1299
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境不支持定时触发器,
1300
+ * 且该接口走 SCF 后端,对 CBF 的函数会返回「未找到指定的函数」这类误导性报错,
1301
+ * 故 CBF 下直接抛错。
1302
+ *
1209
1303
  * @param {string} name 云函数名称
1210
1304
  * @param {string} triggerName 云函数触发器名称
1211
1305
  * @returns {Promise<IResponseInfo>}
1212
1306
  */
1213
1307
  async deleteFunctionTrigger(name, triggerName) {
1214
- const { namespace } = this.getFunctionConfig();
1308
+ const { namespace, backend } = this.getFunctionConfig();
1309
+ // CBF(云开发云函数)不支持定时触发器:不下发到 SCF 后端
1310
+ // (否则会报「未找到指定的函数」,误导用户以为是函数不存在)
1311
+ if (backend === 'cbf') {
1312
+ (0, error_1.throwInvalidParam)(`[${name}] CBF(云开发云函数)环境不支持定时触发器`);
1313
+ }
1215
1314
  try {
1216
1315
  return await this.scfService.request('DeleteTrigger', {
1217
1316
  FunctionName: name,
@@ -1546,10 +1645,10 @@ class FunctionService {
1546
1645
  async publishVersion(publishParams) {
1547
1646
  const { namespace } = this.getFunctionConfig();
1548
1647
  const { functionName: FunctionName, description: Description } = publishParams;
1549
- return this.scfService.request('PublishVersion', {
1648
+ return this.tcbService.request('PublishVersion', {
1550
1649
  FunctionName,
1551
1650
  Description,
1552
- Namespace: namespace
1651
+ EnvId: namespace
1553
1652
  });
1554
1653
  }
1555
1654
  /**
@@ -1560,10 +1659,11 @@ class FunctionService {
1560
1659
  */
1561
1660
  async listVersionByFunction(listVersionParams) {
1562
1661
  const { namespace } = this.getFunctionConfig();
1563
- const { functionName: FunctionName, offset: Offset, limit: Limit, order: Order, orderBy: OrderBy } = listVersionParams;
1564
- return this.scfService.request('ListVersionByFunction', {
1662
+ const { functionName: FunctionName, searchKey: SearchKey, offset: Offset, limit: Limit, order: Order, orderBy: OrderBy } = listVersionParams;
1663
+ return this.tcbService.request('ListVersionByFunction', {
1565
1664
  FunctionName,
1566
- Namespace: namespace,
1665
+ EnvId: namespace,
1666
+ SearchKey,
1567
1667
  Offset,
1568
1668
  Limit,
1569
1669
  Order,
@@ -1571,7 +1671,23 @@ class FunctionService {
1571
1671
  });
1572
1672
  }
1573
1673
  /**
1574
- *
1674
+ * 删除函数指定版本
1675
+ * @param {IDeleteFunctionVersionParams} params
1676
+ * @returns {Promise<IResponseInfo>}
1677
+ * @memberof FunctionService
1678
+ */
1679
+ async deleteFunctionVersion(params) {
1680
+ const { namespace } = this.getFunctionConfig();
1681
+ const { functionName: FunctionName, qualifier: Qualifier } = params;
1682
+ return this.tcbService.request('DeleteFunctionVersion', {
1683
+ FunctionName,
1684
+ EnvId: namespace,
1685
+ Qualifier
1686
+ });
1687
+ }
1688
+ /**
1689
+ * 更新函数流量配置(旧版 SCF 协议)
1690
+ * @deprecated 请使用 updateFunctionAliasConfigV2
1575
1691
  * @param {IUpdateFunctionAliasConfig} updateVersionConfigParams
1576
1692
  * @returns {Promise<IResponseInfo>}
1577
1693
  * @memberof FunctionService
@@ -1589,7 +1705,24 @@ class FunctionService {
1589
1705
  });
1590
1706
  }
1591
1707
  /**
1592
- * 查询函数别名详情
1708
+ * 更新函数流量策略(V2,TCB Traffic 协议)
1709
+ * @param {IUpdateFunctionAliasConfigV2} updateVersionConfigParams
1710
+ * @returns {Promise<IResponseInfo>}
1711
+ * @memberof FunctionService
1712
+ */
1713
+ async updateFunctionAliasConfigV2(updateVersionConfigParams) {
1714
+ const { namespace } = this.getFunctionConfig();
1715
+ const { functionName: FunctionName, name: Name, traffic: Traffic } = updateVersionConfigParams;
1716
+ return this.tcbService.request('UpdateAlias', {
1717
+ FunctionName,
1718
+ Name,
1719
+ EnvId: namespace,
1720
+ Traffic
1721
+ });
1722
+ }
1723
+ /**
1724
+ * 查询函数别名详情(旧版 SCF 协议)
1725
+ * @deprecated 请使用 getFunctionAliasV2
1593
1726
  * @param {IGetFunctionAlias} params
1594
1727
  * @returns {Promise<IGetFunctionAliasRes>}
1595
1728
  * @memberof FunctionService
@@ -1604,10 +1737,33 @@ class FunctionService {
1604
1737
  });
1605
1738
  }
1606
1739
  /**
1607
- * 通过 SCF COS 上传方式(通过 GetTempCosInfo + COS SDK 上传)
1608
- * 返回 TempCosObjectName 用于创建/更新函数
1740
+ * 查询函数别名详情(V2,TCB Traffic 协议)
1741
+ * @param {IGetFunctionAliasV2} params
1742
+ * @returns {Promise<IGetFunctionAliasResV2>}
1743
+ * @memberof FunctionService
1744
+ */
1745
+ async getFunctionAliasV2(params) {
1746
+ const { namespace } = this.getFunctionConfig();
1747
+ const { functionName: FunctionName, name: Name } = params;
1748
+ return this.tcbService.request('GetAlias', {
1749
+ FunctionName,
1750
+ Name,
1751
+ EnvId: namespace
1752
+ });
1753
+ }
1754
+ /**
1755
+ * COS 上传方式上传函数代码包,返回 { Key }
1756
+ * - CBF(backend=cbf):tcb.GetTempCosInfo 获取 PutUrl 直传,Key = 服务端生成的 ObjectKey
1757
+ * - SCF(backend=scf,默认):scf.GetTempCosInfo + Sign + COS SDK 上传
1758
+ * Key 由 getCodeParams 格式化为 TempCosObjectName 用于创建/更新函数
1609
1759
  */
1610
1760
  async uploadFunctionZipToCos(options, installDependency) {
1761
+ const { backend } = this.getFunctionConfig();
1762
+ // CBF 环境:tcb.GetTempCosInfo + PutUrl 直传
1763
+ if (backend === 'cbf') {
1764
+ return this.uploadFunctionZipViaPutUrl(options, installDependency);
1765
+ }
1766
+ // SCF 环境:保留原链路(scf.GetTempCosInfo + Sign + COS SDK)
1611
1767
  const { func, functionPath, functionRootPath } = options;
1612
1768
  const { env, appId } = this.getFunctionConfig();
1613
1769
  if (!appId) {
@@ -1780,15 +1936,117 @@ class FunctionService {
1780
1936
  ZipFile: base64
1781
1937
  };
1782
1938
  }
1783
- // 默认走 COS 上传(GetTempCosInfo + COS SDK)
1939
+ // 默认走 COS 上传(SCF: scf.GetTempCosInfo + COS SDK;CBF: tcb.GetTempCosInfo + PutUrl 直传)
1784
1940
  console.log(`[${func.name}] 部署方式: COS 上传`);
1941
+ const { backend } = this.getFunctionConfig();
1785
1942
  const region = this.environment.cloudBaseContext.region || constant_1.SCF_TEMP_COS.DEFAULT_REGION;
1786
1943
  const result = await this.uploadFunctionZipToCos(options, installDependency);
1944
+ // CBF:ObjectKey 由服务端生成,原样填入(无前导斜杠);SCF:保持原有 /{Key} 格式
1945
+ if (backend === 'cbf') {
1946
+ return {
1947
+ CosBucketRegion: region,
1948
+ TempCosObjectName: result.Key
1949
+ };
1950
+ }
1787
1951
  return {
1788
1952
  CosBucketRegion: region,
1789
1953
  TempCosObjectName: `/${result.Key}`
1790
1954
  };
1791
1955
  }
1956
+ /**
1957
+ * CBF 环境的临时代码包上传(tcb.GetTempCosInfo + PutUrl 直传)
1958
+ * - 先压缩再取 PutUrl,避免压缩耗时消耗 PutUrl 约 300 秒的有效期
1959
+ * - PutUrl 过期(403)/ 5xx / 网络错误时重新调用 GetTempCosInfo 刷新地址,不复用旧地址(初始 + 重试共 3 次)
1960
+ * - ObjectKey 由服务端生成,多次调用得到不同上传路径,上传成功后原样返回
1961
+ * @private
1962
+ */
1963
+ async uploadFunctionZipViaPutUrl(options, installDependency) {
1964
+ const { func, functionPath, functionRootPath } = options;
1965
+ const { env } = this.getFunctionConfig();
1966
+ // FileName 格式为 `{FunctionName}.zip`,最大 64 字符
1967
+ const fileName = `${func.name}.zip`;
1968
+ if (fileName.length > 64) {
1969
+ (0, error_1.throwInvalidParam)(`[${func.name}] 代码包文件名 ${fileName} 超过 64 字符上限`);
1970
+ }
1971
+ // 1. 本地压缩(云端安装依赖时自动忽略 node_modules 目录,与 SCF 链路一致)
1972
+ const ignore = installDependency === 'TRUE'
1973
+ ? ['node_modules/**/*', 'node_modules', ...(func.ignore || [])]
1974
+ : [...(func.ignore || [])];
1975
+ const packer = new packer_1.FunctionPacker({
1976
+ ignore,
1977
+ codeType: packer_1.CodeType.File,
1978
+ functionPath,
1979
+ name: func.name,
1980
+ root: functionRootPath
1981
+ });
1982
+ const zipFilePath = await packer.compressFiles();
1983
+ try {
1984
+ const maxAttempts = 3;
1985
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1986
+ // 2. 获取上传信息(每次调用服务端生成新的 PutUrl / ObjectKey)
1987
+ const { PutUrl, ObjectKey } = await this.tcbService.request('GetTempCosInfo', {
1988
+ EnvId: env,
1989
+ FileName: fileName
1990
+ });
1991
+ if (!PutUrl || !ObjectKey) {
1992
+ (0, error_1.throwApiError)(`[${func.name}] GetTempCosInfo 返回数据异常:缺少 PutUrl 或 ObjectKey`);
1993
+ }
1994
+ // 3. 对 PutUrl 直接 HTTP PUT 上传 zip,无需拼接桶域名或 Authorization
1995
+ // 网络错误/超时返回 null,由外层刷新 PutUrl 重试
1996
+ const response = await this.putZipFileToUrl(PutUrl, zipFilePath).catch(e => {
1997
+ if (attempt === maxAttempts) {
1998
+ // R3:继承上游错误码(FetchError 自带 ECONNREFUSED / ETIMEDOUT 等)
1999
+ const errorCode = e.code || e.statusCode || '';
2000
+ throw new error_1.CloudBaseError(`[${func.name}] COS 上传失败: ${e.message}`, {
2001
+ code: errorCode,
2002
+ original: e
2003
+ });
2004
+ }
2005
+ return null;
2006
+ });
2007
+ if (!response) {
2008
+ continue;
2009
+ }
2010
+ if (response.ok) {
2011
+ return { Key: ObjectKey };
2012
+ }
2013
+ let errorDetail = '';
2014
+ try {
2015
+ errorDetail = await response.text();
2016
+ }
2017
+ catch (e) {
2018
+ // 忽略响应体读取失败
2019
+ }
2020
+ const message = `COS 上传失败: ${response.status} ${response.statusText}${errorDetail ? ` - ${errorDetail}` : ''}`;
2021
+ // 403(PutUrl 过期)/ 5xx 可刷新地址重试;其余 4xx 直接失败
2022
+ const retryable = response.status === 403 || response.status >= 500;
2023
+ if (!retryable || attempt === maxAttempts) {
2024
+ // HTTP 状态码属平台返回,不作为本层自有码,保留在 message 中
2025
+ (0, error_1.throwApiError)(message);
2026
+ }
2027
+ }
2028
+ /* istanbul ignore next */
2029
+ (0, error_1.throwApiError)(`[${func.name}] COS 上传失败`);
2030
+ }
2031
+ finally {
2032
+ // 4. 清理临时 zip
2033
+ await packer.clean();
2034
+ }
2035
+ }
2036
+ /**
2037
+ * 对 PutUrl 发起 HTTP PUT 上传 zip 文件(超时 120 秒,支持 http_proxy 代理)
2038
+ * @private
2039
+ */
2040
+ async putZipFileToUrl(putUrl, zipFilePath) {
2041
+ return (0, utils_1.fetchStream)(putUrl, {
2042
+ method: 'PUT',
2043
+ body: fs_1.default.createReadStream(zipFilePath),
2044
+ headers: {
2045
+ 'Content-Type': 'application/zip'
2046
+ },
2047
+ timeout: 120000
2048
+ });
2049
+ }
1792
2050
  async createAccessPath(name, path) {
1793
2051
  const access = this.environment.getAccessService();
1794
2052
  try {
@@ -2018,12 +2276,21 @@ __decorate([
2018
2276
  __decorate([
2019
2277
  (0, utils_1.preLazy)()
2020
2278
  ], FunctionService.prototype, "listVersionByFunction", null);
2279
+ __decorate([
2280
+ (0, utils_1.preLazy)()
2281
+ ], FunctionService.prototype, "deleteFunctionVersion", null);
2021
2282
  __decorate([
2022
2283
  (0, utils_1.preLazy)()
2023
2284
  ], FunctionService.prototype, "updateFunctionAliasConfig", null);
2285
+ __decorate([
2286
+ (0, utils_1.preLazy)()
2287
+ ], FunctionService.prototype, "updateFunctionAliasConfigV2", null);
2024
2288
  __decorate([
2025
2289
  (0, utils_1.preLazy)()
2026
2290
  ], FunctionService.prototype, "getFunctionAlias", null);
2291
+ __decorate([
2292
+ (0, utils_1.preLazy)()
2293
+ ], FunctionService.prototype, "getFunctionAliasV2", null);
2027
2294
  __decorate([
2028
2295
  (0, utils_1.preLazy)()
2029
2296
  ], FunctionService.prototype, "uploadFunctionZipToCos", null);
@@ -2033,6 +2300,9 @@ __decorate([
2033
2300
  __decorate([
2034
2301
  (0, utils_1.preLazy)()
2035
2302
  ], FunctionService.prototype, "getCodeParams", null);
2303
+ __decorate([
2304
+ (0, utils_1.preLazy)()
2305
+ ], FunctionService.prototype, "uploadFunctionZipViaPutUrl", null);
2036
2306
  __decorate([
2037
2307
  (0, utils_1.preLazy)()
2038
2308
  ], FunctionService.prototype, "createAccessPath", null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/manager-node",
3
- "version": "5.9.0",
3
+ "version": "5.9.1",
4
4
  "description": "The node manage service api for cloudbase.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -124,14 +124,30 @@ export interface IPublishVersionRes extends IResponseInfo {
124
124
  Handler: string;
125
125
  Timeout: number;
126
126
  Runtime: string;
127
- Namespace: string;
127
+ EnvId: string;
128
+ /** @deprecated 请改用 EnvId */
129
+ Namespace?: string;
128
130
  }
129
131
  export interface IListFunctionVersionParams {
130
132
  functionName: string;
133
+ /**
134
+ * 兼容 SCF 的搜索字段。
135
+ *
136
+ * 实测仅接受数字型取值(传其它值报 InvalidParameterValue),但服务端**未按它过滤**:
137
+ * 传存在的版本号与不存在的数字都返回全量版本列表。
138
+ */
139
+ searchKey?: string;
131
140
  offset?: number;
141
+ /** 返回数量,默认 20,最大 100(超过报 Offset must be nonnegative and Limit must be between 0 and 100) */
132
142
  limit?: number;
133
- order?: string;
134
- orderBy?: string;
143
+ /** 排序方向,仅支持 ASC / DESC(传其它值报 Order must be ASC or DESC) */
144
+ order?: 'ASC' | 'DESC';
145
+ /** 排序字段,仅支持 AddTime / ModTime(传其它值报 OrderBy must be AddTime or ModTime) */
146
+ orderBy?: 'AddTime' | 'ModTime';
147
+ }
148
+ export interface IDeleteFunctionVersionParams {
149
+ functionName: string;
150
+ qualifier: string;
135
151
  }
136
152
  export interface IFunctionVersion {
137
153
  Version: string;
@@ -170,6 +186,51 @@ export interface IGetFunctionAlias {
170
186
  functionName: string;
171
187
  name: string;
172
188
  }
189
+ export type IFunctionTrafficType = 'FLOW' | 'HEADERS' | 'UNSUPPORTED';
190
+ /**
191
+ * 可写的流量策略类型:`UNSUPPORTED` 是查询返回的只读兼容态,不可用于 UpdateAlias
192
+ */
193
+ export type IUpdatableFunctionTrafficType = 'FLOW' | 'HEADERS';
194
+ export interface IFunctionTrafficRule {
195
+ Version: string;
196
+ Weight?: number;
197
+ Key?: string;
198
+ Value?: string;
199
+ }
200
+ export interface IFunctionTraffic {
201
+ Type: IFunctionTrafficType | string;
202
+ DefaultVersion: string;
203
+ Rules: IFunctionTrafficRule[];
204
+ }
205
+ /** 传入 UpdateAlias 的可写流量策略(`Type` 不含只读的 `UNSUPPORTED`) */
206
+ export interface IUpdatableFunctionTraffic extends Omit<IFunctionTraffic, 'Type'> {
207
+ Type: IUpdatableFunctionTrafficType;
208
+ }
209
+ export interface IFunctionBackendVersionWeight {
210
+ Version: string;
211
+ Weight: number;
212
+ }
213
+ export interface IFunctionBackendVersionMatch {
214
+ Version: string;
215
+ Key: string;
216
+ Method: string;
217
+ Expression: string;
218
+ }
219
+ export interface IFunctionBackendRoutingConfig {
220
+ AdditionalVersionWeights: IFunctionBackendVersionWeight[];
221
+ AdditionVersionMatches: IFunctionBackendVersionMatch[];
222
+ }
223
+ export type ITrafficRule = IFunctionTrafficRule;
224
+ export type ITraffic = IFunctionTraffic;
225
+ export interface IUpdateFunctionAliasConfigV2 {
226
+ functionName: string;
227
+ name?: string;
228
+ traffic: IUpdatableFunctionTraffic;
229
+ }
230
+ export interface IGetFunctionAliasV2 {
231
+ functionName: string;
232
+ name?: string;
233
+ }
173
234
  export interface IGetFunctionAliasRes extends IResponseInfo {
174
235
  FunctionVersion: string;
175
236
  Name: string;
@@ -178,6 +239,14 @@ export interface IGetFunctionAliasRes extends IResponseInfo {
178
239
  AddTime: string;
179
240
  ModTime: string;
180
241
  }
242
+ export interface IGetFunctionAliasResV2 extends IResponseInfo {
243
+ Name: string;
244
+ FunctionVersion: string;
245
+ Traffic: IFunctionTraffic;
246
+ TrafficEditable: boolean;
247
+ TrafficCompatibilityReason: string;
248
+ BackendRoutingConfig: IFunctionBackendRoutingConfig;
249
+ }
181
250
  export interface IListFunctionOptions {
182
251
  limit?: number;
183
252
  offset?: number;
@@ -251,6 +320,14 @@ export declare class FunctionService {
251
320
  updateFunctionIncrementalCode(funcParam: IUpdateFunctionIncrementalCodeParam): Promise<IResponseInfo>;
252
321
  /**
253
322
  * 创建云函数
323
+ *
324
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境差异:
325
+ * - 默认 runtime 为 `Nodejs24.11`(见 `CBF_ALLOWED_RUNTIMES`)
326
+ * - 不再注入 `Stamp` / `ClsTopicId` / `ClsLogsetId` 与默认 `Role`
327
+ * - 不支持定时触发器,内部跳过触发器创建
328
+ *
329
+ * 用户显式配置的字段一律原样下发,不支持的字段由服务端报错透传。
330
+ *
254
331
  * @param {ICreateFunctionParam} funcParam
255
332
  * @returns {(Promise<IResponseInfo | ICreateFunctionRes>)}
256
333
  */
@@ -303,6 +380,13 @@ export declare class FunctionService {
303
380
  }): Promise<void>;
304
381
  /**
305
382
  * 获取云函数详细信息
383
+ *
384
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境差异:
385
+ * - 不再注入 `ShowCode`(CBF 不接受该参数),因此也拿不到函数代码内容,
386
+ * 需要代码请使用 `downloadFunction`
387
+ * - 不转发 `codeSecret`:CBF 不支持代码保护,若在此下发会掩盖
388
+ * `CreateFunction` / `UpdateFunctionCode` 的真实报错
389
+ *
306
390
  * @param {string} name 云函数名称
307
391
  * @returns {Promise<Record<string, string>>}
308
392
  */
@@ -372,11 +456,24 @@ export declare class FunctionService {
372
456
  getCompleteFunctionLogs(_options: IFunctionLogOptionsV2): Promise<IFunctionLogDetailRes[]>;
373
457
  /**
374
458
  * 更新云函数配置
459
+ *
460
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境差异:
461
+ * - 不再注入 `ClsTopicId` / `ClsLogsetId`,也不转发 `InstallDependency`
462
+ * - 环境变量:不传不接受 Key 为空的占位项,清空需提交空数组(传 `envVariables: {}` 即清空)
463
+ * - 不支持定时触发器:配置里的 `triggers` 会被跳过
464
+ *
465
+ * 用户显式配置的字段一律原样下发,不支持的字段由服务端报错透传。
466
+ *
375
467
  * @param {ICloudFunction} func 云函数配置
376
468
  * @returns {Promise<IResponseInfo>}
377
469
  */
378
470
  updateFunctionConfig(func: ICloudFunction): Promise<IResponseInfo>;
379
471
  /**
472
+ * 更新云函数代码
473
+ *
474
+ * `UpdateFunctionCode` 只传 `EnvId` 即可(SCF 与 CBF 均实测支持),不再下发冗余的 `Namespace`。
475
+ *
476
+ * 注意:CBF(云开发云函数)不支持 `codeSecret`(代码保护),传入后会由服务端报错。
380
477
  *
381
478
  * @param {IUpdateFunctionCodeParam} funcParam
382
479
  * @returns {Promise<IResponseInfo>}
@@ -428,6 +525,11 @@ export declare class FunctionService {
428
525
  copyFunction(name: string, newFunctionName: string, targetEnvId?: string, force?: boolean): Promise<IResponseInfo>;
429
526
  /**
430
527
  * 创建云函数触发器
528
+ *
529
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境不支持定时触发器,
530
+ * 且该接口走 SCF 后端,对 CBF 的函数会返回「未找到指定的函数」这类误导性报错,
531
+ * 故 CBF 下直接抛错。内部调用点(`createFunction` / `updateFunctionConfig`)会跳过本方法。
532
+ *
431
533
  * @param {string} name 云函数名称
432
534
  * @param {ICloudFunctionTrigger[]} triggers 云函数触发器配置
433
535
  * @returns {Promise<IResponseInfo>}
@@ -436,6 +538,11 @@ export declare class FunctionService {
436
538
  batchCreateTriggers(options: IFunctionBatchOptions): Promise<void>;
437
539
  /**
438
540
  * 删除云函数触发器
541
+ *
542
+ * CBF(云开发云函数,`Functions[0].Backend === 'cbf'`)环境不支持定时触发器,
543
+ * 且该接口走 SCF 后端,对 CBF 的函数会返回「未找到指定的函数」这类误导性报错,
544
+ * 故 CBF 下直接抛错。
545
+ *
439
546
  * @param {string} name 云函数名称
440
547
  * @param {string} triggerName 云函数触发器名称
441
548
  * @returns {Promise<IResponseInfo>}
@@ -505,22 +612,47 @@ export declare class FunctionService {
505
612
  */
506
613
  listVersionByFunction(listVersionParams: IListFunctionVersionParams): Promise<IFunctionVersionsRes>;
507
614
  /**
508
- *
615
+ * 删除函数指定版本
616
+ * @param {IDeleteFunctionVersionParams} params
617
+ * @returns {Promise<IResponseInfo>}
618
+ * @memberof FunctionService
619
+ */
620
+ deleteFunctionVersion(params: IDeleteFunctionVersionParams): Promise<IResponseInfo>;
621
+ /**
622
+ * 更新函数流量配置(旧版 SCF 协议)
623
+ * @deprecated 请使用 updateFunctionAliasConfigV2
509
624
  * @param {IUpdateFunctionAliasConfig} updateVersionConfigParams
510
625
  * @returns {Promise<IResponseInfo>}
511
626
  * @memberof FunctionService
512
627
  */
513
628
  updateFunctionAliasConfig(updateVersionConfigParams: IUpdateFunctionAliasConfig): Promise<IResponseInfo>;
514
629
  /**
515
- * 查询函数别名详情
630
+ * 更新函数流量策略(V2,TCB Traffic 协议)
631
+ * @param {IUpdateFunctionAliasConfigV2} updateVersionConfigParams
632
+ * @returns {Promise<IResponseInfo>}
633
+ * @memberof FunctionService
634
+ */
635
+ updateFunctionAliasConfigV2(updateVersionConfigParams: IUpdateFunctionAliasConfigV2): Promise<IResponseInfo>;
636
+ /**
637
+ * 查询函数别名详情(旧版 SCF 协议)
638
+ * @deprecated 请使用 getFunctionAliasV2
516
639
  * @param {IGetFunctionAlias} params
517
640
  * @returns {Promise<IGetFunctionAliasRes>}
518
641
  * @memberof FunctionService
519
642
  */
520
643
  getFunctionAlias(params: IGetFunctionAlias): Promise<IGetFunctionAliasRes>;
521
644
  /**
522
- * 通过 SCF COS 上传方式(通过 GetTempCosInfo + COS SDK 上传)
523
- * 返回 TempCosObjectName 用于创建/更新函数
645
+ * 查询函数别名详情(V2,TCB Traffic 协议)
646
+ * @param {IGetFunctionAliasV2} params
647
+ * @returns {Promise<IGetFunctionAliasResV2>}
648
+ * @memberof FunctionService
649
+ */
650
+ getFunctionAliasV2(params: IGetFunctionAliasV2): Promise<IGetFunctionAliasResV2>;
651
+ /**
652
+ * COS 上传方式上传函数代码包,返回 { Key }
653
+ * - CBF(backend=cbf):tcb.GetTempCosInfo 获取 PutUrl 直传,Key = 服务端生成的 ObjectKey
654
+ * - SCF(backend=scf,默认):scf.GetTempCosInfo + Sign + COS SDK 上传
655
+ * Key 由 getCodeParams 格式化为 TempCosObjectName 用于创建/更新函数
524
656
  */
525
657
  uploadFunctionZipToCos(options: IFunctionCode, installDependency: 'TRUE' | 'FALSE'): Promise<{
526
658
  Key: string;
@@ -542,6 +674,19 @@ export declare class FunctionService {
542
674
  TempCosObjectName: string;
543
675
  ZipFile?: undefined;
544
676
  }>;
677
+ /**
678
+ * CBF 环境的临时代码包上传(tcb.GetTempCosInfo + PutUrl 直传)
679
+ * - 先压缩再取 PutUrl,避免压缩耗时消耗 PutUrl 约 300 秒的有效期
680
+ * - PutUrl 过期(403)/ 5xx / 网络错误时重新调用 GetTempCosInfo 刷新地址,不复用旧地址(初始 + 重试共 3 次)
681
+ * - ObjectKey 由服务端生成,多次调用得到不同上传路径,上传成功后原样返回
682
+ * @private
683
+ */
684
+ private uploadFunctionZipViaPutUrl;
685
+ /**
686
+ * 对 PutUrl 发起 HTTP PUT 上传 zip 文件(超时 120 秒,支持 http_proxy 代理)
687
+ * @private
688
+ */
689
+ private putZipFileToUrl;
545
690
  private createAccessPath;
546
691
  private getTempCosInfo;
547
692
  /**