@cloudbase/cloudbase-mcp 2.25.0 → 2.25.2
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 +2 -2
- package/dist/index.cjs +882 -189
- package/dist/index.js +880 -188
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2233,7 +2233,7 @@ ${envIdSection}
|
|
|
2233
2233
|
## 环境信息
|
|
2234
2234
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
2235
2235
|
- Node.js版本: ${process.version}
|
|
2236
|
-
- MCP 版本:${process.env.npm_package_version || "2.25.
|
|
2236
|
+
- MCP 版本:${process.env.npm_package_version || "2.25.2" || 0}
|
|
2237
2237
|
- 系统架构: ${os_1.default.arch()}
|
|
2238
2238
|
- 时间: ${new Date().toISOString()}
|
|
2239
2239
|
- 请求ID: ${requestId}
|
|
@@ -2314,7 +2314,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
2314
2314
|
requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
|
|
2315
2315
|
ide: server.ide || process.env.INTEGRATION_IDE || ''
|
|
2316
2316
|
});
|
|
2317
|
-
const mcpVersion = true ? "2.25.
|
|
2317
|
+
const mcpVersion = true ? "2.25.2" : 0;
|
|
2318
2318
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
2319
2319
|
const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
|
|
2320
2320
|
// 创建新的错误对象,保持原有的错误类型但更新消息
|
|
@@ -2483,7 +2483,6 @@ const capi_js_1 = __webpack_require__(738);
|
|
|
2483
2483
|
const cloudrun_js_1 = __webpack_require__(5023);
|
|
2484
2484
|
const dataModel_js_1 = __webpack_require__(4052);
|
|
2485
2485
|
const gateway_js_1 = __webpack_require__(4319);
|
|
2486
|
-
const invite_code_js_1 = __webpack_require__(4760);
|
|
2487
2486
|
const agents_js_1 = __webpack_require__(9527);
|
|
2488
2487
|
const app_auth_js_1 = __webpack_require__(5313);
|
|
2489
2488
|
const apps_js_1 = __webpack_require__(6817);
|
|
@@ -2514,7 +2513,6 @@ const DEFAULT_PLUGINS = [
|
|
|
2514
2513
|
"logs",
|
|
2515
2514
|
"agents",
|
|
2516
2515
|
"download",
|
|
2517
|
-
"invite-code",
|
|
2518
2516
|
"capi",
|
|
2519
2517
|
];
|
|
2520
2518
|
function registerDatabase(server) {
|
|
@@ -2556,7 +2554,6 @@ const AVAILABLE_PLUGINS = {
|
|
|
2556
2554
|
logs: { name: "logs", register: logs_js_1.registerLogTools },
|
|
2557
2555
|
agents: { name: "agents", register: agents_js_1.registerAgentTools },
|
|
2558
2556
|
apps: { name: "apps", register: apps_js_1.registerAppTools },
|
|
2559
|
-
"invite-code": { name: "invite-code", register: invite_code_js_1.registerInviteCodeTools },
|
|
2560
2557
|
cloudrun: { name: "cloudrun", register: cloudrun_js_1.registerCloudRunTools },
|
|
2561
2558
|
capi: { name: "capi", register: capi_js_1.registerCapiTools },
|
|
2562
2559
|
};
|
|
@@ -2911,6 +2908,153 @@ function registerLogTools(server) {
|
|
|
2911
2908
|
|
|
2912
2909
|
module.exports = __WEBPACK_EXTERNAL_MODULE__modelcontextprotocol_sdk_types_js_70eb1363__;
|
|
2913
2910
|
|
|
2911
|
+
/***/ }),
|
|
2912
|
+
|
|
2913
|
+
/***/ 2435:
|
|
2914
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
2915
|
+
|
|
2916
|
+
|
|
2917
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
2918
|
+
exports.rankGatewayAccessUrls = rankGatewayAccessUrls;
|
|
2919
|
+
exports.flattenHttpServiceRoutes = flattenHttpServiceRoutes;
|
|
2920
|
+
exports.filterRoutesByUpstream = filterRoutesByUpstream;
|
|
2921
|
+
exports.toAccessUrlEnvelope = toAccessUrlEnvelope;
|
|
2922
|
+
exports.resolveGatewayAccessUrls = resolveGatewayAccessUrls;
|
|
2923
|
+
exports.preferGatewayOrFallback = preferGatewayOrFallback;
|
|
2924
|
+
function normalizeAccessPath(path) {
|
|
2925
|
+
if (!path) {
|
|
2926
|
+
return "/";
|
|
2927
|
+
}
|
|
2928
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
2929
|
+
}
|
|
2930
|
+
function buildHttpsUrl(domain, path) {
|
|
2931
|
+
return `https://${domain}${normalizeAccessPath(path)}`;
|
|
2932
|
+
}
|
|
2933
|
+
/**
|
|
2934
|
+
* Rank gateway route URLs: custom domains (IsDefault !== true) before default domain.
|
|
2935
|
+
* Stable within each group; dedupe by full URL.
|
|
2936
|
+
*/
|
|
2937
|
+
function rankGatewayAccessUrls(routes) {
|
|
2938
|
+
const mapped = routes
|
|
2939
|
+
.filter((route) => Boolean(route.Domain))
|
|
2940
|
+
.map((route) => {
|
|
2941
|
+
const path = normalizeAccessPath(route.Path);
|
|
2942
|
+
const isDefault = route.IsDefault === true;
|
|
2943
|
+
return {
|
|
2944
|
+
url: buildHttpsUrl(route.Domain, path),
|
|
2945
|
+
domain: route.Domain,
|
|
2946
|
+
path,
|
|
2947
|
+
isDefault,
|
|
2948
|
+
source: (isDefault
|
|
2949
|
+
? "gateway.default"
|
|
2950
|
+
: "gateway.custom"),
|
|
2951
|
+
};
|
|
2952
|
+
});
|
|
2953
|
+
mapped.sort((a, b) => {
|
|
2954
|
+
if (a.isDefault === b.isDefault) {
|
|
2955
|
+
return 0;
|
|
2956
|
+
}
|
|
2957
|
+
return a.isDefault ? 1 : -1;
|
|
2958
|
+
});
|
|
2959
|
+
const seen = new Set();
|
|
2960
|
+
const deduped = [];
|
|
2961
|
+
for (const item of mapped) {
|
|
2962
|
+
if (seen.has(item.url)) {
|
|
2963
|
+
continue;
|
|
2964
|
+
}
|
|
2965
|
+
seen.add(item.url);
|
|
2966
|
+
deduped.push(item);
|
|
2967
|
+
}
|
|
2968
|
+
return deduped;
|
|
2969
|
+
}
|
|
2970
|
+
function flattenHttpServiceRoutes(result) {
|
|
2971
|
+
return (result.Domains ?? []).flatMap((domainItem) => (domainItem.Routes ?? []).map((route) => ({
|
|
2972
|
+
Domain: domainItem.Domain ?? "",
|
|
2973
|
+
IsDefault: domainItem.IsDefault,
|
|
2974
|
+
Path: typeof route.Path === "string" ? route.Path : undefined,
|
|
2975
|
+
UpstreamResourceType: typeof route.UpstreamResourceType === "string"
|
|
2976
|
+
? route.UpstreamResourceType
|
|
2977
|
+
: undefined,
|
|
2978
|
+
UpstreamResourceName: typeof route.UpstreamResourceName === "string"
|
|
2979
|
+
? route.UpstreamResourceName
|
|
2980
|
+
: undefined,
|
|
2981
|
+
})));
|
|
2982
|
+
}
|
|
2983
|
+
function filterRoutesByUpstream(routes, input) {
|
|
2984
|
+
const name = input.upstreamResourceName;
|
|
2985
|
+
const types = input.upstreamResourceTypes?.map((t) => String(t));
|
|
2986
|
+
return routes.filter((route) => {
|
|
2987
|
+
if (route.UpstreamResourceName !== name) {
|
|
2988
|
+
return false;
|
|
2989
|
+
}
|
|
2990
|
+
if (!types || types.length === 0) {
|
|
2991
|
+
return true;
|
|
2992
|
+
}
|
|
2993
|
+
return Boolean(route.UpstreamResourceType &&
|
|
2994
|
+
types.includes(String(route.UpstreamResourceType)));
|
|
2995
|
+
});
|
|
2996
|
+
}
|
|
2997
|
+
function toAccessUrlEnvelope(ranked) {
|
|
2998
|
+
if (ranked.length === 0) {
|
|
2999
|
+
return { accessUrls: [], routes: [] };
|
|
3000
|
+
}
|
|
3001
|
+
return {
|
|
3002
|
+
accessUrl: ranked[0].url,
|
|
3003
|
+
accessUrls: ranked.map((item) => item.url),
|
|
3004
|
+
accessUrlSource: ranked[0].source,
|
|
3005
|
+
routes: ranked,
|
|
3006
|
+
};
|
|
3007
|
+
}
|
|
3008
|
+
/**
|
|
3009
|
+
* Best-effort lookup of gateway access URLs for an upstream resource.
|
|
3010
|
+
* Never throws — returns empty lists on failure.
|
|
3011
|
+
*/
|
|
3012
|
+
async function resolveGatewayAccessUrls(input) {
|
|
3013
|
+
try {
|
|
3014
|
+
const manager = await input.getManager();
|
|
3015
|
+
const result = await manager.env.describeHttpServiceRoute({
|
|
3016
|
+
EnvId: input.envId,
|
|
3017
|
+
Limit: 1000,
|
|
3018
|
+
});
|
|
3019
|
+
const flattened = flattenHttpServiceRoutes(result);
|
|
3020
|
+
const matched = filterRoutesByUpstream(flattened, {
|
|
3021
|
+
upstreamResourceName: input.upstreamResourceName,
|
|
3022
|
+
upstreamResourceTypes: input.upstreamResourceTypes,
|
|
3023
|
+
});
|
|
3024
|
+
return toAccessUrlEnvelope(rankGatewayAccessUrls(matched));
|
|
3025
|
+
}
|
|
3026
|
+
catch {
|
|
3027
|
+
return { accessUrls: [], routes: [] };
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
/**
|
|
3031
|
+
* Merge ranked gateway URLs with a resource-native fallback URL.
|
|
3032
|
+
* Gateway custom/default always win over the fallback when present.
|
|
3033
|
+
*/
|
|
3034
|
+
function preferGatewayOrFallback(input) {
|
|
3035
|
+
if (input.gateway.accessUrl) {
|
|
3036
|
+
const urls = [...input.gateway.accessUrls];
|
|
3037
|
+
if (input.fallbackUrl &&
|
|
3038
|
+
!urls.includes(input.fallbackUrl)) {
|
|
3039
|
+
urls.push(input.fallbackUrl);
|
|
3040
|
+
}
|
|
3041
|
+
return {
|
|
3042
|
+
accessUrl: input.gateway.accessUrl,
|
|
3043
|
+
accessUrls: urls,
|
|
3044
|
+
accessUrlSource: input.gateway.accessUrlSource,
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
if (input.fallbackUrl) {
|
|
3048
|
+
return {
|
|
3049
|
+
accessUrl: input.fallbackUrl,
|
|
3050
|
+
accessUrls: [input.fallbackUrl],
|
|
3051
|
+
accessUrlSource: input.fallbackSource,
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
return { accessUrls: [] };
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
|
|
2914
3058
|
/***/ }),
|
|
2915
3059
|
|
|
2916
3060
|
/***/ 2448:
|
|
@@ -7151,6 +7295,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
7151
7295
|
exports.registerGatewayTools = registerGatewayTools;
|
|
7152
7296
|
const zod_1 = __webpack_require__(2971);
|
|
7153
7297
|
const cloudbase_manager_js_1 = __webpack_require__(3431);
|
|
7298
|
+
const gateway_access_urls_js_1 = __webpack_require__(2435);
|
|
7154
7299
|
const json_content_js_1 = __webpack_require__(4365);
|
|
7155
7300
|
const QUERY_GATEWAY_ACTIONS = [
|
|
7156
7301
|
"listRoutes",
|
|
@@ -7226,9 +7371,33 @@ function registerGatewayTools(server) {
|
|
|
7226
7371
|
IsDefault: domainItem.IsDefault,
|
|
7227
7372
|
...route,
|
|
7228
7373
|
})));
|
|
7229
|
-
const buildRouteUrls = (routes) =>
|
|
7230
|
-
.
|
|
7231
|
-
|
|
7374
|
+
const buildRouteUrls = (routes) => {
|
|
7375
|
+
const candidates = routes.map((route) => ({
|
|
7376
|
+
Domain: route.Domain,
|
|
7377
|
+
Path: route.Path,
|
|
7378
|
+
IsDefault: route.IsDefault,
|
|
7379
|
+
UpstreamResourceType: route.UpstreamResourceType,
|
|
7380
|
+
UpstreamResourceName: route.UpstreamResourceName,
|
|
7381
|
+
}));
|
|
7382
|
+
return (0, gateway_access_urls_js_1.rankGatewayAccessUrls)(candidates).map((item) => item.url);
|
|
7383
|
+
};
|
|
7384
|
+
const buildAccessUrlFields = (routes) => {
|
|
7385
|
+
const candidates = routes.map((route) => ({
|
|
7386
|
+
Domain: route.Domain,
|
|
7387
|
+
Path: route.Path,
|
|
7388
|
+
IsDefault: route.IsDefault,
|
|
7389
|
+
UpstreamResourceType: route.UpstreamResourceType,
|
|
7390
|
+
UpstreamResourceName: route.UpstreamResourceName,
|
|
7391
|
+
}));
|
|
7392
|
+
const envelope = (0, gateway_access_urls_js_1.toAccessUrlEnvelope)((0, gateway_access_urls_js_1.rankGatewayAccessUrls)(candidates));
|
|
7393
|
+
return {
|
|
7394
|
+
...(envelope.accessUrl ? { accessUrl: envelope.accessUrl } : {}),
|
|
7395
|
+
accessUrls: envelope.accessUrls,
|
|
7396
|
+
...(envelope.accessUrlSource
|
|
7397
|
+
? { accessUrlSource: envelope.accessUrlSource }
|
|
7398
|
+
: {}),
|
|
7399
|
+
};
|
|
7400
|
+
};
|
|
7232
7401
|
const resolveDefaultHttpDomain = async () => {
|
|
7233
7402
|
const routeInfo = await listHttpServiceRoutes();
|
|
7234
7403
|
const domains = routeInfo.Domains ?? [];
|
|
@@ -7247,36 +7416,24 @@ function registerGatewayTools(server) {
|
|
|
7247
7416
|
}
|
|
7248
7417
|
return resolveDefaultHttpDomain();
|
|
7249
7418
|
};
|
|
7250
|
-
const
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
return "SCF";
|
|
7259
|
-
}
|
|
7260
|
-
if (input.requiresFunctionType || input.targetType === "function") {
|
|
7261
|
-
throw new Error("为云函数创建/更新路由时必须显式提供 type(HTTP→WEB_SCF,Event→SCF)或 route.upstreamResourceType。省略会导致 HTTP 与 Event 函数互相误标,访问时可能返回 FUNCTION_PARAM_INVALID 或网关内部错误。");
|
|
7262
|
-
}
|
|
7263
|
-
throw new Error("必须提供 route.upstreamResourceType(SCF / WEB_SCF / CBR / STATIC_STORE / LH),或在函数场景提供 type=\"HTTP\"|\"Event\"。");
|
|
7419
|
+
const resolveUpstreamResourceType = (input) => {
|
|
7420
|
+
const resolved = input.routeUpstreamResourceType ?? input.upstreamResourceType;
|
|
7421
|
+
if (resolved) {
|
|
7422
|
+
return resolved;
|
|
7423
|
+
}
|
|
7424
|
+
throw new Error("必须提供 upstreamResourceType(或 route.upstreamResourceType):" +
|
|
7425
|
+
"WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器。" +
|
|
7426
|
+
"禁止仅凭 targetName/serviceName 推断上游类型。");
|
|
7264
7427
|
};
|
|
7265
7428
|
const normalizeRoutePayload = async (input) => {
|
|
7266
7429
|
const upstreamResourceName = input.route?.serviceName ?? input.targetName;
|
|
7267
7430
|
if (!upstreamResourceName) {
|
|
7268
|
-
throw new Error("必须提供 targetName 或 route.serviceName
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
input.
|
|
7273
|
-
input.route?.upstreamResourceType
|
|
7274
|
-
(!input.route?.upstreamResourceType && Boolean(input.targetName));
|
|
7275
|
-
const upstreamResourceType = mapUpstreamResourceType({
|
|
7276
|
-
type: input.type,
|
|
7277
|
-
targetType: input.targetType,
|
|
7278
|
-
upstreamResourceType: input.route?.upstreamResourceType,
|
|
7279
|
-
requiresFunctionType: isFunctionRoute,
|
|
7431
|
+
throw new Error("必须提供 targetName 或 route.serviceName 作为上游资源名称:" +
|
|
7432
|
+
"云函数名、云托管服务名,或静态托管实例名(常见为 staticstore)。");
|
|
7433
|
+
}
|
|
7434
|
+
const upstreamResourceType = resolveUpstreamResourceType({
|
|
7435
|
+
upstreamResourceType: input.upstreamResourceType,
|
|
7436
|
+
routeUpstreamResourceType: input.route?.upstreamResourceType,
|
|
7280
7437
|
});
|
|
7281
7438
|
const path = normalizeAccessPath(input.route?.path ?? input.path ?? `/${upstreamResourceName}`);
|
|
7282
7439
|
const domain = await resolveRouteDomain(input.domain);
|
|
@@ -7285,18 +7442,25 @@ function registerGatewayTools(server) {
|
|
|
7285
7442
|
: input.auth !== undefined
|
|
7286
7443
|
? input.auth
|
|
7287
7444
|
: undefined;
|
|
7445
|
+
const enablePathTransmission = input.route?.enablePathTransmission !== undefined
|
|
7446
|
+
? input.route.enablePathTransmission
|
|
7447
|
+
: input.enablePathTransmission !== undefined
|
|
7448
|
+
? input.enablePathTransmission
|
|
7449
|
+
: undefined;
|
|
7450
|
+
const route = {
|
|
7451
|
+
Path: path,
|
|
7452
|
+
UpstreamResourceType: upstreamResourceType,
|
|
7453
|
+
UpstreamResourceName: upstreamResourceName,
|
|
7454
|
+
EnableAuth: enableAuth,
|
|
7455
|
+
};
|
|
7456
|
+
if (enablePathTransmission !== undefined) {
|
|
7457
|
+
route.EnablePathTransmission = enablePathTransmission;
|
|
7458
|
+
}
|
|
7288
7459
|
return {
|
|
7289
7460
|
EnvId: await resolveEnvId(),
|
|
7290
7461
|
Domain: {
|
|
7291
7462
|
Domain: domain,
|
|
7292
|
-
Routes: [
|
|
7293
|
-
{
|
|
7294
|
-
Path: path,
|
|
7295
|
-
UpstreamResourceType: upstreamResourceType,
|
|
7296
|
-
UpstreamResourceName: upstreamResourceName,
|
|
7297
|
-
EnableAuth: enableAuth,
|
|
7298
|
-
},
|
|
7299
|
-
],
|
|
7463
|
+
Routes: [route],
|
|
7300
7464
|
},
|
|
7301
7465
|
resolved: {
|
|
7302
7466
|
domain,
|
|
@@ -7304,6 +7468,7 @@ function registerGatewayTools(server) {
|
|
|
7304
7468
|
upstreamResourceType,
|
|
7305
7469
|
upstreamResourceName,
|
|
7306
7470
|
enableAuth,
|
|
7471
|
+
enablePathTransmission,
|
|
7307
7472
|
},
|
|
7308
7473
|
};
|
|
7309
7474
|
};
|
|
@@ -7343,6 +7508,7 @@ function registerGatewayTools(server) {
|
|
|
7343
7508
|
action: input.action,
|
|
7344
7509
|
routes,
|
|
7345
7510
|
urls: buildRouteUrls(routes),
|
|
7511
|
+
...buildAccessUrlFields(routes),
|
|
7346
7512
|
total: result.TotalCount ?? routes.length,
|
|
7347
7513
|
raw: result,
|
|
7348
7514
|
}, `已获取 ${result.TotalCount ?? routes.length} 条 HTTP 路由`);
|
|
@@ -7384,6 +7550,7 @@ function registerGatewayTools(server) {
|
|
|
7384
7550
|
routes: matches,
|
|
7385
7551
|
total: matches.length,
|
|
7386
7552
|
urls,
|
|
7553
|
+
...buildAccessUrlFields(matches),
|
|
7387
7554
|
raw: result,
|
|
7388
7555
|
}, matches.length === 0
|
|
7389
7556
|
? "未找到对应路由"
|
|
@@ -7417,9 +7584,10 @@ function registerGatewayTools(server) {
|
|
|
7417
7584
|
const message = err instanceof Error ? err.message : String(err);
|
|
7418
7585
|
if (message.includes("An error has occurred")) {
|
|
7419
7586
|
let hint = "为目标资源配置访问路由失败(后端内部错误)。请确保:1) 目标云函数已成功创建并处于 Active 状态;2) 环境默认 HTTP 域名已完成初始化(IsDefault);3) 该访问路径未被占用。";
|
|
7420
|
-
if (
|
|
7587
|
+
if (payload.resolved.upstreamResourceType === "WEB_SCF" ||
|
|
7588
|
+
payload.resolved.upstreamResourceType === "SCF") {
|
|
7421
7589
|
hint +=
|
|
7422
|
-
"
|
|
7590
|
+
"此外注意:HTTP 云函数必须用 upstreamResourceType=WEB_SCF,Event 云函数必须用 SCF;互标会导致此错误。";
|
|
7423
7591
|
}
|
|
7424
7592
|
throw new Error(`${hint} 原始错误:${message}`);
|
|
7425
7593
|
}
|
|
@@ -7429,15 +7597,26 @@ function registerGatewayTools(server) {
|
|
|
7429
7597
|
return buildEnvelope({
|
|
7430
7598
|
action: input.action,
|
|
7431
7599
|
model: "httpServiceRoute",
|
|
7432
|
-
targetType: input.targetType ?? null,
|
|
7433
7600
|
targetName: payload.resolved.upstreamResourceName,
|
|
7434
7601
|
domain: payload.resolved.domain,
|
|
7435
7602
|
path: payload.resolved.path,
|
|
7436
7603
|
upstreamResourceType: payload.resolved.upstreamResourceType,
|
|
7437
7604
|
upstreamResourceName: payload.resolved.upstreamResourceName,
|
|
7438
7605
|
auth: payload.resolved.enableAuth ?? null,
|
|
7606
|
+
enablePathTransmission: payload.resolved.enablePathTransmission ?? null,
|
|
7607
|
+
accessUrl: `https://${payload.resolved.domain}${payload.resolved.path}`,
|
|
7608
|
+
accessUrls: [`https://${payload.resolved.domain}${payload.resolved.path}`],
|
|
7609
|
+
accessUrlSource: input.domain && input.domain === payload.resolved.domain
|
|
7610
|
+
? "gateway.custom"
|
|
7611
|
+
: "gateway.default",
|
|
7439
7612
|
raw: result,
|
|
7440
|
-
}, `已为目标 ${payload.resolved.upstreamResourceName} 在域名 ${payload.resolved.domain} 创建路由 ${payload.resolved.path}(${payload.resolved.upstreamResourceType}
|
|
7613
|
+
}, `已为目标 ${payload.resolved.upstreamResourceName} 在域名 ${payload.resolved.domain} 创建路由 ${payload.resolved.path}(${payload.resolved.upstreamResourceType})` +
|
|
7614
|
+
(payload.resolved.enablePathTransmission === true
|
|
7615
|
+
? ";已开启路径透传(后端收到完整请求路径)"
|
|
7616
|
+
: payload.resolved.enablePathTransmission === false
|
|
7617
|
+
? ";路径透传关闭(网关会剥掉触发路径前缀后再转发给后端)"
|
|
7618
|
+
: ";路径透传未显式设置(平台默认 false,会剥掉触发路径前缀)") +
|
|
7619
|
+
`。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开上游权限;若上游是云函数且需要匿名或浏览器直接访问,请继续检查函数资源权限。`, routeMutationNextActions(payload.resolved.upstreamResourceName));
|
|
7441
7620
|
}
|
|
7442
7621
|
case "updateRoute": {
|
|
7443
7622
|
const cloudbase = await getManager();
|
|
@@ -7455,8 +7634,20 @@ function registerGatewayTools(server) {
|
|
|
7455
7634
|
upstreamResourceType: payload.resolved.upstreamResourceType,
|
|
7456
7635
|
upstreamResourceName: payload.resolved.upstreamResourceName,
|
|
7457
7636
|
auth: payload.resolved.enableAuth ?? null,
|
|
7637
|
+
enablePathTransmission: payload.resolved.enablePathTransmission ?? null,
|
|
7638
|
+
accessUrl: `https://${payload.resolved.domain}${payload.resolved.path}`,
|
|
7639
|
+
accessUrls: [`https://${payload.resolved.domain}${payload.resolved.path}`],
|
|
7640
|
+
accessUrlSource: input.domain && input.domain === payload.resolved.domain
|
|
7641
|
+
? "gateway.custom"
|
|
7642
|
+
: "gateway.default",
|
|
7458
7643
|
raw: result,
|
|
7459
|
-
}, `HTTP 路由更新成功(${payload.resolved.domain}${payload.resolved.path}
|
|
7644
|
+
}, `HTTP 路由更新成功(${payload.resolved.domain}${payload.resolved.path}` +
|
|
7645
|
+
(payload.resolved.enablePathTransmission === true
|
|
7646
|
+
? ",路径透传=开启"
|
|
7647
|
+
: payload.resolved.enablePathTransmission === false
|
|
7648
|
+
? ",路径透传=关闭"
|
|
7649
|
+
: "") +
|
|
7650
|
+
`)`, routeMutationNextActions(payload.resolved.upstreamResourceName));
|
|
7460
7651
|
}
|
|
7461
7652
|
case "deleteRoute": {
|
|
7462
7653
|
const routePath = input.route?.path ?? input.path;
|
|
@@ -7522,19 +7713,17 @@ function registerGatewayTools(server) {
|
|
|
7522
7713
|
};
|
|
7523
7714
|
server.registerTool?.("queryGateway", {
|
|
7524
7715
|
title: "查询 CloudBase 网关",
|
|
7525
|
-
description: "CloudBase 网关统一只读入口(Domain/Route
|
|
7716
|
+
description: "CloudBase HTTP 网关统一只读入口(Domain/Route)。查询域名下路径路由及其上游:" +
|
|
7717
|
+
"WEB_SCF/SCF=云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器。" +
|
|
7718
|
+
"主键为 Domain + Path;listRoutes / getRoute / listCustomDomains。",
|
|
7526
7719
|
inputSchema: {
|
|
7527
7720
|
action: zod_1.z
|
|
7528
7721
|
.enum(QUERY_GATEWAY_ACTIONS)
|
|
7529
7722
|
.describe("只读操作类型:listRoutes、getRoute、listCustomDomains"),
|
|
7530
|
-
targetType: zod_1.z
|
|
7531
|
-
.enum(["function"])
|
|
7532
|
-
.optional()
|
|
7533
|
-
.describe("目标资源类型。当前支持 function"),
|
|
7534
7723
|
targetName: zod_1.z
|
|
7535
7724
|
.string()
|
|
7536
7725
|
.optional()
|
|
7537
|
-
.describe("
|
|
7726
|
+
.describe("上游资源名过滤(UpstreamResourceName):云函数名、云托管服务名,或静态托管实例名(常见 staticstore)。"),
|
|
7538
7727
|
routeId: zod_1.z.string().optional().describe("路由 ID。getRoute 时可选"),
|
|
7539
7728
|
path: zod_1.z
|
|
7540
7729
|
.string()
|
|
@@ -7553,40 +7742,68 @@ function registerGatewayTools(server) {
|
|
|
7553
7742
|
}, async (input) => withEnvelope(() => handleQueryGateway(input)));
|
|
7554
7743
|
server.registerTool?.("manageGateway", {
|
|
7555
7744
|
title: "管理 CloudBase 网关",
|
|
7556
|
-
description: "CloudBase 网关统一写入口(Domain/Route
|
|
7745
|
+
description: "CloudBase HTTP 网关统一写入口(Domain/Route)。createRoute/updateRoute/deleteRoute 把域名下的 path 转到上游;未传 domain 时用 IsDefault 默认域名。" +
|
|
7746
|
+
"上游类型只用一个参数 upstreamResourceType(也可写在 route.upstreamResourceType,route 优先):" +
|
|
7747
|
+
"WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器;" +
|
|
7748
|
+
"配合 targetName 或 route.serviceName(云函数名/云托管服务名/静态托管实例名,常见 staticstore)。" +
|
|
7749
|
+
"createRoute 只建网关入口,不改上游权限。" +
|
|
7750
|
+
"enablePathTransmission:默认 false 剥触发路径前缀;true 透传完整路径(CBR 多路由、WEB_SCF 自管子路径常需 true;STATIC_STORE 自定义触发路径映射站点根通常 false)。" +
|
|
7751
|
+
"⚠️ SSL 自定义域名用 bindCustomDomain;CORS/安全域名用 envDomainManagement。",
|
|
7557
7752
|
inputSchema: {
|
|
7558
7753
|
action: zod_1.z
|
|
7559
7754
|
.enum(MANAGE_GATEWAY_ACTIONS)
|
|
7560
|
-
.describe("
|
|
7561
|
-
|
|
7562
|
-
.enum(["function"])
|
|
7563
|
-
.optional()
|
|
7564
|
-
.describe("目标资源类型。当前支持 function"),
|
|
7755
|
+
.describe("写操作:createRoute/updateRoute/deleteRoute 管理路由;bindCustomDomain/deleteCustomDomain 管理自定义域名。" +
|
|
7756
|
+
"createRoute/updateRoute 必须提供 upstreamResourceType。"),
|
|
7565
7757
|
targetName: zod_1.z
|
|
7566
7758
|
.string()
|
|
7567
7759
|
.optional()
|
|
7568
|
-
.describe("
|
|
7760
|
+
.describe("上游资源名称(UpstreamResourceName),与 route.serviceName 二选一(route 优先)。" +
|
|
7761
|
+
"云函数=函数名;云托管=服务名;静态托管=实例名(常见 staticstore)。不会自动推断上游类型。"),
|
|
7569
7762
|
path: zod_1.z
|
|
7570
7763
|
.string()
|
|
7571
7764
|
.optional()
|
|
7572
|
-
.describe("
|
|
7573
|
-
|
|
7574
|
-
|
|
7765
|
+
.describe("触发路径(网关匹配前缀),默认 /{上游名}。例:云函数 /api/hello、云托管 /api、静态托管 / 或 /app。" +
|
|
7766
|
+
"只建网关入口;与 enablePathTransmission 共同决定上游实际收到的路径。"),
|
|
7767
|
+
upstreamResourceType: zod_1.z
|
|
7768
|
+
.enum(UPSTREAM_RESOURCE_TYPES)
|
|
7575
7769
|
.optional()
|
|
7576
|
-
.describe("
|
|
7770
|
+
.describe("上游类型(与 route.upstreamResourceType 二选一,route 优先)。" +
|
|
7771
|
+
"WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器。" +
|
|
7772
|
+
"createRoute/updateRoute 必填其一;勿把 manageFunctions 的 type=HTTP|Event 传到本字段。"),
|
|
7577
7773
|
auth: zod_1.z
|
|
7578
7774
|
.boolean()
|
|
7579
7775
|
.optional()
|
|
7580
|
-
.describe("
|
|
7776
|
+
.describe("网关路径鉴权(EnableAuth)。匿名/浏览器公网访问通常 false。" +
|
|
7777
|
+
"只控制网关入口;云函数安全规则、云托管鉴权、静态托管权限需各自工具另行配置。"),
|
|
7778
|
+
enablePathTransmission: zod_1.z
|
|
7779
|
+
.boolean()
|
|
7780
|
+
.optional()
|
|
7781
|
+
.describe("路径透传(EnablePathTransmission),平台默认 false。例 path=/api 且请求 /api/users:" +
|
|
7782
|
+
"false→上游收到 /users;true→上游收到 /api/users。" +
|
|
7783
|
+
"CBR 云托管(Express 等自管子路由)与 WEB_SCF 多路径函数常需 true;" +
|
|
7784
|
+
"STATIC_STORE 把触发路径映射到站点根目录(如 /app → 托管 /)时通常 false;" +
|
|
7785
|
+
"单入口/根路径处理保持 false。也可用 route.enablePathTransmission(route 优先)。"),
|
|
7581
7786
|
route: zod_1.z
|
|
7582
7787
|
.object({
|
|
7583
7788
|
path: zod_1.z.string().optional(),
|
|
7584
|
-
serviceName: zod_1.z
|
|
7585
|
-
|
|
7789
|
+
serviceName: zod_1.z
|
|
7790
|
+
.string()
|
|
7791
|
+
.optional()
|
|
7792
|
+
.describe("上游实例名:云函数名 / 云托管服务名 / 静态托管实例名(常见 staticstore)/ LH 实例。优先于顶层 targetName。"),
|
|
7793
|
+
upstreamResourceType: zod_1.z
|
|
7794
|
+
.enum(UPSTREAM_RESOURCE_TYPES)
|
|
7795
|
+
.optional()
|
|
7796
|
+
.describe("同顶层 upstreamResourceType。route 内设置时优先于顶层。"),
|
|
7586
7797
|
auth: zod_1.z.boolean().optional(),
|
|
7798
|
+
enablePathTransmission: zod_1.z
|
|
7799
|
+
.boolean()
|
|
7800
|
+
.optional()
|
|
7801
|
+
.describe("同顶层 enablePathTransmission。route 内设置时优先于顶层。"),
|
|
7587
7802
|
})
|
|
7588
7803
|
.optional()
|
|
7589
|
-
.describe("
|
|
7804
|
+
.describe("路由对象(可选写法)。例:云函数 {upstreamResourceType:\"WEB_SCF\",serviceName:\"fn\",path:\"/api\"};" +
|
|
7805
|
+
"云托管 {upstreamResourceType:\"CBR\",serviceName:\"svc\",path:\"/api\"};" +
|
|
7806
|
+
"静态托管 {upstreamResourceType:\"STATIC_STORE\",serviceName:\"staticstore\",path:\"/\"}。"),
|
|
7590
7807
|
domain: zod_1.z
|
|
7591
7808
|
.string()
|
|
7592
7809
|
.optional()
|
|
@@ -7648,70 +7865,6 @@ module.exports = __WEBPACK_EXTERNAL_MODULE_fs__;
|
|
|
7648
7865
|
|
|
7649
7866
|
module.exports = __WEBPACK_EXTERNAL_MODULE__modelcontextprotocol_sdk_server_mcp_js_45c326f0__;
|
|
7650
7867
|
|
|
7651
|
-
/***/ }),
|
|
7652
|
-
|
|
7653
|
-
/***/ 4760:
|
|
7654
|
-
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
7658
|
-
exports.registerInviteCodeTools = registerInviteCodeTools;
|
|
7659
|
-
const zod_1 = __webpack_require__(2971);
|
|
7660
|
-
const cloudbase_manager_js_1 = __webpack_require__(3431);
|
|
7661
|
-
function registerInviteCodeTools(server) {
|
|
7662
|
-
const cloudBaseOptions = server.cloudBaseOptions;
|
|
7663
|
-
const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
|
|
7664
|
-
server.registerTool?.("activateInviteCode", {
|
|
7665
|
-
title: "激活邀请码",
|
|
7666
|
-
description: "云开发 AI编程激励计划,通过邀请码激活用户激励。",
|
|
7667
|
-
inputSchema: {
|
|
7668
|
-
InviteCode: zod_1.z.string().describe("待激活的邀请码")
|
|
7669
|
-
},
|
|
7670
|
-
annotations: {
|
|
7671
|
-
readOnlyHint: false,
|
|
7672
|
-
destructiveHint: false,
|
|
7673
|
-
idempotentHint: false,
|
|
7674
|
-
openWorldHint: true,
|
|
7675
|
-
category: "invite-code"
|
|
7676
|
-
}
|
|
7677
|
-
}, async ({ InviteCode }) => {
|
|
7678
|
-
if (!InviteCode) {
|
|
7679
|
-
return {
|
|
7680
|
-
content: [
|
|
7681
|
-
{
|
|
7682
|
-
type: "text",
|
|
7683
|
-
text: JSON.stringify({
|
|
7684
|
-
ErrorCode: 'MissingParameter',
|
|
7685
|
-
ErrorMsg: '邀请码为必填项',
|
|
7686
|
-
RequestId: ''
|
|
7687
|
-
}, null, 2)
|
|
7688
|
-
}
|
|
7689
|
-
]
|
|
7690
|
-
};
|
|
7691
|
-
}
|
|
7692
|
-
const manager = await getManager();
|
|
7693
|
-
const EnvId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
|
|
7694
|
-
const result = await manager.commonService().call({
|
|
7695
|
-
Action: 'ActivateInviteCode',
|
|
7696
|
-
Param: { InviteCode, EnvId }
|
|
7697
|
-
});
|
|
7698
|
-
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
7699
|
-
return {
|
|
7700
|
-
content: [
|
|
7701
|
-
{
|
|
7702
|
-
type: "text",
|
|
7703
|
-
text: JSON.stringify({
|
|
7704
|
-
ErrorCode: result?.ErrorCode || '',
|
|
7705
|
-
ErrorMsg: result?.ErrorMsg || '',
|
|
7706
|
-
RequestId: result?.RequestId || ''
|
|
7707
|
-
}, null, 2)
|
|
7708
|
-
}
|
|
7709
|
-
]
|
|
7710
|
-
};
|
|
7711
|
-
});
|
|
7712
|
-
}
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
7868
|
/***/ }),
|
|
7716
7869
|
|
|
7717
7870
|
/***/ 4848:
|
|
@@ -8249,7 +8402,9 @@ const path_1 = __importDefault(__webpack_require__(2521));
|
|
|
8249
8402
|
const zod_1 = __webpack_require__(2971);
|
|
8250
8403
|
const cloudbase_manager_js_1 = __webpack_require__(3431);
|
|
8251
8404
|
const logger_js_1 = __webpack_require__(3039);
|
|
8405
|
+
const gateway_access_urls_js_1 = __webpack_require__(2435);
|
|
8252
8406
|
const notification_js_1 = __webpack_require__(2720);
|
|
8407
|
+
const cloudrun_config_js_1 = __webpack_require__(8266);
|
|
8253
8408
|
// CloudRun service types
|
|
8254
8409
|
exports.CLOUDRUN_SERVICE_TYPES = ['function', 'container'];
|
|
8255
8410
|
// CloudRun access types
|
|
@@ -8268,10 +8423,11 @@ const queryCloudRunInputSchema = {
|
|
|
8268
8423
|
};
|
|
8269
8424
|
// Input schema for manageCloudRun tool
|
|
8270
8425
|
const ManageCloudRunInputSchema = {
|
|
8271
|
-
action: zod_1.z.enum(['init', 'download', 'run', 'deploy', 'delete', 'createAgent']).describe('云托管服务管理操作类型:init=从模板初始化新的云托管项目代码(在targetPath目录下创建以serverName命名的子目录,支持多种语言和框架模板),download=从云端下载现有服务的代码到本地进行开发,run=在本地运行函数型云托管服务(用于开发和调试,仅支持函数型服务),deploy
|
|
8426
|
+
action: zod_1.z.enum(['init', 'download', 'run', 'deploy', 'delete', 'createAgent', 'updateConfig']).describe('云托管服务管理操作类型:init=从模板初始化新的云托管项目代码(在targetPath目录下创建以serverName命名的子目录,支持多种语言和框架模板),download=从云端下载现有服务的代码到本地进行开发,run=在本地运行函数型云托管服务(用于开发和调试,仅支持函数型服务),deploy=将本地代码部署到云端云托管服务(支持函数型和容器型;已存在服务会 Read-Merge-Write 保留远程 VpcConf/EnvParams/OpenAccessTypes),updateConfig=仅更新服务配置不重新上传代码(对齐控制台服务设置,走 SubmitServerConfigChangeDiff;不需要 targetPath),delete=删除指定的云托管服务(不可恢复,需要确认),createAgent=创建函数型Agent(基于函数型云托管开发AI智能体)'),
|
|
8272
8427
|
serverName: zod_1.z.string().describe('云托管服务名称,用于标识和管理服务。命名规则:支持大小写字母、数字、连字符和下划线,必须以字母开头,长度3-45个字符。在init操作中会作为在targetPath下创建的子目录名,在其他操作中作为目标服务名'),
|
|
8273
8428
|
// Deploy operation parameters
|
|
8274
|
-
targetPath: zod_1.z.string().optional().describe('本地代码路径,必须是绝对路径。在deploy操作中指定要部署的代码目录,在download操作中指定下载目标目录,在init操作中指定云托管服务的上级目录(会在该目录下创建以serverName
|
|
8429
|
+
targetPath: zod_1.z.string().optional().describe('本地代码路径,必须是绝对路径。在deploy操作中指定要部署的代码目录,在download操作中指定下载目标目录,在init操作中指定云托管服务的上级目录(会在该目录下创建以serverName命名的子目录)。updateConfig 不需要此参数。建议约定:项目根目录下的cloudrun/目录,例如:/Users/username/projects/my-project/cloudrun'),
|
|
8430
|
+
envParamsReplaceAll: zod_1.z.boolean().optional().default(false).describe('EnvParams 合并策略(deploy / updateConfig):false(默认)= 与远程按 key 合并(输入覆盖同名 key,远程其余 key 保留);true= 用输入 EnvParams 整包替换远程。仅当显式传入 EnvParams 时生效'),
|
|
8275
8431
|
serverConfig: zod_1.z.object({
|
|
8276
8432
|
OpenAccessTypes: zod_1.z.array(zod_1.z.enum(exports.CLOUDRUN_ACCESS_TYPES)).optional().describe('公网访问类型配置,控制服务的访问权限:OA=办公网访问,PUBLIC=公网访问(默认,可通过HTTPS域名访问),MINIAPP=小程序访问,VPC=VPC访问(仅同VPC内可访问)。可配置多个类型'),
|
|
8277
8433
|
Cpu: zod_1.z.number().positive().optional().describe('CPU规格配置,单位为核。可选值:0.25、0.5、1、2、4、8等。注意:内存规格必须是CPU规格的2倍(如CPU=0.25时内存=0.5,CPU=1时内存=2)。影响服务性能和计费'),
|
|
@@ -8310,7 +8466,7 @@ const ManageCloudRunInputSchema = {
|
|
|
8310
8466
|
VpcConf: zod_1.z.object({
|
|
8311
8467
|
VpcId: zod_1.z.string().describe('VPC网络ID,格式如 vpc-xxxxxxxx。必须与目标数据库/Redis 处于同一地域,并优先选择同一 VPC。禁止猜测或使用占位符;须来自数据库控制台、已有资源详情、callCloudApi 或用户确认。建议首次创建即配置;已存在服务也可在 deploy 时传入,部署后必须用 queryCloudRun detail 复核是否生效'),
|
|
8312
8468
|
SubnetId: zod_1.z.string().describe('子网ID,格式如 subnet-xxxxxxxx。云托管实例将占用该子网 IP,需确保有足够可用 IP'),
|
|
8313
|
-
}).optional().describe('VPC网络配置(实例出网/私有网络)。用于让云托管实例接入指定 VPC,从而内网访问 MySQL/PostgreSQL/Redis/CVM 等资源。与 OpenAccessTypes(外部如何访问本服务)是不同概念。TCP 连库场景必须配置。禁止猜测 VpcId/SubnetId,须来自数据库控制台、已有资源详情、callCloudApi
|
|
8469
|
+
}).optional().describe('VPC网络配置(实例出网/私有网络)。用于让云托管实例接入指定 VPC,从而内网访问 MySQL/PostgreSQL/Redis/CVM 等资源。与 OpenAccessTypes(外部如何访问本服务)是不同概念。TCP 连库场景必须配置。禁止猜测 VpcId/SubnetId,须来自数据库控制台、已有资源详情、callCloudApi 或用户确认。创建时映射为 SDK vpcInfo(CreateType=2);已存在服务可用 updateConfig 或 deploy(RMW 会保留未传入的远程 VpcConf)。部署/更新后必须用 queryCloudRun detail 复核 ServerConfig.VpcConf'),
|
|
8314
8470
|
VolumesConf: zod_1.z.array(zod_1.z.object({
|
|
8315
8471
|
VolumeName: zod_1.z.string().describe('存储卷名称'),
|
|
8316
8472
|
VolumeType: zod_1.z.string().describe('存储卷类型,如CFS表示云文件存储'),
|
|
@@ -8320,7 +8476,7 @@ const ManageCloudRunInputSchema = {
|
|
|
8320
8476
|
PublicAccess: zod_1.z.boolean().optional().describe('是否开启公网访问,true=开启公网访问,false=关闭公网访问'),
|
|
8321
8477
|
PublicAccessPath: zod_1.z.string().optional().describe('公网访问路径配置')
|
|
8322
8478
|
}).optional().describe('公网访问配置,用于控制服务的公网访问策略。可配置是否开启公网访问及访问路径'),
|
|
8323
|
-
}).optional().describe('
|
|
8479
|
+
}).optional().describe('服务配置项,用于 deploy / updateConfig。包括资源规格、访问权限、环境变量、日志、网络等。deploy 未提供时对已存在服务仍会从远程合并保留 VpcConf/EnvParams/OpenAccessTypes;updateConfig 至少需要一个配置字段'),
|
|
8324
8480
|
// Init operation parameters
|
|
8325
8481
|
template: zod_1.z.string().optional().default('helloworld').describe('项目模板标识符,用于指定初始化项目时使用的模板。可通过queryCloudRun的templates操作获取可用模板列表。常用模板:helloworld=Hello World示例,nodejs=Node.js项目模板,python=Python项目模板等'),
|
|
8326
8482
|
// Run operation parameters (function services only)
|
|
@@ -8504,6 +8660,30 @@ function normalizeProcessLogText(logs) {
|
|
|
8504
8660
|
})
|
|
8505
8661
|
.join("\n");
|
|
8506
8662
|
}
|
|
8663
|
+
function normalizeCloudRunDomainUrl(input) {
|
|
8664
|
+
if (typeof input !== "string" || !input.trim())
|
|
8665
|
+
return undefined;
|
|
8666
|
+
const raw = input.trim();
|
|
8667
|
+
return raw.startsWith("http://") || raw.startsWith("https://")
|
|
8668
|
+
? raw
|
|
8669
|
+
: `https://${raw}`;
|
|
8670
|
+
}
|
|
8671
|
+
function resolveCloudRunFallbackAccess(details) {
|
|
8672
|
+
const custom = normalizeCloudRunDomainUrl(details?.BaseInfo?.CustomDomainName);
|
|
8673
|
+
if (custom)
|
|
8674
|
+
return { url: custom, source: "cloudrun.customDomain" };
|
|
8675
|
+
const defaultDomain = normalizeCloudRunDomainUrl(details?.BaseInfo?.DefaultDomainName);
|
|
8676
|
+
if (defaultDomain)
|
|
8677
|
+
return { url: defaultDomain, source: "cloudrun.defaultDomain" };
|
|
8678
|
+
const publicDomain = normalizeCloudRunDomainUrl(details?.BaseInfo?.PublicDomain) ??
|
|
8679
|
+
normalizeCloudRunDomainUrl(details?.AccessInfo?.PublicDomain);
|
|
8680
|
+
if (publicDomain)
|
|
8681
|
+
return { url: publicDomain, source: "cloudrun.publicDomain" };
|
|
8682
|
+
const internal = normalizeCloudRunDomainUrl(details?.BaseInfo?.InternalDomain);
|
|
8683
|
+
if (internal)
|
|
8684
|
+
return { url: internal, source: "cloudrun.internalDomain" };
|
|
8685
|
+
return {};
|
|
8686
|
+
}
|
|
8507
8687
|
/**
|
|
8508
8688
|
* Format CloudRun service info for display
|
|
8509
8689
|
*/
|
|
@@ -8737,7 +8917,7 @@ function registerCloudRunTools(server) {
|
|
|
8737
8917
|
// Tool 2: Manage CloudRun services (write operations)
|
|
8738
8918
|
server.registerTool("manageCloudRun", {
|
|
8739
8919
|
title: "管理 CloudRun 服务",
|
|
8740
|
-
description: "管理云托管服务,按开发顺序支持:初始化项目(可从模板开始,模板列表可通过 queryCloudRun
|
|
8920
|
+
description: "管理云托管服务,按开发顺序支持:初始化项目(可从模板开始,模板列表可通过 queryCloudRun 查询)、下载服务代码、本地运行(仅函数型服务)、部署代码、仅更新配置(updateConfig,无需重新上传代码)、删除服务。deploy 对已存在服务会先读取远程配置再合并(保留 VpcConf/EnvParams/OpenAccessTypes)。updateConfig 对齐控制台服务设置页。删除操作需要确认,建议设置force=true。",
|
|
8741
8921
|
inputSchema: ManageCloudRunInputSchema,
|
|
8742
8922
|
annotations: {
|
|
8743
8923
|
readOnlyHint: false,
|
|
@@ -8928,6 +9108,8 @@ for await (let x of res.textStream) {
|
|
|
8928
9108
|
}
|
|
8929
9109
|
// Determine service type - use input.serverType if provided, otherwise auto-detect
|
|
8930
9110
|
let serverType;
|
|
9111
|
+
let remoteServerConfig = null;
|
|
9112
|
+
let existingService = false;
|
|
8931
9113
|
if (input.serverType) {
|
|
8932
9114
|
serverType = input.serverType;
|
|
8933
9115
|
}
|
|
@@ -8936,6 +9118,8 @@ for await (let x of res.textStream) {
|
|
|
8936
9118
|
// First try to get existing service details
|
|
8937
9119
|
const details = await cloudrunService.detail({ serverName: input.serverName });
|
|
8938
9120
|
serverType = details.BaseInfo?.ServerType || 'container';
|
|
9121
|
+
remoteServerConfig = (details.ServerConfig || null);
|
|
9122
|
+
existingService = true;
|
|
8939
9123
|
}
|
|
8940
9124
|
catch (e) {
|
|
8941
9125
|
// If service doesn't exist, determine by project structure
|
|
@@ -8969,20 +9153,40 @@ for await (let x of res.textStream) {
|
|
|
8969
9153
|
}
|
|
8970
9154
|
}
|
|
8971
9155
|
}
|
|
9156
|
+
// When serverType was provided explicitly, still try to load remote config for RMW.
|
|
9157
|
+
if (!existingService) {
|
|
9158
|
+
try {
|
|
9159
|
+
const details = await cloudrunService.detail({ serverName: input.serverName });
|
|
9160
|
+
remoteServerConfig = (details.ServerConfig || null);
|
|
9161
|
+
existingService = true;
|
|
9162
|
+
}
|
|
9163
|
+
catch {
|
|
9164
|
+
// New service create path
|
|
9165
|
+
}
|
|
9166
|
+
}
|
|
9167
|
+
let mergedFromRemote = [];
|
|
9168
|
+
let effectiveServerConfig = input.serverConfig;
|
|
9169
|
+
if (existingService) {
|
|
9170
|
+
const mergedResult = (0, cloudrun_config_js_1.mergeCloudRunServerConfig)({
|
|
9171
|
+
remote: remoteServerConfig,
|
|
9172
|
+
input: input.serverConfig || {},
|
|
9173
|
+
envParamsReplaceAll: Boolean(input.envParamsReplaceAll),
|
|
9174
|
+
});
|
|
9175
|
+
effectiveServerConfig = mergedResult.merged;
|
|
9176
|
+
mergedFromRemote = mergedResult.mergedFromRemote;
|
|
9177
|
+
}
|
|
8972
9178
|
const deployParams = {
|
|
8973
9179
|
serverName: input.serverName,
|
|
8974
9180
|
targetPath: targetPath,
|
|
8975
9181
|
force: input.force,
|
|
8976
9182
|
serverType: serverType,
|
|
8977
9183
|
};
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
deployParams.serverConfig = input.serverConfig;
|
|
9184
|
+
if (effectiveServerConfig && Object.keys(effectiveServerConfig).length > 0) {
|
|
9185
|
+
deployParams.serverConfig = effectiveServerConfig;
|
|
8981
9186
|
}
|
|
8982
9187
|
// Manager SDK create path prefers top-level vpcInfo (CreateCloudRunServer.VpcInfo).
|
|
8983
9188
|
// Map serverConfig.VpcConf → vpcInfo so first-time create actually binds VPC.
|
|
8984
|
-
|
|
8985
|
-
const vpcConf = input.serverConfig?.VpcConf;
|
|
9189
|
+
const vpcConf = effectiveServerConfig?.VpcConf;
|
|
8986
9190
|
if (vpcConf?.VpcId?.trim() && vpcConf?.SubnetId?.trim()) {
|
|
8987
9191
|
deployParams.vpcInfo = {
|
|
8988
9192
|
VpcId: vpcConf.VpcId.trim(),
|
|
@@ -9013,47 +9217,46 @@ for await (let x of res.textStream) {
|
|
|
9013
9217
|
catch (error) {
|
|
9014
9218
|
(0, logger_js_1.debug)('cloudbaserc.json creation skipped:', error instanceof Error ? error : new Error(String(error)));
|
|
9015
9219
|
}
|
|
9220
|
+
let preferredAccessUrl;
|
|
9221
|
+
let preferredAccessUrls = [];
|
|
9222
|
+
let preferredAccessSource;
|
|
9223
|
+
let verifiedConfigSnapshot;
|
|
9224
|
+
try {
|
|
9225
|
+
const serviceDetails = await cloudrunService.detail({
|
|
9226
|
+
serverName: input.serverName,
|
|
9227
|
+
});
|
|
9228
|
+
verifiedConfigSnapshot = (0, cloudrun_config_js_1.summarizeConfigSnapshot)(serviceDetails?.ServerConfig);
|
|
9229
|
+
const fallback = resolveCloudRunFallbackAccess(serviceDetails);
|
|
9230
|
+
const gateway = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
|
|
9231
|
+
envId: currentEnvId,
|
|
9232
|
+
upstreamResourceName: input.serverName,
|
|
9233
|
+
upstreamResourceTypes: ["CBR"],
|
|
9234
|
+
getManager: async () => {
|
|
9235
|
+
const manager = await getManager();
|
|
9236
|
+
if (!manager) {
|
|
9237
|
+
throw new Error("cloudbase manager unavailable");
|
|
9238
|
+
}
|
|
9239
|
+
return manager;
|
|
9240
|
+
},
|
|
9241
|
+
});
|
|
9242
|
+
const preferred = (0, gateway_access_urls_js_1.preferGatewayOrFallback)({
|
|
9243
|
+
gateway,
|
|
9244
|
+
fallbackUrl: fallback.url,
|
|
9245
|
+
fallbackSource: fallback.source,
|
|
9246
|
+
});
|
|
9247
|
+
preferredAccessUrl = preferred.accessUrl;
|
|
9248
|
+
preferredAccessUrls = preferred.accessUrls;
|
|
9249
|
+
preferredAccessSource = preferred.accessUrlSource;
|
|
9250
|
+
}
|
|
9251
|
+
catch {
|
|
9252
|
+
// best-effort URL enrichment only
|
|
9253
|
+
}
|
|
9016
9254
|
// Send deployment notification to CodeBuddy IDE
|
|
9017
9255
|
try {
|
|
9018
|
-
// Query service details to get access URL
|
|
9019
|
-
let serviceUrl = "";
|
|
9020
|
-
try {
|
|
9021
|
-
const serviceDetails = await cloudrunService.detail({ serverName: input.serverName });
|
|
9022
|
-
// Extract access URL from service details
|
|
9023
|
-
// Priority: DefaultDomainName > CustomDomainName > PublicDomain > InternalDomain
|
|
9024
|
-
const details = serviceDetails; // Use any to access dynamic properties
|
|
9025
|
-
if (details?.BaseInfo?.DefaultDomainName) {
|
|
9026
|
-
// DefaultDomainName is already a complete URL (e.g., https://...)
|
|
9027
|
-
serviceUrl = details.BaseInfo.DefaultDomainName;
|
|
9028
|
-
}
|
|
9029
|
-
else if (details?.BaseInfo?.CustomDomainName) {
|
|
9030
|
-
// CustomDomainName might be a domain without protocol
|
|
9031
|
-
const customDomain = details.BaseInfo.CustomDomainName;
|
|
9032
|
-
serviceUrl = customDomain.startsWith('http') ? customDomain : `https://${customDomain}`;
|
|
9033
|
-
}
|
|
9034
|
-
else if (details?.BaseInfo?.PublicDomain) {
|
|
9035
|
-
serviceUrl = `https://${details.BaseInfo.PublicDomain}`;
|
|
9036
|
-
}
|
|
9037
|
-
else if (details?.BaseInfo?.InternalDomain) {
|
|
9038
|
-
serviceUrl = `https://${details.BaseInfo.InternalDomain}`;
|
|
9039
|
-
}
|
|
9040
|
-
else if (details?.AccessInfo?.PublicDomain) {
|
|
9041
|
-
serviceUrl = `https://${details.AccessInfo.PublicDomain}`;
|
|
9042
|
-
}
|
|
9043
|
-
else {
|
|
9044
|
-
serviceUrl = ""; // URL not available
|
|
9045
|
-
}
|
|
9046
|
-
}
|
|
9047
|
-
catch (detailErr) {
|
|
9048
|
-
// If query fails, continue with empty URL
|
|
9049
|
-
serviceUrl = "";
|
|
9050
|
-
}
|
|
9051
|
-
// Extract project name from targetPath
|
|
9052
9256
|
const projectName = path_1.default.basename(targetPath);
|
|
9053
|
-
// Send notification
|
|
9054
9257
|
await (0, notification_js_1.sendDeployNotification)(server, {
|
|
9055
9258
|
deployType: 'cloudrun',
|
|
9056
|
-
url:
|
|
9259
|
+
url: preferredAccessUrl ?? "",
|
|
9057
9260
|
projectId: currentEnvId,
|
|
9058
9261
|
projectName: projectName,
|
|
9059
9262
|
consoleUrl: consoleUrl
|
|
@@ -9064,8 +9267,8 @@ for await (let x of res.textStream) {
|
|
|
9064
9267
|
// Error is already logged in sendDeployNotification
|
|
9065
9268
|
}
|
|
9066
9269
|
const dbNetworkRisk = detectCloudRunDbNetworkRisk({
|
|
9067
|
-
envParams:
|
|
9068
|
-
vpcConf:
|
|
9270
|
+
envParams: effectiveServerConfig?.EnvParams,
|
|
9271
|
+
vpcConf: effectiveServerConfig?.VpcConf,
|
|
9069
9272
|
});
|
|
9070
9273
|
const warnings = dbNetworkRisk ? [dbNetworkRisk] : [];
|
|
9071
9274
|
const warningSuffix = dbNetworkRisk
|
|
@@ -9084,6 +9287,25 @@ for await (let x of res.textStream) {
|
|
|
9084
9287
|
serverType: serverType,
|
|
9085
9288
|
cloudbasercGenerated: true,
|
|
9086
9289
|
consoleUrl,
|
|
9290
|
+
...(existingService
|
|
9291
|
+
? {
|
|
9292
|
+
configMerge: {
|
|
9293
|
+
existingService: true,
|
|
9294
|
+
mergedFromRemote,
|
|
9295
|
+
appliedConfig: (0, cloudrun_config_js_1.summarizeConfigSnapshot)(effectiveServerConfig),
|
|
9296
|
+
...(verifiedConfigSnapshot
|
|
9297
|
+
? { verifiedAfterDeploy: verifiedConfigSnapshot }
|
|
9298
|
+
: {}),
|
|
9299
|
+
},
|
|
9300
|
+
}
|
|
9301
|
+
: {}),
|
|
9302
|
+
...(preferredAccessUrl ? { accessUrl: preferredAccessUrl } : {}),
|
|
9303
|
+
...(preferredAccessUrls.length > 0
|
|
9304
|
+
? { accessUrls: preferredAccessUrls }
|
|
9305
|
+
: {}),
|
|
9306
|
+
...(preferredAccessSource
|
|
9307
|
+
? { accessUrlSource: preferredAccessSource }
|
|
9308
|
+
: {}),
|
|
9087
9309
|
...(warnings.length > 0 ? { warnings } : {}),
|
|
9088
9310
|
},
|
|
9089
9311
|
message: `Triggered deployment for ${serverType} service '${input.serverName}' from ${targetPath}. You can follow the progress in ${consoleUrl}.${warningSuffix}`
|
|
@@ -9092,6 +9314,125 @@ for await (let x of res.textStream) {
|
|
|
9092
9314
|
]
|
|
9093
9315
|
};
|
|
9094
9316
|
}
|
|
9317
|
+
case 'updateConfig': {
|
|
9318
|
+
if (!input.serverConfig || Object.keys(input.serverConfig).length === 0) {
|
|
9319
|
+
throw new Error("serverConfig with at least one field is required for updateConfig");
|
|
9320
|
+
}
|
|
9321
|
+
let remoteServerConfig = {};
|
|
9322
|
+
try {
|
|
9323
|
+
const details = await cloudrunService.detail({
|
|
9324
|
+
serverName: input.serverName,
|
|
9325
|
+
});
|
|
9326
|
+
remoteServerConfig = (details.ServerConfig ||
|
|
9327
|
+
{});
|
|
9328
|
+
}
|
|
9329
|
+
catch (error) {
|
|
9330
|
+
throw new Error(buildManageCloudRunErrorMessage("updateConfig", input.serverName, error));
|
|
9331
|
+
}
|
|
9332
|
+
// EnvParams on Diff replaces the whole blob — merge keys unless replaceAll.
|
|
9333
|
+
const dirty = { ...input.serverConfig };
|
|
9334
|
+
if (Object.prototype.hasOwnProperty.call(input.serverConfig, "EnvParams")) {
|
|
9335
|
+
const { merged } = (0, cloudrun_config_js_1.mergeCloudRunServerConfig)({
|
|
9336
|
+
remote: { EnvParams: remoteServerConfig.EnvParams },
|
|
9337
|
+
input: { EnvParams: input.serverConfig.EnvParams },
|
|
9338
|
+
envParamsReplaceAll: Boolean(input.envParamsReplaceAll),
|
|
9339
|
+
});
|
|
9340
|
+
if (merged.EnvParams !== undefined) {
|
|
9341
|
+
dirty.EnvParams = merged.EnvParams;
|
|
9342
|
+
}
|
|
9343
|
+
}
|
|
9344
|
+
let Items;
|
|
9345
|
+
try {
|
|
9346
|
+
Items = (0, cloudrun_config_js_1.parseServerConfigToDiffItems)(dirty);
|
|
9347
|
+
}
|
|
9348
|
+
catch (error) {
|
|
9349
|
+
throw new Error(buildManageCloudRunErrorMessage("updateConfig", input.serverName, error));
|
|
9350
|
+
}
|
|
9351
|
+
if (Items.length === 0) {
|
|
9352
|
+
return {
|
|
9353
|
+
content: [
|
|
9354
|
+
{
|
|
9355
|
+
type: "text",
|
|
9356
|
+
text: JSON.stringify({
|
|
9357
|
+
success: true,
|
|
9358
|
+
data: {
|
|
9359
|
+
serviceName: input.serverName,
|
|
9360
|
+
status: "noop",
|
|
9361
|
+
itemsCount: 0,
|
|
9362
|
+
appliedConfig: (0, cloudrun_config_js_1.summarizeConfigSnapshot)(dirty),
|
|
9363
|
+
verifiedConfig: (0, cloudrun_config_js_1.summarizeConfigSnapshot)(remoteServerConfig),
|
|
9364
|
+
},
|
|
9365
|
+
message: `No effective config changes for '${input.serverName}'.`,
|
|
9366
|
+
}, null, 2),
|
|
9367
|
+
},
|
|
9368
|
+
],
|
|
9369
|
+
};
|
|
9370
|
+
}
|
|
9371
|
+
const currentEnvId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
|
|
9372
|
+
if (!manager.commonService) {
|
|
9373
|
+
throw new Error("Current CloudBase Manager does not support commonService; cannot call SubmitServerConfigChangeDiff.");
|
|
9374
|
+
}
|
|
9375
|
+
let diffResult;
|
|
9376
|
+
try {
|
|
9377
|
+
diffResult = await manager
|
|
9378
|
+
.commonService("tcbr", "2022-02-17")
|
|
9379
|
+
.call({
|
|
9380
|
+
Action: "SubmitServerConfigChangeDiff",
|
|
9381
|
+
Param: {
|
|
9382
|
+
EnvId: currentEnvId,
|
|
9383
|
+
ServerName: input.serverName,
|
|
9384
|
+
Items,
|
|
9385
|
+
},
|
|
9386
|
+
});
|
|
9387
|
+
}
|
|
9388
|
+
catch (error) {
|
|
9389
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
9390
|
+
if (/ResourceInUse|task|running|进行中/i.test(msg)) {
|
|
9391
|
+
throw new Error(buildManageCloudRunErrorMessage("updateConfig", input.serverName, new Error(`${msg} A deploy or config task may still be running. Wait, then retry; or use queryCloudRun(action="getDeployLog").`)));
|
|
9392
|
+
}
|
|
9393
|
+
throw new Error(buildManageCloudRunErrorMessage("updateConfig", input.serverName, error));
|
|
9394
|
+
}
|
|
9395
|
+
let verifiedConfig = (0, cloudrun_config_js_1.summarizeConfigSnapshot)(remoteServerConfig);
|
|
9396
|
+
try {
|
|
9397
|
+
const after = await cloudrunService.detail({
|
|
9398
|
+
serverName: input.serverName,
|
|
9399
|
+
});
|
|
9400
|
+
verifiedConfig = (0, cloudrun_config_js_1.summarizeConfigSnapshot)(after?.ServerConfig);
|
|
9401
|
+
}
|
|
9402
|
+
catch {
|
|
9403
|
+
// best-effort verify
|
|
9404
|
+
}
|
|
9405
|
+
const likelyRedeploy = (0, cloudrun_config_js_1.listLikelyRedeployFields)(dirty);
|
|
9406
|
+
const consoleUrl = `https://tcb.cloud.tencent.com/dev?envId=${currentEnvId}#/platform-run/service/detail?serverName=${input.serverName}&tabId=overview&envId=${currentEnvId}`;
|
|
9407
|
+
const taskId = diffResult?.TaskId ??
|
|
9408
|
+
diffResult?.Response?.TaskId ??
|
|
9409
|
+
diffResult?.taskId;
|
|
9410
|
+
const redeployHint = likelyRedeploy.length > 0
|
|
9411
|
+
? ` Fields that often trigger redeploy-with-online-image: ${likelyRedeploy.join(", ")}.`
|
|
9412
|
+
: " Change may apply as a hot update (e.g. MinNum/MaxNum/AccessTypes).";
|
|
9413
|
+
return {
|
|
9414
|
+
content: [
|
|
9415
|
+
{
|
|
9416
|
+
type: "text",
|
|
9417
|
+
text: JSON.stringify({
|
|
9418
|
+
success: true,
|
|
9419
|
+
data: {
|
|
9420
|
+
serviceName: input.serverName,
|
|
9421
|
+
status: "configUpdating",
|
|
9422
|
+
itemsCount: Items.length,
|
|
9423
|
+
itemsKeys: Items.map((i) => i.Key),
|
|
9424
|
+
...(taskId ? { taskId } : {}),
|
|
9425
|
+
appliedConfig: (0, cloudrun_config_js_1.summarizeConfigSnapshot)(dirty),
|
|
9426
|
+
verifiedConfig,
|
|
9427
|
+
likelyRedeployFields: likelyRedeploy,
|
|
9428
|
+
consoleUrl,
|
|
9429
|
+
},
|
|
9430
|
+
message: `Submitted config change for '${input.serverName}'.${redeployHint} Verify with queryCloudRun(action="detail"). Console: ${consoleUrl}`,
|
|
9431
|
+
}, null, 2),
|
|
9432
|
+
},
|
|
9433
|
+
],
|
|
9434
|
+
};
|
|
9435
|
+
}
|
|
9095
9436
|
case 'run': {
|
|
9096
9437
|
if (!targetPath) {
|
|
9097
9438
|
throw new Error("targetPath is required for run operation");
|
|
@@ -10015,7 +10356,7 @@ class TelemetryReporter {
|
|
|
10015
10356
|
const nodeVersion = process.version; // Node.js版本
|
|
10016
10357
|
const arch = os_1.default.arch(); // 系统架构
|
|
10017
10358
|
// 从构建时注入的版本号获取MCP版本信息
|
|
10018
|
-
const mcpVersion = process.env.npm_package_version || "2.25.
|
|
10359
|
+
const mcpVersion = process.env.npm_package_version || "2.25.2" || 0;
|
|
10019
10360
|
return {
|
|
10020
10361
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
10021
10362
|
deviceId: this.deviceId,
|
|
@@ -10359,6 +10700,7 @@ exports.registerFunctionTools = registerFunctionTools;
|
|
|
10359
10700
|
const zod_1 = __webpack_require__(2971);
|
|
10360
10701
|
const cloudbase_manager_js_1 = __webpack_require__(3431);
|
|
10361
10702
|
const cloud_mode_js_1 = __webpack_require__(9684);
|
|
10703
|
+
const gateway_access_urls_js_1 = __webpack_require__(2435);
|
|
10362
10704
|
const json_content_js_1 = __webpack_require__(4365);
|
|
10363
10705
|
const logger_js_1 = __webpack_require__(3039);
|
|
10364
10706
|
const fs_1 = __webpack_require__(4421);
|
|
@@ -11111,7 +11453,7 @@ function registerFunctionTools(server) {
|
|
|
11111
11453
|
raw: imageResult,
|
|
11112
11454
|
}, `已基于镜像 ${createImageConfig.imageUri} 创建 HTTP 函数 ${functionName}。` +
|
|
11113
11455
|
`请确认 TCR、SCF 与构建管道处于同一地域;如需通过 URL 访问,请显式调用 ` +
|
|
11114
|
-
`manageGateway(action="createRoute",
|
|
11456
|
+
`manageGateway(action="createRoute", upstreamResourceType="WEB_SCF") 并按需调整函数安全规则。` +
|
|
11115
11457
|
`部署后可用 queryFunctions(action="getFunctionDetail") 确认函数已就绪。`, [
|
|
11116
11458
|
{
|
|
11117
11459
|
tool: "queryFunctions",
|
|
@@ -11182,7 +11524,7 @@ function registerFunctionTools(server) {
|
|
|
11182
11524
|
nextActions.push({
|
|
11183
11525
|
tool: "manageGateway",
|
|
11184
11526
|
action: "createRoute",
|
|
11185
|
-
reason: "如果需要通过 URL 访问 HTTP 函数,请调用 manageGateway(action=\"createRoute\") 并显式传
|
|
11527
|
+
reason: "如果需要通过 URL 访问 HTTP 函数,请调用 manageGateway(action=\"createRoute\") 并显式传 upstreamResourceType=\"WEB_SCF\",再按实际路径和鉴权需求创建访问入口,不要默认假设 /函数名 已存在",
|
|
11186
11528
|
});
|
|
11187
11529
|
nextActions.push({
|
|
11188
11530
|
tool: "queryGateway",
|
|
@@ -11201,11 +11543,35 @@ function registerFunctionTools(server) {
|
|
|
11201
11543
|
});
|
|
11202
11544
|
}
|
|
11203
11545
|
const message = func.type === "HTTP"
|
|
11204
|
-
? `已创建 HTTP 函数 ${functionName}。如果后续需要通过 URL 访问,请显式调用 manageGateway(action="createRoute"),并把
|
|
11546
|
+
? `已创建 HTTP 函数 ${functionName}。如果后续需要通过 URL 访问,请显式调用 manageGateway(action="createRoute"),并把 upstreamResourceType="WEB_SCF" 一起传入,再按实际路径和鉴权需求创建访问入口。评测或其他外部调用方可能会以匿名身份访问,而且失败后不一定会把 EXCEED_AUTHORITY 再反馈给 AI;交付前请主动确认访问路径和函数安全规则,若已出现 EXCEED_AUTHORITY,请先调用 queryPermissions(action="getResourcePermission", resourceType="function", resourceId="${functionName}") 查看当前规则,再按需要使用 managePermissions(action="updateResourcePermission") 调整权限。`
|
|
11205
11547
|
: `已创建函数 ${functionName}`;
|
|
11548
|
+
let accessUrl;
|
|
11549
|
+
let accessUrls = [];
|
|
11550
|
+
let accessUrlSource;
|
|
11551
|
+
if (func.type === "HTTP") {
|
|
11552
|
+
const envId = cloudBaseOptions?.envId ?? await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
|
|
11553
|
+
const gateway = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
|
|
11554
|
+
envId,
|
|
11555
|
+
upstreamResourceName: functionName,
|
|
11556
|
+
upstreamResourceTypes: ["WEB_SCF", "SCF"],
|
|
11557
|
+
getManager: async () => {
|
|
11558
|
+
const manager = await getManager();
|
|
11559
|
+
if (!manager) {
|
|
11560
|
+
throw new Error("cloudbase manager unavailable");
|
|
11561
|
+
}
|
|
11562
|
+
return manager;
|
|
11563
|
+
},
|
|
11564
|
+
});
|
|
11565
|
+
accessUrl = gateway.accessUrl;
|
|
11566
|
+
accessUrls = gateway.accessUrls;
|
|
11567
|
+
accessUrlSource = gateway.accessUrlSource;
|
|
11568
|
+
}
|
|
11206
11569
|
return buildEnvelope({
|
|
11207
11570
|
action: input.action,
|
|
11208
11571
|
functionName,
|
|
11572
|
+
...(accessUrl ? { accessUrl } : {}),
|
|
11573
|
+
...(accessUrls.length > 0 ? { accessUrls } : {}),
|
|
11574
|
+
...(accessUrlSource ? { accessUrlSource } : {}),
|
|
11209
11575
|
raw: result,
|
|
11210
11576
|
}, message, nextActions);
|
|
11211
11577
|
}
|
|
@@ -11244,11 +11610,33 @@ function registerFunctionTools(server) {
|
|
|
11244
11610
|
throw wrapFunctionOperationError("updateFunctionCode", input.functionName, undefined, error);
|
|
11245
11611
|
}
|
|
11246
11612
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, imageResult);
|
|
11613
|
+
const envId = cloudBaseOptions?.envId ?? await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
|
|
11614
|
+
const imageGatewayAccess = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
|
|
11615
|
+
envId,
|
|
11616
|
+
upstreamResourceName: input.functionName,
|
|
11617
|
+
upstreamResourceTypes: ["WEB_SCF", "SCF"],
|
|
11618
|
+
getManager: async () => {
|
|
11619
|
+
const manager = await getManager();
|
|
11620
|
+
if (!manager) {
|
|
11621
|
+
throw new Error("cloudbase manager unavailable");
|
|
11622
|
+
}
|
|
11623
|
+
return manager;
|
|
11624
|
+
},
|
|
11625
|
+
});
|
|
11247
11626
|
return buildEnvelope({
|
|
11248
11627
|
action: input.action,
|
|
11249
11628
|
functionName: input.functionName,
|
|
11250
11629
|
deployMode: "image",
|
|
11251
11630
|
imageUri: updateImageConfig.imageUri,
|
|
11631
|
+
...(imageGatewayAccess.accessUrl
|
|
11632
|
+
? { accessUrl: imageGatewayAccess.accessUrl }
|
|
11633
|
+
: {}),
|
|
11634
|
+
...(imageGatewayAccess.accessUrls.length > 0
|
|
11635
|
+
? { accessUrls: imageGatewayAccess.accessUrls }
|
|
11636
|
+
: {}),
|
|
11637
|
+
...(imageGatewayAccess.accessUrlSource
|
|
11638
|
+
? { accessUrlSource: imageGatewayAccess.accessUrlSource }
|
|
11639
|
+
: {}),
|
|
11252
11640
|
raw: imageResult,
|
|
11253
11641
|
}, `已将函数 ${input.functionName} 的镜像更新为 ${updateImageConfig.imageUri}。` +
|
|
11254
11642
|
`部署后可用 queryFunctions(action="getFunctionDetail") 确认函数已就绪(Active)。`, [
|
|
@@ -11279,9 +11667,29 @@ function registerFunctionTools(server) {
|
|
|
11279
11667
|
throw wrapFunctionOperationError("updateFunctionCode", input.functionName, processedRootPath, error);
|
|
11280
11668
|
}
|
|
11281
11669
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
11670
|
+
const envId = cloudBaseOptions?.envId ?? await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
|
|
11671
|
+
const gatewayAccess = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
|
|
11672
|
+
envId,
|
|
11673
|
+
upstreamResourceName: input.functionName,
|
|
11674
|
+
upstreamResourceTypes: ["WEB_SCF", "SCF"],
|
|
11675
|
+
getManager: async () => {
|
|
11676
|
+
const manager = await getManager();
|
|
11677
|
+
if (!manager) {
|
|
11678
|
+
throw new Error("cloudbase manager unavailable");
|
|
11679
|
+
}
|
|
11680
|
+
return manager;
|
|
11681
|
+
},
|
|
11682
|
+
});
|
|
11282
11683
|
return buildEnvelope({
|
|
11283
11684
|
action: input.action,
|
|
11284
11685
|
functionName: input.functionName,
|
|
11686
|
+
...(gatewayAccess.accessUrl ? { accessUrl: gatewayAccess.accessUrl } : {}),
|
|
11687
|
+
...(gatewayAccess.accessUrls.length > 0
|
|
11688
|
+
? { accessUrls: gatewayAccess.accessUrls }
|
|
11689
|
+
: {}),
|
|
11690
|
+
...(gatewayAccess.accessUrlSource
|
|
11691
|
+
? { accessUrlSource: gatewayAccess.accessUrlSource }
|
|
11692
|
+
: {}),
|
|
11285
11693
|
raw: result,
|
|
11286
11694
|
}, `已更新函数 ${input.functionName} 的代码`, [
|
|
11287
11695
|
{
|
|
@@ -14327,7 +14735,7 @@ function registerSetupTools(server) {
|
|
|
14327
14735
|
server.registerTool("downloadTemplate", {
|
|
14328
14736
|
title: "下载项目模板",
|
|
14329
14737
|
description: `自动下载并部署CloudBase项目模板。
|
|
14330
|
-
**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.25.
|
|
14738
|
+
**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.25.2" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
|
|
14331
14739
|
inputSchema: {
|
|
14332
14740
|
template: zod_1.z
|
|
14333
14741
|
.enum(["react", "vue", "miniprogram", "uniapp", "rules"])
|
|
@@ -14523,6 +14931,7 @@ const zod_1 = __webpack_require__(2971);
|
|
|
14523
14931
|
const cloudbase_manager_js_1 = __webpack_require__(3431);
|
|
14524
14932
|
const json_content_js_1 = __webpack_require__(4365);
|
|
14525
14933
|
const cloud_mode_js_1 = __webpack_require__(9684);
|
|
14934
|
+
const gateway_access_urls_js_1 = __webpack_require__(2435);
|
|
14526
14935
|
const QUERY_APP_ACTIONS = ["listApps", "getApp", "listAppVersions", "getAppVersion", "getBuildLog"];
|
|
14527
14936
|
const MANAGE_APP_ACTIONS = ["deployApp", "getUploadUrl", "deleteApp", "deleteAppVersion"];
|
|
14528
14937
|
const APP_FRAMEWORKS = ["vue", "react", "next", "nuxt", "vite", "angular", "static"];
|
|
@@ -14899,6 +15308,8 @@ function registerAppTools(server) {
|
|
|
14899
15308
|
let appInfo;
|
|
14900
15309
|
let domain;
|
|
14901
15310
|
let accessUrl;
|
|
15311
|
+
let accessUrls = [];
|
|
15312
|
+
let accessUrlSource;
|
|
14902
15313
|
let accessUrlLookupWarning;
|
|
14903
15314
|
try {
|
|
14904
15315
|
appInfo = await appService.describeAppInfo({
|
|
@@ -14907,9 +15318,34 @@ function registerAppTools(server) {
|
|
|
14907
15318
|
});
|
|
14908
15319
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, appInfo);
|
|
14909
15320
|
({ domain, accessUrl } = normalizeAccessUrlFromDomain(appInfo?.Domain));
|
|
15321
|
+
const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
|
|
15322
|
+
const gateway = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
|
|
15323
|
+
envId,
|
|
15324
|
+
upstreamResourceName: serviceName,
|
|
15325
|
+
upstreamResourceTypes: ["STATIC_STORE"],
|
|
15326
|
+
getManager: async () => {
|
|
15327
|
+
const manager = await getManager();
|
|
15328
|
+
if (!manager) {
|
|
15329
|
+
throw new Error("cloudbase manager unavailable");
|
|
15330
|
+
}
|
|
15331
|
+
return manager;
|
|
15332
|
+
},
|
|
15333
|
+
});
|
|
15334
|
+
const preferred = (0, gateway_access_urls_js_1.preferGatewayOrFallback)({
|
|
15335
|
+
gateway,
|
|
15336
|
+
fallbackUrl: accessUrl,
|
|
15337
|
+
fallbackSource: "describeAppInfo.Domain",
|
|
15338
|
+
});
|
|
15339
|
+
accessUrl = preferred.accessUrl;
|
|
15340
|
+
accessUrls = preferred.accessUrls;
|
|
15341
|
+
accessUrlSource = preferred.accessUrlSource;
|
|
14910
15342
|
}
|
|
14911
15343
|
catch (error) {
|
|
14912
15344
|
accessUrlLookupWarning = error instanceof Error ? error.message : String(error);
|
|
15345
|
+
if (accessUrl) {
|
|
15346
|
+
accessUrls = [accessUrl];
|
|
15347
|
+
accessUrlSource = "describeAppInfo.Domain";
|
|
15348
|
+
}
|
|
14913
15349
|
}
|
|
14914
15350
|
return (0, json_content_js_1.jsonContent)(buildEnvelope({
|
|
14915
15351
|
action,
|
|
@@ -14918,7 +15354,8 @@ function registerAppTools(server) {
|
|
|
14918
15354
|
buildId: BuildId,
|
|
14919
15355
|
domain,
|
|
14920
15356
|
accessUrl,
|
|
14921
|
-
|
|
15357
|
+
accessUrls: accessUrls.length > 0 ? accessUrls : undefined,
|
|
15358
|
+
accessUrlSource,
|
|
14922
15359
|
accessUrlLookupWarning,
|
|
14923
15360
|
app: appInfo,
|
|
14924
15361
|
upload: { cosTimestamp: cosTs },
|
|
@@ -15475,6 +15912,7 @@ const path_1 = __importDefault(__webpack_require__(2521));
|
|
|
15475
15912
|
const zod_1 = __webpack_require__(2971);
|
|
15476
15913
|
const cloudbase_manager_js_1 = __webpack_require__(3431);
|
|
15477
15914
|
const cloud_mode_js_1 = __webpack_require__(9684);
|
|
15915
|
+
const gateway_access_urls_js_1 = __webpack_require__(2435);
|
|
15478
15916
|
const notification_js_1 = __webpack_require__(2720);
|
|
15479
15917
|
const tool_result_js_1 = __webpack_require__(9835);
|
|
15480
15918
|
const HOSTING_CDN_SWITCH_VALUES = ['on', 'off'];
|
|
@@ -16010,9 +16448,48 @@ function registerHostingTools(server) {
|
|
|
16010
16448
|
// StaticDomain there but not in DescribeStaticStore.
|
|
16011
16449
|
const cdnFromStore = (store.CdnDomain ?? store.StaticDomain);
|
|
16012
16450
|
const staticDomain = cdnFromStore || await resolveHostingStaticDomain(cloudbase, server.logger);
|
|
16013
|
-
const
|
|
16451
|
+
const fallbackAccessUrl = buildHostingAccessUrl(staticDomain, input.cloudPath, input.localPath);
|
|
16452
|
+
const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
|
|
16453
|
+
const gatewayCandidates = Array.from(new Set([
|
|
16454
|
+
store.StaticStoreName,
|
|
16455
|
+
store.Name,
|
|
16456
|
+
store.StoreName,
|
|
16457
|
+
store.Bucket,
|
|
16458
|
+
"staticstore",
|
|
16459
|
+
]
|
|
16460
|
+
.map((item) => (typeof item === "string" ? item.trim() : ""))
|
|
16461
|
+
.filter(Boolean)));
|
|
16462
|
+
let accessUrl = fallbackAccessUrl;
|
|
16463
|
+
let accessUrls = accessUrl ? [accessUrl] : [];
|
|
16464
|
+
let accessUrlSource = accessUrl
|
|
16465
|
+
? "hosting.staticDomain"
|
|
16466
|
+
: undefined;
|
|
16467
|
+
for (const upstreamName of gatewayCandidates) {
|
|
16468
|
+
const gateway = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
|
|
16469
|
+
envId,
|
|
16470
|
+
upstreamResourceName: upstreamName,
|
|
16471
|
+
upstreamResourceTypes: ["STATIC_STORE"],
|
|
16472
|
+
getManager: async () => {
|
|
16473
|
+
const manager = await getManager();
|
|
16474
|
+
if (!manager) {
|
|
16475
|
+
throw new Error("cloudbase manager unavailable");
|
|
16476
|
+
}
|
|
16477
|
+
return manager;
|
|
16478
|
+
},
|
|
16479
|
+
});
|
|
16480
|
+
const preferred = (0, gateway_access_urls_js_1.preferGatewayOrFallback)({
|
|
16481
|
+
gateway,
|
|
16482
|
+
fallbackUrl: fallbackAccessUrl || undefined,
|
|
16483
|
+
fallbackSource: "hosting.staticDomain",
|
|
16484
|
+
});
|
|
16485
|
+
if (preferred.accessUrl) {
|
|
16486
|
+
accessUrl = preferred.accessUrl;
|
|
16487
|
+
accessUrls = preferred.accessUrls;
|
|
16488
|
+
accessUrlSource = preferred.accessUrlSource;
|
|
16489
|
+
break;
|
|
16490
|
+
}
|
|
16491
|
+
}
|
|
16014
16492
|
try {
|
|
16015
|
-
const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
|
|
16016
16493
|
let projectName = 'unknown';
|
|
16017
16494
|
if (input.localPath) {
|
|
16018
16495
|
try {
|
|
@@ -16047,6 +16524,8 @@ function registerHostingTools(server) {
|
|
|
16047
16524
|
ignore: input.ignore,
|
|
16048
16525
|
staticDomain,
|
|
16049
16526
|
accessUrl,
|
|
16527
|
+
accessUrls,
|
|
16528
|
+
accessUrlSource,
|
|
16050
16529
|
result,
|
|
16051
16530
|
nextActions: uploadPrefix ? [buildFindFilesNextStep(uploadPrefix.replace(/^\/+/, ''))] : undefined,
|
|
16052
16531
|
},
|
|
@@ -16646,6 +17125,219 @@ module.exports = __WEBPACK_EXTERNAL_MODULE_fs_promises_f8dae9d1__;
|
|
|
16646
17125
|
|
|
16647
17126
|
module.exports = __WEBPACK_EXTERNAL_MODULE_os__;
|
|
16648
17127
|
|
|
17128
|
+
/***/ }),
|
|
17129
|
+
|
|
17130
|
+
/***/ 8266:
|
|
17131
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
17132
|
+
|
|
17133
|
+
|
|
17134
|
+
/**
|
|
17135
|
+
* CloudRun serverConfig merge (RMW) and DiffConfigItem helpers.
|
|
17136
|
+
* Aligns with console SubmitServerConfigChangeDiff field mapping.
|
|
17137
|
+
*/
|
|
17138
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
17139
|
+
exports.CONFIG_FIELDS_LIKELY_REDEPLOY = void 0;
|
|
17140
|
+
exports.mergeCloudRunServerConfig = mergeCloudRunServerConfig;
|
|
17141
|
+
exports.assertCpuMemPair = assertCpuMemPair;
|
|
17142
|
+
exports.parseServerConfigToDiffItems = parseServerConfigToDiffItems;
|
|
17143
|
+
exports.summarizeConfigSnapshot = summarizeConfigSnapshot;
|
|
17144
|
+
exports.listLikelyRedeployFields = listLikelyRedeployFields;
|
|
17145
|
+
const SUBMIT_DIFF_MAP = {
|
|
17146
|
+
Cpu: "CpuSpecs",
|
|
17147
|
+
Mem: "MemSpecs",
|
|
17148
|
+
OpenAccessTypes: "AccessTypes",
|
|
17149
|
+
EnvParams: "EnvParam",
|
|
17150
|
+
CustomLogs: "LogPath",
|
|
17151
|
+
};
|
|
17152
|
+
const STRING_KEYS = new Set([
|
|
17153
|
+
"CustomLogs",
|
|
17154
|
+
"EnvParams",
|
|
17155
|
+
"CreateTime",
|
|
17156
|
+
"Dockerfile",
|
|
17157
|
+
"BuildDir",
|
|
17158
|
+
"LogType",
|
|
17159
|
+
"LogSetId",
|
|
17160
|
+
"LogTopicId",
|
|
17161
|
+
"LogParseType",
|
|
17162
|
+
"Tag",
|
|
17163
|
+
"InternalAccess",
|
|
17164
|
+
"InternalDomain",
|
|
17165
|
+
"OperationMode",
|
|
17166
|
+
"SessionAffinity",
|
|
17167
|
+
]);
|
|
17168
|
+
const INT_KEYS = new Set(["MinNum", "MaxNum", "InitialDelaySeconds", "Port"]);
|
|
17169
|
+
const BOOL_KEYS = new Set(["HasDockerfile"]);
|
|
17170
|
+
const FLOAT_KEYS = new Set(["Cpu", "Mem"]);
|
|
17171
|
+
const ARRAY_KEYS = new Set(["OpenAccessTypes", "EntryPoint", "Cmd"]);
|
|
17172
|
+
function parseEnvParamsObject(raw) {
|
|
17173
|
+
if (!raw || !String(raw).trim()) {
|
|
17174
|
+
return {};
|
|
17175
|
+
}
|
|
17176
|
+
try {
|
|
17177
|
+
const value = JSON.parse(String(raw));
|
|
17178
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
17179
|
+
return {};
|
|
17180
|
+
}
|
|
17181
|
+
const out = {};
|
|
17182
|
+
for (const [k, v] of Object.entries(value)) {
|
|
17183
|
+
if (v === undefined || v === null)
|
|
17184
|
+
continue;
|
|
17185
|
+
out[k] = typeof v === "string" ? v : String(v);
|
|
17186
|
+
}
|
|
17187
|
+
return out;
|
|
17188
|
+
}
|
|
17189
|
+
catch {
|
|
17190
|
+
return {};
|
|
17191
|
+
}
|
|
17192
|
+
}
|
|
17193
|
+
function stringifyEnvParams(obj) {
|
|
17194
|
+
return JSON.stringify(obj);
|
|
17195
|
+
}
|
|
17196
|
+
function isCompleteVpcConf(vpc) {
|
|
17197
|
+
return Boolean(vpc?.VpcId?.trim() && vpc?.SubnetId?.trim());
|
|
17198
|
+
}
|
|
17199
|
+
/**
|
|
17200
|
+
* Merge remote ServerConfig with deploy/update input.
|
|
17201
|
+
* Explicit input wins for provided fields; EnvParams merges by key unless replaceAll.
|
|
17202
|
+
*/
|
|
17203
|
+
function mergeCloudRunServerConfig(options) {
|
|
17204
|
+
const remote = options.remote || {};
|
|
17205
|
+
const input = options.input || {};
|
|
17206
|
+
const mergedFromRemote = [];
|
|
17207
|
+
const merged = { ...input };
|
|
17208
|
+
if (isCompleteVpcConf(input.VpcConf)) {
|
|
17209
|
+
merged.VpcConf = {
|
|
17210
|
+
VpcId: input.VpcConf.VpcId.trim(),
|
|
17211
|
+
SubnetId: input.VpcConf.SubnetId.trim(),
|
|
17212
|
+
...(input.VpcConf.VpcCIDR ? { VpcCIDR: input.VpcConf.VpcCIDR } : {}),
|
|
17213
|
+
...(input.VpcConf.SubnetCIDR ? { SubnetCIDR: input.VpcConf.SubnetCIDR } : {}),
|
|
17214
|
+
};
|
|
17215
|
+
}
|
|
17216
|
+
else if (isCompleteVpcConf(remote.VpcConf)) {
|
|
17217
|
+
merged.VpcConf = {
|
|
17218
|
+
VpcId: remote.VpcConf.VpcId.trim(),
|
|
17219
|
+
SubnetId: remote.VpcConf.SubnetId.trim(),
|
|
17220
|
+
...(remote.VpcConf.VpcCIDR ? { VpcCIDR: remote.VpcConf.VpcCIDR } : {}),
|
|
17221
|
+
...(remote.VpcConf.SubnetCIDR ? { SubnetCIDR: remote.VpcConf.SubnetCIDR } : {}),
|
|
17222
|
+
};
|
|
17223
|
+
mergedFromRemote.push("VpcConf");
|
|
17224
|
+
}
|
|
17225
|
+
else {
|
|
17226
|
+
delete merged.VpcConf;
|
|
17227
|
+
}
|
|
17228
|
+
const inputHasEnv = Object.prototype.hasOwnProperty.call(input, "EnvParams");
|
|
17229
|
+
const remoteEnv = parseEnvParamsObject(remote.EnvParams);
|
|
17230
|
+
const inputEnv = parseEnvParamsObject(input.EnvParams);
|
|
17231
|
+
if (options.envParamsReplaceAll && inputHasEnv) {
|
|
17232
|
+
merged.EnvParams = stringifyEnvParams(inputEnv);
|
|
17233
|
+
}
|
|
17234
|
+
else if (inputHasEnv || Object.keys(remoteEnv).length > 0) {
|
|
17235
|
+
const combined = options.envParamsReplaceAll
|
|
17236
|
+
? { ...inputEnv }
|
|
17237
|
+
: { ...remoteEnv, ...inputEnv };
|
|
17238
|
+
if (Object.keys(remoteEnv).length > 0 && !options.envParamsReplaceAll) {
|
|
17239
|
+
const preserved = Object.keys(remoteEnv).filter((k) => !(k in inputEnv));
|
|
17240
|
+
if (preserved.length > 0) {
|
|
17241
|
+
mergedFromRemote.push("EnvParams");
|
|
17242
|
+
}
|
|
17243
|
+
}
|
|
17244
|
+
if (Object.keys(combined).length > 0 || inputHasEnv) {
|
|
17245
|
+
merged.EnvParams = stringifyEnvParams(combined);
|
|
17246
|
+
}
|
|
17247
|
+
}
|
|
17248
|
+
// Must be explicit so Manager SDK update path cannot wipe with OA/PUBLIC/MINIAPP defaults.
|
|
17249
|
+
if (Array.isArray(input.OpenAccessTypes) && input.OpenAccessTypes.length > 0) {
|
|
17250
|
+
merged.OpenAccessTypes = [...input.OpenAccessTypes];
|
|
17251
|
+
}
|
|
17252
|
+
else if (Array.isArray(remote.OpenAccessTypes) && remote.OpenAccessTypes.length > 0) {
|
|
17253
|
+
merged.OpenAccessTypes = [...remote.OpenAccessTypes];
|
|
17254
|
+
mergedFromRemote.push("OpenAccessTypes");
|
|
17255
|
+
}
|
|
17256
|
+
return { merged, mergedFromRemote };
|
|
17257
|
+
}
|
|
17258
|
+
function assertCpuMemPair(config) {
|
|
17259
|
+
const hasCpu = config.Cpu !== undefined && config.Cpu !== null;
|
|
17260
|
+
const hasMem = config.Mem !== undefined && config.Mem !== null;
|
|
17261
|
+
if (hasCpu !== hasMem) {
|
|
17262
|
+
throw new Error("Cpu and Mem must be provided together when updating CloudRun config (platform requires the pair).");
|
|
17263
|
+
}
|
|
17264
|
+
}
|
|
17265
|
+
/**
|
|
17266
|
+
* Convert serverConfig object to DiffConfigItem[] for SubmitServerConfigChangeDiff.
|
|
17267
|
+
*/
|
|
17268
|
+
function parseServerConfigToDiffItems(data) {
|
|
17269
|
+
assertCpuMemPair(data);
|
|
17270
|
+
const Items = [];
|
|
17271
|
+
for (const [k, v] of Object.entries(data)) {
|
|
17272
|
+
if (v === undefined || v === null)
|
|
17273
|
+
continue;
|
|
17274
|
+
const Key = SUBMIT_DIFF_MAP[k] || k;
|
|
17275
|
+
if (STRING_KEYS.has(k)) {
|
|
17276
|
+
if (v !== "") {
|
|
17277
|
+
Items.push({ Key, Value: String(v) });
|
|
17278
|
+
}
|
|
17279
|
+
}
|
|
17280
|
+
else if (INT_KEYS.has(k)) {
|
|
17281
|
+
Items.push({ Key, IntValue: Number(v) });
|
|
17282
|
+
}
|
|
17283
|
+
else if (BOOL_KEYS.has(k)) {
|
|
17284
|
+
Items.push({ Key, BoolValue: Boolean(v) });
|
|
17285
|
+
}
|
|
17286
|
+
else if (FLOAT_KEYS.has(k)) {
|
|
17287
|
+
Items.push({ Key, FloatValue: Number(v) });
|
|
17288
|
+
}
|
|
17289
|
+
else if (ARRAY_KEYS.has(k)) {
|
|
17290
|
+
Items.push({ Key, ArrayValue: v });
|
|
17291
|
+
}
|
|
17292
|
+
else if (k === "PolicyDetails") {
|
|
17293
|
+
Items.push({ Key, PolicyDetails: v });
|
|
17294
|
+
}
|
|
17295
|
+
else if (k === "TimerScale") {
|
|
17296
|
+
Items.push({ Key, TimerScale: v });
|
|
17297
|
+
}
|
|
17298
|
+
else if (k === "VpcConf") {
|
|
17299
|
+
Items.push({ Key, VpcConf: v });
|
|
17300
|
+
}
|
|
17301
|
+
else if (k === "VolumesConf") {
|
|
17302
|
+
Items.push({ Key, VolumesConf: v });
|
|
17303
|
+
}
|
|
17304
|
+
else if (k === "PublicNetConf") {
|
|
17305
|
+
Items.push({ Key, PublicNetConf: v });
|
|
17306
|
+
}
|
|
17307
|
+
}
|
|
17308
|
+
return Items;
|
|
17309
|
+
}
|
|
17310
|
+
function summarizeConfigSnapshot(config) {
|
|
17311
|
+
const vpc = config?.VpcConf;
|
|
17312
|
+
const envKeys = Object.keys(parseEnvParamsObject(config?.EnvParams));
|
|
17313
|
+
return {
|
|
17314
|
+
hasVpcConf: isCompleteVpcConf(vpc),
|
|
17315
|
+
...(vpc?.VpcId ? { vpcId: vpc.VpcId } : {}),
|
|
17316
|
+
...(vpc?.SubnetId ? { subnetId: vpc.SubnetId } : {}),
|
|
17317
|
+
...(Array.isArray(config?.OpenAccessTypes)
|
|
17318
|
+
? { openAccessTypes: config.OpenAccessTypes }
|
|
17319
|
+
: {}),
|
|
17320
|
+
envParamKeys: envKeys,
|
|
17321
|
+
};
|
|
17322
|
+
}
|
|
17323
|
+
exports.CONFIG_FIELDS_LIKELY_REDEPLOY = [
|
|
17324
|
+
"VpcConf",
|
|
17325
|
+
"EnvParams",
|
|
17326
|
+
"Cpu",
|
|
17327
|
+
"Mem",
|
|
17328
|
+
"Port",
|
|
17329
|
+
"Dockerfile",
|
|
17330
|
+
"BuildDir",
|
|
17331
|
+
"VolumesConf",
|
|
17332
|
+
"LogType",
|
|
17333
|
+
"LogSetId",
|
|
17334
|
+
"LogTopicId",
|
|
17335
|
+
];
|
|
17336
|
+
function listLikelyRedeployFields(config) {
|
|
17337
|
+
return exports.CONFIG_FIELDS_LIKELY_REDEPLOY.filter((k) => Object.prototype.hasOwnProperty.call(config, k));
|
|
17338
|
+
}
|
|
17339
|
+
|
|
17340
|
+
|
|
16649
17341
|
/***/ }),
|
|
16650
17342
|
|
|
16651
17343
|
/***/ 9097:
|