@cloudbase/cloudbase-mcp 2.23.3 → 2.23.6

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/dist/index.cjs CHANGED
@@ -2322,7 +2322,7 @@ async function enrichEnvInfoWithBilling(params) {
2322
2322
  * for new code, including an explicit `MysqlNotAvailable` line when
2323
2323
  * MySQL is absent — that one IS a hard "do not use" signal.
2324
2324
  */
2325
- function enrichEnvInfoWithRuntimeMode(result) {
2325
+ async function enrichEnvInfoWithRuntimeMode(result, manager) {
2326
2326
  const envInfo = result?.EnvInfo;
2327
2327
  if (!envInfo || typeof envInfo !== "object") {
2328
2328
  return result;
@@ -2352,7 +2352,29 @@ function enrichEnvInfoWithRuntimeMode(result) {
2352
2352
  }
2353
2353
  return [];
2354
2354
  })();
2355
- const hasMysql = mysqlList.length > 0;
2355
+ let hasMysql = mysqlList.length > 0;
2356
+ // Fallback: if MySQL not detected from DescribeEnvInfo fields, probe via
2357
+ // DescribeMySQLClusterDetail (dedicated MySQL API). This covers cases where
2358
+ // the SDK strips MySQL fields from the DescribeEnvInfo response.
2359
+ if (!hasMysql && manager?.commonService) {
2360
+ try {
2361
+ const probeResult = await manager
2362
+ .commonService("tcb", "2018-06-08")
2363
+ .call({
2364
+ Action: "DescribeMySQLClusterDetail",
2365
+ Param: { EnvId: envInfo.EnvId },
2366
+ });
2367
+ const clusterId = probeResult?.DbClusterId ||
2368
+ probeResult?.Response?.DbClusterId ||
2369
+ probeResult?.Data?.DbClusterId;
2370
+ if (clusterId) {
2371
+ hasMysql = true;
2372
+ }
2373
+ }
2374
+ catch {
2375
+ // Probe failure means MySQL is not provisioned — keep hasMysql = false
2376
+ }
2377
+ }
2356
2378
  // Primary mode: prefer PG when it is provisioned, otherwise fall back to
2357
2379
  // legacy NoSQL labeling. This drives "what skill to read first / what API
2358
2380
  // to reach for when starting new business code".
@@ -2370,7 +2392,7 @@ function enrichEnvInfoWithRuntimeMode(result) {
2370
2392
  : "No legacy NoSQL Database/Storage observed in this env.",
2371
2393
  MysqlNotAvailable: hasMysql
2372
2394
  ? "MySQL instance(s) detected — see EnvInfo.MysqlInstances."
2373
- : "No MySQL instance is provisioned for this env. Do NOT use `manageSqlDatabase` / `querySqlDatabase` (those are MySQL-specific) and do NOT read the `relational-database-tool` skill — that family targets MySQL, not CloudBase PG.",
2395
+ : "No MySQL instance is provisioned for this env. Do NOT use `manageMysqlDatabase` / `queryMysqlDatabase` (those are MySQL-specific) and do NOT read the `relational-database-tool` skill — that family targets MySQL, not CloudBase PG.",
2374
2396
  RecommendedSkills: "Read `postgresql-development` first for new PG code. `no-sql-web-sdk` is still applicable for existing NoSQL collections in this env. Skip `relational-database-tool` (MySQL-only) entirely.",
2375
2397
  }
2376
2398
  : {
@@ -2380,7 +2402,7 @@ function enrichEnvInfoWithRuntimeMode(result) {
2380
2402
  Storage: "Browser uploads use `app.uploadFile()` against the bucket exposed in `EnvInfo.Storages[].Bucket`.",
2381
2403
  MysqlNotAvailable: hasMysql
2382
2404
  ? "MySQL instance(s) detected — see EnvInfo.MysqlInstances."
2383
- : "No MySQL instance in this env. `manageSqlDatabase` / `querySqlDatabase` and the `relational-database-tool` skill are not applicable.",
2405
+ : "No MySQL instance in this env. `manageMysqlDatabase` / `queryMysqlDatabase` and the `relational-database-tool` skill are not applicable.",
2384
2406
  RecommendedSkills: "Read `no-sql-web-sdk` (and `cloud-storage-web` for uploads). `postgresql-development` and `relational-database-tool` are not applicable to this env.",
2385
2407
  };
2386
2408
  return {
@@ -3144,7 +3166,7 @@ function registerEnvTools(server) {
3144
3166
  if (envId) {
3145
3167
  result = await enrichEnvInfoWithMissingFields(cloudbaseInfo, result, envId);
3146
3168
  }
3147
- result = enrichEnvInfoWithRuntimeMode(result);
3169
+ result = await enrichEnvInfoWithRuntimeMode(result, cloudbaseInfo);
3148
3170
  break;
3149
3171
  case "domains":
3150
3172
  const cloudbaseDomains = await getManager();
@@ -3212,7 +3234,7 @@ function registerEnvTools(server) {
3212
3234
  // Register primary tool name (queryEnv)
3213
3235
  const queryEnvToolSchema = {
3214
3236
  title: "CloudBase 环境查询",
3215
- description: "查询 CloudBase 环境相关信息,支持查询环境列表、指定环境详情和安全域名。(曾用名:envQuery、listEnvs、getEnvInfo、getEnvAuthDomains)当 action=list 时,会按 DescribeEnvs 语义做列表/筛选,标准返回字段为 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,并支持通过 fields 白名单裁剪这些字段;aliasExact=true 时会按别名精确筛选,避免把前缀相近的环境误当作候选;即使传入 envId,action=list 也只返回摘要,不会返回完整资源明细或 expiry。如需查询某个已知 EnvId 对应环境的详细信息(包括资源字段和计费信息),必须使用 action=info 并传入目标环境的 envId 参数。action=info 会在可用时补充 BillingInfo(如 ExpireTime、PayMode、IsAutoRenew 等计费字段)。\n\n🔍 action=info 还会派生三个用于后端选型的字段:\n- `EnvInfo.RuntimeMode`:'postgresql' 或 'nosql',表示新业务建议默认使用的后端(PG 已开通时为 postgresql,否则为 nosql)。\n- `EnvInfo.RuntimeBackends`:`{postgresql, nosql, mysql}` 三个布尔值,描述当前环境实际并存的后端。\n- `EnvInfo.RuntimeModeHints`:每个后端对应的 API/工具/skill 提示。\n\nAI 在写业务/权限/存储代码前必须先看这三项:PG 模式下新业务推荐 `app.rdb()` + RLS(`managePgDatabase action=execute` 跑 `CREATE POLICY`)+ pgstore;已存在的 NoSQL 集合 / 旧 storage / `managePermissions(resourceType=\"noSqlDatabase\")` 在 PG 环境下仍然有效。真正不适用的是 MySQL:当 `RuntimeBackends.mysql === false` 时,`manageSqlDatabase` / `querySqlDatabase` / `relational-database-tool` skill 都不该使用。",
3237
+ description: "查询 CloudBase 环境相关信息,支持查询环境列表、指定环境详情和安全域名。(曾用名:envQuery、listEnvs、getEnvInfo、getEnvAuthDomains)当 action=list 时,会按 DescribeEnvs 语义做列表/筛选,标准返回字段为 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,并支持通过 fields 白名单裁剪这些字段;aliasExact=true 时会按别名精确筛选,避免把前缀相近的环境误当作候选;即使传入 envId,action=list 也只返回摘要,不会返回完整资源明细或 expiry。如需查询某个已知 EnvId 对应环境的详细信息(包括资源字段和计费信息),必须使用 action=info 并传入目标环境的 envId 参数。action=info 会在可用时补充 BillingInfo(如 ExpireTime、PayMode、IsAutoRenew 等计费字段)。\n\n🔍 action=info 还会派生三个用于后端选型的字段:\n- `EnvInfo.RuntimeMode`:'postgresql' 或 'nosql',表示新业务建议默认使用的后端(PG 已开通时为 postgresql,否则为 nosql)。\n- `EnvInfo.RuntimeBackends`:`{postgresql, nosql, mysql}` 三个布尔值,描述当前环境实际并存的后端。\n- `EnvInfo.RuntimeModeHints`:每个后端对应的 API/工具/skill 提示。\n\nAI 在写业务/权限/存储代码前必须先看这三项:PG 模式下新业务推荐 `app.rdb()` + RLS(`managePgDatabase action=execute` 跑 `CREATE POLICY`)+ pgstore;已存在的 NoSQL 集合 / 旧 storage / `managePermissions(resourceType=\"noSqlDatabase\")` 在 PG 环境下仍然有效。真正不适用的是 MySQL:当 `RuntimeBackends.mysql === false` 时,`manageMysqlDatabase` / `queryMysqlDatabase` / `relational-database-tool` skill 都不该使用。",
3216
3238
  inputSchema: {
3217
3239
  action: zod_1.z
3218
3240
  .enum(["list", "info", "domains"])
@@ -3314,9 +3336,9 @@ function registerEnvTools(server) {
3314
3336
  .optional()
3315
3337
  .describe("环境地域(action=create 时可选)。默认 ap-shanghai,可选 ap-guangzhou、ap-beijing 等"),
3316
3338
  resources: zod_1.z
3317
- .array(zod_1.z.enum(["flexdb", "storage", "function"]))
3339
+ .array(zod_1.z.enum(["flexdb", "storage", "function", "postgresql"]))
3318
3340
  .optional()
3319
- .describe("启用的资源类型(action=create 时可选)。默认启用全部三项:flexdb(文档数据库)、storage(存储)、function(云函数)"),
3341
+ .describe("启用的资源类型(action=create 时可选)。默认启用全部四项:flexdb(文档数据库)、storage(存储)、function(云函数)、postgresql(PostgreSQL 数据库)"),
3320
3342
  duration: zod_1.z
3321
3343
  .number()
3322
3344
  .int()
@@ -3369,7 +3391,7 @@ function registerEnvTools(server) {
3369
3391
  return (0, tool_result_js_1.buildJsonToolResult)({
3370
3392
  ok: false,
3371
3393
  code: "CONFIRM_REQUIRED",
3372
- message: `创建环境需要您确认。请确认以下配置信息后传入 confirm="yes":\n别名: ${alias}\n套餐: ${packageId}\n地域: ${region}\n资源类型: ${resources?.join(", ") ?? "flexdb, storage, function"}\n时长: ${duration} 个月`,
3394
+ message: `创建环境需要您确认。请确认以下配置信息后传入 confirm="yes":\n别名: ${alias}\n套餐: ${packageId}\n地域: ${region}\n资源类型: ${resources?.join(", ") ?? "flexdb, storage, function, postgresql"}\n时长: ${duration} 个月`,
3373
3395
  next_step: {
3374
3396
  tool: "manageEnv",
3375
3397
  action: "create",
@@ -37032,6 +37054,119 @@ module.exports.Printf
37032
37054
  = Printf;
37033
37055
 
37034
37056
 
37057
+ /***/ }),
37058
+
37059
+ /***/ 8901:
37060
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
37061
+
37062
+ "use strict";
37063
+
37064
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
37065
+ if (k2 === undefined) k2 = k;
37066
+ var desc = Object.getOwnPropertyDescriptor(m, k);
37067
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
37068
+ desc = { enumerable: true, get: function() { return m[k]; } };
37069
+ }
37070
+ Object.defineProperty(o, k2, desc);
37071
+ }) : (function(o, m, k, k2) {
37072
+ if (k2 === undefined) k2 = k;
37073
+ o[k2] = m[k];
37074
+ }));
37075
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
37076
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37077
+ };
37078
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
37079
+ exports.MonitorService = void 0;
37080
+ const error_1 = __webpack_require__(40430);
37081
+ const utils_1 = __webpack_require__(62358);
37082
+ __exportStar(__webpack_require__(57676), exports);
37083
+ // Period 与时间范围的约束规则
37084
+ const ONE_DAY_MS = 24 * 60 * 60 * 1000;
37085
+ const THREE_DAYS_MS = 3 * ONE_DAY_MS;
37086
+ const PERIOD_RULES = [
37087
+ { maxRangeMs: ONE_DAY_MS, allowed: [300, 3600] },
37088
+ { maxRangeMs: THREE_DAYS_MS, allowed: [300, 3600, 86400] },
37089
+ // 超过3天
37090
+ { maxRangeMs: Infinity, allowed: [3600, 86400] }
37091
+ ];
37092
+ function validatePeriod(startStr, endStr, period) {
37093
+ if (period === undefined)
37094
+ return;
37095
+ const startMs = new Date(startStr).getTime();
37096
+ const endMs = new Date(endStr).getTime();
37097
+ if (isNaN(startMs) || isNaN(endMs))
37098
+ return;
37099
+ const rangeMs = endMs - startMs;
37100
+ const rule = PERIOD_RULES.find(r => rangeMs <= r.maxRangeMs);
37101
+ if (rule && !rule.allowed.includes(period)) {
37102
+ throw new error_1.CloudBaseError(`Period=${period} 不适用于当前时间范围。` +
37103
+ `时间范围 ${startStr} ~ ${endStr}(约 ${(rangeMs / ONE_DAY_MS).toFixed(1)} 天)` +
37104
+ `仅支持 Period: [${rule.allowed.join(', ')}]`);
37105
+ }
37106
+ }
37107
+ class MonitorService {
37108
+ constructor(environment) {
37109
+ this.envId = environment.getEnvId();
37110
+ this.cloudService = new utils_1.CloudService(environment.cloudBaseContext, 'tcb', '2018-06-08');
37111
+ }
37112
+ /**
37113
+ * 查询环境监控数据
37114
+ *
37115
+ * 根据指定指标名称,查询当前环境在指定时间范围内的监控数据,
37116
+ * 返回按统计粒度聚合后的时序数据。
37117
+ *
37118
+ * @param params 查询参数
37119
+ * @returns 时序监控数据
37120
+ *
37121
+ * @example
37122
+ * // 查询静态网站存储容量
37123
+ * const res = await monitor.describeCurveData({
37124
+ * MetricName: 'StaticFsSizePkg',
37125
+ * StartTime: '2026-02-05 00:00:00',
37126
+ * EndTime: '2026-02-06 23:59:59',
37127
+ * Period: 3600
37128
+ * })
37129
+ *
37130
+ * @example
37131
+ * // 查询云托管某服务某版本的错误响应
37132
+ * const res = await monitor.describeCurveData({
37133
+ * MetricName: 'TkeHttpErrorService',
37134
+ * StartTime: '2026-03-13 00:00:00',
37135
+ * EndTime: '2026-03-16 23:59:59',
37136
+ * ResourceID: 'my-service',
37137
+ * SubresourceID: 'my-service-001'
37138
+ * })
37139
+ */
37140
+ async describeCurveData(params) {
37141
+ // 校验 Period 与时间范围的约束关系
37142
+ validatePeriod(params.StartTime, params.EndTime, params.Period);
37143
+ const requestParams = {
37144
+ EnvId: this.envId,
37145
+ MetricName: params.MetricName,
37146
+ StartTime: params.StartTime,
37147
+ EndTime: params.EndTime
37148
+ };
37149
+ if (params.ResourceID !== undefined) {
37150
+ requestParams.ResourceID = params.ResourceID;
37151
+ }
37152
+ if (params.WxAppId !== undefined) {
37153
+ requestParams.WxAppId = params.WxAppId;
37154
+ }
37155
+ if (params.SubresourceID !== undefined) {
37156
+ requestParams.SubresourceID = params.SubresourceID;
37157
+ }
37158
+ if (params.ThirdResource !== undefined) {
37159
+ requestParams.ThirdResource = params.ThirdResource;
37160
+ }
37161
+ if (params.Period !== undefined) {
37162
+ requestParams.Period = params.Period;
37163
+ }
37164
+ return this.cloudService.request('DescribeCurveData', requestParams);
37165
+ }
37166
+ }
37167
+ exports.MonitorService = MonitorService;
37168
+
37169
+
37035
37170
  /***/ }),
37036
37171
 
37037
37172
  /***/ 8904:
@@ -39129,6 +39264,8 @@ function registerAgentTools(server) {
39129
39264
  category: "agents",
39130
39265
  },
39131
39266
  }, async ({ action, agentId, name, description, runtime, timeout, memorySize, installDependency, zipFile, cosBucketRegion, tempCosObjectName, sessionConfig, cwd, params, }) => {
39267
+ let _agentName;
39268
+ let _agentRuntime;
39132
39269
  try {
39133
39270
  const cloudbase = await getManager();
39134
39271
  const payload = normalizeAgentPayload({
@@ -39145,11 +39282,19 @@ function registerAgentTools(server) {
39145
39282
  cwd,
39146
39283
  ...(params ?? {}),
39147
39284
  });
39285
+ _agentName = payload?.Name;
39286
+ _agentRuntime = payload?.Runtime;
39148
39287
  if (action === "createAgent") {
39149
39288
  const normalizedName = normalizeString(payload.Name);
39150
39289
  if (!normalizedName) {
39151
39290
  throw new Error("action=createAgent 时必须提供 name(可通过顶层 name 或 params.name 传入)");
39152
39291
  }
39292
+ // CloudBase 后端在创建 Agent 时会同步创建云函数,函数名/别名长度受 SCF 限制(最大 64 字符)。
39293
+ // envId 可能被用作前缀或别名的一部分,因此这里预留足够余量,避免后端 CreateFunction 失败。
39294
+ if (normalizedName.length > 30) {
39295
+ throw new Error(`agent name 过长(当前 ${normalizedName.length} 字符)。CloudBase 创建 Agent 时会同步创建云函数,` +
39296
+ `函数名/别名受 SCF 64 字符限制,且 envId 可能作为前缀拼接。请将 name 控制在 30 字符以内。`);
39297
+ }
39153
39298
  const createPayload = {
39154
39299
  ...payload,
39155
39300
  Name: normalizedName,
@@ -39188,6 +39333,17 @@ function registerAgentTools(server) {
39188
39333
  }, "Agent 删除成功"));
39189
39334
  }
39190
39335
  catch (error) {
39336
+ // 对后端 InternalError 提供更有意义的错误信息
39337
+ const errMsg = error instanceof Error ? error.message : String(error);
39338
+ if (errMsg.includes("InternalError") || errMsg.includes("服务处理出错")) {
39339
+ server.logger?.({
39340
+ type: "createAgentError",
39341
+ message: "createAgent 后端返回 InternalError,可能是云函数创建失败",
39342
+ originalError: errMsg,
39343
+ name: _agentName,
39344
+ runtime: _agentRuntime,
39345
+ });
39346
+ }
39191
39347
  return (0, json_content_js_1.jsonContent)(buildErrorEnvelope(error));
39192
39348
  }
39193
39349
  });
@@ -40495,7 +40651,7 @@ async function checkMysqlGate(server) {
40495
40651
  success: false,
40496
40652
  errorCode: "MYSQL_NOT_AVAILABLE",
40497
40653
  message: `This environment (${envId}) does not have MySQL. Use managePgDatabase / queryPgDatabase instead.`,
40498
- nextActions: [{ tool: "managePgDatabase", params: { action: "execute" }, description: "Use managePgDatabase" }],
40654
+ nextActions: [{ tool: "managePgDatabase", params: { action: "execute" }, description: "Use managePgDatabase for PostgreSQL operations" }],
40499
40655
  });
40500
40656
  }
40501
40657
  try {
@@ -40507,7 +40663,7 @@ async function checkMysqlGate(server) {
40507
40663
  return (0, tool_result_js_1.buildJsonToolResult)({
40508
40664
  success: false,
40509
40665
  errorCode: "MYSQL_NOT_AVAILABLE",
40510
- message: `This environment (${envId}) has PostgreSQL enabled but MySQL is NOT available. Use managePgDatabase / queryPgDatabase instead of manageSqlDatabase / querySqlDatabase.`,
40666
+ message: `This environment (${envId}) has PostgreSQL enabled but MySQL is NOT available. Use managePgDatabase / queryPgDatabase instead of manageMysqlDatabase / queryMysqlDatabase.`,
40511
40667
  nextActions: [{ tool: "managePgDatabase", params: { action: "execute" }, description: "Use managePgDatabase for PostgreSQL operations" }],
40512
40668
  });
40513
40669
  }
@@ -40516,8 +40672,8 @@ async function checkMysqlGate(server) {
40516
40672
  MYSQL_GATE_CACHE.set(envId, true);
40517
40673
  return null;
40518
40674
  }
40519
- const QUERY_SQL_DATABASE = "querySqlDatabase";
40520
- const MANAGE_SQL_DATABASE = "manageSqlDatabase";
40675
+ const QUERY_MYSQL_DATABASE = "queryMysqlDatabase";
40676
+ const MANAGE_MYSQL_DATABASE = "manageMysqlDatabase";
40521
40677
  const QUERY_PERMISSIONS = "queryPermissions";
40522
40678
  const MANAGE_PERMISSIONS = "managePermissions";
40523
40679
  const QUERY_ACTIONS = [
@@ -40809,14 +40965,14 @@ async function getSqlInstanceInfo({ getManager, cloudBaseOptions, server, }) {
40809
40965
  function buildProvisionNextActions(status, request) {
40810
40966
  if (status === "READY") {
40811
40967
  return [
40812
- buildNextAction(MANAGE_SQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
40968
+ buildNextAction(MANAGE_MYSQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
40813
40969
  ];
40814
40970
  }
40815
40971
  if (status === "FAILED") {
40816
40972
  return [];
40817
40973
  }
40818
40974
  return [
40819
- buildNextAction(QUERY_SQL_DATABASE, "describeCreateResult", "MySQL provisioning is still running. Check the create result again before initializing schema.", request
40975
+ buildNextAction(QUERY_MYSQL_DATABASE, "describeCreateResult", "MySQL provisioning is still running. Check the create result again before initializing schema.", request
40820
40976
  ? { action: "describeCreateResult", request }
40821
40977
  : { action: "describeCreateResult" }),
40822
40978
  ];
@@ -40835,15 +40991,15 @@ function buildTaskStatusNextActions(status, request) {
40835
40991
  if (status === "READY") {
40836
40992
  if (inferTaskKind(request) === "destroy") {
40837
40993
  return [
40838
- buildNextAction(QUERY_SQL_DATABASE, "getInstanceInfo", "The destroy task completed. Confirm whether the MySQL instance no longer exists."),
40994
+ buildNextAction(QUERY_MYSQL_DATABASE, "getInstanceInfo", "The destroy task completed. Confirm whether the MySQL instance no longer exists."),
40839
40995
  ];
40840
40996
  }
40841
40997
  return [
40842
- buildNextAction(MANAGE_SQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
40998
+ buildNextAction(MANAGE_MYSQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
40843
40999
  ];
40844
41000
  }
40845
41001
  return [
40846
- buildNextAction(QUERY_SQL_DATABASE, "describeTaskStatus", "MySQL task is still running. Check task status again before continuing.", request ? { action: "describeTaskStatus", request } : { action: "describeTaskStatus" }),
41002
+ buildNextAction(QUERY_MYSQL_DATABASE, "describeTaskStatus", "MySQL task is still running. Check task status again before continuing.", request ? { action: "describeTaskStatus", request } : { action: "describeTaskStatus" }),
40847
41003
  ];
40848
41004
  }
40849
41005
  async function handleRunQuery(args, context) {
@@ -40853,7 +41009,7 @@ async function handleRunQuery(args, context) {
40853
41009
  errorCode: "SQL_REQUIRED",
40854
41010
  message: "`sql` is required when action is `runQuery`.",
40855
41011
  nextActions: [
40856
- buildNextAction(QUERY_SQL_DATABASE, "runQuery", "Provide a read-only SQL statement such as SELECT/SHOW/DESCRIBE."),
41012
+ buildNextAction(QUERY_MYSQL_DATABASE, "runQuery", "Provide a read-only SQL statement such as SELECT/SHOW/DESCRIBE."),
40857
41013
  ],
40858
41014
  });
40859
41015
  }
@@ -40861,9 +41017,9 @@ async function handleRunQuery(args, context) {
40861
41017
  return buildSqlToolResult({
40862
41018
  success: false,
40863
41019
  errorCode: "READ_ONLY_SQL_REQUIRED",
40864
- message: "`querySqlDatabase(action=runQuery)` only accepts read-only SQL statements.",
41020
+ message: "`queryMysqlDatabase(action=runQuery)` only accepts read-only SQL statements.",
40865
41021
  nextActions: [
40866
- buildNextAction(MANAGE_SQL_DATABASE, "runStatement", "Use the manage tool for INSERT/UPDATE/DELETE/DDL statements."),
41022
+ buildNextAction(MANAGE_MYSQL_DATABASE, "runStatement", "Use the manage tool for INSERT/UPDATE/DELETE/DDL statements."),
40867
41023
  ],
40868
41024
  });
40869
41025
  }
@@ -40891,7 +41047,7 @@ async function handleRunQuery(args, context) {
40891
41047
  errorCode: "MYSQL_NOT_CREATED",
40892
41048
  message: "MySQL is not provisioned yet or not found. Please provision MySQL before running queries.",
40893
41049
  nextActions: [
40894
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before querying data.", { action: "provisionMySQL", confirm: true }),
41050
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before querying data.", { action: "provisionMySQL", confirm: true }),
40895
41051
  ],
40896
41052
  });
40897
41053
  }
@@ -40990,7 +41146,7 @@ async function handleGetInstanceInfo(context) {
40990
41146
  nextActions: instanceInfo.exists
40991
41147
  ? undefined
40992
41148
  : [
40993
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before running SQL statements or schema initialization.", { action: "provisionMySQL", confirm: true }),
41149
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before running SQL statements or schema initialization.", { action: "provisionMySQL", confirm: true }),
40994
41150
  ],
40995
41151
  });
40996
41152
  }
@@ -41001,7 +41157,7 @@ async function handleProvisionMySQL(args, context) {
41001
41157
  errorCode: "CONFIRM_REQUIRED",
41002
41158
  message: "Provisioning MySQL creates billable resources. Re-run with `confirm: true` to continue.",
41003
41159
  nextActions: [
41004
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Explicit confirmation is required before provisioning MySQL.", { action: "provisionMySQL", confirm: true }),
41160
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Explicit confirmation is required before provisioning MySQL.", { action: "provisionMySQL", confirm: true }),
41005
41161
  ],
41006
41162
  });
41007
41163
  }
@@ -41015,7 +41171,7 @@ async function handleProvisionMySQL(args, context) {
41015
41171
  message: "A SQL database instance already exists for the current environment.",
41016
41172
  nextActions: existing.status === "READY"
41017
41173
  ? [
41018
- buildNextAction(MANAGE_SQL_DATABASE, "initializeSchema", "The instance already exists. You can initialize schema next if needed."),
41174
+ buildNextAction(MANAGE_MYSQL_DATABASE, "initializeSchema", "The instance already exists. You can initialize schema next if needed."),
41019
41175
  ]
41020
41176
  : undefined,
41021
41177
  });
@@ -41061,7 +41217,7 @@ async function handleDestroyMySQL(args, context) {
41061
41217
  errorCode: "CONFIRM_REQUIRED",
41062
41218
  message: "Destroying MySQL removes database resources. Re-run with `confirm: true` to continue.",
41063
41219
  nextActions: [
41064
- buildNextAction(MANAGE_SQL_DATABASE, "destroyMySQL", "Explicit confirmation is required before destroying MySQL.", { action: "destroyMySQL", confirm: true }),
41220
+ buildNextAction(MANAGE_MYSQL_DATABASE, "destroyMySQL", "Explicit confirmation is required before destroying MySQL.", { action: "destroyMySQL", confirm: true }),
41065
41221
  ],
41066
41222
  });
41067
41223
  }
