@cloudbase/cloudbase-mcp 2.34.7 → 2.34.8
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/cli.cjs +1 -1
- package/dist/index.cjs +317 -25
- package/dist/index.js +317 -25
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -200009,6 +200009,7 @@ const logger_js_1 = __webpack_require__(40781);
|
|
|
200009
200009
|
const tool_result_js_1 = __webpack_require__(69645);
|
|
200010
200010
|
const site_map_js_1 = __webpack_require__(34533);
|
|
200011
200011
|
const project_config_js_1 = __webpack_require__(39175);
|
|
200012
|
+
const local_endpoint_js_1 = __webpack_require__(16156);
|
|
200012
200013
|
// Timeout for envId auto-resolution flow.
|
|
200013
200014
|
// 10 minutes (600 seconds) - matches InteractiveServer timeout
|
|
200014
200015
|
const ENV_ID_TIMEOUT = 600000;
|
|
@@ -200170,7 +200171,7 @@ async function listAvailableEnvCandidates(options) {
|
|
|
200170
200171
|
}
|
|
200171
200172
|
// When CLOUDBASE_ENV_ID is set and credentials are not explicit, skip DescribeEnvs.
|
|
200172
200173
|
const hasExplicitCredentials = !!(cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey);
|
|
200173
|
-
if (process.env.CLOUDBASE_ENV_ID && !hasExplicitCredentials) {
|
|
200174
|
+
if (process.env.CLOUDBASE_ENV_ID && !hasExplicitCredentials && !cloudBaseOptions?.requestFn && !process.env.CLOUDBASE_LOCAL_ENDPOINT) {
|
|
200174
200175
|
return [{
|
|
200175
200176
|
envId: process.env.CLOUDBASE_ENV_ID,
|
|
200176
200177
|
}];
|
|
@@ -200181,7 +200182,7 @@ async function listAvailableEnvCandidates(options) {
|
|
|
200181
200182
|
...(regionOverride ? { region: regionOverride } : {}),
|
|
200182
200183
|
}).region;
|
|
200183
200184
|
let cloudbase;
|
|
200184
|
-
if (cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey) {
|
|
200185
|
+
if (cloudBaseOptions?.requestFn || (cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey)) {
|
|
200185
200186
|
cloudbase = createCloudBaseManagerWithOptions({
|
|
200186
200187
|
...cloudBaseOptions,
|
|
200187
200188
|
region,
|
|
@@ -200420,11 +200421,13 @@ const envManager = new EnvironmentManager();
|
|
|
200420
200421
|
exports.envManager = envManager;
|
|
200421
200422
|
// 导出环境ID获取函数
|
|
200422
200423
|
async function getEnvId(cloudBaseOptions) {
|
|
200423
|
-
// 如果传入了 cloudBaseOptions 且包含 envId,直接返回
|
|
200424
200424
|
if (cloudBaseOptions?.envId) {
|
|
200425
200425
|
(0, logger_js_1.debug)('使用传入的 envId:', { envId: cloudBaseOptions.envId });
|
|
200426
200426
|
return cloudBaseOptions.envId;
|
|
200427
200427
|
}
|
|
200428
|
+
if ((0, local_endpoint_js_1.resolveLocalEndpoint)()) {
|
|
200429
|
+
return 'local';
|
|
200430
|
+
}
|
|
200428
200431
|
const cachedEnvId = envManager.getCachedEnvId() || process.env.CLOUDBASE_ENV_ID;
|
|
200429
200432
|
if (cachedEnvId) {
|
|
200430
200433
|
(0, logger_js_1.debug)('使用缓存中的 envId:', { envId: cachedEnvId });
|
|
@@ -200529,7 +200532,16 @@ async function getDatabaseInstanceId(options) {
|
|
|
200529
200532
|
* 每次都实时获取最新的 token/secretId/secretKey
|
|
200530
200533
|
*/
|
|
200531
200534
|
async function getCloudBaseManager(options = {}) {
|
|
200532
|
-
const { requireEnvId = true,
|
|
200535
|
+
const { requireEnvId = true, authStrategy = 'fail_fast', } = options;
|
|
200536
|
+
let cloudBaseOptions = options.cloudBaseOptions;
|
|
200537
|
+
const localEndpoint = (0, local_endpoint_js_1.resolveLocalEndpoint)();
|
|
200538
|
+
if (localEndpoint && !cloudBaseOptions?.requestFn) {
|
|
200539
|
+
cloudBaseOptions = {
|
|
200540
|
+
...cloudBaseOptions,
|
|
200541
|
+
envId: cloudBaseOptions?.envId || 'local',
|
|
200542
|
+
requestFn: (0, local_endpoint_js_1.createLocalCloudApiRequestFn)(localEndpoint),
|
|
200543
|
+
};
|
|
200544
|
+
}
|
|
200533
200545
|
const hasDirectCredentials = !!(cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey);
|
|
200534
200546
|
const hasRequestFn = !!(cloudBaseOptions?.requestFn);
|
|
200535
200547
|
// 如果传入了完整凭据或 requestFn,优先使用显式 CloudBase 配置
|
|
@@ -201807,7 +201819,7 @@ const types_js_1 = __webpack_require__(89921);
|
|
|
201807
201819
|
exports.apps = (0, types_js_1.defineModule)({
|
|
201808
201820
|
queryTitle: "查询 CloudBase 应用部署状态",
|
|
201809
201821
|
queryDescription: "查询 CloudBase 应用部署的应用和版本。可查应用列表/详情、版本列表/详情;部署后用 getAppVersion 按 buildId 轮询构建状态;getBuildLog 可查询构建日志用于诊断失败原因。\n" +
|
|
201810
|
-
"action=getUploadUrl(只读)可获取预签名上传 URL:无本地文件系统时(cloud mode),先拿到 uploadUrl 自行 PUT 代码 zip,再用返回的 unixTimestamp 调 manageApps(action=deployApp, cosTimestamp) 触发部署。",
|
|
201822
|
+
"action=getUploadUrl(只读)可获取预签名上传 URL:无本地文件系统时(cloud mode),先拿到 uploadUrl 自行 PUT 代码 zip,再用返回的 unixTimestamp 调 manageApps(action=deployApp, cosTimestamp) 触发部署。uploadUrl 是一次性上传凭据,不要外传或写进工单。",
|
|
201811
201823
|
manageTitle: "部署应用到 CloudBase(独立子域名)",
|
|
201812
201824
|
manageDescription: "部署 Web 应用到 CloudBase(构建前后端,部署到独立子域名)。\n" +
|
|
201813
201825
|
"云端上传通道(cloud mode,无本地文件系统):queryApps(action=getUploadUrl) 或 manageApps(action=getUploadUrl) 获取预签名上传 URL → agent 自行 PUT 代码 zip 到 uploadUrl(带 uploadHeaders 与 Content-Type: application/zip)→ 用返回的 unixTimestamp 作为 cosTimestamp 调 deployApp 触发部署。\n" +
|
|
@@ -201840,7 +201852,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
201840
201852
|
uploadStep1: "1. 将代码打包为 zip(排除 node_modules/.git)",
|
|
201841
201853
|
uploadStep2: "2. 用 PUT 方法把 zip 上传到 uploadUrl,请求头带 Content-Type: application/zip 以及 uploadHeaders 中的每个 header",
|
|
201842
201854
|
uploadStep3: "3. 调用 manageApps(action=\"deployApp\", serviceName=\"{serviceName}\", cosTimestamp=<unixTimestamp>) 触发部署",
|
|
201843
|
-
getUploadUrlSuccess: "预签名上传 URL 获取成功。请将代码 zip PUT 上传到 uploadUrl(携带 uploadHeaders 与 Content-Type: application/zip),然后用返回的 unixTimestamp 作为 cosTimestamp 调用 manageApps(action=deployApp) 触发部署。",
|
|
201855
|
+
getUploadUrlSuccess: "预签名上传 URL 获取成功。请将代码 zip PUT 上传到 uploadUrl(携带 uploadHeaders 与 Content-Type: application/zip),然后用返回的 unixTimestamp 作为 cosTimestamp 调用 manageApps(action=deployApp) 触发部署。uploadUrl 是一次性上传凭据,不要外传或写进工单。",
|
|
201844
201856
|
getSuccess: "CloudBase 应用详情查询成功",
|
|
201845
201857
|
listVersionsSuccess: "CloudBase 应用版本列表查询成功",
|
|
201846
201858
|
buildIdRequired: "action=getBuildLog 时必须提供 buildId",
|
|
@@ -201903,7 +201915,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
201903
201915
|
}, {
|
|
201904
201916
|
queryTitle: "Query CloudBase app deployment status",
|
|
201905
201917
|
queryDescription: "Query CloudBase deployed apps and versions. Supports app list/detail and version list/detail; after deployment, poll build status by buildId with getAppVersion; getBuildLog retrieves build logs to diagnose failures.\n" +
|
|
201906
|
-
"action=getUploadUrl (read-only) returns a pre-signed upload URL: without a local filesystem (cloud mode), fetch the uploadUrl, PUT the code zip yourself, then call manageApps(action=deployApp, cosTimestamp) with the returned unixTimestamp to trigger deployment.",
|
|
201918
|
+
"action=getUploadUrl (read-only) returns a pre-signed upload URL: without a local filesystem (cloud mode), fetch the uploadUrl, PUT the code zip yourself, then call manageApps(action=deployApp, cosTimestamp) with the returned unixTimestamp to trigger deployment. The uploadUrl is a one-time upload credential; do not forward it or paste it into tickets.",
|
|
201907
201919
|
manageTitle: "Deploy app to CloudBase (dedicated subdomain)",
|
|
201908
201920
|
manageDescription: "Deploy web apps to CloudBase (builds frontend and backend, deploys to a dedicated subdomain).\n" +
|
|
201909
201921
|
"Cloud upload channel (cloud mode, no local filesystem): queryApps(action=getUploadUrl) or manageApps(action=getUploadUrl) returns a pre-signed upload URL → agent PUTs the code zip to uploadUrl itself (with uploadHeaders and Content-Type: application/zip) → call deployApp with the returned unixTimestamp as cosTimestamp to trigger deployment.\n" +
|
|
@@ -201936,7 +201948,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
201936
201948
|
uploadStep1: "1. Pack the code into a zip (exclude node_modules/.git)",
|
|
201937
201949
|
uploadStep2: "2. PUT the zip to uploadUrl with header Content-Type: application/zip and every header from uploadHeaders",
|
|
201938
201950
|
uploadStep3: "3. Call manageApps(action=\"deployApp\", serviceName=\"{serviceName}\", cosTimestamp=<unixTimestamp>) to trigger deployment",
|
|
201939
|
-
getUploadUrlSuccess: "Pre-signed upload URL obtained. PUT the code zip to uploadUrl (with uploadHeaders and Content-Type: application/zip), then call manageApps(action=deployApp) with the returned unixTimestamp as cosTimestamp to trigger deployment.",
|
|
201951
|
+
getUploadUrlSuccess: "Pre-signed upload URL obtained. PUT the code zip to uploadUrl (with uploadHeaders and Content-Type: application/zip), then call manageApps(action=deployApp) with the returned unixTimestamp as cosTimestamp to trigger deployment. The uploadUrl is a one-time upload credential; do not forward it or paste it into tickets.",
|
|
201940
201952
|
getSuccess: "CloudBase app details retrieved successfully",
|
|
201941
201953
|
listVersionsSuccess: "CloudBase app version list retrieved successfully",
|
|
201942
201954
|
buildIdRequired: "buildId is required when action=getBuildLog",
|
|
@@ -204515,6 +204527,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
204515
204527
|
unsupportedAction: "不支持的操作类型: {action}",
|
|
204516
204528
|
storageMissing: "当前环境没有可用的对象存储桶(DescribeEnvs 未返回 Storages),无法使用 COS 两段式部署。请检查环境存储配置,或改用本地模式部署。共享存储桶(ExternalStorage)环境同样不支持该通道。",
|
|
204517
204529
|
credentialMissing: "当前凭据缺少 SecretId/SecretKey(如 IDE 代理模式),无法本地铸造 COS 预签名上传地址。请改用本地模式或包含永久密钥/临时密钥的登录方式。",
|
|
204530
|
+
uploadTargetNotFound: "代码包上传目标不在本进程的登记里:{objectName}。ZIP 两段式部署要求 code 三元组来自本进程刚返回的 getFunctionUploadUrl(同一个 MCP 进程、同一个环境);MCP Server 已重启、换了环境、或自行拼装 cosObjectName / cosBucketName 都会落到这里。请重新调用 queryFunctions action=getFunctionUploadUrl 取地址,按返回值上传代码包,再用返回的三元组调用本 action。",
|
|
204518
204531
|
// ---- nextActions reasons ----
|
|
204519
204532
|
"reason.continuePolling": "继续查询云函数部署状态",
|
|
204520
204533
|
"reason.getDetail": "查看单个函数详情",
|
|
@@ -204573,7 +204586,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
204573
204586
|
gotLayerVersionDetail: "已获取层 {layerName} 版本 {layerVersion} 的详情",
|
|
204574
204587
|
gotFunctionTriggers: "已获取函数 {fnName} 的触发器列表",
|
|
204575
204588
|
gotDownloadUrl: "已获取函数 {fnName} 的代码下载链接",
|
|
204576
|
-
gotUploadUrl: "已生成函数代码包上传地址({seconds} 秒内有效)。下一步:PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带),再调用 manageFunctions createFunction/updateFunctionCode 并传入 code 三元组(cosBucketName/cosObjectName/cosBucketRegion
|
|
204589
|
+
gotUploadUrl: "已生成函数代码包上传地址({seconds} 秒内有效)。下一步:PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带),再调用 manageFunctions createFunction/updateFunctionCode 并传入 code 三元组(cosBucketName/cosObjectName/cosBucketRegion)完成部署。该 uploadUrl 等同一次性上传凭据,不要外传或写进工单;若上传前已过期,重新调用 getFunctionUploadUrl 取新地址",
|
|
204577
204590
|
gotFunctionVersions: "已获取函数 {fnName} 的版本列表",
|
|
204578
204591
|
gotFunctionAlias: "已获取函数 {fnName} 的别名 {aliasName}",
|
|
204579
204592
|
publishedVersion: "已发布函数 {fnName} 的新版本 {version}",
|
|
@@ -204647,7 +204660,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
204647
204660
|
"schema.create.layers": "Layer 配置",
|
|
204648
204661
|
"schema.manageLayer.name": "层名称",
|
|
204649
204662
|
"schema.manageLayer.version": "层版本号",
|
|
204650
|
-
"schema.query.action": "只读操作类型:\n- `listFunctions`: 列出所有 CloudBase 云函数\n- `getFunctionDetail`: 获取 CloudBase 云函数详情(需要 functionName)\n- `listFunctionLogs`: 查询 CloudBase 云函数执行日志(需要 functionName)\n- `getFunctionLogDetail`: 获取日志详情(需要 requestId)\n- `listFunctionLayers`: 列出函数绑定的层\n- `listLayers`: 列出所有层(账号级视图,含其他环境创建的层)\n- `listLayerVersions`: 列出层的版本(注意:是 Versions 不是 Version;账号级视图)\n- `getLayerVersionDetail`: 获取层版本详情(账号级视图)\n- `listFunctionTriggers`: 列出函数触发器(用于查看定时任务 / cron / timer 配置)\n- `getFunctionDownloadUrl`: 获取函数代码下载地址\n- `getFunctionDeployStatus`: 按 taskId 查询异步部署状态、阶段进度和最终结果。返回 data.build(构建子状态)、data.deploy(部署子状态)、data.progress(阶段事件);status=running 时 data.result 与 data.error 一律为 null,不得报告部署完成。调用方必须持续轮询直到 status=succeeded/failed;status=expired 表示任务超过最长保留时间(2 小时)被终结,云端可能仍在部署,需用 getFunctionDetail 确认。任务只保存在 MCP 进程内存中,过期或 MCP Server 重启后返回 errorCode=DEPLOY_TASK_NOT_FOUND;任务按环境隔离,只能查到当前环境自己发起的部署。cloud mode 下本 action 不可用:异步任务只由 buildStrategy=cloud/local 的真实部署创建,而这两种策略在 cloud mode 下都不支持真实执行,image 策略则走同步部署不产生 taskId。\n- `listVersionByFunction`: 列出函数已发布版本(对齐 tcb fn list-function-versions / SDK listVersionByFunction;需要 functionName)\n- `getFunctionAlias`: 查询函数别名与流量路由(对齐 tcb fn get-route / SDK getFunctionAlias;需要 functionName;aliasName 默认 $DEFAULT)\n- `getFunctionUploadUrl`: 获取函数代码包的 COS 预签名上传地址(ZIP 两段式部署阶段 A):PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带对应请求头),再调用 manageFunctions 的 createFunction/updateFunctionCode 并传 code 三元组(阶段 B)。functionName 可选,仅用于生成上传对象 key。返回的 uploadUrl
|
|
204663
|
+
"schema.query.action": "只读操作类型:\n- `listFunctions`: 列出所有 CloudBase 云函数\n- `getFunctionDetail`: 获取 CloudBase 云函数详情(需要 functionName)\n- `listFunctionLogs`: 查询 CloudBase 云函数执行日志(需要 functionName)\n- `getFunctionLogDetail`: 获取日志详情(需要 requestId)\n- `listFunctionLayers`: 列出函数绑定的层\n- `listLayers`: 列出所有层(账号级视图,含其他环境创建的层)\n- `listLayerVersions`: 列出层的版本(注意:是 Versions 不是 Version;账号级视图)\n- `getLayerVersionDetail`: 获取层版本详情(账号级视图)\n- `listFunctionTriggers`: 列出函数触发器(用于查看定时任务 / cron / timer 配置)\n- `getFunctionDownloadUrl`: 获取函数代码下载地址\n- `getFunctionDeployStatus`: 按 taskId 查询异步部署状态、阶段进度和最终结果。返回 data.build(构建子状态)、data.deploy(部署子状态)、data.progress(阶段事件);status=running 时 data.result 与 data.error 一律为 null,不得报告部署完成。调用方必须持续轮询直到 status=succeeded/failed;status=expired 表示任务超过最长保留时间(2 小时)被终结,云端可能仍在部署,需用 getFunctionDetail 确认。任务只保存在 MCP 进程内存中,过期或 MCP Server 重启后返回 errorCode=DEPLOY_TASK_NOT_FOUND;任务按环境隔离,只能查到当前环境自己发起的部署。cloud mode 下本 action 不可用:异步任务只由 buildStrategy=cloud/local 的真实部署创建,而这两种策略在 cloud mode 下都不支持真实执行,image 策略则走同步部署不产生 taskId。\n- `listVersionByFunction`: 列出函数已发布版本(对齐 tcb fn list-function-versions / SDK listVersionByFunction;需要 functionName)\n- `getFunctionAlias`: 查询函数别名与流量路由(对齐 tcb fn get-route / SDK getFunctionAlias;需要 functionName;aliasName 默认 $DEFAULT)\n- `getFunctionUploadUrl`: 获取函数代码包的 COS 预签名上传地址(ZIP 两段式部署阶段 A):PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带对应请求头),再调用 manageFunctions 的 createFunction/updateFunctionCode 并传 code 三元组(阶段 B)。functionName 可选,仅用于生成上传对象 key。返回的 uploadUrl 含凭据签名,不得写入日志或持久化;阶段 A 与阶段 B 必须落在同一个 MCP 进程(MCP Server 重启后需重新取地址并重新上传);地址默认 300 秒内有效",
|
|
204651
204664
|
"schema.query.functionName": "CloudBase 云函数名称。`getFunctionDetail`、`listFunctionLogs`、`listFunctionLayers`、`listFunctionTriggers`、`getFunctionDownloadUrl`、`listVersionByFunction`、`getFunctionAlias` 时必填;`getFunctionUploadUrl` 可选(仅用于生成上传对象 key)",
|
|
204652
204665
|
"schema.query.limit": "分页数量(limit)。列表类 action 可选,默认值由后端决定",
|
|
204653
204666
|
"schema.query.offset": "分页偏移(offset)。列表类 action 可选,默认 0",
|
|
@@ -204671,7 +204684,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
204671
204684
|
"schema.manage.force": "createFunction 时是否覆盖",
|
|
204672
204685
|
"schema.manage.functionName": "目标函数名称(顶层)。updateFunctionCode / updateFunctionConfig / invokeFunction / publishVersion / updateFunctionAliasConfig 等 action 使用此字段。不要只写在 func.name:createFunction 用 func.name,其它 action 用顶层 functionName。若误传 func.name,也会被识别为 functionName。",
|
|
204673
204686
|
"schema.manage.zipFile": "仅兼容特殊场景:预先准备好的代码包 base64 编码。普通 createFunction/updateFunctionCode 默认不要先压缩 zip,优先使用 functionRootPath。",
|
|
204674
|
-
"schema.manage.code": "ZIP 两段式部署阶段 B:代码包已通过 queryFunctions action=getFunctionUploadUrl 上传到环境 COS 桶。三元组(cosBucketName/cosObjectName/cosBucketRegion)直接使用 getFunctionUploadUrl 返回值原样透传。传入 code 后 createFunction/updateFunctionCode 不再读取本地目录(functionRootPath/zipFile 均不需要),默认不触发云端依赖安装(可用 func.installDependency 覆盖)。",
|
|
204687
|
+
"schema.manage.code": "ZIP 两段式部署阶段 B:代码包已通过 queryFunctions action=getFunctionUploadUrl 上传到环境 COS 桶。三元组(cosBucketName/cosObjectName/cosBucketRegion)直接使用 getFunctionUploadUrl 返回值原样透传。传入 code 后 createFunction/updateFunctionCode 不再读取本地目录(functionRootPath/zipFile 均不需要),默认不触发云端依赖安装(可用 func.installDependency 覆盖)。code 三元组必须是同一个 MCP 进程的 getFunctionUploadUrl 刚返回的那一组(该 process 会在阶段 A 登记上传目标),自行拼装或跨环境复用会被拒绝并要求重新取地址。",
|
|
204675
204688
|
"schema.code.cosBucketName": "环境存储桶短名(不含 -appid 后缀),直接使用 getFunctionUploadUrl 返回的 cosBucketName,不要自填",
|
|
204676
204689
|
"schema.code.cosObjectName": "上传对象 key,直接使用 getFunctionUploadUrl 返回的 cosObjectName",
|
|
204677
204690
|
"schema.code.cosBucketRegion": "存储桶地域,省略时自动使用当前环境存储桶地域",
|
|
@@ -204795,6 +204808,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
204795
204808
|
unsupportedAction: "Unsupported action: {action}",
|
|
204796
204809
|
storageMissing: "The current environment has no usable object storage bucket (DescribeEnvs returned no Storages), so COS two-phase deployment is unavailable. Check the environment storage configuration, or deploy in local mode. Environments with a shared bucket (ExternalStorage) are not supported either.",
|
|
204797
204810
|
credentialMissing: "The current credential lacks SecretId/SecretKey (e.g. IDE proxy mode), so a COS presigned upload URL cannot be minted locally. Use local mode or a login method with permanent/temporary keys.",
|
|
204811
|
+
uploadTargetNotFound: "The code package upload target is not registered in this process: {objectName}. Two-phase ZIP deployment requires the code triplet to come from a getFunctionUploadUrl response minted by this same MCP process and environment; a restarted MCP Server, a different environment, or a hand-built cosObjectName / cosBucketName all land here. Call queryFunctions action=getFunctionUploadUrl again, upload the code package to the returned address, then call this action with the returned triplet.",
|
|
204798
204812
|
// ---- nextActions reasons ----
|
|
204799
204813
|
"reason.continuePolling": "Keep polling the cloud function deployment status",
|
|
204800
204814
|
"reason.getDetail": "View details of a single function",
|
|
@@ -204853,7 +204867,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
204853
204867
|
gotLayerVersionDetail: "Retrieved details of layer {layerName} version {layerVersion}",
|
|
204854
204868
|
gotFunctionTriggers: "Retrieved the trigger list of function {fnName}",
|
|
204855
204869
|
gotDownloadUrl: "Retrieved the code download URL of function {fnName}",
|
|
204856
|
-
gotUploadUrl: "Generated the code package upload URL (valid for {seconds} seconds). Next: PUT the code zip to uploadUrl (include the uploadHeaders when non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (cosBucketName/cosObjectName/cosBucketRegion) to deploy",
|
|
204870
|
+
gotUploadUrl: "Generated the code package upload URL (valid for {seconds} seconds). Next: PUT the code zip to uploadUrl (include the uploadHeaders when non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (cosBucketName/cosObjectName/cosBucketRegion) to deploy. Treat the uploadUrl as a one-time upload credential: do not forward it or paste it into tickets; if it expires before the upload, call getFunctionUploadUrl again for a fresh address",
|
|
204857
204871
|
gotFunctionVersions: "Retrieved the version list of function {fnName}",
|
|
204858
204872
|
gotFunctionAlias: "Retrieved alias {aliasName} of function {fnName}",
|
|
204859
204873
|
publishedVersion: "Published new version {version} of function {fnName}",
|
|
@@ -204927,7 +204941,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
204927
204941
|
"schema.create.layers": "Layer configuration",
|
|
204928
204942
|
"schema.manageLayer.name": "Layer name",
|
|
204929
204943
|
"schema.manageLayer.version": "Layer version number",
|
|
204930
|
-
"schema.query.action": "Read-only action type:\n- `listFunctions`: list all CloudBase cloud functions\n- `getFunctionDetail`: get function details (requires functionName)\n- `listFunctionLogs`: query function execution logs (requires functionName)\n- `getFunctionLogDetail`: get log details (requires requestId)\n- `listFunctionLayers`: list layers bound to a function\n- `listLayers`: list all layers (account-level view, including layers from other environments)\n- `listLayerVersions`: list layer versions (Versions, not Version; account-level view)\n- `getLayerVersionDetail`: get layer version details (account-level view)\n- `listFunctionTriggers`: list function triggers (scheduled task / cron / timer configuration)\n- `getFunctionDownloadUrl`: get the function code download URL\n- `getFunctionDeployStatus`: query async deployment status, stage progress, and final result by taskId. Returns data.build, data.deploy, and data.progress. While status=running, data.result and data.error are null and deployment must not be reported as complete. Keep polling until status=succeeded/failed. status=expired means the task exceeded the 2-hour retention limit; cloud deployment may still be running, so confirm with getFunctionDetail. Tasks exist only in MCP process memory; expired tasks or a restarted MCP Server return errorCode=DEPLOY_TASK_NOT_FOUND. Tasks are isolated by environment. This action is unavailable in cloud mode because real cloud/local builds cannot run there, while image deployment is synchronous and creates no taskId.\n- `listVersionByFunction`: list published function versions (aligns with tcb fn list-function-versions / SDK listVersionByFunction; requires functionName)\n- `getFunctionAlias`: get function alias and traffic routing (aligns with tcb fn get-route / SDK getFunctionAlias; requires functionName; aliasName defaults to $DEFAULT)\n- `getFunctionUploadUrl`: get a COS presigned upload URL for a function code package (two-phase ZIP deployment phase A): PUT the code zip to uploadUrl (include the corresponding request headers when uploadHeaders is non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (phase B). functionName is optional and only shapes the upload object key. The uploadUrl carries credential-bound signatures; never log or persist it",
|
|
204944
|
+
"schema.query.action": "Read-only action type:\n- `listFunctions`: list all CloudBase cloud functions\n- `getFunctionDetail`: get function details (requires functionName)\n- `listFunctionLogs`: query function execution logs (requires functionName)\n- `getFunctionLogDetail`: get log details (requires requestId)\n- `listFunctionLayers`: list layers bound to a function\n- `listLayers`: list all layers (account-level view, including layers from other environments)\n- `listLayerVersions`: list layer versions (Versions, not Version; account-level view)\n- `getLayerVersionDetail`: get layer version details (account-level view)\n- `listFunctionTriggers`: list function triggers (scheduled task / cron / timer configuration)\n- `getFunctionDownloadUrl`: get the function code download URL\n- `getFunctionDeployStatus`: query async deployment status, stage progress, and final result by taskId. Returns data.build, data.deploy, and data.progress. While status=running, data.result and data.error are null and deployment must not be reported as complete. Keep polling until status=succeeded/failed. status=expired means the task exceeded the 2-hour retention limit; cloud deployment may still be running, so confirm with getFunctionDetail. Tasks exist only in MCP process memory; expired tasks or a restarted MCP Server return errorCode=DEPLOY_TASK_NOT_FOUND. Tasks are isolated by environment. This action is unavailable in cloud mode because real cloud/local builds cannot run there, while image deployment is synchronous and creates no taskId.\n- `listVersionByFunction`: list published function versions (aligns with tcb fn list-function-versions / SDK listVersionByFunction; requires functionName)\n- `getFunctionAlias`: get function alias and traffic routing (aligns with tcb fn get-route / SDK getFunctionAlias; requires functionName; aliasName defaults to $DEFAULT)\n- `getFunctionUploadUrl`: get a COS presigned upload URL for a function code package (two-phase ZIP deployment phase A): PUT the code zip to uploadUrl (include the corresponding request headers when uploadHeaders is non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (phase B). functionName is optional and only shapes the upload object key. The uploadUrl carries credential-bound signatures; never log or persist it; phase A and phase B must run in the same MCP process (after an MCP Server restart, fetch a new address and upload again); the address is valid for 300 seconds by default",
|
|
204931
204945
|
"schema.query.functionName": "CloudBase cloud function name. Required for `getFunctionDetail`, `listFunctionLogs`, `listFunctionLayers`, `listFunctionTriggers`, `getFunctionDownloadUrl`, `listVersionByFunction`, and `getFunctionAlias`. Optional for `getFunctionUploadUrl` (only used to generate the upload object key).",
|
|
204932
204946
|
"schema.query.limit": "Page size (limit). Optional for list actions; the backend determines the default.",
|
|
204933
204947
|
"schema.query.offset": "Pagination offset. Optional for list actions; defaults to 0.",
|
|
@@ -204951,7 +204965,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
204951
204965
|
"schema.manage.force": "Whether createFunction overwrites an existing function.",
|
|
204952
204966
|
"schema.manage.functionName": "Target function name at the top level. Used by updateFunctionCode, updateFunctionConfig, invokeFunction, publishVersion, updateFunctionAliasConfig, and similar actions. createFunction uses func.name; other actions use top-level functionName. A mistakenly supplied func.name is also recognized as functionName.",
|
|
204953
204967
|
"schema.manage.zipFile": "Compatibility only: base64-encoded prebuilt code package. For ordinary createFunction/updateFunctionCode, do not create a ZIP first; prefer functionRootPath.",
|
|
204954
|
-
"schema.manage.code": "Two-phase ZIP deployment phase B: the code package has been uploaded to the environment COS bucket via queryFunctions action=getFunctionUploadUrl. Pass the triplet (cosBucketName/cosObjectName/cosBucketRegion) through unchanged from the getFunctionUploadUrl response. With code provided, createFunction/updateFunctionCode no longer reads local directories (functionRootPath/zipFile are unnecessary), and cloud dependency installation is skipped by default (override with func.installDependency).",
|
|
204968
|
+
"schema.manage.code": "Two-phase ZIP deployment phase B: the code package has been uploaded to the environment COS bucket via queryFunctions action=getFunctionUploadUrl. Pass the triplet (cosBucketName/cosObjectName/cosBucketRegion) through unchanged from the getFunctionUploadUrl response. With code provided, createFunction/updateFunctionCode no longer reads local directories (functionRootPath/zipFile are unnecessary), and cloud dependency installation is skipped by default (override with func.installDependency). The code triplet must be the one just returned by getFunctionUploadUrl in the same MCP process (that process registers the upload target in phase A); hand-built triplets or cross-environment reuse are rejected and require fetching a new address.",
|
|
204955
204969
|
"schema.code.cosBucketName": "Environment bucket short name (without the -appid suffix); pass through the cosBucketName returned by getFunctionUploadUrl, do not invent one",
|
|
204956
204970
|
"schema.code.cosObjectName": "Uploaded object key; pass through the cosObjectName returned by getFunctionUploadUrl",
|
|
204957
204971
|
"schema.code.cosBucketRegion": "Bucket region; defaults to the current environment bucket region when omitted",
|
|
@@ -206796,6 +206810,107 @@ async function getInteractiveServerAsync() {
|
|
|
206796
206810
|
}
|
|
206797
206811
|
|
|
206798
206812
|
|
|
206813
|
+
/***/ },
|
|
206814
|
+
|
|
206815
|
+
/***/ 16156
|
|
206816
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
206817
|
+
|
|
206818
|
+
"use strict";
|
|
206819
|
+
|
|
206820
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
206821
|
+
exports.assertLocalEndpoint = assertLocalEndpoint;
|
|
206822
|
+
exports.resolveLocalEndpoint = resolveLocalEndpoint;
|
|
206823
|
+
exports.createLocalCloudApiRequestFn = createLocalCloudApiRequestFn;
|
|
206824
|
+
const logger_js_1 = __webpack_require__(40781);
|
|
206825
|
+
/** Loopback hosts only. WHATWG URL keeps the brackets on IPv6 hostnames. */
|
|
206826
|
+
const ALLOWED_HOSTS = new Set(['127.0.0.1', '[::1]', 'localhost']);
|
|
206827
|
+
/** Upper bound for one cloud API call, so a hung endpoint cannot block a tool call forever. */
|
|
206828
|
+
const ENDPOINT_TIMEOUT_MS = 30_000;
|
|
206829
|
+
let announcedEndpoint;
|
|
206830
|
+
/**
|
|
206831
|
+
* Validate and normalise CLOUDBASE_LOCAL_ENDPOINT.
|
|
206832
|
+
*
|
|
206833
|
+
* Setting this variable makes cloud API calls skip the login and credential
|
|
206834
|
+
* checks, so it must never point off the local machine.
|
|
206835
|
+
*/
|
|
206836
|
+
function assertLocalEndpoint(endpoint) {
|
|
206837
|
+
let parsed;
|
|
206838
|
+
try {
|
|
206839
|
+
parsed = new URL(endpoint);
|
|
206840
|
+
}
|
|
206841
|
+
catch {
|
|
206842
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT is not a valid URL');
|
|
206843
|
+
}
|
|
206844
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
206845
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT must use http or https');
|
|
206846
|
+
}
|
|
206847
|
+
if (!ALLOWED_HOSTS.has(parsed.hostname)) {
|
|
206848
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT must point at a loopback host');
|
|
206849
|
+
}
|
|
206850
|
+
return endpoint.replace(/\/+$/, '');
|
|
206851
|
+
}
|
|
206852
|
+
/**
|
|
206853
|
+
* Read and validate CLOUDBASE_LOCAL_ENDPOINT. Returns undefined when unset.
|
|
206854
|
+
*
|
|
206855
|
+
* A malformed value throws instead of silently falling back, so a bad config
|
|
206856
|
+
* surfaces as a config error rather than looking like an auth failure.
|
|
206857
|
+
*/
|
|
206858
|
+
function resolveLocalEndpoint() {
|
|
206859
|
+
const raw = process.env.CLOUDBASE_LOCAL_ENDPOINT;
|
|
206860
|
+
if (!raw) {
|
|
206861
|
+
return undefined;
|
|
206862
|
+
}
|
|
206863
|
+
const base = assertLocalEndpoint(raw);
|
|
206864
|
+
if (announcedEndpoint !== base) {
|
|
206865
|
+
announcedEndpoint = base;
|
|
206866
|
+
(0, logger_js_1.warn)(`CLOUDBASE_LOCAL_ENDPOINT is set: cloud API calls go to ${base} and the login/credential check is skipped`);
|
|
206867
|
+
}
|
|
206868
|
+
return base;
|
|
206869
|
+
}
|
|
206870
|
+
/**
|
|
206871
|
+
* manager-node 5.8.8 routes both DatabaseService.executePGSql and
|
|
206872
|
+
* commonService().call through CloudService.request. That method delegates
|
|
206873
|
+
* to context.requestFn and skips TC3 when the function is set.
|
|
206874
|
+
*/
|
|
206875
|
+
function createLocalCloudApiRequestFn(endpoint) {
|
|
206876
|
+
const base = assertLocalEndpoint(endpoint);
|
|
206877
|
+
return async ({ service, action, version, region, payload }) => {
|
|
206878
|
+
const response = await fetch(`${base}/capi`, {
|
|
206879
|
+
method: 'POST',
|
|
206880
|
+
headers: {
|
|
206881
|
+
'content-type': 'application/json',
|
|
206882
|
+
'x-tc-action': action,
|
|
206883
|
+
'x-tc-version': version,
|
|
206884
|
+
'x-tc-region': region,
|
|
206885
|
+
'x-tc-service': service,
|
|
206886
|
+
},
|
|
206887
|
+
body: JSON.stringify(payload ?? {}),
|
|
206888
|
+
signal: AbortSignal.timeout(ENDPOINT_TIMEOUT_MS),
|
|
206889
|
+
redirect: 'manual',
|
|
206890
|
+
});
|
|
206891
|
+
// With redirect: 'manual' a 3xx comes back as an opaque redirect (status 0)
|
|
206892
|
+
// instead of being followed, so both shapes must be rejected explicitly.
|
|
206893
|
+
if (response.type === 'opaqueredirect' || (response.status >= 300 && response.status < 400)) {
|
|
206894
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT responded with a redirect; redirects are not followed');
|
|
206895
|
+
}
|
|
206896
|
+
const body = await response.json();
|
|
206897
|
+
const inner = body.Response;
|
|
206898
|
+
if (!inner) {
|
|
206899
|
+
const error = new Error('missing Response');
|
|
206900
|
+
error.code = 'InternalError';
|
|
206901
|
+
throw error;
|
|
206902
|
+
}
|
|
206903
|
+
const apiError = inner.Error;
|
|
206904
|
+
if (apiError) {
|
|
206905
|
+
const error = new Error(apiError.Message || apiError.Code || 'cloud api error');
|
|
206906
|
+
error.code = apiError.Code;
|
|
206907
|
+
throw error;
|
|
206908
|
+
}
|
|
206909
|
+
return inner;
|
|
206910
|
+
};
|
|
206911
|
+
}
|
|
206912
|
+
|
|
206913
|
+
|
|
206799
206914
|
/***/ },
|
|
206800
206915
|
|
|
206801
206916
|
/***/ 46324
|
|
@@ -221322,6 +221437,7 @@ function registerEnvTools(server) {
|
|
|
221322
221437
|
typeof cloudBaseOptions?.envId === "string" &&
|
|
221323
221438
|
cloudBaseOptions.envId.length > 0;
|
|
221324
221439
|
const envIdFromEnv = !cloudBaseOptions?.requestFn &&
|
|
221440
|
+
!process.env.CLOUDBASE_LOCAL_ENDPOINT &&
|
|
221325
221441
|
(process.env.CLOUDBASE_ENV_ID ||
|
|
221326
221442
|
(isEnvScopedCredential ? cloudBaseOptions.envId : undefined));
|
|
221327
221443
|
const shouldPinToEnvVar = Boolean(envIdFromEnv &&
|
|
@@ -222343,7 +222459,7 @@ function resolveMcpVersion(declared, packageVersion) {
|
|
|
222343
222459
|
return fromPackage;
|
|
222344
222460
|
}
|
|
222345
222461
|
function readDeclaredMcpVersion() {
|
|
222346
|
-
return true ? "2.34.
|
|
222462
|
+
return true ? "2.34.8" : 0;
|
|
222347
222463
|
}
|
|
222348
222464
|
function blank(value, lang) {
|
|
222349
222465
|
return value.trim().length > 0 ? value.trim() : (lang === "en" ? "blank" : "留空");
|
|
@@ -222702,7 +222818,7 @@ function encodeKv(obj) {
|
|
|
222702
222818
|
* Host 头始终签入(对齐 SDK ForceSignHost 默认 true),query 为空故 q-url-param-list 为空。
|
|
222703
222819
|
*/
|
|
222704
222820
|
function buildCosPutAuthorization(options) {
|
|
222705
|
-
const { secretId, secretKey, bucket, region, objectKey, securityToken, expiresInSeconds =
|
|
222821
|
+
const { secretId, secretKey, bucket, region, objectKey, securityToken, expiresInSeconds = 300, } = options;
|
|
222706
222822
|
if (!secretId)
|
|
222707
222823
|
throw new Error("missing param SecretId");
|
|
222708
222824
|
if (!secretKey)
|
|
@@ -222750,15 +222866,20 @@ function buildCosPutAuthorization(options) {
|
|
|
222750
222866
|
}
|
|
222751
222867
|
/**
|
|
222752
222868
|
* 生成两段式部署阶段 A 的完整返回体:预签名 PUT URL + 阶段 B 所需的 COS 三元组。
|
|
222753
|
-
* 对象 key 形如 `fnzip-upload/{ts}-{rand}/{functionName|code}.zip
|
|
222754
|
-
*
|
|
222869
|
+
* 对象 key 形如 `fnzip-upload/{ts}-{rand}/{functionName|code}.zip`。functionName 会被
|
|
222870
|
+
* 收窄到 COS 签名安全字符(字母数字与 -_),保证签名 pathname 与请求 URL 一致。
|
|
222755
222871
|
*/
|
|
222756
222872
|
function buildFunctionZipUpload(params) {
|
|
222757
222873
|
const { storage, credential, functionName } = params;
|
|
222758
|
-
const expiresIn = params.expiresIn ??
|
|
222874
|
+
const expiresIn = params.expiresIn ?? 300;
|
|
222759
222875
|
const ts = params.now ?? Math.floor(Date.now() / 1000);
|
|
222760
222876
|
const rand = params.randomSuffix ?? (0, crypto_1.randomBytes)(8).toString("hex");
|
|
222761
|
-
|
|
222877
|
+
// functionName 只用于让对象 key 可读,必须收窄:否则 "../" 之类能把对象写到
|
|
222878
|
+
// fnzip-upload/ 前缀之外
|
|
222879
|
+
const safeFunctionName = functionName && /^[A-Za-z0-9_-]{1,64}$/.test(functionName)
|
|
222880
|
+
? functionName
|
|
222881
|
+
: "code";
|
|
222882
|
+
const objectKey = `fnzip-upload/${ts}-${rand}/${safeFunctionName}.zip`;
|
|
222762
222883
|
const keyTime = params.keyTime ?? `${ts - 1};${ts + expiresIn}`;
|
|
222763
222884
|
const authorization = buildCosPutAuthorization({
|
|
222764
222885
|
secretId: credential.secretId,
|
|
@@ -224141,6 +224262,127 @@ async function waitUntilFunctionActive(getStatus, options = {}) {
|
|
|
224141
224262
|
}
|
|
224142
224263
|
|
|
224143
224264
|
|
|
224265
|
+
/***/ },
|
|
224266
|
+
|
|
224267
|
+
/***/ 77499
|
|
224268
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
224269
|
+
|
|
224270
|
+
"use strict";
|
|
224271
|
+
|
|
224272
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
224273
|
+
exports.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE = exports.FUNCTION_UPLOAD_TARGET_LIMITS = void 0;
|
|
224274
|
+
exports.registerFunctionUploadTarget = registerFunctionUploadTarget;
|
|
224275
|
+
exports.findFunctionUploadTarget = findFunctionUploadTarget;
|
|
224276
|
+
exports.getFunctionUploadTargetCount = getFunctionUploadTargetCount;
|
|
224277
|
+
exports.resetFunctionUploadTargets = resetFunctionUploadTargets;
|
|
224278
|
+
const function_cos_upload_js_1 = __webpack_require__(65735);
|
|
224279
|
+
/**
|
|
224280
|
+
* 云函数 ZIP 两段式部署的「上传目标」进程内登记。
|
|
224281
|
+
*
|
|
224282
|
+
* 阶段 A(queryFunctions action=getFunctionUploadUrl)铸造预签名上传地址时,
|
|
224283
|
+
* 在本进程登记这次铸造出来的 (envId, bucket, region, objectKey);阶段 B
|
|
224284
|
+
* (manageFunctions createFunction / updateFunctionCode 带 code 三元组)只接受
|
|
224285
|
+
* 登记过的组合。
|
|
224286
|
+
*
|
|
224287
|
+
* 为什么需要它:code.cosObjectName 是模型可以自由填写的字符串,如果不校验,
|
|
224288
|
+
* 它可以指向环境桶里的任意对象,也可以指向另一个桶(包括调用方自己的桶)——
|
|
224289
|
+
* SCF 会用环境角色去拉取那个对象。登记把可用面收窄成「本进程刚为当前环境铸造
|
|
224290
|
+
* 出来的那个 key」。
|
|
224291
|
+
*
|
|
224292
|
+
* 取舍(刻意不做的事):
|
|
224293
|
+
* - 不做「用一次即作废」:同一个 key 在保留期内可以重复提交。上传失败重试、
|
|
224294
|
+
* updateFunctionCode 撞上 ResourceInUse 后的重试、以及同一份代码包重复部署
|
|
224295
|
+
* 都要能重放,收窄的只是「谁能成为目标」,不是「能用几次」。
|
|
224296
|
+
* - 不区分「没登记」与「登记在别的环境」:登记按 envId 隔离,跨环境查询直接
|
|
224297
|
+
* 未命中,调用方只需要知道「这个目标不在登记里,请重新取地址」。
|
|
224298
|
+
*
|
|
224299
|
+
* 登记只保存在当前 MCP 进程内存中,MCP Server 重启即丢失 —— 此时重新调用
|
|
224300
|
+
* getFunctionUploadUrl 取地址、重新上传即可。这与 function-deploy-task-store
|
|
224301
|
+
* 的语义一致(异步部署任务同样只活在进程内)。
|
|
224302
|
+
*/
|
|
224303
|
+
exports.FUNCTION_UPLOAD_TARGET_LIMITS = {
|
|
224304
|
+
/**
|
|
224305
|
+
* 登记的保留时间。远长于上传地址本身的有效期(默认 300 秒):地址过期只影响
|
|
224306
|
+
* 「还能不能 PUT」,而登记要覆盖「取地址 → 上传 → 提交部署」整条链在客户端
|
|
224307
|
+
* 可能的等待(大包上传、人工确认、agent 多轮编排)。
|
|
224308
|
+
*/
|
|
224309
|
+
ttlMs: 60 * 60 * 1000,
|
|
224310
|
+
/** 最大登记数,超出时淘汰最旧的 */
|
|
224311
|
+
maxTargets: 500,
|
|
224312
|
+
};
|
|
224313
|
+
exports.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE = "FUNCTION_UPLOAD_TARGET_NOT_FOUND";
|
|
224314
|
+
const uploadTargets = new Map();
|
|
224315
|
+
/**
|
|
224316
|
+
* envId 与 objectKey 都不可能含 NUL,用它拼主键不会产生歧义;
|
|
224317
|
+
* 反过来,跨环境的查询无法构造出同一主键(前缀 envId 由服务端解析,调用方改不了)。
|
|
224318
|
+
*/
|
|
224319
|
+
function targetKey(envId, objectKey) {
|
|
224320
|
+
return `${envId}\u0000${objectKey}`;
|
|
224321
|
+
}
|
|
224322
|
+
function cleanupUploadTargets(now) {
|
|
224323
|
+
for (const [key, target] of uploadTargets) {
|
|
224324
|
+
if (now - target.createdAtMs > exports.FUNCTION_UPLOAD_TARGET_LIMITS.ttlMs) {
|
|
224325
|
+
uploadTargets.delete(key);
|
|
224326
|
+
}
|
|
224327
|
+
}
|
|
224328
|
+
}
|
|
224329
|
+
/**
|
|
224330
|
+
* 达到上限时淘汰最旧的登记。
|
|
224331
|
+
*
|
|
224332
|
+
* 与部署任务表不同,这里每一条登记都可以淘汰 —— 淘汰最坏的结果是调用方重新
|
|
224333
|
+
* 取一次上传地址,不会影响任何正在进行中的云端操作,因此不需要 warn。
|
|
224334
|
+
*/
|
|
224335
|
+
function enforceMaxTargets() {
|
|
224336
|
+
const { maxTargets } = exports.FUNCTION_UPLOAD_TARGET_LIMITS;
|
|
224337
|
+
if (uploadTargets.size < maxTargets) {
|
|
224338
|
+
return;
|
|
224339
|
+
}
|
|
224340
|
+
const oldestFirst = [...uploadTargets.entries()].sort((left, right) => left[1].createdAtMs - right[1].createdAtMs);
|
|
224341
|
+
for (const [key] of oldestFirst) {
|
|
224342
|
+
if (uploadTargets.size < maxTargets) {
|
|
224343
|
+
return;
|
|
224344
|
+
}
|
|
224345
|
+
uploadTargets.delete(key);
|
|
224346
|
+
}
|
|
224347
|
+
}
|
|
224348
|
+
/** 阶段 A 登记本次铸造的上传目标。 */
|
|
224349
|
+
function registerFunctionUploadTarget(input) {
|
|
224350
|
+
const now = input.now ?? Date.now();
|
|
224351
|
+
cleanupUploadTargets(now);
|
|
224352
|
+
enforceMaxTargets();
|
|
224353
|
+
uploadTargets.set(targetKey(input.envId, input.objectKey), {
|
|
224354
|
+
envId: input.envId,
|
|
224355
|
+
bucket: input.bucket,
|
|
224356
|
+
region: input.region,
|
|
224357
|
+
objectKey: input.objectKey,
|
|
224358
|
+
createdAtMs: now,
|
|
224359
|
+
});
|
|
224360
|
+
}
|
|
224361
|
+
/**
|
|
224362
|
+
* 阶段 B 校验:命中登记且桶、地域都对得上才返回目标,否则返回 undefined。
|
|
224363
|
+
*
|
|
224364
|
+
* 地域与桶都要比对 —— 只比对象 key 的话,仍然可以把同一个 key 指到别的桶或
|
|
224365
|
+
* 别的地域(例如把代码指到调用方自己的桶)上。
|
|
224366
|
+
*/
|
|
224367
|
+
function findFunctionUploadTarget(input) {
|
|
224368
|
+
const now = input.now ?? Date.now();
|
|
224369
|
+
cleanupUploadTargets(now);
|
|
224370
|
+
const target = uploadTargets.get(targetKey(input.envId, input.objectKey));
|
|
224371
|
+
if (!target) {
|
|
224372
|
+
return undefined;
|
|
224373
|
+
}
|
|
224374
|
+
const bucketMatches = (0, function_cos_upload_js_1.stripAppIdSuffix)(input.bucketName) === (0, function_cos_upload_js_1.stripAppIdSuffix)(target.bucket);
|
|
224375
|
+
return bucketMatches && input.region === target.region ? target : undefined;
|
|
224376
|
+
}
|
|
224377
|
+
function getFunctionUploadTargetCount() {
|
|
224378
|
+
return uploadTargets.size;
|
|
224379
|
+
}
|
|
224380
|
+
/** 测试用:清空登记表 */
|
|
224381
|
+
function resetFunctionUploadTargets() {
|
|
224382
|
+
uploadTargets.clear();
|
|
224383
|
+
}
|
|
224384
|
+
|
|
224385
|
+
|
|
224144
224386
|
/***/ },
|
|
224145
224387
|
|
|
224146
224388
|
/***/ 51546
|
|
@@ -224173,10 +224415,35 @@ const tool_result_js_1 = __webpack_require__(69645);
|
|
|
224173
224415
|
const function_deploy_js_1 = __webpack_require__(39151);
|
|
224174
224416
|
const function_deploy_schema_js_1 = __webpack_require__(76427);
|
|
224175
224417
|
const function_cos_upload_js_1 = __webpack_require__(65735);
|
|
224418
|
+
const function_upload_target_store_js_1 = __webpack_require__(77499);
|
|
224176
224419
|
const function_updating_js_1 = __webpack_require__(70326);
|
|
224177
224420
|
const index_js_1 = __webpack_require__(24908);
|
|
224178
224421
|
const fs_1 = __webpack_require__(29021);
|
|
224179
224422
|
const path_1 = __importDefault(__webpack_require__(33873));
|
|
224423
|
+
/**
|
|
224424
|
+
* 阶段 B 校验:code 三元组必须是本进程阶段 A 登记过的上传目标。
|
|
224425
|
+
*
|
|
224426
|
+
* 未命中时统一按「目标不在登记里」返回,不区分「没登记」与「登记在别的环境」——
|
|
224427
|
+
* 与部署任务表同款取舍,调用方只需要知道下一步该重新取上传地址。
|
|
224428
|
+
*/
|
|
224429
|
+
function assertFunctionUploadTarget(input) {
|
|
224430
|
+
if ((0, function_upload_target_store_js_1.findFunctionUploadTarget)(input)) {
|
|
224431
|
+
return;
|
|
224432
|
+
}
|
|
224433
|
+
(0, tool_result_js_1.throwToolPayloadError)({
|
|
224434
|
+
success: false,
|
|
224435
|
+
errorCode: function_upload_target_store_js_1.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE,
|
|
224436
|
+
data: {
|
|
224437
|
+
action: input.action,
|
|
224438
|
+
cosBucketName: input.bucketName,
|
|
224439
|
+
cosBucketRegion: input.region,
|
|
224440
|
+
cosObjectName: input.objectKey,
|
|
224441
|
+
},
|
|
224442
|
+
message: (0, index_js_1.t)("functions.uploadTargetNotFound", {
|
|
224443
|
+
objectName: input.objectKey,
|
|
224444
|
+
}),
|
|
224445
|
+
});
|
|
224446
|
+
}
|
|
224180
224447
|
exports.SUPPORTED_RUNTIMES = {
|
|
224181
224448
|
nodejs: [
|
|
224182
224449
|
"Nodejs20.19",
|
|
@@ -224692,7 +224959,8 @@ function registerFunctionTools(server) {
|
|
|
224692
224959
|
if (!bucket || !region) {
|
|
224693
224960
|
throw new Error((0, index_js_1.t)("functions.storageMissing"));
|
|
224694
224961
|
}
|
|
224695
|
-
|
|
224962
|
+
// envId 一并返回:阶段 A 的上传目标登记与阶段 B 的校验都按环境隔离
|
|
224963
|
+
return { bucket, region, envId };
|
|
224696
224964
|
};
|
|
224697
224965
|
const ensureActionAllowedInCloudMode = (input) => {
|
|
224698
224966
|
if (!(0, cloud_mode_js_1.isCloudMode)()) {
|
|
@@ -225083,7 +225351,9 @@ function registerFunctionTools(server) {
|
|
|
225083
225351
|
}
|
|
225084
225352
|
const cloudbase = await getManager();
|
|
225085
225353
|
const result = await cloudbase.functions.getFunctionDownloadUrl(input.functionName, input.codeSecret);
|
|
225086
|
-
|
|
225354
|
+
// downloadUrl 是带凭据签名的临时链接:与 apps getUploadUrl 同款处理,只落 RequestId,
|
|
225355
|
+
// 避免整条 URL 随宿主日志持久化
|
|
225356
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, { RequestId: result.RequestId });
|
|
225087
225357
|
return buildEnvelope({
|
|
225088
225358
|
action: input.action,
|
|
225089
225359
|
functionName: input.functionName,
|
|
@@ -225184,6 +225454,14 @@ function registerFunctionTools(server) {
|
|
|
225184
225454
|
},
|
|
225185
225455
|
functionName: input.functionName,
|
|
225186
225456
|
});
|
|
225457
|
+
// 阶段 A 在进程内登记本次铸造的上传目标:阶段 B 只接受登记过的
|
|
225458
|
+
// (envId, bucket, region, objectKey),cosObjectName 因此不再是任意字符串。
|
|
225459
|
+
(0, function_upload_target_store_js_1.registerFunctionUploadTarget)({
|
|
225460
|
+
envId: storage.envId,
|
|
225461
|
+
bucket: storage.bucket,
|
|
225462
|
+
region: storage.region,
|
|
225463
|
+
objectKey: upload.cosObjectName,
|
|
225464
|
+
});
|
|
225187
225465
|
// uploadUrl 内含凭据绑定的签名(临时凭据还绑定 token),禁止落日志
|
|
225188
225466
|
(0, logger_js_1.debug)(`[getFunctionUploadUrl] envId=${authConfig.envId ?? "n/a"}, cosObjectName=${upload.cosObjectName}, expiresIn=${upload.expiresInSeconds}s`);
|
|
225189
225467
|
return buildEnvelope({
|
|
@@ -225465,6 +225743,13 @@ function registerFunctionTools(server) {
|
|
|
225465
225743
|
const storage = await resolveEnvFunctionCosStorage();
|
|
225466
225744
|
const cosBucketName = (0, function_cos_upload_js_1.stripAppIdSuffix)(input.code.cosBucketName || storage.bucket);
|
|
225467
225745
|
const cosBucketRegion = input.code.cosBucketRegion ?? storage.region;
|
|
225746
|
+
assertFunctionUploadTarget({
|
|
225747
|
+
envId: storage.envId,
|
|
225748
|
+
bucketName: input.code.cosBucketName || storage.bucket,
|
|
225749
|
+
region: cosBucketRegion,
|
|
225750
|
+
objectKey: input.code.cosObjectName,
|
|
225751
|
+
action: input.action,
|
|
225752
|
+
});
|
|
225468
225753
|
const codeFunc = { ...func };
|
|
225469
225754
|
// 用户 zip 自带依赖语义(装没装由上传方决定),默认不触发云端依赖安装
|
|
225470
225755
|
delete codeFunc.installDependency;
|
|
@@ -225730,6 +226015,13 @@ function registerFunctionTools(server) {
|
|
|
225730
226015
|
const storage = await resolveEnvFunctionCosStorage();
|
|
225731
226016
|
const cosBucketName = (0, function_cos_upload_js_1.stripAppIdSuffix)(input.code.cosBucketName || storage.bucket);
|
|
225732
226017
|
const cosBucketRegion = input.code.cosBucketRegion ?? storage.region;
|
|
226018
|
+
assertFunctionUploadTarget({
|
|
226019
|
+
envId: storage.envId,
|
|
226020
|
+
bucketName: input.code.cosBucketName || storage.bucket,
|
|
226021
|
+
region: cosBucketRegion,
|
|
226022
|
+
objectKey: input.code.cosObjectName,
|
|
226023
|
+
action: input.action,
|
|
226024
|
+
});
|
|
225733
226025
|
let cosUpdateResult;
|
|
225734
226026
|
try {
|
|
225735
226027
|
cosUpdateResult = await cloudbase.functions.updateFunctionCode({
|
|
@@ -235425,7 +235717,7 @@ class TelemetryReporter {
|
|
|
235425
235717
|
const arch = os_1.default.arch(); // 系统架构
|
|
235426
235718
|
// Build-time injected version; guard for vitest / non-webpack runtimes.
|
|
235427
235719
|
const mcpVersion = process.env.npm_package_version ||
|
|
235428
|
-
( true ? "2.34.
|
|
235720
|
+
( true ? "2.34.8" : 0);
|
|
235429
235721
|
return {
|
|
235430
235722
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
235431
235723
|
deviceId: this.deviceId,
|
|
@@ -236149,7 +236441,7 @@ ${envIdSection}
|
|
|
236149
236441
|
## 环境信息
|
|
236150
236442
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
236151
236443
|
- Node.js版本: ${process.version}
|
|
236152
|
-
- MCP 版本:${( true ? "2.34.
|
|
236444
|
+
- MCP 版本:${( true ? "2.34.8" : 0) || 0 || 0}
|
|
236153
236445
|
- 系统架构: ${os_1.default.arch()}
|
|
236154
236446
|
- 时间: ${new Date().toISOString()}
|
|
236155
236447
|
- 请求ID: ${requestId}
|
|
@@ -236247,7 +236539,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
236247
236539
|
requestId,
|
|
236248
236540
|
ide: server.ide || process.env.INTEGRATION_IDE || ''
|
|
236249
236541
|
});
|
|
236250
|
-
const mcpVersion = true ? "2.34.
|
|
236542
|
+
const mcpVersion = true ? "2.34.8" : 0;
|
|
236251
236543
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
236252
236544
|
const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
|
|
236253
236545
|
// 创建新的错误对象,保持原有的错误类型但更新消息
|