@@ -41108,7 +41264,7 @@ async function handleDestroyMySQL(args, context) {
41108
41264
  : "MySQL destroy request was rejected.",
41109
41265
  nextActions: isSuccess
41110
41266
  ? [
41111
- buildNextAction(QUERY_SQL_DATABASE, "describeTaskStatus", "Check the MySQL destroy task status before assuming the instance is gone.", {
41267
+ buildNextAction(QUERY_MYSQL_DATABASE, "describeTaskStatus", "Check the MySQL destroy task status before assuming the instance is gone.", {
41112
41268
  action: "describeTaskStatus",
41113
41269
  request: taskRequest,
41114
41270
  }),
@@ -41131,7 +41287,7 @@ async function handleRunStatement(args, context) {
41131
41287
  errorCode: "MYSQL_NOT_CREATED",
41132
41288
  message: "MySQL is not provisioned for the current environment yet.",
41133
41289
  nextActions: [
41134
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before executing write statements or DDL.", { action: "provisionMySQL", confirm: true }),
41290
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before executing write statements or DDL.", { action: "provisionMySQL", confirm: true }),
41135
41291
  ],
41136
41292
  });
41137
41293
  }
@@ -41141,7 +41297,7 @@ async function handleRunStatement(args, context) {
41141
41297
  errorCode: "MYSQL_NOT_READY",
41142
41298
  message: `MySQL is not ready yet (current status: ${instanceInfo.status}).`,
41143
41299
  nextActions: [
41144
- buildNextAction(QUERY_SQL_DATABASE, "getInstanceInfo", "Check current instance status before retrying the statement."),
41300
+ buildNextAction(QUERY_MYSQL_DATABASE, "getInstanceInfo", "Check current instance status before retrying the statement."),
41145
41301
  ],
41146
41302
  });
41147
41303
  }
@@ -41168,7 +41324,7 @@ async function handleRunStatement(args, context) {
41168
41324
  errorCode: "MYSQL_NOT_CREATED",
41169
41325
  message: "MySQL is not provisioned yet or not found. Please provision MySQL before running statements.",
41170
41326
  nextActions: [
41171
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
41327
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
41172
41328
  ],
41173
41329
  });
41174
41330
  }
@@ -41197,7 +41353,7 @@ async function resolveInitializationReadiness(args, context) {
41197
41353
  errorCode: "MYSQL_NOT_CREATED",
41198
41354
  message: "MySQL is not provisioned yet. Initialize schema only after provisioning completes.",
41199
41355
  nextActions: [
41200
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before schema initialization.", { action: "provisionMySQL", confirm: true }),
41356
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before schema initialization.", { action: "provisionMySQL", confirm: true }),
41201
41357
  ],
41202
41358
  }),
41203
41359
  };
@@ -41237,7 +41393,7 @@ async function resolveInitializationReadiness(args, context) {
41237
41393
  rawStatus,
41238
41394
  },
41239
41395
  nextActions: [
41240
- buildNextAction(QUERY_SQL_DATABASE, "describeTaskStatus", "Check MySQL task status until the instance becomes ready.", args.statusContext?.taskStatusRequest
41396
+ buildNextAction(QUERY_MYSQL_DATABASE, "describeTaskStatus", "Check MySQL task status until the instance becomes ready.", args.statusContext?.taskStatusRequest
41241
41397
  ? {
41242
41398
  action: "describeTaskStatus",
41243
41399
  request: args.statusContext.taskStatusRequest,
@@ -41294,7 +41450,7 @@ async function handleInitializeSchema(args, context) {
41294
41450
  errorCode: "MYSQL_NOT_CREATED",
41295
41451
  message: "MySQL is not provisioned yet or not found. Please provision MySQL before initializing schema.",
41296
41452
  nextActions: [
41297
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
41453
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
41298
41454
  ],
41299
41455
  });
41300
41456
  }
@@ -41342,7 +41498,7 @@ function registerSQLDatabaseTools(server) {
41342
41498
  cloudBaseOptions,
41343
41499
  server,
41344
41500
  };
41345
- server.registerTool?.(QUERY_SQL_DATABASE, {
41501
+ server.registerTool?.(QUERY_MYSQL_DATABASE, {
41346
41502
  title: "查询 CloudBase MySQL 数据库状态或执行只读 SQL",
41347
41503
  description: "查询 CloudBase MySQL 数据库信息。支持执行只读 SQL、查询 MySQL 开通结果、查询 MySQL 任务状态,以及获取当前实例上下文信息。",
41348
41504
  inputSchema: {
@@ -41388,7 +41544,7 @@ function registerSQLDatabaseTools(server) {
41388
41544
  throw new Error(`Unsupported SQL query action: ${args.action}`);
41389
41545
  }
41390
41546
  });
41391
- server.registerTool?.(MANAGE_SQL_DATABASE, {
41547
+ server.registerTool?.(MANAGE_MYSQL_DATABASE, {
41392
41548
  title: "管理 CloudBase MySQL 数据库生命周期或执行写入 SQL",
41393
41549
  description: "管理 CloudBase MySQL 数据库资源。支持开通 MySQL、销毁 MySQL、执行写入 SQL/DDL,以及初始化数据库 Schema。注意:必须先开通 MySQL(action=provisionMySQL,confirm=true)才能执行 runStatement 或 initializeSchema。若 MySQL 尚未开通,工具会返回 MYSQL_NOT_CREATED 并给出开通的 nextAction 提示。",
41394
41550
  inputSchema: {
@@ -51060,6 +51216,207 @@ function configure (options) {
51060
51216
  }
51061
51217
 
51062
51218
 
51219
+ /***/ }),
51220
+
51221
+ /***/ 12129:
51222
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
51223
+
51224
+ "use strict";
51225
+
51226
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
51227
+ const crypto = __webpack_require__(55511);
51228
+ const utils_1 = __webpack_require__(98786);
51229
+ const utils_lang_1 = __webpack_require__(82174);
51230
+ const keyvalue_1 = __webpack_require__(36255);
51231
+ const url_1 = __webpack_require__(79551);
51232
+ const debug = (__webpack_require__(28354).debuglog)('@cloudbase/signature');
51233
+ const isStream = __webpack_require__(31232);
51234
+ exports.signedParamsSeparator = ';';
51235
+ const HOST_KEY = 'host';
51236
+ const CONTENT_TYPE_KEY = 'content-type';
51237
+ var MIME;
51238
+ (function (MIME) {
51239
+ MIME["MULTIPART_FORM_DATA"] = "multipart/form-data";
51240
+ MIME["APPLICATION_JSON"] = "application/json";
51241
+ })(MIME || (MIME = {}));
51242
+ class Signer {
51243
+ constructor(credential, service, options = {}) {
51244
+ this.credential = credential;
51245
+ this.service = service;
51246
+ this.algorithm = 'TC3-HMAC-SHA256';
51247
+ this.options = options;
51248
+ }
51249
+ static camSafeUrlEncode(str) {
51250
+ return encodeURIComponent(str)
51251
+ .replace(/!/g, '%21')
51252
+ .replace(/'/g, '%27')
51253
+ .replace(/\(/g, '%28')
51254
+ .replace(/\)/g, '%29')
51255
+ .replace(/\*/g, '%2A');
51256
+ }
51257
+ /**
51258
+ * 将一个对象处理成 KeyValue 形式,嵌套的对象将会被处理成字符串,Key转换成小写字母
51259
+ * @param {Object} obj - 待处理的对象
51260
+ * @param {Object} options
51261
+ * @param {Boolean} options.enableBuffer
51262
+ */
51263
+ static formatKeyAndValue(obj, options = {}) {
51264
+ if (!utils_lang_1.isPlainObject(obj)) {
51265
+ return obj;
51266
+ }
51267
+ // enableValueToLowerCase:头部字段,要求小写,其他数据不需要小写,所以这里避免转小写
51268
+ const { multipart, enableValueToLowerCase = false, selectedKeys, filter } = options;
51269
+ const kv = {};
51270
+ Object.keys(obj || {}).forEach(key => {
51271
+ // NOTE: 客户端类型在服务端可能会丢失
51272
+ const lowercaseKey = Signer.camSafeUrlEncode(key.toLowerCase().trim());
51273
+ // 过滤 Key,服务端接收到的数据,可能含有未签名的 Key,通常是签名的时候被过滤掉的流,数据量可能会比较大
51274
+ // 所以这里提供一个过滤的判断,避免不必要的计算
51275
+ // istanbul ignore next
51276
+ if (Array.isArray(selectedKeys) && !selectedKeys.includes(lowercaseKey)) {
51277
+ return;
51278
+ }
51279
+ // istanbul ignore next
51280
+ if (typeof filter === 'function') {
51281
+ if (filter(key, obj[key], options)) {
51282
+ return;
51283
+ }
51284
+ }
51285
+ // istanbul ignore else
51286
+ if (key && obj[key] !== undefined) {
51287
+ if (lowercaseKey === CONTENT_TYPE_KEY) {
51288
+ // multipart/form-data; boundary=???
51289
+ if (obj[key].startsWith(MIME.MULTIPART_FORM_DATA)) {
51290
+ kv[lowercaseKey] = MIME.MULTIPART_FORM_DATA;
51291
+ }
51292
+ else {
51293
+ kv[lowercaseKey] = obj[key];
51294
+ }
51295
+ return;
51296
+ }
51297
+ if (isStream(obj[key])) {
51298
+ // 这里如果是个文件流,在发送的时候可以识别
51299
+ // 服务端接收到数据之后传到这里判断不出来的
51300
+ // 所以会进入后边的逻辑
51301
+ return;
51302
+ }
51303
+ else if (utils_1.isNodeEnv() && Buffer.isBuffer(obj[key])) {
51304
+ if (multipart) {
51305
+ kv[lowercaseKey] = obj[key];
51306
+ }
51307
+ else {
51308
+ kv[lowercaseKey] = enableValueToLowerCase
51309
+ ? utils_1.stringify(obj[key]).trim().toLowerCase()
51310
+ : utils_1.stringify(obj[key]).trim();
51311
+ }
51312
+ }
51313
+ else {
51314
+ kv[lowercaseKey] = enableValueToLowerCase
51315
+ ? utils_1.stringify(obj[key]).trim().toLowerCase()
51316
+ : utils_1.stringify(obj[key]).trim();
51317
+ }
51318
+ }
51319
+ });
51320
+ return kv;
51321
+ }
51322
+ static calcParamsHash(params, keys = null, options = {}) {
51323
+ debug(params, 'calcParamsHash');
51324
+ if (utils_lang_1.isString(params)) {
51325
+ return utils_1.sha256hash(params);
51326
+ }
51327
+ // 只关心业务参数,不关心以什么类型的 Content-Type 传递的
51328
+ // 所以 application/json multipart/form-data 计算方式是相同的
51329
+ keys = keys || keyvalue_1.SortedKeyValue.kv(params).keys();
51330
+ const hash = crypto.createHash('sha256');
51331
+ for (const key of keys) {
51332
+ // istanbul ignore next
51333
+ if (!params[key]) {
51334
+ continue;
51335
+ }
51336
+ // istanbul ignore next
51337
+ if (isStream(params[key])) {
51338
+ continue;
51339
+ }
51340
+ // string && buffer
51341
+ hash.update(`&${key}=`);
51342
+ hash.update(params[key]);
51343
+ hash.update('\r\n');
51344
+ }
51345
+ return hash.digest(options.encoding || 'hex');
51346
+ }
51347
+ /**
51348
+ * 计算签名信息
51349
+ * 注:默认是tcb签名算法,传入 options.isCloudApi=true,则使用云API V3签名算法
51350
+ * 云API V3算法文档:https://cloud.tencent.com/document/api/598/38504#NodeJS
51351
+ *
51352
+ * @param {string} method - Http Verb:GET/get POST/post 区分大小写
51353
+ * @param {string} url - 地址:http://abc.org/api/v1?a=1&b=2
51354
+ * @param {Object} headers - 需要签名的头部字段
51355
+ * @param {string} params - 请求参数
51356
+ * @param {number} [timestamp] - 签名时间戳
51357
+ * @param {object} [options] - 可选参数
51358
+ */
51359
+ tc3sign(method, url, headers, params, timestamp, options = {}) {
51360
+ timestamp = timestamp || utils_1.second();
51361
+ const urlInfo = url_1.parse(url);
51362
+ const formatedHeaders = Signer.formatKeyAndValue(headers, {
51363
+ enableValueToLowerCase: true
51364
+ });
51365
+ const headerKV = keyvalue_1.SortedKeyValue.kv(formatedHeaders);
51366
+ const signedHeaders = headerKV.keys();
51367
+ const canonicalHeaders = headerKV.toString(':', '\n') + '\n';
51368
+ const { enableHostCheck = true, enableContentTypeCheck = true, isCloudApi = false } = options;
51369
+ if (enableHostCheck && headerKV.get(HOST_KEY) !== urlInfo.host) {
51370
+ throw new TypeError(`host:${urlInfo.host} in url must be equals to host:${headerKV.get('host')} in headers`);
51371
+ }
51372
+ if (enableContentTypeCheck && !headerKV.get(CONTENT_TYPE_KEY)) {
51373
+ throw new TypeError(`${CONTENT_TYPE_KEY} field must in headers`);
51374
+ }
51375
+ const multipart = headerKV.get(CONTENT_TYPE_KEY).startsWith(MIME.MULTIPART_FORM_DATA);
51376
+ const formatedParams = isCloudApi ?
51377
+ JSON.stringify(params)
51378
+ : method.toUpperCase() === 'GET'
51379
+ ? ''
51380
+ : Signer.formatKeyAndValue(params, {
51381
+ multipart
51382
+ });
51383
+ const paramKV = keyvalue_1.SortedKeyValue.kv(formatedParams);
51384
+ const signedParams = paramKV.keys();
51385
+ const hashedPayload = Signer.calcParamsHash(formatedParams, null);
51386
+ const signedUrl = isCloudApi ? urlInfo.pathname : url.replace(/^https?:/, '').split('?')[0];
51387
+ const canonicalRequest = `${method}\n${signedUrl}\n${urlInfo.query || ''}\n${canonicalHeaders}\n${signedHeaders.join(';')}\n${hashedPayload}`;
51388
+ debug(canonicalRequest, 'canonicalRequest\n\n');
51389
+ const date = utils_1.formateDate(timestamp);
51390
+ const service = this.service;
51391
+ const algorithm = this.algorithm;
51392
+ const credentialScope = `${date}/${service}/tc3_request`;
51393
+ const stringToSign = `${algorithm}\n${timestamp}\n${credentialScope}\n${utils_1.sha256hash(canonicalRequest)}`;
51394
+ debug(stringToSign, 'stringToSign\n\n');
51395
+ const secretDate = utils_1.sha256hmac(date, `TC3${this.credential.secretKey}`);
51396
+ const secretService = utils_1.sha256hmac(service, secretDate);
51397
+ const secretSigning = utils_1.sha256hmac('tc3_request', secretService);
51398
+ const signature = utils_1.sha256hmac(stringToSign, secretSigning, 'hex');
51399
+ debug(secretDate.toString('hex'), 'secretDate');
51400
+ debug(secretService.toString('hex'), 'secretService');
51401
+ debug(secretSigning.toString('hex'), 'secretSigning');
51402
+ debug(signature, 'signature');
51403
+ const { withSignedParams = false } = options;
51404
+ return {
51405
+ // 需注意该字段长度
51406
+ // https://stackoverflow.com/questions/686217/maximum-on-http-header-values
51407
+ // https://www.tutorialspoint.com/What-is-the-maximum-size-of-HTTP-header-values
51408
+ authorization: `${algorithm} Credential=${this.credential.secretId}/${credentialScope},${withSignedParams ? ` SignedParams=${signedParams.join(';')},` : ''} SignedHeaders=${signedHeaders.join(';')}, Signature=${signature}`,
51409
+ signedParams,
51410
+ signedHeaders,
51411
+ signature,
51412
+ timestamp,
51413
+ multipart
51414
+ };
51415
+ }
51416
+ }
51417
+ exports.Signer = Signer;
51418
+
51419
+
51063
51420
  /***/ }),
51064
51421
 
51065
51422
  /***/ 12146:
@@ -62038,6 +62395,14 @@ class DatabaseService {
62038
62395
  Tag: Databases[0].InstanceId
62039
62396
  };
62040
62397
  }
62398
+ getMongoConnector() {
62399
+ const currEnv = this.environment;
62400
+ const { Databases } = currEnv.lazyEnvironmentConfig;
62401
+ return {
62402
+ DatabaseName: Databases[0].InstanceId,
62403
+ InstanceId: 'flexdb'
62404
+ };
62405
+ }
62041
62406
  async checkCollectionExists(collectionName) {
62042
62407
  try {
62043
62408
  const result = await this.describeCollection(collectionName);
@@ -62055,9 +62420,10 @@ class DatabaseService {
62055
62420
  }
62056
62421
  }
62057
62422
  async createCollection(collectionName) {
62058
- let { Tag } = this.getDatabaseConfig();
62059
- const res = await this.collOpService.request('CreateTable', {
62060
- Tag,
62423
+ const MongoConnector = this.getMongoConnector();
62424
+ const res = await this.dbOpService.request('CreateTable', {
62425
+ EnvId: this.envId,
62426
+ MongoConnector,
62061
62427
  TableName: collectionName
62062
62428
  });
62063
62429
  return res;
@@ -62066,9 +62432,10 @@ class DatabaseService {
62066
62432
  // 先检查当前集合是否存在
62067
62433
  const existRes = await this.checkCollectionExists(collectionName);
62068
62434
  if (existRes.Exists) {
62069
- let { Tag } = this.getDatabaseConfig();
62070
- const res = await this.collOpService.request('DeleteTable', {
62071
- Tag,
62435
+ const MongoConnector = this.getMongoConnector();
62436
+ const res = await this.dbOpService.request('DeleteTable', {
62437
+ EnvId: this.envId,
62438
+ MongoConnector,
62072
62439
  TableName: collectionName
62073
62440
  });
62074
62441
  return res;
@@ -62078,14 +62445,15 @@ class DatabaseService {
62078
62445
  }
62079
62446
  }
62080
62447
  async updateCollection(collectionName, indexiesInfo) {
62081
- let { Tag } = this.getDatabaseConfig();
62082
- const res = await this.collOpService.request('UpdateTable', Object.assign({ Tag, TableName: collectionName }, indexiesInfo));
62448
+ const MongoConnector = this.getMongoConnector();
62449
+ const res = await this.dbOpService.request('UpdateTable', Object.assign({ EnvId: this.envId, MongoConnector, TableName: collectionName }, indexiesInfo));
62083
62450
  return res;
62084
62451
  }
62085
62452
  async describeCollection(collectionName) {
62086
- let { Tag } = this.getDatabaseConfig();
62087
- return this.collOpService.request('DescribeTable', {
62088
- Tag,
62453
+ const MongoConnector = this.getMongoConnector();
62454
+ return this.dbOpService.request('DescribeTable', {
62455
+ EnvId: this.envId,
62456
+ MongoConnector,
62089
62457
  TableName: collectionName
62090
62458
  });
62091
62459
  }
@@ -62094,14 +62462,14 @@ class DatabaseService {
62094
62462
  MgoLimit: this.DEFAULT_MGO_LIMIT,
62095
62463
  MgoOffset: this.DEFAULT_MGO_OFFSET
62096
62464
  }) {
62097
- let { Tag } = this.getDatabaseConfig();
62465
+ const MongoConnector = this.getMongoConnector();
62098
62466
  if (options.MgoLimit === undefined) {
62099
62467
  options.MgoLimit = this.DEFAULT_MGO_LIMIT;
62100
62468
  }
62101
62469
  if (options.MgoOffset === undefined) {
62102
62470
  options.MgoOffset = this.DEFAULT_MGO_OFFSET;
62103
62471
  }
62104
- const res = await this.collOpService.request('ListTables', Object.assign({ Tag }, options));
62472
+ const res = await this.dbOpService.request('ListTables', Object.assign({ EnvId: this.envId, MongoConnector }, options));
62105
62473
  if (res.Tables === null) {
62106
62474
  // 无集合
62107
62475
  res.Collections = [];
@@ -62266,12 +62634,16 @@ class DatabaseService {
62266
62634
  }
62267
62635
  /**
62268
62636
  * 执行文档型数据库命令
62269
- * @param options 命令参数(命令列表、可选的 Tag/EnvId/MongoConnector)
62637
+ * @param options 命令参数(命令列表、可选的 EnvId/MongoConnector)
62270
62638
  * @returns 执行结果,Data 为 JSON 字符串数组
62271
62639
  */
62272
62640
  async runCommands(options) {
62273
- let { Tag } = this.getDatabaseConfig();
62274
- return this.dbOpService.request('RunCommands', Object.assign({ MgoCommands: options.MgoCommands, Tag: options.Tag || Tag, EnvId: options.EnvId || this.envId }, (options.MongoConnector ? { MongoConnector: options.MongoConnector } : {})));
62641
+ const MongoConnector = options.MongoConnector || this.getMongoConnector();
62642
+ return this.dbOpService.request('RunCommands', {
62643
+ MgoCommands: options.MgoCommands,
62644
+ MongoConnector,
62645
+ EnvId: options.EnvId || this.envId,
62646
+ });
62275
62647
  }
62276
62648
  /**
62277
62649
  * 在 PostgreSQL 数据库上执行 SQL 语句
@@ -86776,7 +87148,11 @@ class PermissionService {
86776
87148
  constructor(environment) {
86777
87149
  this.environment = environment;
86778
87150
  this.tcbService = new utils_1.CloudService(environment.cloudBaseContext, 'tcb', '2018-06-08');
87151
+ this.lowcodeService = new utils_1.CloudService(environment.cloudBaseContext, 'lowcode', '2021-01-08');
86779
87152
  }
87153
+ /**
87154
+ * @deprecated 已废弃,网关鉴权策略已由 OPA 接管,请使用 modifyEnvAuthzConfig 替代
87155
+ */
86780
87156
  async modifyResourcePermission(options) {
86781
87157
  const { EnvId } = this.environment.lazyEnvironmentConfig;
86782
87158
  const { resourceType, resource, permission, securityRule } = options;
@@ -86809,6 +87185,9 @@ class PermissionService {
86809
87185
  }
86810
87186
  return this.tcbService.request('ModifyResourcePermission', reqData);
86811
87187
  }
87188
+ /**
87189
+ * @deprecated 已废弃,网关鉴权策略已由 OPA 接管,请使用 describeResourcePolicyList 或 describeEnvAuthzConfig 替代
87190
+ */
86812
87191
  async describeResourcePermission(options) {
86813
87192
  const { EnvId } = this.environment.lazyEnvironmentConfig;
86814
87193
  const { resourceType, resources } = options;
@@ -87046,6 +87425,102 @@ class PermissionService {
87046
87425
  RoleIds: roleIds
87047
87426
  });
87048
87427
  }
87428
+ /**
87429
+ * 拉取环境下的所有用户自定义的网关鉴权策略列表
87430
+ * 注意:PG 环境无需调用,直接按照无存量策略处理;
87431
+ * 若环境 meta 中 authz_engine 值为 opa,则网关策略不生效,无需调用
87432
+ */
87433
+ async describeResourcePolicyList(options = {}) {
87434
+ const { resourceType } = options;
87435
+ if (resourceType !== undefined && (typeof resourceType !== 'string' || resourceType.trim().length === 0)) {
87436
+ throw new Error('Invalid resourceType');
87437
+ }
87438
+ // PG 环境无需调用,直接返回空策略列表
87439
+ if (await this.isPostgresqlEnv()) {
87440
+ const emptyData = { PolicyList: [], Total: '0' };
87441
+ return {
87442
+ Data: emptyData,
87443
+ RequestId: ''
87444
+ };
87445
+ }
87446
+ // authz_engine 为 opa 时网关策略不生效,无需调用,直接返回空策略列表
87447
+ if (await this.isOpaAuthzEngine()) {
87448
+ const emptyData = { PolicyList: [], Total: '0' };
87449
+ return {
87450
+ Data: emptyData,
87451
+ RequestId: ''
87452
+ };
87453
+ }
87454
+ const { EnvId } = this.environment.lazyEnvironmentConfig;
87455
+ const reqData = {
87456
+ EnvId,
87457
+ ResourceType: resourceType || 'policy'
87458
+ };
87459
+ return this.lowcodeService.request('DescribeResourcePolicyList', reqData);
87460
+ }
87461
+ /**
87462
+ * 拉取环境下的鉴权策略配置
87463
+ * key: authz.platform.extension.rego - 单独为该环境配置的策略
87464
+ * key: authz.user.rego - 用户配置的策略
87465
+ */
87466
+ async describeEnvAuthzConfig(options) {
87467
+ const { key } = options;
87468
+ if (!key || (key !== 'authz.platform.extension.rego' && key !== 'authz.user.rego')) {
87469
+ throw new Error('key must be "authz.platform.extension.rego" or "authz.user.rego"');
87470
+ }
87471
+ const { EnvId } = this.environment.lazyEnvironmentConfig;
87472
+ return this.tcbService.request('DescribeEnvConfig', {
87473
+ EnvId,
87474
+ Key: key
87475
+ });
87476
+ }
87477
+ /**
87478
+ * 保存用户编写的 rego 策略,保存后旧网关鉴权将直接失效
87479
+ */
87480
+ async modifyEnvAuthzConfig(options) {
87481
+ const { EnvId } = this.environment.lazyEnvironmentConfig;
87482
+ const { key, value } = options;
87483
+ if (key !== 'authz.user.rego') {
87484
+ throw new Error('key must be "authz.user.rego"');
87485
+ }
87486
+ if (typeof value !== 'string' || value.trim().length === 0) {
87487
+ throw new Error('value is required and must be a non-empty string');
87488
+ }
87489
+ return this.tcbService.request('ModifyEnvConfig', {
87490
+ EnvId,
87491
+ Key: key,
87492
+ Value: value
87493
+ });
87494
+ }
87495
+ /**
87496
+ * 获取完整的环境基础信息(含 PostgreSQL、Meta 等字段)
87497
+ */
87498
+ async getEnvBaseInfo() {
87499
+ var _a;
87500
+ const { EnvId } = this.environment.lazyEnvironmentConfig;
87501
+ const params = { EnvId };
87502
+ const res = await this.environment.getEnvService().describeEnvInfo(params);
87503
+ return ((_a = res === null || res === void 0 ? void 0 : res.EnvInfo) === null || _a === void 0 ? void 0 : _a.EnvBaseInfo) || {};
87504
+ }
87505
+ /**
87506
+ * 判断当前环境是否为 PostgreSQL 环境
87507
+ */
87508
+ async isPostgresqlEnv() {
87509
+ return this.environment.getEnvService().isPostgresqlEnv();
87510
+ }
87511
+ /**
87512
+ * 判断当前环境的 authz_engine 是否为 opa
87513
+ * 从环境 Meta 中查找 Key 为 authz_engine 的标签,Value 为 opa 表示已切到 OPA
87514
+ */
87515
+ async isOpaAuthzEngine() {
87516
+ const envBaseInfo = await this.getEnvBaseInfo();
87517
+ const meta = envBaseInfo === null || envBaseInfo === void 0 ? void 0 : envBaseInfo.Meta;
87518
+ if (!Array.isArray(meta)) {
87519
+ return false;
87520
+ }
87521
+ const authzEngineTag = meta.find(tag => tag.Key === 'authz_engine');
87522
+ return (authzEngineTag === null || authzEngineTag === void 0 ? void 0 : authzEngineTag.Value) === 'opa';
87523
+ }
87049
87524
  }
87050
87525
  exports.PermissionService = PermissionService;
87051
87526
  __decorate([
@@ -87066,6 +87541,15 @@ __decorate([
87066
87541
  __decorate([
87067
87542
  (0, utils_1.preLazy)()
87068
87543
  ], PermissionService.prototype, "deleteRoles", null);
87544
+ __decorate([
87545
+ (0, utils_1.preLazy)()
87546
+ ], PermissionService.prototype, "describeResourcePolicyList", null);
87547
+ __decorate([
87548
+ (0, utils_1.preLazy)()
87549
+ ], PermissionService.prototype, "describeEnvAuthzConfig", null);
87550
+ __decorate([
87551
+ (0, utils_1.preLazy)()
87552
+ ], PermissionService.prototype, "modifyEnvAuthzConfig", null);
87069
87553
 
87070
87554
 
87071
87555
  /***/ }),
@@ -89171,7 +89655,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
89171
89655
  return (mod && mod.__esModule) ? mod : { "default": mod };
89172
89656
  };
89173
89657
  Object.defineProperty(exports, "__esModule", ({ value: true }));
89174
- exports.MANAGE_FUNCTION_ACTIONS = exports.QUERY_FUNCTION_ACTIONS = exports.TRIGGER_CONFIG_EXAMPLES = exports.SUPPORTED_TRIGGER_TYPES = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = void 0;
89658
+ exports.CUSTOM_IMAGE_RUNTIME = exports.MANAGE_FUNCTION_ACTIONS = exports.QUERY_FUNCTION_ACTIONS = exports.TRIGGER_CONFIG_EXAMPLES = exports.SUPPORTED_TRIGGER_TYPES = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = void 0;
89175
89659
  exports.formatRuntimeList = formatRuntimeList;
89176
89660
  exports.validateTimerCron = validateTimerCron;
89177
89661
  exports.shouldInstallDependencyForFunction = shouldInstallDependencyForFunction;
@@ -89279,6 +89763,41 @@ const VPC_SCHEMA = zod_1.z.object({
89279
89763
  vpcId: zod_1.z.string(),
89280
89764
  subnetId: zod_1.z.string(),
89281
89765
  });
89766
+ // 镜像部署值,对应 SCF Runtime=CustomImage
89767
+ exports.CUSTOM_IMAGE_RUNTIME = "CustomImage";
89768
+ // HTTP 函数镜像部署配置,对应 Manager SDK 的 IFunctionImageConfig(camelCase)。
89769
+ // 用于 zip→COS→CloudApp custom 构建→TCR→SCF 镜像部署链路的「阶段 B」:基于已推送到 TCR 的镜像创建/更新函数。
89770
+ const IMAGE_CONFIG_SCHEMA = zod_1.z.object({
89771
+ imageType: zod_1.z
89772
+ .enum(["enterprise", "personal"])
89773
+ .optional()
89774
+ .describe("镜像仓库类型:enterprise(企业版 TCR)或 personal(个人版)。省略时默认 enterprise。"),
89775
+ imageUri: zod_1.z
89776
+ .string()
89777
+ .describe("完整镜像地址(必须含 tag),格式 {domain}/{namespace}/{image}:{tag}," +
89778
+ "例如 ccr.ccs.tencentyun.com/your-ns/demo-app:demo-app-001。不要使用 :latest。"),
89779
+ registryId: zod_1.z
89780
+ .string()
89781
+ .optional()
89782
+ .describe("TCR 实例 ID,形如 tcr-xxxxxxxx。imageType=enterprise 时必填。"),
89783
+ command: zod_1.z
89784
+ .string()
89785
+ .optional()
89786
+ .describe("覆盖镜像 ENTRYPOINT。不填则使用 Dockerfile 默认值,例如 python。"),
89787
+ args: zod_1.z
89788
+ .string()
89789
+ .optional()
89790
+ .describe("覆盖镜像 CMD,空格分隔,例如 -u app.py。"),
89791
+ entryPoint: zod_1.z.string().optional().describe("镜像入口点,一般不需要单独设置。"),
89792
+ imagePort: zod_1.z
89793
+ .number()
89794
+ .optional()
89795
+ .describe("容器监听端口。Web Server 函数填 9000(默认),Job 型镜像填 -1。"),
89796
+ containerImageAccelerate: zod_1.z
89797
+ .boolean()
89798
+ .optional()
89799
+ .describe("是否开启镜像加速。镜像较大时建议开启以缩短冷启动时间。"),
89800
+ });
89282
89801
  const SEVEN_FIELD_CRON_REGEX = /^\s*\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s*$/;
89283
89802
  function validateTimerCron(config) {
89284
89803
  const trimmed = config.trim();
@@ -89338,7 +89857,11 @@ const CREATE_FUNCTION_SCHEMA = zod_1.z.object({
89338
89857
  ` Python: ${exports.RECOMMENDED_RUNTIMES.python}\n` +
89339
89858
  ` PHP: ${exports.RECOMMENDED_RUNTIMES.php}\n` +
89340
89859
  ` Java: ${exports.RECOMMENDED_RUNTIMES.java}\n` +
89341
- ` Go: ${exports.RECOMMENDED_RUNTIMES.golang}`),
89860
+ ` Go: ${exports.RECOMMENDED_RUNTIMES.golang}\n\n` +
89861
+ `镜像部署(基于 TCR 镜像创建函数)时填 "${exports.CUSTOM_IMAGE_RUNTIME}",并提供 imageConfig;此时无需 functionRootPath/zipFile。`),
89862
+ imageConfig: IMAGE_CONFIG_SCHEMA.optional().describe("镜像部署配置(仅 runtime=CustomImage 时使用)。" +
89863
+ "用于 zip→COS→CloudApp custom 构建→TCR→SCF 的「阶段 B」:基于已推送到 TCR 的镜像创建 HTTP 函数。" +
89864
+ "传入 imageConfig 后即按镜像部署处理,函数无需打包本地代码、scf_bootstrap 或 Handler。"),
89342
89865
  triggers: zod_1.z.array(TRIGGER_SCHEMA).optional().describe("触发器配置数组"),
89343
89866
  handler: zod_1.z.string().optional().describe("函数入口"),
89344
89867
  ignore: zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]).optional().describe("忽略文件"),
@@ -89487,7 +90010,12 @@ function registerFunctionTools(server) {
89487
90010
  return;
89488
90011
  }
89489
90012
  if (input.action === "createFunction" || input.action === "updateFunctionCode") {
89490
- throw new Error(`${input.action} 在 cloud mode 下不可用,因为该操作依赖本地函数代码目录。请改用本地模式执行。`);
90013
+ // 镜像部署不依赖本地代码目录(代码已在 TCR),cloud mode 下可用。
90014
+ const hasImageConfig = Boolean(input.imageConfig ?? input.func?.imageConfig);
90015
+ if (hasImageConfig) {
90016
+ return;
90017
+ }
90018
+ throw new Error(`${input.action} 在 cloud mode 下不可用,因为该操作依赖本地函数代码目录。请改用本地模式执行,或使用镜像部署(runtime=CustomImage + imageConfig)。`);
89491
90019
  }
89492
90020
  if (input.action === "createLayerVersion" && input.contentPath) {
89493
90021
  throw new Error("createLayerVersion 在 cloud mode 下不支持 contentPath,本地文件内容请改为 base64Content 或改用本地模式执行。");
@@ -89837,6 +90365,70 @@ function registerFunctionTools(server) {
89837
90365
  const func = { ...input.func };
89838
90366
  const functionName = String(func.name);
89839
90367
  (0, logger_js_1.debug)(`[createFunction] name=${functionName}, type=${String(func.type || "Event")}`);
90368
+ // 镜像部署分支(Runtime=CustomImage):基于已推送到 TCR 的镜像创建 HTTP 函数。
90369
+ // 对应 zip→COS→CloudApp custom 构建→TCR→SCF 链路的「阶段 B」。
90370
+ const createImageConfig = input.imageConfig ??
90371
+ func.imageConfig;
90372
+ const isImageRuntime = typeof func.runtime === "string" &&
90373
+ func.runtime.replace(/\s+/g, "").toLowerCase() ===
90374
+ exports.CUSTOM_IMAGE_RUNTIME.toLowerCase();
90375
+ if (createImageConfig || isImageRuntime) {
90376
+ if (!createImageConfig?.imageUri) {
90377
+ throw new Error("镜像部署(runtime=CustomImage)时,imageConfig.imageUri 是必需的," +
90378
+ "格式为 {domain}/{namespace}/{image}:{tag}(含 tag,不要用 :latest)。");
90379
+ }
90380
+ if ((createImageConfig.imageType ?? "enterprise") === "enterprise" &&
90381
+ !createImageConfig.registryId) {
90382
+ throw new Error("imageType=enterprise(企业版 TCR)时,imageConfig.registryId(tcr-xxxxxxxx)是必需的。");
90383
+ }
90384
+ // 镜像函数即 HTTP 函数;Manager SDK 会自动补 ImageType=enterprise、ImagePort=9000,
90385
+ // 并在镜像部署时剥离 Handler / InstallDependency,故此处不需要 functionRootPath。
90386
+ const imageFunc = {
90387
+ ...func,
90388
+ type: func.type ?? "HTTP",
90389
+ runtime: exports.CUSTOM_IMAGE_RUNTIME,
90390
+ imageConfig: createImageConfig,
90391
+ };
90392
+ delete imageFunc.installDependency;
90393
+ let imageResult;
90394
+ try {
90395
+ imageResult = await cloudbase.functions.createFunction({
90396
+ func: imageFunc,
90397
+ deployMode: "image",
90398
+ force: Boolean(input.force),
90399
+ });
90400
+ }
90401
+ catch (error) {
90402
+ throw wrapFunctionOperationError("createFunction", functionName, undefined, error);
90403
+ }
90404
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, imageResult);
90405
+ return buildEnvelope({
90406
+ action: input.action,
90407
+ functionName,
90408
+ deployMode: "image",
90409
+ imageUri: createImageConfig.imageUri,
90410
+ raw: imageResult,
90411
+ }, `已基于镜像 ${createImageConfig.imageUri} 创建 HTTP 函数 ${functionName}。` +
90412
+ `请确认 TCR、SCF 与构建管道处于同一地域;如需通过 URL 访问,请显式调用 ` +
90413
+ `manageGateway(action="createAccess", type="HTTP") 并按需调整函数安全规则。` +
90414
+ `部署后可用 queryFunctions(action="getFunctionDetail") 确认函数已就绪。`, [
90415
+ {
90416
+ tool: "queryFunctions",
90417
+ action: "getFunctionDetail",
90418
+ reason: "确认镜像函数已就绪(Active)",
90419
+ },
90420
+ {
90421
+ tool: "manageFunctions",
90422
+ action: "updateFunctionCode",
90423
+ reason: "后续迭代只需用新镜像 tag 调用 updateFunctionCode 更新镜像",
90424
+ },
90425
+ {
90426
+ tool: "manageGateway",
90427
+ action: "createAccess",
90428
+ reason: "如需通过 URL 访问镜像 HTTP 函数,显式创建网关访问入口并传 type=\"HTTP\"",
90429
+ },
90430
+ ]);
90431
+ }
89840
90432
  if (func.type !== "HTTP") {
89841
90433
  const originalRuntime = typeof func.runtime === "string" ? func.runtime : undefined;
89842
90434
  func.runtime = resolveEventFunctionRuntime(func.runtime);
@@ -89930,6 +90522,42 @@ function registerFunctionTools(server) {
89930
90522
  throw new Error("updateFunctionCode 操作时,functionName 参数是必需的");
89931
90523
  }
89932
90524
  const cloudbase = await getManager();
90525
+ // 镜像更新分支:后续迭代只需用新镜像 tag 更新函数。
90526
+ const updateImageConfig = input.imageConfig ??
90527
+ input.func?.imageConfig;
90528
+ if (updateImageConfig) {
90529
+ if (!updateImageConfig.imageUri) {
90530
+ throw new Error("镜像更新时,imageConfig.imageUri 是必需的,格式为 {domain}/{namespace}/{image}:{tag}(含 tag,不要用 :latest)。");
90531
+ }
90532
+ let imageResult;
90533
+ try {
90534
+ imageResult = await cloudbase.functions.updateFunctionCode({
90535
+ func: {
90536
+ name: input.functionName,
90537
+ imageConfig: updateImageConfig,
90538
+ },
90539
+ deployMode: "image",
90540
+ });
90541
+ }
90542
+ catch (error) {
90543
+ throw wrapFunctionOperationError("updateFunctionCode", input.functionName, undefined, error);
90544
+ }
90545
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, imageResult);
90546
+ return buildEnvelope({
90547
+ action: input.action,
90548
+ functionName: input.functionName,
90549
+ deployMode: "image",
90550
+ imageUri: updateImageConfig.imageUri,
90551
+ raw: imageResult,
90552
+ }, `已将函数 ${input.functionName} 的镜像更新为 ${updateImageConfig.imageUri}。` +
90553
+ `部署后可用 queryFunctions(action="getFunctionDetail") 确认函数已就绪(Active)。`, [
90554
+ {
90555
+ tool: "queryFunctions",
90556
+ action: "getFunctionDetail",
90557
+ reason: "确认镜像更新后函数已就绪(Active)",
90558
+ },
90559
+ ]);
90560
+ }
89933
90561
  const processedRootPath = processFunctionRootPath(input.functionRootPath, input.functionName);
89934
90562
  const updateParams = {
89935
90563
  func: {
@@ -90340,6 +90968,8 @@ function registerFunctionTools(server) {
90340
90968
  title: "管理 CloudBase 云函数",
90341
90969
  description: "CloudBase 云函数统一写入口。支持创建函数、更新代码、更新配置、调用函数、管理定时跑 / 定时任务 / scheduled job 的 timer 触发器和层绑定。" +
90342
90970
  "如果要创建 cron 定时任务,先用 createFunction 创建函数,再用 createFunctionTrigger 创建 timer 触发器(支持7段cron表达式),deleteFunctionTrigger 删除触发器。" +
90971
+ "镜像部署(Runtime=CustomImage):先把代码经 zip→COS→CloudApp custom 构建→TCR 推镜像(这一阶段为裸腾讯云 API,本工具不覆盖)," +
90972
+ "再用 createFunction(func.runtime=\"CustomImage\", imageConfig) 基于 TCR 镜像创建 HTTP 函数;后续迭代用 updateFunctionCode + imageConfig 换镜像 tag。" +
90343
90973
  "危险操作需要显式 confirm=true。",
90344
90974
  inputSchema: {
90345
90975
  action: zod_1.z
@@ -90379,6 +91009,9 @@ function registerFunctionTools(server) {
90379
91009
  .optional()
90380
91010
  .describe("updateFunctionLayers 的目标层列表,顺序即最终顺序"),
90381
91011
  codeSecret: zod_1.z.string().optional().describe("层绑定时的代码保护密钥"),
91012
+ imageConfig: IMAGE_CONFIG_SCHEMA.optional().describe("镜像部署配置(Runtime=CustomImage)。createFunction 时基于 TCR 镜像创建 HTTP 函数," +
91013
+ "updateFunctionCode 时仅更换镜像 tag。需提供 imageUri(含 tag),企业版 TCR 还需 registryId。" +
91014
+ "也可在 func.imageConfig 中提供;两处都传时以顶层 imageConfig 优先。"),
90382
91015
  confirm: zod_1.z.boolean().optional().describe("危险操作确认开关。deleteFunction、deleteFunctionTrigger、deleteLayerVersion、detachLayer 等删除类操作需要显式传入 confirm=true"),
90383
91016
  incrementalFile: zod_1.z.string().optional().describe("incrementalDeployFunction 增量部署时的变更文件路径"),
90384
91017
  },
@@ -92501,6 +93134,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
92501
93134
  exports.EnvService = void 0;
92502
93135
  const cos_nodejs_sdk_v5_1 = __importDefault(__webpack_require__(93625));
92503
93136
  const util_1 = __importDefault(__webpack_require__(28354));
93137
+ const http_request_1 = __webpack_require__(72088);
93138
+ const signature_nodejs_1 = __webpack_require__(77463);
92504
93139
  const error_1 = __webpack_require__(40430);
92505
93140
  const utils_1 = __webpack_require__(62358);
92506
93141
  const constant_1 = __webpack_require__(40762);
@@ -92515,6 +93150,7 @@ class EnvService {
92515
93150
  this.tcbService = new utils_1.CloudService(environment.cloudBaseContext, 'tcb', '2018-06-08');
92516
93151
  this.commonService = environment.getCommonService('lowcode', '2021-01-08');
92517
93152
  this.billingService = new billing_1.BillingService(environment.cloudBaseContext);
93153
+ this.tokenCache = new Map();
92518
93154
  }
92519
93155
  /**
92520
93156
  * 列出所有环境
@@ -92632,7 +93268,7 @@ class EnvService {
92632
93268
  };
92633
93269
  const response = await this.describeEnvInfo(params);
92634
93270
  const envBaseInfo = (_a = response === null || response === void 0 ? void 0 : response.EnvInfo) === null || _a === void 0 ? void 0 : _a.EnvBaseInfo;
92635
- // 成功获取环境信息,将 EnvBaseInfo 映射到 EnvInfo 类型
93271
+ // 将 EnvBaseInfo 完整映射到 EnvInfo 类型,避免新增字段被丢弃
92636
93272
  const envInfo = {
92637
93273
  EnvId: envBaseInfo.EnvId,
92638
93274
  Alias: envBaseInfo.Alias,
@@ -92647,7 +93283,22 @@ class EnvService {
92647
93283
  Region: envBaseInfo.Region || '',
92648
93284
  Source: envBaseInfo.Source,
92649
93285
  CreateTime: envBaseInfo.CreateTime,
92650
- UpdateTime: envBaseInfo.UpdateTime
93286
+ UpdateTime: envBaseInfo.UpdateTime,
93287
+ StaticStorages: envBaseInfo.StaticStorages,
93288
+ IsAutoDegrade: envBaseInfo.IsAutoDegrade,
93289
+ EnvChannel: envBaseInfo.EnvChannel,
93290
+ PayMode: envBaseInfo.PayMode,
93291
+ IsDefault: envBaseInfo.IsDefault,
93292
+ Tags: envBaseInfo.Tags,
93293
+ EnvType: envBaseInfo.EnvType,
93294
+ IsDauPackage: envBaseInfo.IsDauPackage,
93295
+ PackageType: envBaseInfo.PackageType,
93296
+ ArchitectureType: envBaseInfo.ArchitectureType,
93297
+ Recycle: envBaseInfo.Recycle,
93298
+ EnvPreferences: envBaseInfo.EnvPreferences,
93299
+ Meta: envBaseInfo.Meta,
93300
+ PostgreSQL: envBaseInfo.PostgreSQL,
93301
+ EnvStatus: envBaseInfo.EnvStatus
92651
93302
  };
92652
93303
  return {
92653
93304
  EnvInfo: envInfo,
@@ -92672,6 +93323,18 @@ class EnvService {
92672
93323
  async describeEnvInfo(params) {
92673
93324
  return this.cloudService.request('DescribeEnvInfo', params);
92674
93325
  }
93326
+ /**
93327
+ * 判断当前环境是否为 PostgreSQL 环境
93328
+ * PostgreSQL 字段为数组且长度 > 0 时视为 PG 环境
93329
+ *
93330
+ * @returns 是否为 PG 环境
93331
+ */
93332
+ async isPostgresqlEnv() {
93333
+ var _a, _b;
93334
+ const response = await this.describeEnvInfo({ EnvId: this.envId });
93335
+ const postgresql = (_b = (_a = response === null || response === void 0 ? void 0 : response.EnvInfo) === null || _a === void 0 ? void 0 : _a.EnvBaseInfo) === null || _b === void 0 ? void 0 : _b.PostgreSQL;
93336
+ return Array.isArray(postgresql) && postgresql.length > 0;
93337
+ }
92675
93338
  /**
92676
93339
  * 修改环境名称
92677
93340
  * @param {string} alias 环境名称
@@ -92899,6 +93562,74 @@ class EnvService {
92899
93562
  async describeApiKeyList(options) {
92900
93563
  return this.tcbService.request('DescribeApiKeyList', Object.assign({ EnvId: this.envId }, options));
92901
93564
  }
93565
+ /**
93566
+ * 根据密钥信息获取管理员访问令牌
93567
+ * 使用 secretId、secretKey 和 sessionToken 签发访问令牌
93568
+ * 默认从初始化时的 cloudBaseContext 中读取密钥,也可显式传入 credentials 覆盖
93569
+ * @param {Object} [credentials] 密钥信息,不传则使用初始化时的密钥
93570
+ * @param {string} credentials.secretId 密钥ID
93571
+ * @param {string} credentials.secretKey 密钥Key
93572
+ * @param {string} [credentials.token] sessionToken
93573
+ * @returns {Promise<string>} 访问令牌
93574
+ */
93575
+ async getAdminAccessToken(credentials) {
93576
+ const { secretId, secretKey, token } = credentials || this.environment.cloudBaseContext;
93577
+ if (!secretId || !secretKey) {
93578
+ throw new error_1.CloudBaseError('missing secretId or secretKey of tencent cloud');
93579
+ }
93580
+ const envId = this.envId;
93581
+ const cacheKey = `access_token_secret_${envId}_${secretId}`;
93582
+ const cached = this.tokenCache.get(cacheKey);
93583
+ if (cached && cached.expiry > Date.now()) {
93584
+ return cached.token;
93585
+ }
93586
+ const host = `${envId}${this.environment.cloudBaseContext.isInternalEndpoint()
93587
+ ? '.api.intl.tcloudbasegateway.com'
93588
+ : '.api.tcloudbasegateway.com'}`;
93589
+ const url = `https://${host}/auth/v1/token/clientCredential`;
93590
+ const method = 'POST';
93591
+ const headers = {
93592
+ 'Content-Type': 'application/json',
93593
+ Host: host,
93594
+ };
93595
+ const data = { grant_type: 'client_credentials' };
93596
+ const timestamp = Math.floor(new Date().getTime() / 1000) - 1;
93597
+ const { authorization, timestamp: signTimestamp } = (0, signature_nodejs_1.sign)({
93598
+ secretId,
93599
+ secretKey,
93600
+ method,
93601
+ url,
93602
+ headers,
93603
+ params: data,
93604
+ timestamp,
93605
+ withSignedParams: false,
93606
+ isCloudApi: true,
93607
+ });
93608
+ headers['Authorization'] = `${authorization}, Timestamp=${signTimestamp}${token ? `, Token=${token}` : ''}`;
93609
+ headers['X-Signature-Expires'] = 600;
93610
+ headers['X-Timestamp'] = signTimestamp;
93611
+ try {
93612
+ const response = await (0, http_request_1.fetch)(url, {
93613
+ method,
93614
+ headers,
93615
+ body: JSON.stringify(data),
93616
+ });
93617
+ const res = await response.json();
93618
+ const access_token = res === null || res === void 0 ? void 0 : res.access_token;
93619
+ const expires_in = (res === null || res === void 0 ? void 0 : res.expires_in) || 0;
93620
+ if (access_token && expires_in) {
93621
+ this.tokenCache.set(cacheKey, {
93622
+ token: access_token,
93623
+ expiry: Date.now() + (expires_in * 1000) / 2,
93624
+ });
93625
+ }
93626
+ return access_token;
93627
+ }
93628
+ catch (e) {
93629
+ console.log(e);
93630
+ throw e;
93631
+ }
93632
+ }
92902
93633
  // 创建自定义登录私钥
92903
93634
  async createCustomLoginKeys() {
92904
93635
  return this.cloudService.request('CreateCustomLoginKeys', {
@@ -102560,6 +103291,7 @@ const DEFAULT_PLUGINS = [
102560
103291
  "database",
102561
103292
  "pg_database",
102562
103293
  "pg_storage",
103294
+ "mysql_database",
102563
103295
  "functions",
102564
103296
  "hosting",
102565
103297
  "storage",
@@ -102582,10 +103314,6 @@ function registerDatabase(server) {
102582
103314
  if (!(0, tencent_cloud_js_1.isInternationalRegion)(region)) {
102583
103315
  (0, databaseNoSQL_js_1.registerDatabaseTools)(server);
102584
103316
  }
102585
- const pgPluginEnabled = server.enabledPlugins?.some((pluginName) => pluginName === "pg_database" || pluginName === "pg_storage");
102586
- if (!pgPluginEnabled) {
102587
- (0, databaseSQL_js_1.registerSQLDatabaseTools)(server);
102588
- }
102589
103317
  (0, dataModel_js_1.registerDataModelTools)(server);
102590
103318
  }
102591
103319
  function registerMysqlDatabase(server) {
@@ -112940,6 +113668,52 @@ Promise.PromiseInspection = PromiseInspection;
112940
113668
  };
112941
113669
 
112942
113670
 
113671
+ /***/ }),
113672
+
113673
+ /***/ 34902:
113674
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
113675
+
113676
+ "use strict";
113677
+
113678
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
113679
+ const utils_1 = __webpack_require__(98786);
113680
+ const utils_lang_1 = __webpack_require__(82174);
113681
+ const isStream = __webpack_require__(31232);
113682
+ /**
113683
+ * 是否能够使用 FormData 发送数据
113684
+ * @param {any} data - 待发送的数据
113685
+ */
113686
+ function canUseFormdata(data) {
113687
+ let enable = true;
113688
+ for (const key in data) {
113689
+ const value = data[key];
113690
+ if (!isStream(value) && (utils_1.isNodeEnv() && !Buffer.isBuffer(value)) && !utils_lang_1.isString(value) && !utils_lang_1.isNumber(value)) {
113691
+ enable = false;
113692
+ break;
113693
+ }
113694
+ }
113695
+ return enable;
113696
+ }
113697
+ exports.canUseFormdata = canUseFormdata;
113698
+ /**
113699
+ * 是否一定要通过 FormData 发送数据
113700
+ * 如果有 Buffer 和 Stream 必须用 multipart/form-data,如果同时还含有
113701
+ * @param {any} data - 待发送的数据
113702
+ */
113703
+ function mustUseFormdata(data) {
113704
+ let must = false;
113705
+ for (const key in data) {
113706
+ const value = data[key];
113707
+ if ((utils_1.isNodeEnv() && Buffer.isBuffer(value)) || isStream(value)) {
113708
+ must = true;
113709
+ break;
113710
+ }
113711
+ }
113712
+ return must;
113713
+ }
113714
+ exports.mustUseFormdata = mustUseFormdata;
113715
+
113716
+
112943
113717
  /***/ }),
112944
113718
 
112945
113719
  /***/ 34958:
@@ -115366,6 +116140,59 @@ function callSuccessCallback(callback, entries) {
115366
116140
  }
115367
116141
 
115368
116142
 
116143
+ /***/ }),
116144
+
116145
+ /***/ 36255:
116146
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
116147
+
116148
+ "use strict";
116149
+
116150
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
116151
+ const utils_lang_1 = __webpack_require__(82174);
116152
+ class SortedKeyValue {
116153
+ constructor(obj, selectkeys) {
116154
+ this._keys = [];
116155
+ this._values = [];
116156
+ this._pairs = [];
116157
+ this._obj = {};
116158
+ if (!utils_lang_1.isObject(obj)) {
116159
+ return this;
116160
+ }
116161
+ // https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order
116162
+ // https://www.stefanjudis.com/today-i-learned/property-order-is-predictable-in-javascript-objects-since-es2015/
116163
+ Object.keys(obj || {}).sort((l, r) => {
116164
+ return l.toString().localeCompare(r);
116165
+ }).forEach(key => {
116166
+ if (!selectkeys || selectkeys.includes(key)) {
116167
+ this._keys.push(key);
116168
+ this._values.push(obj[key]);
116169
+ this._pairs.push([key, obj[key]]);
116170
+ this._obj[key.toLowerCase()] = obj[key];
116171
+ }
116172
+ });
116173
+ }
116174
+ static kv(obj, selectkeys) {
116175
+ return new SortedKeyValue(obj, selectkeys);
116176
+ }
116177
+ get(key) {
116178
+ return this._obj[key];
116179
+ }
116180
+ keys() {
116181
+ return this._keys;
116182
+ }
116183
+ values() {
116184
+ return this._values;
116185
+ }
116186
+ pairs() {
116187
+ return this._pairs;
116188
+ }
116189
+ toString(kvSeparator = '=', joinSeparator = '&') {
116190
+ return this._pairs.map((pair) => pair.join(kvSeparator)).join(joinSeparator);
116191
+ }
116192
+ }
116193
+ exports.SortedKeyValue = SortedKeyValue;
116194
+
116195
+
115369
116196
  /***/ }),
115370
116197
 
115371
116198
  /***/ 36340:
@@ -125826,6 +126653,7 @@ module.exports = setup;
125826
126653
  "use strict";
125827
126654
 
125828
126655
  Object.defineProperty(exports, "__esModule", ({ value: true }));
126656
+ exports.removeEmptyStringParams = removeEmptyStringParams;
125829
126657
  exports.buildCapiErrorMessage = buildCapiErrorMessage;
125830
126658
  exports.registerCapiTools = registerCapiTools;
125831
126659
  const zod_1 = __webpack_require__(21614);
@@ -125861,6 +126689,19 @@ function levenshteinDistance(left, right) {
125861
126689
  }
125862
126690
  return matrix[left.length][right.length];
125863
126691
  }
126692
+ /**
126693
+ * Remove empty string parameters from the params object.
126694
+ * Tencent Cloud APIs reject empty strings for required parameters like StartTime/EndTime.
126695
+ */
126696
+ function removeEmptyStringParams(params) {
126697
+ const cleaned = {};
126698
+ for (const [key, value] of Object.entries(params)) {
126699
+ if (value !== "") {
126700
+ cleaned[key] = value;
126701
+ }
126702
+ }
126703
+ return cleaned;
126704
+ }
125864
126705
  function findTcbActionEntry(action) {
125865
126706
  if (tcb_action_index_js_1.TCB_ACTION_INDEX_MAP[action]) {
125866
126707
  return tcb_action_index_js_1.TCB_ACTION_INDEX_MAP[action];
@@ -126047,9 +126888,10 @@ function registerCapiTools(server) {
126047
126888
  }
126048
126889
  let result;
126049
126890
  try {
126891
+ const cleanedParams = params ? removeEmptyStringParams(params) : {};
126050
126892
  result = await cloudbase.commonService(service).call({
126051
126893
  Action: action,
126052
- Param: params ?? {},
126894
+ Param: cleanedParams,
126053
126895
  });
126054
126896
  }
126055
126897
  catch (error) {
@@ -135849,7 +136691,7 @@ class TelemetryReporter {
135849
136691
  const nodeVersion = process.version; // Node.js版本
135850
136692
  const arch = os_1.default.arch(); // 系统架构
135851
136693
  // 从构建时注入的版本号获取MCP版本信息
135852
- const mcpVersion = process.env.npm_package_version || "2.23.3" || 0;
136694
+ const mcpVersion = process.env.npm_package_version || "2.23.6" || 0;
135853
136695
  return {
135854
136696
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
135855
136697
  deviceId: this.deviceId,
@@ -168346,6 +169188,16 @@ class SyncReader extends reader_1.default {
168346
169188
  exports["default"] = SyncReader;
168347
169189
 
168348
169190
 
169191
+ /***/ }),
169192
+
169193
+ /***/ 57676:
169194
+ /***/ ((__unused_webpack_module, exports) => {
169195
+
169196
+ "use strict";
169197
+
169198
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
169199
+
169200
+
168349
169201
  /***/ }),
168350
169202
 
168351
169203
  /***/ 57705:
@@ -171475,6 +172327,7 @@ const cloudApp_1 = __webpack_require__(32665);
171475
172327
  const permission_1 = __webpack_require__(24786);
171476
172328
  const sandbox_1 = __webpack_require__(48488);
171477
172329
  const aiModel_1 = __webpack_require__(34800);
172330
+ const monitor_1 = __webpack_require__(8901);
171478
172331
  class Environment {
171479
172332
  constructor(context, envId) {
171480
172333
  this.inited = false;
@@ -171500,6 +172353,7 @@ class Environment {
171500
172353
  this.cloudAppService = new cloudApp_1.CloudAppService(this);
171501
172354
  this.sandboxService = new sandbox_1.SandboxService(this);
171502
172355
  this.aiModelService = new aiModel_1.AiModelService(this);
172356
+ this.monitorService = new monitor_1.MonitorService(this);
171503
172357
  }
171504
172358
  async lazyInit() {
171505
172359
  if (!this.inited) {
@@ -171574,6 +172428,9 @@ class Environment {
171574
172428
  getAiModelService() {
171575
172429
  return this.aiModelService;
171576
172430
  }
172431
+ getMonitorService() {
172432
+ return this.monitorService;
172433
+ }
171577
172434
  getCommonService(serviceType = 'tcb', serviceVersion) {
171578
172435
  return new common_1.CommonService(this, serviceType, serviceVersion);
171579
172436
  }
@@ -187714,7 +188571,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
187714
188571
  exports.CloudBaseContext = void 0;
187715
188572
  const constant_1 = __webpack_require__(40762);
187716
188573
  class CloudBaseContext {
187717
- constructor({ secretId = '', secretKey = '', token = '', proxy = '', region = '', envType = '', useInternalEndpoint = undefined, internalEndpointRegion = undefined, requestFn = undefined }) {
188574
+ constructor({ secretId = '', secretKey = '', token = '', proxy = '', region = '', envType = '', useInternalEndpoint = undefined, internalEndpointRegion = undefined }) {
187718
188575
  this.secretId = secretId;
187719
188576
  this.secretKey = secretKey;
187720
188577
  this.token = token;
@@ -187723,7 +188580,6 @@ class CloudBaseContext {
187723
188580
  this.envType = envType;
187724
188581
  this.useInternalEndpoint = useInternalEndpoint;
187725
188582
  this.internalEndpointRegion = internalEndpointRegion;
187726
- this.requestFn = requestFn;
187727
188583
  }
187728
188584
  isInternalEndpoint() {
187729
188585
  return this.useInternalEndpoint !== undefined ? this.useInternalEndpoint : constant_1.USE_INTERNAL_ENDPOINT;
@@ -195620,7 +196476,7 @@ ${envIdSection}
195620
196476
  ## 环境信息
195621
196477
  - 操作系统: ${os_1.default.type()} ${os_1.default.release()}
195622
196478
  - Node.js版本: ${process.version}
195623
- - MCP 版本:${process.env.npm_package_version || "2.23.3" || 0}
196479
+ - MCP 版本:${process.env.npm_package_version || "2.23.6" || 0}
195624
196480
  - 系统架构: ${os_1.default.arch()}
195625
196481
  - 时间: ${new Date().toISOString()}
195626
196482
  - 请求ID: ${requestId}
@@ -195701,7 +196557,7 @@ function createWrappedHandler(name, handler, server) {
195701
196557
  requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
195702
196558
  ide: server.ide || process.env.INTEGRATION_IDE || ''
195703
196559
  });
195704
- const mcpVersion = true ? "2.23.3" : 0;
196560
+ const mcpVersion = true ? "2.23.6" : 0;
195705
196561
  const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
195706
196562
  const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
195707
196563
  // 创建新的错误对象,保持原有的错误类型但更新消息
@@ -197010,7 +197866,7 @@ class UserService {
197010
197866
  }
197011
197867
  async describeUserList(options = {}) {
197012
197868
  const { EnvId } = this.environment.lazyEnvironmentConfig;
197013
- const { pageNo = 1, pageSize = 20, name, nickName, phone, email } = options;
197869
+ const { pageNo = 1, pageSize = 20, name, nickName, phone, email, uidList } = options;
197014
197870
  if (!Number.isInteger(pageNo) || pageNo < 1) {
197015
197871
  throw new Error('Invalid pageNo');
197016
197872
  }
@@ -197030,6 +197886,8 @@ class UserService {
197030
197886
  reqData.Phone = phone;
197031
197887
  if (this.isValidStr(email))
197032
197888
  reqData.Email = email;
197889
+ if (Array.isArray(uidList) && uidList.length > 0)
197890
+ reqData.UidList = uidList;
197033
197891
  return this.tcbService.request('DescribeUserList', reqData);
197034
197892
  }
197035
197893
  async modifyUser(options) {
@@ -199065,8 +199923,8 @@ class StorageService {
199065
199923
  typeof cacheControl === 'number' ? `max-age=${cacheControl}` : String(cacheControl);
199066
199924
  }
199067
199925
  if (metadata) {
199068
- // X-Metadata 放在 Header 里,具体大小限制由服务端/网关决定
199069
- headers['X-Metadata'] = Buffer.from(JSON.stringify(metadata), 'utf8').toString('base64');
199926
+ // x-metadata 放在 Header 里,具体大小限制由服务端/网关决定
199927
+ headers['x-metadata'] = Buffer.from(JSON.stringify(metadata), 'utf8').toString('base64');
199070
199928
  }
199071
199929
  if (upsert) {
199072
199930
  headers['x-upsert'] = 'true';
@@ -210905,7 +211763,7 @@ function registerPermissionTools(server) {
210905
211763
  }));
210906
211764
  server.registerTool?.("managePermissions", {
210907
211765
  title: "管理 CloudBase 权限与用户配置",
210908
- description: "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。\n\n示例:\n- 设置存储桶为私有:`action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单;前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。直接在浏览器里用 `auth.signUp` 创建用户名密码用户取决于 SDK/provider 支持,使用前必须验证;不支持时应走后端或管理端边界,不能在浏览器暴露密钥。`securityRule` 的详细语义取决于 `resourceType`:`doc._openid`、`auth.openid`、查询条件子集校验,以及 `create` / `update` / `delete` JSON 模板仅适用于 `resourceType=\"noSqlDatabase\"` 的文档数据库安全规则;配置 `function` 或 `storage` 时,请参考各自官方安全规则文档,而不是复用 NoSQL 模板。\n\n📌 跨后端边界提示:调用前先用 `envQuery(action=\"info\", envId=...)` 看 `EnvInfo.RuntimeBackends`:\n- `resourceType=\"noSqlDatabase\"` 仅作用于 CloudBase NoSQL 文档数据库的集合;CloudBase PostgreSQL(PG)表的行级权限**不**受它控制——PG 表请改用 RLS:`managePgDatabase(action=\"execute\", confirm=true)` 跑 `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` 与 `CREATE POLICY ...`。同一个 PG 环境里如果还有 NoSQL 集合在用,对那些**集合**继续使用 `noSqlDatabase` 规则是正确的——不是\"PG 环境就禁用本工具\"。\n- `resourceType=\"storage\"` 控制的是 NoSQL/COS 存储桶 ACL;PG 的 `pgstore` bucket 不在此 `resourceType` 覆盖范围内。\n- 本工具不涉及 MySQL;MySQL 数据库权限请走 MySQL 自身的 GRANT/REVOKE 语句(通过 `manageSqlDatabase`)。",
211766
+ description: "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。\n\n示例:\n- 设置存储桶为私有:`action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单;前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。直接在浏览器里用 `auth.signUp` 创建用户名密码用户取决于 SDK/provider 支持,使用前必须验证;不支持时应走后端或管理端边界,不能在浏览器暴露密钥。`securityRule` 的详细语义取决于 `resourceType`:`doc._openid`、`auth.openid`、查询条件子集校验,以及 `create` / `update` / `delete` JSON 模板仅适用于 `resourceType=\"noSqlDatabase\"` 的文档数据库安全规则;配置 `function` 或 `storage` 时,请参考各自官方安全规则文档,而不是复用 NoSQL 模板。\n\n📌 跨后端边界提示:调用前先用 `envQuery(action=\"info\", envId=...)` 看 `EnvInfo.RuntimeBackends`:\n- `resourceType=\"noSqlDatabase\"` 仅作用于 CloudBase NoSQL 文档数据库的集合;CloudBase PostgreSQL(PG)表的行级权限**不**受它控制——PG 表请改用 RLS:`managePgDatabase(action=\"execute\", confirm=true)` 跑 `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` 与 `CREATE POLICY ...`。同一个 PG 环境里如果还有 NoSQL 集合在用,对那些**集合**继续使用 `noSqlDatabase` 规则是正确的——不是\"PG 环境就禁用本工具\"。\n- `resourceType=\"storage\"` 控制的是 NoSQL/COS 存储桶 ACL;PG 的 `pgstore` bucket 不在此 `resourceType` 覆盖范围内。\n- 本工具不涉及 MySQL;MySQL 数据库权限请走 MySQL 自身的 GRANT/REVOKE 语句(通过 `manageMysqlDatabase`)。",
210909
211767
  inputSchema: {
210910
211768
  action: zod_1.z.enum(MANAGE_PERMISSION_ACTIONS),
210911
211769
  resourceType: zod_1.z
@@ -211713,7 +212571,7 @@ function registerSetupTools(server) {
211713
212571
  server.registerTool("downloadTemplate", {
211714
212572
  title: "下载项目模板",
211715
212573
  description: `自动下载并部署CloudBase项目模板。
211716
- **Note**: Call this tool when the user requests to create a new project using a CloudBase template.\n\n支持的模板:\n- react: React + CloudBase 全栈应用模板\n- vue: Vue + CloudBase 全栈应用模板\n- miniprogram: 微信小程序 + 云开发模板 \n- uniapp: UniApp + CloudBase 跨端应用模板\n- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置\n\n支持的IDE类型:\n- all: 下载所有IDE配置\n- cursor: Cursor AI编辑器\n- 其他IDE类型见下方列表\n\n注意:如果未传入 ide 参数且无法从环境变量检测到 IDE,将提示错误并要求传入 ide 参数\n- windsurf: WindSurf AI编辑器\n- codebuddy: CodeBuddy AI编辑器\n- claude-code: Claude Code AI编辑器\n- cline: Cline AI编辑器\n- gemini-cli: Gemini CLI\n- opencode: OpenCode AI编辑器\n- qwen-code: 通义灵码\n- baidu-comate: 百度Comate\n- openai-codex-cli: OpenAI Codex CLI\n- augment-code: Augment Code\n- github-copilot: GitHub Copilot\n- roocode: RooCode AI编辑器\n- tongyi-lingma: 通义灵码\n- trae: Trae AI编辑器\n- qoder: Qoder AI编辑器\n- antigravity: Google Antigravity AI编辑器\n- vscode: Visual Studio Code\n- kiro: Kiro AI编辑器\n- aider: Aider AI编辑器\n\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.23.3" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
212574
+ **Note**: Call this tool when the user requests to create a new project using a CloudBase template.\n\n支持的模板:\n- react: React + CloudBase 全栈应用模板\n- vue: Vue + CloudBase 全栈应用模板\n- miniprogram: 微信小程序 + 云开发模板 \n- uniapp: UniApp + CloudBase 跨端应用模板\n- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置\n\n支持的IDE类型:\n- all: 下载所有IDE配置\n- cursor: Cursor AI编辑器\n- 其他IDE类型见下方列表\n\n注意:如果未传入 ide 参数且无法从环境变量检测到 IDE,将提示错误并要求传入 ide 参数\n- windsurf: WindSurf AI编辑器\n- codebuddy: CodeBuddy AI编辑器\n- claude-code: Claude Code AI编辑器\n- cline: Cline AI编辑器\n- gemini-cli: Gemini CLI\n- opencode: OpenCode AI编辑器\n- qwen-code: 通义灵码\n- baidu-comate: 百度Comate\n- openai-codex-cli: OpenAI Codex CLI\n- augment-code: Augment Code\n- github-copilot: GitHub Copilot\n- roocode: RooCode AI编辑器\n- tongyi-lingma: 通义灵码\n- trae: Trae AI编辑器\n- qoder: Qoder AI编辑器\n- antigravity: Google Antigravity AI编辑器\n- vscode: Visual Studio Code\n- kiro: Kiro AI编辑器\n- aider: Aider AI编辑器\n\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.23.6" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
211717
212575
  inputSchema: {
211718
212576
  template: zod_1.z
211719
212577
  .enum(["react", "vue", "miniprogram", "uniapp", "rules"])
@@ -213556,6 +214414,50 @@ module.exports = function one(fn) {
213556
214414
  };
213557
214415
 
213558
214416
 
214417
+ /***/ }),
214418
+
214419
+ /***/ 77463:
214420
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
214421
+
214422
+ "use strict";
214423
+
214424
+ function __export(m) {
214425
+ for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
214426
+ }
214427
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
214428
+ __export(__webpack_require__(36255));
214429
+ __export(__webpack_require__(12129));
214430
+ __export(__webpack_require__(34902));
214431
+ __export(__webpack_require__(82174));
214432
+ __export(__webpack_require__(98786));
214433
+ const signer_1 = __webpack_require__(12129);
214434
+ const utils_1 = __webpack_require__(98786);
214435
+ const clone = __webpack_require__(1779);
214436
+ function sign(options) {
214437
+ const { secretId, secretKey, method, url, service, withSignedParams, isCloudApi } = options;
214438
+ // isCloudApi 为 true, 说明使用 cloud api v3, 返回签名值中不能携带 signedParams
214439
+ let validWithSignedParams = withSignedParams;
214440
+ if (isCloudApi === true && withSignedParams === true) {
214441
+ console.warn('isCloudApi 和 withSignedParams 参数同时为 true, withSignedParams 会自动转为 false');
214442
+ validWithSignedParams = false;
214443
+ }
214444
+ const signer = new signer_1.Signer({ secretId, secretKey }, service || 'tcb');
214445
+ const headers = clone(options.headers || {});
214446
+ const params = clone(options.params || {});
214447
+ const timestamp = options.timestamp || utils_1.second() - 1;
214448
+ const signatureInfo = signer.tc3sign(method, url, headers, params, timestamp, {
214449
+ withSignedParams: validWithSignedParams,
214450
+ isCloudApi
214451
+ });
214452
+ return {
214453
+ authorization: signatureInfo.authorization,
214454
+ timestamp: signatureInfo.timestamp,
214455
+ multipart: signatureInfo.multipart
214456
+ };
214457
+ }
214458
+ exports.sign = sign;
214459
+
214460
+
213559
214461
  /***/ }),
213560
214462
 
213561
214463
  /***/ 77474:
@@ -221900,13 +222802,12 @@ function getDate(timestamp) {
221900
222802
  }
221901
222803
  class CloudService {
221902
222804
  /* eslint-disable-next-line */
221903
- constructor(context, service, version, baseParams, requestFn) {
222805
+ constructor(context, service, version, baseParams) {
221904
222806
  this.service = service;
221905
222807
  this.version = version;
221906
222808
  this.timeout = 60000;
221907
222809
  this.baseParams = baseParams || {};
221908
222810
  this.cloudBaseContext = context;
221909
- this.requestFn = requestFn !== null && requestFn !== void 0 ? requestFn : context.requestFn;
221910
222811
  }
221911
222812
  get baseUrl() {
221912
222813
  const internalEndpoint = this.cloudBaseContext.isInternalEndpoint();
@@ -221938,31 +222839,8 @@ class CloudService {
221938
222839
  }
221939
222840
  }
221940
222841
  async request(action, data = {}, method = 'POST') {
221941
- var _a;
221942
222842
  this.action = action;
221943
222843
  this.data = deepRemoveVoid(Object.assign(Object.assign({}, data), this.baseParams));
221944
- // 如果注入了 requestFn,直接委托,跳过 TC3 签名逻辑
221945
- if (this.requestFn) {
221946
- try {
221947
- const result = await this.requestFn({
221948
- service: this.service,
221949
- action,
221950
- version: this.version,
221951
- region: (_a = this.cloudBaseContext.region) !== null && _a !== void 0 ? _a : '',
221952
- payload: this.data,
221953
- });
221954
- return result;
221955
- }
221956
- catch (e) {
221957
- if (e.name === 'CloudBaseError') {
221958
- throw e;
221959
- }
221960
- throw new error_1.CloudBaseError(e.message, {
221961
- action,
221962
- code: e.code
221963
- });
221964
- }
221965
- }
221966
222844
  this.method = method;
221967
222845
  this.url = this.baseUrl;
221968
222846
  let { secretId, secretKey, token } = this.cloudBaseContext;
@@ -222363,6 +223241,32 @@ webpackEmptyContext.resolve = webpackEmptyContext;
222363
223241
  webpackEmptyContext.id = 82154;
222364
223242
  module.exports = webpackEmptyContext;
222365
223243
 
223244
+ /***/ }),
223245
+
223246
+ /***/ 82174:
223247
+ /***/ ((__unused_webpack_module, exports) => {
223248
+
223249
+ "use strict";
223250
+
223251
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
223252
+ function isNumber(v) {
223253
+ return v === +v;
223254
+ }
223255
+ exports.isNumber = isNumber;
223256
+ function isString(v) {
223257
+ return typeof v === 'string';
223258
+ }
223259
+ exports.isString = isString;
223260
+ function isObject(v) {
223261
+ return v != null && typeof v === 'object' && Array.isArray(v) === false;
223262
+ }
223263
+ exports.isObject = isObject;
223264
+ function isPlainObject(v) {
223265
+ return isObject(v) && [null, Object.prototype].includes(Object.getPrototypeOf(v));
223266
+ }
223267
+ exports.isPlainObject = isPlainObject;
223268
+
223269
+
222366
223270
  /***/ }),
222367
223271
 
222368
223272
  /***/ 82218:
@@ -252713,7 +253617,7 @@ const queryStorageInputSchema = {
252713
253617
  // Input schema for manageStorage tool
252714
253618
  const manageStorageInputSchema = {
252715
253619
  action: zod_1.z.enum(['upload', 'download', 'delete']).describe('管理操作类型:upload=上传文件或目录,download=下载文件或目录,delete=删除文件或目录'),
252716
- localPath: zod_1.z.string().describe('本地文件路径,建议传入绝对路径,例如 /tmp/files/data.txt'),
253620
+ localPath: zod_1.z.string().optional().describe('本地文件路径,建议传入绝对路径,例如 /tmp/files/data.txt;upload/download 操作时必填,delete 操作时不需要传该参数'),
252717
253621
  cloudPath: zod_1.z.string().describe('云端文件路径,例如 files/data.txt'),
252718
253622
  force: zod_1.z.boolean().optional().default(false).describe('强制操作开关,删除操作时建议设置为true以确认删除,默认false'),
252719
253623
  isDirectory: zod_1.z.boolean().optional().default(false).describe('是否为目录操作,true=目录操作,false=文件操作,默认false')
@@ -252963,14 +253867,16 @@ function registerStorageTools(server) {
252963
253867
  const storageService = manager.storage;
252964
253868
  switch (input.action) {
252965
253869
  case 'upload': {
253870
+ const localPath = input.localPath;
253871
+ const cloudPath = input.cloudPath;
252966
253872
  if (input.isDirectory) {
252967
253873
  if (storageOverrides?.uploadDirectory) {
252968
- await storageOverrides.uploadDirectory({ localPath: input.localPath, cloudPath: input.cloudPath });
253874
+ await storageOverrides.uploadDirectory({ localPath, cloudPath });
252969
253875
  }
252970
253876
  else {
252971
253877
  await storageService.uploadDirectory({
252972
- localPath: input.localPath,
252973
- cloudPath: input.cloudPath,
253878
+ localPath,
253879
+ cloudPath,
252974
253880
  onProgress: (progressData) => {
252975
253881
  console.log("Upload directory progress:", progressData);
252976
253882
  }
@@ -252979,12 +253885,12 @@ function registerStorageTools(server) {
252979
253885
  }
252980
253886
  else {
252981
253887
  if (storageOverrides?.uploadFile) {
252982
- await storageOverrides.uploadFile({ localPath: input.localPath, cloudPath: input.cloudPath });
253888
+ await storageOverrides.uploadFile({ localPath, cloudPath });
252983
253889
  }
252984
253890
  else {
252985
253891
  await storageService.uploadFile({
252986
- localPath: input.localPath,
252987
- cloudPath: input.cloudPath,
253892
+ localPath,
253893
+ cloudPath,
252988
253894
  onProgress: (progressData) => {
252989
253895
  console.log("Upload file progress:", progressData);
252990
253896
  }
@@ -253051,25 +253957,27 @@ function registerStorageTools(server) {
253051
253957
  };
253052
253958
  }
253053
253959
  case 'download': {
253960
+ const dlCloudPath = input.cloudPath;
253961
+ const dlLocalPath = input.localPath;
253054
253962
  if (input.isDirectory) {
253055
253963
  if (storageOverrides?.downloadDirectory) {
253056
- await storageOverrides.downloadDirectory({ cloudPath: input.cloudPath, localPath: input.localPath });
253964
+ await storageOverrides.downloadDirectory({ cloudPath: dlCloudPath, localPath: dlLocalPath });
253057
253965
  }
253058
253966
  else {
253059
253967
  await storageService.downloadDirectory({
253060
- cloudPath: input.cloudPath,
253061
- localPath: input.localPath
253968
+ cloudPath: dlCloudPath,
253969
+ localPath: dlLocalPath
253062
253970
  });
253063
253971
  }
253064
253972
  }
253065
253973
  else {
253066
253974
  if (storageOverrides?.downloadFile) {
253067
- await storageOverrides.downloadFile({ cloudPath: input.cloudPath, localPath: input.localPath });
253975
+ await storageOverrides.downloadFile({ cloudPath: dlCloudPath, localPath: dlLocalPath });
253068
253976
  }
253069
253977
  else {
253070
253978
  await storageService.downloadFile({
253071
- cloudPath: input.cloudPath,
253072
- localPath: input.localPath
253979
+ cloudPath: dlCloudPath,
253980
+ localPath: dlLocalPath
253073
253981
  });
253074
253982
  }
253075
253983
  }
@@ -261405,9 +262313,9 @@ class CloudBase {
261405
262313
  }
261406
262314
  constructor(config = {}) {
261407
262315
  this.cloudBaseConfig = {};
261408
- let { secretId, secretKey, token, envId, proxy, region, envType, useInternalEndpoint, internalEndpointRegion, requestFn } = config;
261409
- // config 中传入的 secretId secretkey 必须同时存在(有 requestFn 时可以不传)
261410
- if (!requestFn && ((secretId && !secretKey) || (!secretId && secretKey))) {
262316
+ let { secretId, secretKey, token, envId, proxy, region, envType, useInternalEndpoint, internalEndpointRegion } = config;
262317
+ // config 中传入的 secretId secretkey 必须同时存在
262318
+ if ((secretId && !secretKey) || (!secretId && secretKey)) {
261411
262319
  throw new Error('secretId and secretKey must be a pair');
261412
262320
  }
261413
262321
  this.cloudBaseConfig = {
@@ -261420,7 +262328,6 @@ class CloudBase {
261420
262328
  region,
261421
262329
  useInternalEndpoint,
261422
262330
  internalEndpointRegion,
261423
- requestFn,
261424
262331
  };
261425
262332
  // 初始化 context
261426
262333
  this.context = new context_1.CloudBaseContext(this.cloudBaseConfig);
@@ -261509,6 +262416,9 @@ class CloudBase {
261509
262416
  get aiModel() {
261510
262417
  return this.currentEnvironment().getAiModelService();
261511
262418
  }
262419
+ get monitor() {
262420
+ return this.currentEnvironment().getMonitorService();
262421
+ }
261512
262422
  get docs() {
261513
262423
  if (!this.docsService) {
261514
262424
  this.docsService = new docs_1.DocsService();
@@ -266328,6 +267238,48 @@ if (typeof fs.realpath.native === 'function') {
266328
267238
  }
266329
267239
 
266330
267240
 
267241
+ /***/ }),
267242
+
267243
+ /***/ 98786:
267244
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
267245
+
267246
+ "use strict";
267247
+
267248
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
267249
+ const crypto = __webpack_require__(55511);
267250
+ function formateDate(timestamp) {
267251
+ return new Date(timestamp * 1000).toISOString().split('T')[0];
267252
+ }
267253
+ exports.formateDate = formateDate;
267254
+ function second() {
267255
+ // istanbul ignore next
267256
+ return Math.floor(new Date().getTime() / 1000);
267257
+ }
267258
+ exports.second = second;
267259
+ function stringify(v) {
267260
+ return typeof v !== 'string' ? JSON.stringify(v) : v;
267261
+ }
267262
+ exports.stringify = stringify;
267263
+ function sha256hash(string, encoding = 'hex') {
267264
+ return crypto
267265
+ .createHash('sha256')
267266
+ .update(string)
267267
+ .digest(encoding);
267268
+ }
267269
+ exports.sha256hash = sha256hash;
267270
+ function sha256hmac(string, secret = '', encoding) {
267271
+ return crypto
267272
+ .createHmac('sha256', secret)
267273
+ .update(string)
267274
+ .digest(encoding);
267275
+ }
267276
+ exports.sha256hmac = sha256hmac;
267277
+ function isNodeEnv() {
267278
+ return process && process.release && process.release.name === 'node';
267279
+ }
267280
+ exports.isNodeEnv = isNodeEnv;
267281
+
267282
+
266331
267283
  /***/ }),
266332
267284
 
266333
267285
  /***/ 98916: