@cloudbase/cloudbase-mcp 2.36.0 → 2.36.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 +1849 -283
- package/dist/index.d.ts +48 -2
- package/dist/index.js +1855 -285
- package/package.json +3 -2
- package/server.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -199828,6 +199828,7 @@ exports.resolveAuthProgressState = resolveAuthProgressState;
|
|
|
199828
199828
|
exports.rejectAuthProgressState = rejectAuthProgressState;
|
|
199829
199829
|
exports.resetAuthProgressState = resetAuthProgressState;
|
|
199830
199830
|
exports.getCredentialSource = getCredentialSource;
|
|
199831
|
+
exports.isEnvCredentialRemovableByLogout = isEnvCredentialRemovableByLogout;
|
|
199831
199832
|
exports.peekLoginState = peekLoginState;
|
|
199832
199833
|
exports.ensureLogin = ensureLogin;
|
|
199833
199834
|
exports.getLoginState = getLoginState;
|
|
@@ -200261,6 +200262,21 @@ function readProjectCredentialFile(projectRoot) {
|
|
|
200261
200262
|
return null;
|
|
200262
200263
|
}
|
|
200263
200264
|
}
|
|
200265
|
+
/**
|
|
200266
|
+
* 删掉项目级凭据文件。只删这一个文件,目录留着——删目录会顺带清掉同在里面的
|
|
200267
|
+
* `project.json` 等项目配置。
|
|
200268
|
+
*
|
|
200269
|
+
* 不走 toolbox 的 `logout({cwd})`:那个接口会**无条件先删全局凭据**,而「退出本项目」
|
|
200270
|
+
* 不该把用户的账号级登录一起注销掉。
|
|
200271
|
+
*/
|
|
200272
|
+
function deleteProjectCredentialFile(projectRoot) {
|
|
200273
|
+
try {
|
|
200274
|
+
(0, node_fs_1.unlinkSync)((0, node_path_1.join)((0, toolbox_1.getProjectDir)(projectRoot), "auth.json"));
|
|
200275
|
+
}
|
|
200276
|
+
catch {
|
|
200277
|
+
// 文件本来就不在:登出是幂等的,不报错
|
|
200278
|
+
}
|
|
200279
|
+
}
|
|
200264
200280
|
/**
|
|
200265
200281
|
* 项目级凭据优先于账号级全局登录态。
|
|
200266
200282
|
*
|
|
@@ -200318,6 +200334,32 @@ function clearAdoptedProjectEnv() {
|
|
|
200318
200334
|
function isAdoptedProjectCredential(apiKey, envId) {
|
|
200319
200335
|
return adoptedProjectApiKey !== null && apiKey === adoptedProjectApiKey && envId === adoptedProjectEnvId;
|
|
200320
200336
|
}
|
|
200337
|
+
/**
|
|
200338
|
+
* env 里的这一份凭据能不能被 `logout()` 清掉。
|
|
200339
|
+
*
|
|
200340
|
+
* 能清掉的只有两种情况:是我们从项目级凭据文件回填的,或者它与当前项目级凭据文件里
|
|
200341
|
+
* 那一份相同(`auth(login_by_api_key)` 写进程 env 的同时也把同一个 key 落到项目级)。
|
|
200342
|
+
* 这两种都能沿 `logout()` 清掉:删项目级文件、再清 env。
|
|
200343
|
+
*
|
|
200344
|
+
* 其余情况是用户自己在 shell 或宿主配置里设的变量,进程删不掉,只能提示他去源头改。
|
|
200345
|
+
*/
|
|
200346
|
+
function isEnvCredentialRemovableByLogout() {
|
|
200347
|
+
const apiKey = getCloudBaseApiKeyFromEnv();
|
|
200348
|
+
const envId = process.env.CLOUDBASE_ENV_ID;
|
|
200349
|
+
if (!apiKey || !envId) {
|
|
200350
|
+
return false;
|
|
200351
|
+
}
|
|
200352
|
+
if (isAdoptedProjectCredential(apiKey, envId)) {
|
|
200353
|
+
return true;
|
|
200354
|
+
}
|
|
200355
|
+
try {
|
|
200356
|
+
const stored = readProjectCredentialFile((0, project_config_js_1.requireProjectRoot)());
|
|
200357
|
+
return stored?.apiKey === apiKey && stored?.envId === envId;
|
|
200358
|
+
}
|
|
200359
|
+
catch {
|
|
200360
|
+
return false;
|
|
200361
|
+
}
|
|
200362
|
+
}
|
|
200321
200363
|
/**
|
|
200322
200364
|
* 全局凭据文件 `~/.config/.cloudbase/auth.json` 与 CloudBase CLI 共用一份:用户会在终端里
|
|
200323
200365
|
* `tcb login`,宿主连接器的登录按钮执行的也是 `tcb login --flow web --yes`,两者都在
|
|
@@ -200359,6 +200401,8 @@ async function peekLoginState(options) {
|
|
|
200359
200401
|
dropStaleCredentialStoreCache();
|
|
200360
200402
|
credentialSource = null;
|
|
200361
200403
|
const envVarLoginState = normalizeLoginStateFromEnvVars(options);
|
|
200404
|
+
// 回填的那份 key 换不出临时密钥时置位:项目级文件里是同一份,不必再试一次
|
|
200405
|
+
let projectCredentialSkipped = false;
|
|
200362
200406
|
if (envVarLoginState) {
|
|
200363
200407
|
// API Key 模式:需要先用 API Key 换取临时密钥
|
|
200364
200408
|
if ('_type' in envVarLoginState && envVarLoginState._type === 'api_key') {
|
|
@@ -200380,16 +200424,28 @@ async function peekLoginState(options) {
|
|
|
200380
200424
|
}
|
|
200381
200425
|
catch (e) {
|
|
200382
200426
|
(0, logger_js_1.debug)("peekLoginState: API Key login failed", { error: e instanceof Error ? e.message : String(e) });
|
|
200383
|
-
|
|
200427
|
+
// 我们回填的那份失效(密钥被撤、环境被删):先清掉残留,别让它一直占着 env
|
|
200428
|
+
// 把状态查询、登出、重新登录全堵死;项目文件本身不动,用户重新登录会覆盖它。
|
|
200429
|
+
// 清完继续往下走,让账号级登录态接上。
|
|
200430
|
+
if (isAdoptedProjectCredential(envVarLoginState.apiKey, envVarLoginState.envId)) {
|
|
200431
|
+
clearAdoptedProjectEnv();
|
|
200432
|
+
projectCredentialSkipped = true;
|
|
200433
|
+
}
|
|
200434
|
+
else {
|
|
200435
|
+
// 用户自己在 shell / 宿主配置里设的变量,登不登得上由他那边决定
|
|
200436
|
+
return null;
|
|
200437
|
+
}
|
|
200384
200438
|
}
|
|
200385
200439
|
}
|
|
200386
|
-
|
|
200387
|
-
|
|
200388
|
-
|
|
200389
|
-
|
|
200440
|
+
if (!projectCredentialSkipped) {
|
|
200441
|
+
// 腾讯云密钥模式:直接返回
|
|
200442
|
+
(0, logger_js_1.debug)("loginByApiSecret");
|
|
200443
|
+
credentialSource = "env";
|
|
200444
|
+
return envVarLoginState;
|
|
200445
|
+
}
|
|
200390
200446
|
}
|
|
200391
200447
|
// 项目级凭据优先于账号级登录态(与 readProjectEnvId 同一原则)
|
|
200392
|
-
const projectLoginState = await resolveProjectLoginState();
|
|
200448
|
+
const projectLoginState = projectCredentialSkipped ? null : await resolveProjectLoginState();
|
|
200393
200449
|
if (projectLoginState) {
|
|
200394
200450
|
credentialSource = "project";
|
|
200395
200451
|
return projectLoginState;
|
|
@@ -200488,21 +200544,44 @@ async function ensureLogin(options) {
|
|
|
200488
200544
|
async function getLoginState(options) {
|
|
200489
200545
|
return ensureLogin(options);
|
|
200490
200546
|
}
|
|
200547
|
+
/**
|
|
200548
|
+
* 退出登录:只清「当前生效的那一份」。
|
|
200549
|
+
*
|
|
200550
|
+
* 项目级凭据优先于账号级登录态,所以项目里有 API Key 时,登出只删项目文件、清掉
|
|
200551
|
+
* 回填的环境变量,账号登录原样保留(删完它自动接上)。再调一次才轮到全局。
|
|
200552
|
+
*
|
|
200553
|
+
* 不把 cwd 交给 toolbox 的 `logout()`:那个接口会**无条件先删全局凭据**,
|
|
200554
|
+
* 「退出本项目」不该把用户的账号级登录一起注销掉。
|
|
200555
|
+
*/
|
|
200491
200556
|
async function logout(_options) {
|
|
200492
200557
|
// 先同步缓存再删:否则 toolbox 会把本进程启动时的陈旧快照写回盘,
|
|
200493
200558
|
// 把外部(CLI / 宿主登录按钮)刚写入的凭据一起抹掉。
|
|
200494
200559
|
dropStaleCredentialStoreCache();
|
|
200495
|
-
|
|
200560
|
+
const removed = [];
|
|
200561
|
+
let projectRoot;
|
|
200496
200562
|
try {
|
|
200497
|
-
|
|
200563
|
+
projectRoot = (0, project_config_js_1.requireProjectRoot)();
|
|
200498
200564
|
}
|
|
200499
200565
|
catch {
|
|
200500
|
-
|
|
200566
|
+
// 宿主配置目录等非法项目根:没有项目级凭据
|
|
200567
|
+
projectRoot = undefined;
|
|
200568
|
+
}
|
|
200569
|
+
const envApiKey = getCloudBaseApiKeyFromEnv();
|
|
200570
|
+
const hasProjectCredential = !!(projectRoot && readProjectCredentialFile(projectRoot));
|
|
200571
|
+
// env 里那份是用户自己设的(进程删不掉)时,既不算项目级生效,也不该顺手注销账号登录
|
|
200572
|
+
const projectInEffect = hasProjectCredential && (!envApiKey || isEnvCredentialRemovableByLogout());
|
|
200573
|
+
if (projectInEffect && projectRoot) {
|
|
200574
|
+
deleteProjectCredentialFile(projectRoot);
|
|
200575
|
+
clearAdoptedProjectEnv();
|
|
200576
|
+
removed.push("project");
|
|
200577
|
+
}
|
|
200578
|
+
else if (!envApiKey) {
|
|
200579
|
+
await auth.logout();
|
|
200580
|
+
removed.push("global");
|
|
200501
200581
|
}
|
|
200502
|
-
await auth.logout(cwd ? { cwd } : undefined);
|
|
200503
|
-
clearAdoptedProjectEnv();
|
|
200504
200582
|
credentialSource = null;
|
|
200505
200583
|
resetAuthProgressState();
|
|
200584
|
+
return { removed };
|
|
200506
200585
|
}
|
|
200507
200586
|
|
|
200508
200587
|
|
|
@@ -200517,7 +200596,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
200517
200596
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
200518
200597
|
};
|
|
200519
200598
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
200520
|
-
exports.envManager = void 0;
|
|
200599
|
+
exports.envManager = exports.runInEnvSlot = void 0;
|
|
200521
200600
|
exports.probeApiKeyCamCapability = probeApiKeyCamCapability;
|
|
200522
200601
|
exports.fetchEnvOwnerUin = fetchEnvOwnerUin;
|
|
200523
200602
|
exports.probeCamCapabilityForLogin = probeCamCapabilityForLogin;
|
|
@@ -200539,7 +200618,10 @@ const logger_js_1 = __webpack_require__(40781);
|
|
|
200539
200618
|
const tool_result_js_1 = __webpack_require__(69645);
|
|
200540
200619
|
const site_map_js_1 = __webpack_require__(34533);
|
|
200541
200620
|
const project_config_js_1 = __webpack_require__(39175);
|
|
200621
|
+
const cloud_mode_js_1 = __webpack_require__(88694);
|
|
200622
|
+
const env_binding_js_1 = __webpack_require__(61498);
|
|
200542
200623
|
const local_endpoint_js_1 = __webpack_require__(16156);
|
|
200624
|
+
const describe_envs_query_js_1 = __webpack_require__(31284);
|
|
200543
200625
|
function toEnvCandidates(envList) {
|
|
200544
200626
|
if (!Array.isArray(envList)) {
|
|
200545
200627
|
return [];
|
|
@@ -200725,11 +200807,7 @@ async function listAvailableEnvCandidates(options) {
|
|
|
200725
200807
|
try {
|
|
200726
200808
|
const result = await cloudbase.commonService("tcb", "2018-06-08").call({
|
|
200727
200809
|
Action: "DescribeEnvs",
|
|
200728
|
-
Param:
|
|
200729
|
-
EnvTypes: ["weda", "baas"],
|
|
200730
|
-
IsVisible: false,
|
|
200731
|
-
Channels: ["dcloud", "iotenable", "tem", "scene_module"],
|
|
200732
|
-
},
|
|
200810
|
+
Param: (0, describe_envs_query_js_1.buildDescribeEnvsFilter)(),
|
|
200733
200811
|
});
|
|
200734
200812
|
const envList = result?.EnvList || result?.Data?.EnvList || [];
|
|
200735
200813
|
return toEnvCandidates(envList);
|
|
@@ -200947,6 +201025,7 @@ class EnvironmentManager {
|
|
|
200947
201025
|
// 手动设置环境ID(用于外部调用)
|
|
200948
201026
|
async setEnvId(envId) {
|
|
200949
201027
|
this._setCachedEnvId(envId);
|
|
201028
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId, source: "envManager.cachedEnvId" });
|
|
200950
201029
|
(0, logger_js_1.debug)('手动设置环境ID并更新缓存:', { envId });
|
|
200951
201030
|
}
|
|
200952
201031
|
// Get cached envId without triggering fetch (for optimization)
|
|
@@ -200957,44 +201036,136 @@ class EnvironmentManager {
|
|
|
200957
201036
|
// 全局实例
|
|
200958
201037
|
const envManager = new EnvironmentManager();
|
|
200959
201038
|
exports.envManager = envManager;
|
|
200960
|
-
|
|
201039
|
+
function requestHasCloudCredentials(cloudBaseOptions) {
|
|
201040
|
+
return Boolean((cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey) ||
|
|
201041
|
+
cloudBaseOptions?.requestFn);
|
|
201042
|
+
}
|
|
201043
|
+
function throwCloudModeEnvRequired(envCandidates) {
|
|
201044
|
+
const singleEnvId = envCandidates.length === 1 ? envCandidates[0].envId : undefined;
|
|
201045
|
+
(0, tool_result_js_1.throwToolPayloadError)({
|
|
201046
|
+
ok: false,
|
|
201047
|
+
code: "ENV_REQUIRED",
|
|
201048
|
+
message: "当前请求没有带 envId。Cloud mode 不读取本机登录态、项目配置或进程环境变量。",
|
|
201049
|
+
env_candidates: envCandidates,
|
|
201050
|
+
next_step: (0, tool_result_js_1.buildAuthNextStep)("set_env", {
|
|
201051
|
+
requiredParams: singleEnvId ? undefined : ["envId"],
|
|
201052
|
+
suggestedArgs: singleEnvId
|
|
201053
|
+
? { action: "set_env", envId: singleEnvId }
|
|
201054
|
+
: { action: "set_env" },
|
|
201055
|
+
}),
|
|
201056
|
+
});
|
|
201057
|
+
}
|
|
201058
|
+
/**
|
|
201059
|
+
* Cloud mode only sees this request. No envManager, no CLOUDBASE_ENV_ID, no project file, no auth.json.
|
|
201060
|
+
* A single environment is written back onto this request's options and is not cached on the process.
|
|
201061
|
+
*/
|
|
201062
|
+
async function resolveCloudModeEnvId(cloudBaseOptions, requireEnvId) {
|
|
201063
|
+
if (cloudBaseOptions?.envId) {
|
|
201064
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId: cloudBaseOptions.envId, source: "cloudBaseOptions" });
|
|
201065
|
+
return cloudBaseOptions.envId;
|
|
201066
|
+
}
|
|
201067
|
+
if (!requireEnvId) {
|
|
201068
|
+
return undefined;
|
|
201069
|
+
}
|
|
201070
|
+
if (!requestHasCloudCredentials(cloudBaseOptions)) {
|
|
201071
|
+
throwCloudModeEnvRequired([]);
|
|
201072
|
+
}
|
|
201073
|
+
const envCandidates = await listAvailableEnvCandidates({ cloudBaseOptions });
|
|
201074
|
+
if (envCandidates.length === 1) {
|
|
201075
|
+
const singleEnvId = envCandidates[0].envId;
|
|
201076
|
+
if (cloudBaseOptions) {
|
|
201077
|
+
cloudBaseOptions.envId = singleEnvId;
|
|
201078
|
+
}
|
|
201079
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId: singleEnvId, source: "auto_bound" });
|
|
201080
|
+
return singleEnvId;
|
|
201081
|
+
}
|
|
201082
|
+
throwCloudModeEnvRequired(envCandidates);
|
|
201083
|
+
}
|
|
201084
|
+
async function getCloudBaseManagerCloudMode(options) {
|
|
201085
|
+
const requireEnvId = options.requireEnvId !== false;
|
|
201086
|
+
const cloudBaseOptions = options.cloudBaseOptions;
|
|
201087
|
+
if (!requestHasCloudCredentials(cloudBaseOptions)) {
|
|
201088
|
+
throwAuthRequiredError();
|
|
201089
|
+
}
|
|
201090
|
+
const resolvedEnvId = await resolveCloudModeEnvId(cloudBaseOptions, requireEnvId);
|
|
201091
|
+
return createCloudBaseManagerWithOptions({
|
|
201092
|
+
...(cloudBaseOptions ?? {}),
|
|
201093
|
+
envId: resolvedEnvId,
|
|
201094
|
+
});
|
|
201095
|
+
}
|
|
201096
|
+
/**
|
|
201097
|
+
* Fresh slot for tests. Production stdio/hosted pass their own slot into `runWithEnvSlot`.
|
|
201098
|
+
* Re-exported from `env-binding.ts` so there is only one definition.
|
|
201099
|
+
*/
|
|
201100
|
+
var env_binding_js_2 = __webpack_require__(61498);
|
|
201101
|
+
Object.defineProperty(exports, "runInEnvSlot", ({ enumerable: true, get: function () { return env_binding_js_2.runInEnvSlot; } }));
|
|
200961
201102
|
async function getEnvId(cloudBaseOptions) {
|
|
201103
|
+
if ((0, cloud_mode_js_1.isCloudMode)()) {
|
|
201104
|
+
const envId = await resolveCloudModeEnvId(cloudBaseOptions, true);
|
|
201105
|
+
if (!envId) {
|
|
201106
|
+
throwCloudModeEnvRequired([]);
|
|
201107
|
+
}
|
|
201108
|
+
return envId;
|
|
201109
|
+
}
|
|
201110
|
+
return resolveEnvIdForCall(cloudBaseOptions);
|
|
201111
|
+
}
|
|
201112
|
+
async function resolveEnvIdForCall(cloudBaseOptions) {
|
|
200962
201113
|
if (cloudBaseOptions?.envId) {
|
|
200963
201114
|
(0, logger_js_1.debug)('使用传入的 envId:', { envId: cloudBaseOptions.envId });
|
|
201115
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId: cloudBaseOptions.envId, source: "cloudBaseOptions" });
|
|
200964
201116
|
return cloudBaseOptions.envId;
|
|
200965
201117
|
}
|
|
200966
201118
|
if ((0, local_endpoint_js_1.resolveLocalEndpoint)()) {
|
|
200967
201119
|
return 'local';
|
|
200968
201120
|
}
|
|
200969
|
-
const cachedEnvId = envManager.getCachedEnvId()
|
|
201121
|
+
const cachedEnvId = envManager.getCachedEnvId();
|
|
200970
201122
|
if (cachedEnvId) {
|
|
200971
201123
|
(0, logger_js_1.debug)('使用缓存中的 envId:', { envId: cachedEnvId });
|
|
201124
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId: cachedEnvId, source: "envManager.cachedEnvId" });
|
|
200972
201125
|
return cachedEnvId;
|
|
200973
201126
|
}
|
|
200974
|
-
|
|
200975
|
-
|
|
201127
|
+
if (process.env.CLOUDBASE_ENV_ID) {
|
|
201128
|
+
(0, logger_js_1.debug)('使用进程环境变量的 envId:', { envId: process.env.CLOUDBASE_ENV_ID });
|
|
201129
|
+
(0, env_binding_js_1.noteEnvBinding)({
|
|
201130
|
+
envId: process.env.CLOUDBASE_ENV_ID,
|
|
201131
|
+
source: "process.env.CLOUDBASE_ENV_ID",
|
|
201132
|
+
});
|
|
201133
|
+
return process.env.CLOUDBASE_ENV_ID;
|
|
201134
|
+
}
|
|
201135
|
+
// Project config stays ahead of the account login env, and still writes the cache.
|
|
200976
201136
|
const projectEnvId = (0, project_config_js_1.readProjectEnvId)();
|
|
200977
201137
|
if (projectEnvId) {
|
|
200978
201138
|
(0, logger_js_1.debug)('使用项目配置(.cloudbase/project.json)的 envId:', { envId: projectEnvId });
|
|
200979
201139
|
await envManager.setEnvId(projectEnvId);
|
|
201140
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId: projectEnvId, source: "project" });
|
|
200980
201141
|
return projectEnvId;
|
|
200981
201142
|
}
|
|
200982
201143
|
const loginState = await (0, auth_js_1.peekLoginState)();
|
|
200983
201144
|
if (typeof loginState?.envId === 'string' && loginState.envId.length > 0) {
|
|
200984
201145
|
(0, logger_js_1.debug)('使用登录态中的 envId:', { envId: loginState.envId });
|
|
201146
|
+
// Do not cache. A project file that appears later in this process must still win.
|
|
201147
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId: loginState.envId, source: "login_state" });
|
|
200985
201148
|
return loginState.envId;
|
|
200986
201149
|
}
|
|
200987
|
-
|
|
200988
|
-
|
|
201150
|
+
const envId = await envManager.getEnvId();
|
|
201151
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId, source: "auto_bound" });
|
|
201152
|
+
return envId;
|
|
200989
201153
|
}
|
|
200990
|
-
// 导出函数保持兼容性
|
|
200991
201154
|
function resetCloudBaseManagerCache() {
|
|
200992
201155
|
envManager.reset();
|
|
201156
|
+
(0, env_binding_js_1.clearEnvBinding)();
|
|
200993
201157
|
}
|
|
200994
201158
|
// 导出获取缓存环境ID的函数,供遥测模块使用
|
|
200995
201159
|
function getCachedEnvId() {
|
|
200996
201160
|
return envManager.getCachedEnvId();
|
|
200997
201161
|
}
|
|
201162
|
+
/**
|
|
201163
|
+
* 实例 ID 是环境关联的 PaaS 资源标识,正常情况下与 envId 同生命周期。
|
|
201164
|
+
* 但失效通知跨系统没有出口(invalidate 在生产路径上没有任何调用点),
|
|
201165
|
+
* 所以用一个长 TTL 兜底:宁可每半小时多查一次环境信息,
|
|
201166
|
+
* 也不要拿着一份没人能证明还正确的实例 ID 一直用下去。
|
|
201167
|
+
*/
|
|
201168
|
+
const DATABASE_INSTANCE_ID_CACHE_TTL_MS = 30 * 60 * 1000;
|
|
200998
201169
|
const databaseInstanceIdCache = new Map();
|
|
200999
201170
|
function buildDatabaseInstanceIdCacheKey(options) {
|
|
201000
201171
|
const envId = options?.envId ?? options?.cloudBaseOptions?.envId ?? process.env.CLOUDBASE_ENV_ID ?? 'unknown';
|
|
@@ -201025,11 +201196,16 @@ async function getDatabaseInstanceId(options) {
|
|
|
201025
201196
|
});
|
|
201026
201197
|
const cachedEntry = databaseInstanceIdCache.get(cacheKey);
|
|
201027
201198
|
if (cachedEntry?.instanceId) {
|
|
201028
|
-
|
|
201029
|
-
|
|
201030
|
-
|
|
201031
|
-
|
|
201032
|
-
|
|
201199
|
+
if (cachedEntry.expiresAt && cachedEntry.expiresAt <= Date.now()) {
|
|
201200
|
+
databaseInstanceIdCache.delete(cacheKey);
|
|
201201
|
+
}
|
|
201202
|
+
else {
|
|
201203
|
+
return {
|
|
201204
|
+
instanceId: cachedEntry.instanceId,
|
|
201205
|
+
source: 'cache',
|
|
201206
|
+
cacheKey,
|
|
201207
|
+
};
|
|
201208
|
+
}
|
|
201033
201209
|
}
|
|
201034
201210
|
if (cachedEntry?.inflightPromise) {
|
|
201035
201211
|
const instanceId = await cachedEntry.inflightPromise;
|
|
@@ -201054,6 +201230,7 @@ async function getDatabaseInstanceId(options) {
|
|
|
201054
201230
|
const instanceId = await inflightPromise;
|
|
201055
201231
|
databaseInstanceIdCache.set(cacheKey, {
|
|
201056
201232
|
instanceId,
|
|
201233
|
+
expiresAt: Date.now() + DATABASE_INSTANCE_ID_CACHE_TTL_MS,
|
|
201057
201234
|
});
|
|
201058
201235
|
return {
|
|
201059
201236
|
instanceId,
|
|
@@ -201070,6 +201247,9 @@ async function getDatabaseInstanceId(options) {
|
|
|
201070
201247
|
* 每次都实时获取最新的 token/secretId/secretKey
|
|
201071
201248
|
*/
|
|
201072
201249
|
async function getCloudBaseManager(options = {}) {
|
|
201250
|
+
if ((0, cloud_mode_js_1.isCloudMode)()) {
|
|
201251
|
+
return getCloudBaseManagerCloudMode(options);
|
|
201252
|
+
}
|
|
201073
201253
|
const { requireEnvId = true, authStrategy = 'fail_fast', } = options;
|
|
201074
201254
|
let cloudBaseOptions = options.cloudBaseOptions;
|
|
201075
201255
|
const localEndpoint = (0, local_endpoint_js_1.resolveLocalEndpoint)();
|
|
@@ -201085,12 +201265,14 @@ async function getCloudBaseManager(options = {}) {
|
|
|
201085
201265
|
// 如果传入了完整凭据或 requestFn,优先使用显式 CloudBase 配置
|
|
201086
201266
|
if (cloudBaseOptions && (hasDirectCredentials || hasRequestFn)) {
|
|
201087
201267
|
let resolvedEnvId = cloudBaseOptions.envId;
|
|
201268
|
+
let explicitSource = cloudBaseOptions.envId ? "cloudBaseOptions" : "default";
|
|
201088
201269
|
if (requireEnvId && !resolvedEnvId) {
|
|
201089
201270
|
const envCandidates = await listAvailableEnvCandidates({ cloudBaseOptions });
|
|
201090
201271
|
if (envCandidates.length === 1) {
|
|
201091
201272
|
const singleEnvId = envCandidates[0].envId;
|
|
201092
201273
|
cloudBaseOptions.envId = singleEnvId;
|
|
201093
201274
|
resolvedEnvId = singleEnvId;
|
|
201275
|
+
explicitSource = "auto_bound";
|
|
201094
201276
|
(0, logger_js_1.debug)('自动绑定唯一环境(显式配置):', { envId: singleEnvId });
|
|
201095
201277
|
}
|
|
201096
201278
|
else if (authStrategy === 'fail_fast') {
|
|
@@ -201110,6 +201292,9 @@ async function getCloudBaseManager(options = {}) {
|
|
|
201110
201292
|
}
|
|
201111
201293
|
}
|
|
201112
201294
|
(0, logger_js_1.debug)('使用传入的 CloudBase 配置');
|
|
201295
|
+
if (resolvedEnvId && explicitSource !== "default") {
|
|
201296
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId: resolvedEnvId, source: explicitSource });
|
|
201297
|
+
}
|
|
201113
201298
|
return createCloudBaseManagerWithOptions({
|
|
201114
201299
|
...cloudBaseOptions,
|
|
201115
201300
|
envId: resolvedEnvId,
|
|
@@ -201131,27 +201316,33 @@ async function getCloudBaseManager(options = {}) {
|
|
|
201131
201316
|
}
|
|
201132
201317
|
const { envId: loginEnvId, secretId, secretKey, token } = loginState;
|
|
201133
201318
|
let finalEnvId = cloudBaseOptions?.envId;
|
|
201319
|
+
let envSource = finalEnvId ? "cloudBaseOptions" : undefined;
|
|
201134
201320
|
if (requireEnvId) {
|
|
201135
201321
|
if (!finalEnvId) {
|
|
201136
|
-
|
|
201137
|
-
|
|
201138
|
-
|
|
201139
|
-
const cachedEnvId = envManager.getCachedEnvId() || process.env.CLOUDBASE_ENV_ID;
|
|
201140
|
-
const projectEnvId = cachedEnvId ? undefined : (0, project_config_js_1.readProjectEnvId)();
|
|
201322
|
+
const cachedEnvId = envManager.getCachedEnvId();
|
|
201323
|
+
const envFromProcess = process.env.CLOUDBASE_ENV_ID;
|
|
201324
|
+
const projectEnvId = (cachedEnvId || envFromProcess) ? undefined : (0, project_config_js_1.readProjectEnvId)();
|
|
201141
201325
|
if (cachedEnvId) {
|
|
201142
201326
|
(0, logger_js_1.debug)('使用 envManager 缓存的环境ID:', { cachedEnvId });
|
|
201143
201327
|
finalEnvId = cachedEnvId;
|
|
201328
|
+
envSource = "envManager.cachedEnvId";
|
|
201329
|
+
}
|
|
201330
|
+
else if (envFromProcess) {
|
|
201331
|
+
(0, logger_js_1.debug)('使用进程环境变量的环境ID:', { envId: envFromProcess });
|
|
201332
|
+
finalEnvId = envFromProcess;
|
|
201333
|
+
envSource = "process.env.CLOUDBASE_ENV_ID";
|
|
201144
201334
|
}
|
|
201145
201335
|
else if (projectEnvId) {
|
|
201146
|
-
//
|
|
201336
|
+
// Project binding stays ahead of the account login env.
|
|
201147
201337
|
(0, logger_js_1.debug)('使用项目配置(project.json/cloudbaserc.json)的环境ID:', { projectEnvId });
|
|
201148
201338
|
await envManager.setEnvId(projectEnvId);
|
|
201149
201339
|
finalEnvId = projectEnvId;
|
|
201340
|
+
envSource = "project";
|
|
201150
201341
|
}
|
|
201151
201342
|
else if (loginEnvId) {
|
|
201152
|
-
// If no cache but loginState has envId, use it directly
|
|
201153
201343
|
(0, logger_js_1.debug)('使用 loginState 中的环境ID:', { loginEnvId });
|
|
201154
201344
|
finalEnvId = loginEnvId;
|
|
201345
|
+
envSource = "login_state";
|
|
201155
201346
|
}
|
|
201156
201347
|
else {
|
|
201157
201348
|
if (authStrategy === 'fail_fast') {
|
|
@@ -201160,6 +201351,7 @@ async function getCloudBaseManager(options = {}) {
|
|
|
201160
201351
|
const singleEnvId = envCandidates[0].envId;
|
|
201161
201352
|
await envManager.setEnvId(singleEnvId);
|
|
201162
201353
|
finalEnvId = singleEnvId;
|
|
201354
|
+
envSource = "auto_bound";
|
|
201163
201355
|
(0, logger_js_1.debug)('自动绑定唯一环境:', { envId: singleEnvId });
|
|
201164
201356
|
}
|
|
201165
201357
|
else {
|
|
@@ -201167,14 +201359,19 @@ async function getCloudBaseManager(options = {}) {
|
|
|
201167
201359
|
}
|
|
201168
201360
|
}
|
|
201169
201361
|
else {
|
|
201170
|
-
// ensure 模式下也保持非交互:单环境自动绑定,多环境返回 ENV_REQUIRED
|
|
201171
201362
|
finalEnvId = await envManager.getEnvId();
|
|
201363
|
+
envSource = "auto_bound";
|
|
201172
201364
|
}
|
|
201173
201365
|
}
|
|
201174
201366
|
}
|
|
201175
201367
|
}
|
|
201176
|
-
// envId priority: explicit option > envManager cache > loginState.envId
|
|
201177
201368
|
const resolvedEnvId = finalEnvId || loginEnvId;
|
|
201369
|
+
if (!envSource && resolvedEnvId && resolvedEnvId === loginEnvId) {
|
|
201370
|
+
envSource = "login_state";
|
|
201371
|
+
}
|
|
201372
|
+
if (resolvedEnvId && envSource) {
|
|
201373
|
+
(0, env_binding_js_1.noteEnvBinding)({ envId: resolvedEnvId, source: envSource });
|
|
201374
|
+
}
|
|
201178
201375
|
// region 直接使用 fallbackRegion(resolveSiteAndRegion 统一解析)
|
|
201179
201376
|
// 不再通过 DescribeEnvs 查询 region,以兼容 STS 临时密钥场景
|
|
201180
201377
|
const region = fallbackRegion;
|
|
@@ -201905,6 +202102,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
201905
202102
|
exports.handleHostedMcpRequest = handleHostedMcpRequest;
|
|
201906
202103
|
const streamableHttp_js_1 = __webpack_require__(52827);
|
|
201907
202104
|
const server_js_1 = __webpack_require__(46324);
|
|
202105
|
+
const env_binding_js_1 = __webpack_require__(61498);
|
|
201908
202106
|
const feedback_session_js_1 = __webpack_require__(23379);
|
|
201909
202107
|
const client_info_cache_js_1 = __webpack_require__(65454);
|
|
201910
202108
|
function readInitializeClientInfo(body) {
|
|
@@ -201982,36 +202180,42 @@ async function handleHostedMcpRequest(input) {
|
|
|
201982
202180
|
const closeBoth = () => {
|
|
201983
202181
|
void Promise.allSettled([transport?.close(), server?.close()]);
|
|
201984
202182
|
};
|
|
202183
|
+
const injectedEnvId = input.serverOptions.cloudBaseOptions?.envId;
|
|
202184
|
+
const requestSlot = {
|
|
202185
|
+
binding: injectedEnvId
|
|
202186
|
+
? { envId: injectedEnvId, source: "cloudBaseOptions" }
|
|
202187
|
+
: null,
|
|
202188
|
+
};
|
|
201985
202189
|
try {
|
|
201986
|
-
|
|
201987
|
-
|
|
201988
|
-
|
|
201989
|
-
|
|
201990
|
-
|
|
201991
|
-
|
|
201992
|
-
|
|
201993
|
-
|
|
201994
|
-
|
|
201995
|
-
|
|
201996
|
-
|
|
201997
|
-
|
|
201998
|
-
|
|
201999
|
-
|
|
202000
|
-
|
|
202001
|
-
|
|
202002
|
-
|
|
202003
|
-
|
|
202004
|
-
|
|
202005
|
-
|
|
202006
|
-
|
|
202007
|
-
|
|
202008
|
-
|
|
202009
|
-
|
|
202190
|
+
await (0, env_binding_js_1.runWithEnvSlot)(requestSlot, async () => {
|
|
202191
|
+
server = await (0, server_js_1.createCloudBaseMcpServer)({
|
|
202192
|
+
name: input.serverOptions.name,
|
|
202193
|
+
version: input.serverOptions.version,
|
|
202194
|
+
enableTelemetry: input.serverOptions.enableTelemetry,
|
|
202195
|
+
cloudBaseOptions: input.serverOptions.cloudBaseOptions,
|
|
202196
|
+
cloudMode: input.serverOptions.cloudMode ?? true,
|
|
202197
|
+
ide: input.serverOptions.ide,
|
|
202198
|
+
client: input.serverOptions.client,
|
|
202199
|
+
clientInfo,
|
|
202200
|
+
// Session id comes from this transport. Stateless mode leaves it undefined.
|
|
202201
|
+
getSessionId: () => transport?.sessionId,
|
|
202202
|
+
lang: input.serverOptions.lang,
|
|
202203
|
+
pluginsEnabled: input.serverOptions.pluginsEnabled,
|
|
202204
|
+
pluginsDisabled: input.serverOptions.pluginsDisabled,
|
|
202205
|
+
});
|
|
202206
|
+
input.logger?.({
|
|
202207
|
+
type: "cloudbase-mcp-server-create",
|
|
202208
|
+
timeCost: Date.now() - startedAt,
|
|
202209
|
+
});
|
|
202210
|
+
transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
202211
|
+
sessionIdGenerator: undefined,
|
|
202212
|
+
enableJsonResponse: true,
|
|
202213
|
+
});
|
|
202214
|
+
input.res.on("close", closeBoth);
|
|
202215
|
+
input.req.on("aborted", closeBoth);
|
|
202216
|
+
await server.connect(transport);
|
|
202217
|
+
await transport.handleRequest(input.req, input.res, input.body);
|
|
202010
202218
|
});
|
|
202011
|
-
input.res.on("close", closeBoth);
|
|
202012
|
-
input.req.on("aborted", closeBoth);
|
|
202013
|
-
await server.connect(transport);
|
|
202014
|
-
await transport.handleRequest(input.req, input.res, input.body);
|
|
202015
202219
|
}
|
|
202016
202220
|
catch (error) {
|
|
202017
202221
|
await Promise.allSettled([transport?.close(), server?.close()]);
|
|
@@ -202665,7 +202869,7 @@ exports.cloudrun = (0, types_js_1.defineModule)({
|
|
|
202665
202869
|
"error.envNotInitialized": "当前环境({envId})尚未初始化云托管(CloudRun Env)。不能直接创建服务(CreateCloudRunServer 在无大租户记录时会默认创建到小租户,产生错误的小租户服务与版本)。\n请先开通云托管环境,再重试部署:\n- MCP:manageCloudRun(action=\"initEnv\", envId=\"{envId}\")(异步开通,幂等;开通完成后可用 queryCloudRun(action=\"envStatus\", envId=\"{envId}\") 查询 Status=normal)\n- 或控制台:环境 → 云托管 → 开通(https://tcb.cloud.tencent.com/dev?envId={envId}#/platform-run)\n初始化完成后重新调用 manageCloudRun(action=\"deploy\")。",
|
|
202666
202870
|
"error.actionFailed": "[{context}] {baseMessage}",
|
|
202667
202871
|
"error.buildManage": "[manageCloudRun/{action}] {baseMessage}\n建议:{suggestions}",
|
|
202668
|
-
"error.deployTaskRunning": "服务 `{serverName}`
|
|
202872
|
+
"error.deployTaskRunning": "服务 `{serverName}` 当前已有部署任务在执行。**不要再发起 deploy**:先用 queryCloudRun(action=\"getManageTask\", serverName=\"{serverName}\") 读取该任务的真实状态——已结束就重新部署,长时间停在非终态则带上该输出联系 CloudBase 平台排查。",
|
|
202669
202873
|
"error.deployTaskRunningForce": "注意:`force=true` 仅跳过本工具的确认提示,不会取消或覆盖平台上的发布任务。请先用 queryCloudRun(action=\"getManageTask\", serverName=\"{serverName}\") 确认任务真实状态:若任务已结束却仍报此错,或任务长时间停在非终态,请携带该输出联系 CloudBase 平台排查该环境的发布任务。",
|
|
202670
202874
|
"error.vpcRequired": "CreateCloudRunServer 需要有效 VPC:请传 serverConfig.VpcConf(VpcId+SubnetId),或在 initEnv 时传入 vpcId/subnetIds(环境开通后 deploy 会自动从 EnvBaseInfo 回填)。若平台拒绝系统创建网络,必须指定上海地域 VPC。",
|
|
202671
202875
|
"error.genericRetry": "请检查服务状态、部署参数和目标目录后重试。",
|
|
@@ -202855,7 +203059,7 @@ exports.cloudrun = (0, types_js_1.defineModule)({
|
|
|
202855
203059
|
"error.envNotInitialized": "The current environment ({envId}) has not initialized CloudRun (CloudRun Env). You cannot create services directly (without a large-tenant record, CreateCloudRunServer defaults to the small tenant, producing wrong small-tenant services and versions).\nProvision the CloudRun env first, then retry the deploy:\n- MCP: manageCloudRun(action=\"initEnv\", envId=\"{envId}\") (async, idempotent; once done, query Status=normal via queryCloudRun(action=\"envStatus\", envId=\"{envId}\"))\n- Or console: Environment → CloudRun → Provision (https://tcb.cloud.tencent.com/dev?envId={envId}#/platform-run)\nAfter initialization, call manageCloudRun(action=\"deploy\") again.",
|
|
202856
203060
|
"error.actionFailed": "[{context}] {baseMessage}",
|
|
202857
203061
|
"error.buildManage": "[manageCloudRun/{action}] {baseMessage}\nSuggestions: {suggestions}",
|
|
202858
|
-
"error.deployTaskRunning": "Service `{serverName}` already has a deploy task running.
|
|
203062
|
+
"error.deployTaskRunning": "Service `{serverName}` already has a deploy task running. Do NOT call deploy again: first read the real task state with queryCloudRun(action=\"getManageTask\", serverName=\"{serverName}\") - redeploy once it has finished, or contact the CloudBase platform with that output if it stays in a non-terminal state for a long time.",
|
|
202859
203063
|
"error.deployTaskRunningForce": "Note: `force=true` only skips this tool's confirmation prompt; it does not cancel or override the platform-side deploy task. First confirm the real task state with queryCloudRun(action=\"getManageTask\", serverName=\"{serverName}\"): if the task has already finished but this error persists, or it stays in a non-terminal state for a long time, contact the CloudBase platform with that output to investigate this environment's deploy task.",
|
|
202860
203064
|
"error.vpcRequired": "CreateCloudRunServer requires a valid VPC: pass serverConfig.VpcConf (VpcId+SubnetId), or pass vpcId/subnetIds during initEnv (after provisioning, deploy auto-fills from EnvBaseInfo). If the platform rejects system-created networks, you must specify a Shanghai-region VPC.",
|
|
202861
203065
|
"error.genericRetry": "Check the service status, deploy parameters, and target directory, then retry.",
|
|
@@ -204459,9 +204663,12 @@ exports.env = (0, types_js_1.defineModule)({
|
|
|
204459
204663
|
"auth.envReadyWithHint": "环境设置成功,当前环境: {envId}{regionHint}",
|
|
204460
204664
|
"auth.regionHint": ",地域: {region}",
|
|
204461
204665
|
"auth.regionHintUnverified": "。未在当前探测地域中确认该 envId,已按唯一 ID 直绑;若后续接口仍指向错误地域,请设置 TCB_REGION 或 queryEnv(action=\"list\", region=...)",
|
|
204462
|
-
"auth.logoutNotAllowedApiKey": "
|
|
204666
|
+
"auth.logoutNotAllowedApiKey": "当前是 API Key 认证模式,凭据来自环境变量 {varName}。这个变量不是本进程设的、也不由本进程清除,所以没有执行登出。要切换认证方式:在 shell 里 unset {varName},或从启动本 MCP 的客户端配置里移除它,然后重启。",
|
|
204463
204667
|
"auth.logoutConfirmRequired": "action=logout 时必须传 confirm=\"yes\"",
|
|
204464
204668
|
"auth.loggedOut": "✅ 已退出登录",
|
|
204669
|
+
"auth.loggedOutProject": "✅ 已移除本项目的 API Key 登录。这台机器上若还有账号登录,它仍然有效;要一起退出请再执行一次 logout。",
|
|
204670
|
+
"auth.apiKeySwitchHintRemovable": "如需改用账号登录,先执行 logout 退出本项目 API Key,再 start_auth 授权。",
|
|
204671
|
+
"auth.apiKeySwitchHintExternal": "这个 key 来自外部环境变量,MCP 无法退出它;如需改用账号登录,先在 shell 或客户端配置里移除 {varName} 并重启。",
|
|
204465
204672
|
"auth.tempCredNotLoggedIn": "当前未登录,请先完成管理端认证后再获取临时密钥。",
|
|
204466
204673
|
"auth.tempCredConfirmRequired": "action=get_temp_credentials 时必须显式传 confirm=\"yes\",以确认你要导出当前管理端临时密钥。",
|
|
204467
204674
|
"auth.tempCredUnsupportedType": "当前登录态不是可导出的临时密钥。仅支持通过 Web / device 登录得到的临时密钥,永久密钥登录不允许导出。",
|
|
@@ -204722,9 +204929,12 @@ exports.env = (0, types_js_1.defineModule)({
|
|
|
204722
204929
|
"auth.envReadyWithHint": "Environment bound successfully. Current env: {envId}{regionHint}",
|
|
204723
204930
|
"auth.regionHint": ", region: {region}",
|
|
204724
204931
|
"auth.regionHintUnverified": ". This envId was not confirmed in the probed regions, so it was bound directly by its unique ID; if later APIs still target the wrong region, set TCB_REGION or use queryEnv(action=\"list\", region=...)",
|
|
204725
|
-
"auth.logoutNotAllowedApiKey": "API Key authentication mode is in use and
|
|
204932
|
+
"auth.logoutNotAllowedApiKey": "API Key authentication mode is in use, and the credential comes from the {varName} environment variable. This process neither set nor can remove that variable, so logout was skipped. To switch authentication methods, unset {varName} in your shell or remove it from the MCP client configuration, then restart.",
|
|
204726
204933
|
"auth.logoutConfirmRequired": "confirm=\"yes\" must be passed when action=logout",
|
|
204727
204934
|
"auth.loggedOut": "✅ Logged out",
|
|
204935
|
+
"auth.loggedOutProject": "✅ Removed this project's API Key login. An account login on this machine is still active; call logout again to sign out of it.",
|
|
204936
|
+
"auth.apiKeySwitchHintRemovable": "To switch to account login, run logout to remove this project's API Key, then start_auth.",
|
|
204937
|
+
"auth.apiKeySwitchHintExternal": "This key comes from an external environment variable and cannot be removed by MCP. To switch to account login, unset {varName} in your shell or client configuration and restart.",
|
|
204728
204938
|
"auth.tempCredNotLoggedIn": "Not logged in. Complete management-plane authentication before fetching temporary credentials.",
|
|
204729
204939
|
"auth.tempCredConfirmRequired": "confirm=\"yes\" must be passed explicitly when action=get_temp_credentials, to confirm that you want to export the current management-plane temporary credentials.",
|
|
204730
204940
|
"auth.tempCredUnsupportedType": "The current login state is not an exportable temporary credential. Only temporary credentials obtained via Web / device login are supported; permanent key logins cannot be exported.",
|
|
@@ -205103,9 +205313,12 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205103
205313
|
"\n- `limit`: 分页数量,默认值由后端决定" +
|
|
205104
205314
|
"\n- `offset`: 分页偏移,从 0 开始" +
|
|
205105
205315
|
"\n- 示例:`queryFunctions(action=\"listFunctions\", offset=10, limit=10)`" +
|
|
205106
|
-
"\n\n**查询 CloudBase
|
|
205316
|
+
"\n\n**查询 CloudBase 云函数日志**:`action=\"listFunctionLogs\"`,需要提供 `functionName`。日志从 CLS 检索(底层 GetFunctionLogs 接口已下线)。" +
|
|
205107
205317
|
"\n- 示例:`queryFunctions(action=\"listFunctionLogs\", functionName=\"my-function\")`" +
|
|
205108
|
-
"\n-
|
|
205318
|
+
"\n- 不传 startTime/endTime 时默认查最近 1 天;跨度不能超过 1 天,单次最多返回 100 条" +
|
|
205319
|
+
"\n- 返回 `hasMore=true` 表示还有更早的日志:把返回的 `context` 原样传回取下一页(`offset` 只在前 100 条内生效)" +
|
|
205320
|
+
"\n- `logs[]` 已解析成 requestId / log / statusCode / retCode / durationMs / memoryMb / timestamp" +
|
|
205321
|
+
"\n- 想看某一次调用的完整过程(START、业务日志、REPORT):`queryFunctions(action=\"getFunctionLogDetail\", requestId=\"xxx\")`" +
|
|
205109
205322
|
"\n\n**定时任务 / cron / 定时跑**:使用 `listFunctionTriggers` 查询函数的 timer 触发器配置。" +
|
|
205110
205323
|
"\n\n**版本与流量路由**:`listVersionByFunction` 列出已发布版本(对齐 tcb fn list-function-versions);`getFunctionAlias` 查看别名/灰度配置(对齐 tcb fn get-route,aliasName 默认 `$DEFAULT`)。" +
|
|
205111
205324
|
"\n\n**层(Layer)说明**:" +
|
|
@@ -205175,8 +205388,8 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205175
205388
|
endTimeInvalid: "endTime 格式错误: \"{value}\"。必须使用 YYYY-MM-DD HH:mm:ss 格式(如 2024-01-01 23:59:59)",
|
|
205176
205389
|
logRangeInvalidDatetime: "startTime 和 endTime 必须是有效的日期时间字符串",
|
|
205177
205390
|
logRangeTooLong: "startTime 和 endTime 间隔不能超过一天",
|
|
205178
|
-
logsInvalidParamTips: "常见原因:\n1. startTime/endTime 格式错误,必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 00:00:00),不支持 ISO 8601 或时间戳\n2. startTime 和 endTime 间隔超过一天\n3. functionName
|
|
205179
|
-
logDetailInvalidParamTips: "常见原因:\n1. startTime/endTime 格式错误,必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 00:00:00),不支持 ISO 8601 或时间戳\n2. startTime 和 endTime 间隔超过一天\n
|
|
205391
|
+
logsInvalidParamTips: "常见原因:\n1. startTime/endTime 格式错误,必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 00:00:00),不支持 ISO 8601 或时间戳\n2. startTime 和 endTime 间隔超过一天\n3. functionName 与日志里的 function_name 不一致(大小写敏感),或 qualifier 不匹配\n建议:不传 startTime/endTime 时默认查询最近一天的日志。",
|
|
205392
|
+
logDetailInvalidParamTips: "常见原因:\n1. startTime/endTime 格式错误,必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 00:00:00),不支持 ISO 8601 或时间戳\n2. startTime 和 endTime 间隔超过一天\n3. requestId 不在该时间窗口内(日志按请求开始时间归档)\n建议:先用 listFunctionLogs 定位到 requestId 再查详情。",
|
|
205180
205393
|
paramRequired: "{action} 操作时,{param} 参数是必需的",
|
|
205181
205394
|
"deployStatus.cloudMode": "{action} 在 cloud mode 下不可用:异步部署任务只由 buildStrategy=cloud/local 的真实部署创建,而这两种策略的真实执行在 cloud mode 下都不支持(需要读取本地构建上下文或本地 Docker),因此不会存在任何 taskId。buildStrategy=image 走同步部署,直接在 manageFunctions 的返回里拿结果,也不需要查询部署状态。如需异步镜像构建部署,请改用本地 MCP 模式。",
|
|
205182
205395
|
deployTaskNotFound: "未找到部署任务 {taskId};部署任务不存在,可能已过期、不属于当前环境 {envId},或 MCP Server 已重启(任务仅保存在 MCP 进程内存中)。",
|
|
@@ -205191,7 +205404,11 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205191
205404
|
"reason.viewLogs": "查看该函数的执行日志",
|
|
205192
205405
|
"reason.updateConfig": "更新该函数配置",
|
|
205193
205406
|
"reason.checkGateway": "查看该函数是否已暴露网关访问入口",
|
|
205194
|
-
"reason.logDetail": "按 requestId
|
|
205407
|
+
"reason.logDetail": "按 requestId 查看该次调用的完整日志",
|
|
205408
|
+
"reason.nextLogPage": "带上 context 取下一页(更早的)日志",
|
|
205409
|
+
"reason.widenLogRange": "放宽时间范围后重新查询该函数的日志",
|
|
205410
|
+
"reason.createLogService": "开通环境日志服务后再查询函数日志",
|
|
205411
|
+
"reason.searchClsFallback": "改用 queryLogs 直接按同一条 CLS 语句检索",
|
|
205195
205412
|
"reason.attachLayer": "为该函数追加绑定层",
|
|
205196
205413
|
"reason.reorderLayers": "整体调整层顺序或绑定列表",
|
|
205197
205414
|
"reason.layerVersions": "查看某个层的版本列表",
|
|
@@ -205236,6 +205453,10 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205236
205453
|
gotFunctionDetail: "已获取函数 {fnName} 的详情",
|
|
205237
205454
|
gotFunctionLogs: "已获取函数 {fnName} 的日志列表",
|
|
205238
205455
|
gotLogDetail: "已获取 requestId={requestId} 的日志详情",
|
|
205456
|
+
"logs.emptyByFunction": "在 {start} ~ {end} 之间没有查到函数 {fnName} 的日志。常见原因:该时间段内函数没有被调用、日志已过保留期、或 functionName / qualifier 不匹配。可以放宽时间范围后重试。",
|
|
205457
|
+
"logs.emptyByRequest": "在 {start} ~ {end} 之间没有查到 requestId={requestId} 的日志。请确认时间范围覆盖了这次调用(日志按请求开始时间归档),或先用 listFunctionLogs 定位到的 requestId。",
|
|
205458
|
+
"logs.serviceNotEnabled": "当前环境还没有开通日志服务,云函数日志查不到。请先调用 manageLogs(action=\"createLogService\", confirm=true) 开通,再重新查询。",
|
|
205459
|
+
"logs.queryFailed": "查询云函数日志失败:{message}",
|
|
205239
205460
|
gotFunctionLayers: "已获取函数 {fnName} 当前绑定的层",
|
|
205240
205461
|
gotLayers: "已获取 {count} 条层记录",
|
|
205241
205462
|
gotLayerVersions: "已获取层 {layerName} 的版本列表",
|
|
@@ -205316,16 +205537,17 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205316
205537
|
"schema.create.layers": "Layer 配置",
|
|
205317
205538
|
"schema.manageLayer.name": "层名称",
|
|
205318
205539
|
"schema.manageLayer.version": "层版本号",
|
|
205319
|
-
"schema.query.action": "只读操作类型:\n- `listFunctions`: 列出所有 CloudBase 云函数\n- `getFunctionDetail`: 获取 CloudBase 云函数详情(需要 functionName)\n- `listFunctionLogs`:
|
|
205540
|
+
"schema.query.action": "只读操作类型:\n- `listFunctions`: 列出所有 CloudBase 云函数\n- `getFunctionDetail`: 获取 CloudBase 云函数详情(需要 functionName)\n- `listFunctionLogs`: 查询云函数执行日志(需要 functionName;走 CLS 检索,默认最近 1 天,单次最多 100 条,翻页传 context)\n- `getFunctionLogDetail`: 获取某次调用的完整日志序列(需要 requestId,取自 listFunctionLogs 的 logs[].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 含凭据签名,不得写入日志或持久化;阶段 B 会校验三元组的桶与地域必须是本环境自有存储桶,因此该地址只能用于取到它的那个环境;地址默认 300 秒内有效",
|
|
205320
205541
|
"schema.query.functionName": "CloudBase 云函数名称。`getFunctionDetail`、`listFunctionLogs`、`listFunctionLayers`、`listFunctionTriggers`、`getFunctionDownloadUrl`、`listVersionByFunction`、`getFunctionAlias` 时必填;`getFunctionUploadUrl` 可选(仅用于生成上传对象 key)",
|
|
205321
|
-
"schema.query.limit": "分页数量(limit)。列表类 action
|
|
205322
|
-
"schema.query.offset": "分页偏移(offset)。列表类 action 可选,默认 0",
|
|
205542
|
+
"schema.query.limit": "分页数量(limit)。列表类 action 可选,默认值由后端决定;日志类 action 单次最多 100 条,默认 20",
|
|
205543
|
+
"schema.query.offset": "分页偏移(offset)。列表类 action 可选,默认 0。日志类 action 只在前 100 条内生效,更早的日志请用返回的 context 翻页",
|
|
205323
205544
|
"schema.query.codeSecret": "代码保护密钥,用于解密函数代码",
|
|
205324
205545
|
"schema.query.revealEnvValues": "getFunctionDetail / listFunctionTriggers / listFunctionLayers 时是否返回环境变量明文值。默认 false:Value 脱敏为 ***,仅保留 Key 与 ValueLength,足以确认配置了哪些变量及变更是否生效;true 时返回明文,敏感变量会进入模型上下文,谨慎使用。如需查看明文,建议优先使用控制台或 CLI",
|
|
205325
|
-
"schema.query.startTime": "日志查询开始时间,格式必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 00:00:00
|
|
205326
|
-
"schema.query.endTime": "日志查询结束时间,格式必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 23:59:59
|
|
205327
|
-
"schema.query.requestId": "日志请求 ID。`getFunctionLogDetail`
|
|
205328
|
-
"schema.query.qualifier": "函数版本别名,如 $LATEST、$DEFAULT
|
|
205546
|
+
"schema.query.startTime": "日志查询开始时间,格式必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 00:00:00,按北京时间理解)。与 endTime 间隔不能超过一天。不传时默认查询最近一天",
|
|
205547
|
+
"schema.query.endTime": "日志查询结束时间,格式必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 23:59:59,按北京时间理解)。与 startTime 间隔不能超过一天。不传时默认为当前时间",
|
|
205548
|
+
"schema.query.requestId": "日志请求 ID。`getFunctionLogDetail` 操作必填;取自 `listFunctionLogs` 返回的 logs[].requestId,也可传具体业务日志里出现的 RequestId",
|
|
205549
|
+
"schema.query.qualifier": "函数版本别名,如 $LATEST、$DEFAULT。日志查询时可选,作为 CLS 检索条件",
|
|
205550
|
+
"schema.query.context": "日志翻页游标。把上一次 `listFunctionLogs` 返回的 `context` 原样传回即可取下一页;不要自己构造,null 表示没有更多",
|
|
205329
205551
|
"schema.query.runtime": "层查询的运行时筛选,如 Nodejs18.15",
|
|
205330
205552
|
"schema.query.searchKey": "层名称搜索关键字",
|
|
205331
205553
|
"schema.query.layerName": "层名称。`listLayerVersions`、`getLayerVersionDetail` 操作必填。层为账号级共享命名空间;推荐固定格式 `{layerName}_{当前envId}`(如 common_cloud1-d9ghadgak3edf6b36)",
|
|
@@ -205384,9 +205606,12 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205384
205606
|
"\n- `limit`: page size, the default is decided by the backend" +
|
|
205385
205607
|
"\n- `offset`: pagination offset, starting from 0" +
|
|
205386
205608
|
"\n- Example: `queryFunctions(action=\"listFunctions\", offset=10, limit=10)`" +
|
|
205387
|
-
"\n\n**Querying cloud function logs**: use `action=\"listFunctionLogs\"`, which requires
|
|
205609
|
+
"\n\n**Querying cloud function logs**: use `action=\"listFunctionLogs\"`, which requires `functionName`. Logs are retrieved from CLS (the underlying GetFunctionLogs API has been retired)." +
|
|
205388
205610
|
"\n- Example: `queryFunctions(action=\"listFunctionLogs\", functionName=\"my-function\")`" +
|
|
205389
|
-
"\n-
|
|
205611
|
+
"\n- Without startTime/endTime it queries the last day; the span must not exceed 1 day and a single call returns at most 100 entries" +
|
|
205612
|
+
"\n- `hasMore=true` means older logs exist: pass the returned `context` back unchanged to fetch the next page (`offset` only works within the first 100 entries)" +
|
|
205613
|
+
"\n- Each `logs[]` item is parsed into requestId / log / statusCode / retCode / durationMs / memoryMb / timestamp" +
|
|
205614
|
+
"\n- To see the full sequence of one invocation (START, business logs, REPORT): `queryFunctions(action=\"getFunctionLogDetail\", requestId=\"xxx\")`" +
|
|
205390
205615
|
"\n\n**Scheduled tasks / cron / timers**: use `listFunctionTriggers` to query a function's timer trigger configuration." +
|
|
205391
205616
|
"\n\n**Versions and traffic routing**: `listVersionByFunction` lists published versions (aligns with tcb fn list-function-versions); `getFunctionAlias` views alias / canary config (aligns with tcb fn get-route; aliasName defaults to `$DEFAULT`)." +
|
|
205392
205617
|
"\n\n**Layers**:" +
|
|
@@ -205456,8 +205681,8 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205456
205681
|
endTimeInvalid: "Invalid endTime: \"{value}\". It must use the YYYY-MM-DD HH:mm:ss format (e.g. 2024-01-01 23:59:59)",
|
|
205457
205682
|
logRangeInvalidDatetime: "startTime and endTime must be valid datetime strings",
|
|
205458
205683
|
logRangeTooLong: "The interval between startTime and endTime must not exceed one day",
|
|
205459
|
-
logsInvalidParamTips: "Common causes:\n1. startTime/endTime format error; it must be YYYY-MM-DD HH:mm:ss (e.g. 2024-01-01 00:00:00); ISO 8601 or timestamps are not supported\n2. The interval between startTime and endTime exceeds one day\n3. functionName does not
|
|
205460
|
-
logDetailInvalidParamTips: "Common causes:\n1. startTime/endTime format error; it must be YYYY-MM-DD HH:mm:ss (e.g. 2024-01-01 00:00:00); ISO 8601 or timestamps are not supported\n2. The interval between startTime and endTime exceeds one day\
|
|
205684
|
+
logsInvalidParamTips: "Common causes:\n1. startTime/endTime format error; it must be YYYY-MM-DD HH:mm:ss (e.g. 2024-01-01 00:00:00); ISO 8601 or timestamps are not supported\n2. The interval between startTime and endTime exceeds one day\n3. functionName does not match function_name in the logs (case-sensitive), or qualifier does not match\nTip: without startTime/endTime, logs from the most recent day are queried by default.",
|
|
205685
|
+
logDetailInvalidParamTips: "Common causes:\n1. startTime/endTime format error; it must be YYYY-MM-DD HH:mm:ss (e.g. 2024-01-01 00:00:00); ISO 8601 or timestamps are not supported\n2. The interval between startTime and endTime exceeds one day\n3. requestId falls outside that window (logs are filed by request start time)\nTip: locate the requestId with listFunctionLogs first.",
|
|
205461
205686
|
paramRequired: "The {param} parameter is required for the {action} action",
|
|
205462
205687
|
"deployStatus.cloudMode": "{action} is unavailable in cloud mode: async deployment tasks are only created by real deployments with buildStrategy=cloud/local, and real execution of both strategies is unsupported in cloud mode (they need the local build context or local Docker), so no taskId can exist. buildStrategy=image uses synchronous deployment and returns the result directly from manageFunctions, so no deployment status query is needed. For async image build deployment, switch to local MCP mode.",
|
|
205463
205688
|
deployTaskNotFound: "Deployment task {taskId} not found; the task does not exist — it may have expired, belong to a different environment than {envId}, or the MCP Server was restarted (tasks are only kept in MCP process memory).",
|
|
@@ -205472,7 +205697,11 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205472
205697
|
"reason.viewLogs": "View the execution logs of this function",
|
|
205473
205698
|
"reason.updateConfig": "Update this function's configuration",
|
|
205474
205699
|
"reason.checkGateway": "Check whether this function has an exposed gateway access URL",
|
|
205475
|
-
"reason.logDetail": "View
|
|
205700
|
+
"reason.logDetail": "View the full logs of that invocation by requestId",
|
|
205701
|
+
"reason.nextLogPage": "Pass context back to fetch the next (older) page of logs",
|
|
205702
|
+
"reason.widenLogRange": "Query this function's logs again with a wider time range",
|
|
205703
|
+
"reason.createLogService": "Enable the environment log service before querying function logs",
|
|
205704
|
+
"reason.searchClsFallback": "Search CLS directly with queryLogs using the same query string",
|
|
205476
205705
|
"reason.attachLayer": "Attach an additional layer to this function",
|
|
205477
205706
|
"reason.reorderLayers": "Adjust layer order or the binding list as a whole",
|
|
205478
205707
|
"reason.layerVersions": "View the version list of a layer",
|
|
@@ -205517,6 +205746,10 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205517
205746
|
gotFunctionDetail: "Retrieved details of function {fnName}",
|
|
205518
205747
|
gotFunctionLogs: "Retrieved the log list of function {fnName}",
|
|
205519
205748
|
gotLogDetail: "Retrieved the log detail for requestId={requestId}",
|
|
205749
|
+
"logs.emptyByFunction": "No logs found for function {fnName} between {start} and {end}. Common causes: the function was not invoked in that window, the logs have passed their retention period, or functionName / qualifier does not match. Widen the time range and retry.",
|
|
205750
|
+
"logs.emptyByRequest": "No logs found for requestId={requestId} between {start} and {end}. Make sure the window covers that invocation (logs are filed by request start time), or use a requestId located through listFunctionLogs.",
|
|
205751
|
+
"logs.serviceNotEnabled": "The log service is not enabled for this environment, so function logs cannot be read. Call manageLogs(action=\"createLogService\", confirm=true) first, then query again.",
|
|
205752
|
+
"logs.queryFailed": "Failed to query function logs: {message}",
|
|
205520
205753
|
gotFunctionLayers: "Retrieved the layers currently bound to function {fnName}",
|
|
205521
205754
|
gotLayers: "Retrieved {count} layer records",
|
|
205522
205755
|
gotLayerVersions: "Retrieved the version list of layer {layerName}",
|
|
@@ -205597,16 +205830,17 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
205597
205830
|
"schema.create.layers": "Layer configuration",
|
|
205598
205831
|
"schema.manageLayer.name": "Layer name",
|
|
205599
205832
|
"schema.manageLayer.version": "Layer version number",
|
|
205600
|
-
"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
|
|
205833
|
+
"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; retrieved via CLS, defaults to the last day, at most 100 entries per call, pass context to page)\n- `getFunctionLogDetail`: get the full log sequence of one invocation (requires requestId, taken from logs[].requestId of listFunctionLogs)\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 B verifies that the triplet's bucket and region are this environment's own bucket, so an address is only usable in the environment it was minted for; the address is valid for 300 seconds by default",
|
|
205601
205834
|
"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).",
|
|
205602
|
-
"schema.query.limit": "Page size (limit). Optional for list actions; the backend determines the default.",
|
|
205603
|
-
"schema.query.offset": "Pagination offset. Optional for list actions; defaults to 0.",
|
|
205835
|
+
"schema.query.limit": "Page size (limit). Optional for list actions; the backend determines the default. Log actions return at most 100 entries and default to 20.",
|
|
205836
|
+
"schema.query.offset": "Pagination offset. Optional for list actions; defaults to 0. For log actions it only works within the first 100 entries — use the returned context to page further back.",
|
|
205604
205837
|
"schema.query.codeSecret": "Code protection secret used to decrypt function code.",
|
|
205605
205838
|
"schema.query.revealEnvValues": "Whether `getFunctionDetail` / `listFunctionTriggers` / `listFunctionLayers` returns plaintext environment variable values. Defaults to false: Value is masked as ***, while Key and ValueLength remain, which is sufficient to verify configured variables and changes. true returns plaintext and may expose secrets to the model context; use cautiously. Prefer the console or CLI for plaintext values.",
|
|
205606
|
-
"schema.query.startTime": "Log query start time in YYYY-MM-DD HH:mm:ss format (for example, 2024-01-01 00:00:00). The interval to endTime must not exceed one day. Defaults to the most recent day when omitted.",
|
|
205607
|
-
"schema.query.endTime": "Log query end time in YYYY-MM-DD HH:mm:ss format (for example, 2024-01-01 23:59:59). The interval from startTime must not exceed one day. Defaults to the current time when omitted.",
|
|
205608
|
-
"schema.query.requestId": "Log request ID. Required for `getFunctionLogDetail`;
|
|
205609
|
-
"schema.query.qualifier": "Function version alias, such as $LATEST or $DEFAULT. Optional for log queries.",
|
|
205839
|
+
"schema.query.startTime": "Log query start time in YYYY-MM-DD HH:mm:ss format (for example, 2024-01-01 00:00:00, interpreted as Beijing time). The interval to endTime must not exceed one day. Defaults to the most recent day when omitted.",
|
|
205840
|
+
"schema.query.endTime": "Log query end time in YYYY-MM-DD HH:mm:ss format (for example, 2024-01-01 23:59:59, interpreted as Beijing time). The interval from startTime must not exceed one day. Defaults to the current time when omitted.",
|
|
205841
|
+
"schema.query.requestId": "Log request ID. Required for `getFunctionLogDetail`; take it from logs[].requestId returned by `listFunctionLogs`, or use the RequestId printed in a business log line.",
|
|
205842
|
+
"schema.query.qualifier": "Function version alias, such as $LATEST or $DEFAULT. Optional for log queries; used as a CLS filter.",
|
|
205843
|
+
"schema.query.context": "Log pagination cursor. Pass the `context` returned by the previous `listFunctionLogs` call back unchanged to fetch the next page; never construct it yourself. null means there are no more results.",
|
|
205610
205844
|
"schema.query.runtime": "Runtime filter for layer queries, such as Nodejs18.15.",
|
|
205611
205845
|
"schema.query.searchKey": "Layer name search keyword.",
|
|
205612
205846
|
"schema.query.layerName": "Layer name. Required for `listLayerVersions` and `getLayerVersionDetail`. Layers use an account-level shared namespace; use the fixed format `{layerName}_{current envId}` (for example, common_cloud1-d9ghadgak3edf6b36).",
|
|
@@ -205672,9 +205906,9 @@ exports.gateway = void 0;
|
|
|
205672
205906
|
const types_js_1 = __webpack_require__(89921);
|
|
205673
205907
|
exports.gateway = (0, types_js_1.defineModule)({
|
|
205674
205908
|
"query.title": "查询 CloudBase 网关",
|
|
205675
|
-
"query.description": "CloudBase HTTP 网关统一只读入口(Domain/Route)。查询域名下路径路由及其上游:WEB_SCF/SCF=云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器。主键为 Domain + Path;listRoutes / getRoute / listCustomDomains / getPrivilege。getPrivilege 查询 HTTP 网关总开关(enableService)与访问鉴权(enableAuth
|
|
205909
|
+
"query.description": "CloudBase HTTP 网关统一只读入口(Domain/Route)。查询域名下路径路由及其上游:WEB_SCF/SCF=云函数,CBR=云托管,STATIC_STORE=静态托管,STORAGE=云存储,LH=轻量应用服务器。主键为 Domain + Path;listRoutes / getRoute / listCustomDomains / getPrivilege / cachePurgeTask。getPrivilege 查询 HTTP 网关总开关(enableService)与访问鉴权(enableAuth)状态。cachePurgeTask 查询域名缓存清除任务(先 manageGateway purgeCache 拿 TaskId)。实现自定义域名访问前,先 listCustomDomains:若已有自定义域名,优先 createRoute 挂路由(无需证书 ID);仅在没有可用自定义域名时才 bindCustomDomain。",
|
|
205676
205910
|
"manage.title": "管理 CloudBase 网关",
|
|
205677
|
-
"manage.description": "CloudBase HTTP 网关统一写入口(Domain/Route)。createRoute/updateRoute/deleteRoute 把域名下的 path 转到上游;enableRoute/disableRoute 启用或禁用已有路由(底层 ModifyHTTPServiceRoute 的 Routes[].Enable,不是 ModifyGatewayRoute)。未传 domain 时用 DomainType=HTTPSERVICE 的 IsDefault 默认 HTTP 域名(形如 *.{region}.app.tcloudbase.com),不会使用静态托管 CDN 域名(*.tcloudbaseapp.com,DomainType=STATIC_STORE)。这是网关默认域上的路径路由,不是 STATIC_STORE 上游绑定;STATIC_STORE 上游必须显式传 upstreamResourceType=STATIC_STORE。关闭静态托管默认域名(*.tcloudbaseapp.com):先 queryGateway(listRoutes) 找到 DomainType=STATIC_STORE 且 IsDefault=true 的 domain,再 manageGateway(action=\"disableRoute\", domain=该域名, path=\"/\");勿用 manageHosting。创建后可用 queryGateway(action=\"listRoutes\") 核对 Domain / DomainType / Path / UpstreamResourceType。上游类型只用一个参数 upstreamResourceType(也可写在 route.upstreamResourceType,route 优先):WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器;配合 targetName 或 route.serviceName(云函数名/云托管服务名/静态托管实例名,常见 staticstore
|
|
205911
|
+
"manage.description": "CloudBase HTTP 网关统一写入口(Domain/Route)。createRoute/updateRoute/deleteRoute 把域名下的 path 转到上游;enableRoute/disableRoute 启用或禁用已有路由(底层 ModifyHTTPServiceRoute 的 Routes[].Enable,不是 ModifyGatewayRoute)。未传 domain 时用 DomainType=HTTPSERVICE 的 IsDefault 默认 HTTP 域名(形如 *.{region}.app.tcloudbase.com),不会使用静态托管 CDN 域名(*.tcloudbaseapp.com,DomainType=STATIC_STORE)。这是网关默认域上的路径路由,不是 STATIC_STORE 上游绑定;STATIC_STORE 上游必须显式传 upstreamResourceType=STATIC_STORE。关闭静态托管默认域名(*.tcloudbaseapp.com):先 queryGateway(listRoutes) 找到 DomainType=STATIC_STORE 且 IsDefault=true 的 domain,再 manageGateway(action=\"disableRoute\", domain=该域名, path=\"/\");勿用 manageHosting。创建后可用 queryGateway(action=\"listRoutes\") 核对 Domain / DomainType / Path / UpstreamResourceType。上游类型只用一个参数 upstreamResourceType(也可写在 route.upstreamResourceType,route 优先):WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,STORAGE=云存储,LH=轻量应用服务器;配合 targetName 或 route.serviceName(云函数名/云托管服务名/静态托管实例名,常见 staticstore/云存储实例名)。createRoute 只建网关入口,不改上游权限。enablePathTransmission:默认 false 剥触发路径前缀;true 透传完整路径(CBR 多路由、WEB_SCF 自管子路径常需 true;STATIC_STORE 自定义触发路径映射站点根通常 false)。⚠️ 自定义域名访问:若环境已有自定义域名(先 queryGateway listCustomDomains),优先 createRoute 并显式传入该 domain,无需 certificateId;仅首次绑定全新自定义域名时用 bindCustomDomain(certificateId 可选:未传时按域名自动检索证书,单证书自动选用、多证书返回选择指引)。createRoute / bindCustomDomain 创建前会调用 VerifyHTTPServiceRoute 做归属权等预检(探测→创建);失败时返回 data.checks 与 DNS TXT 指引,配置后重试。CORS/安全域名(浏览器跨域白名单,与本工具的网关自定义域名无关)用 manageEnv(action=addSecurityDomain/removeSecurityDomain)。enableService/authSwitch:HTTP 网关总开关与访问鉴权开关;createRoute 后若访问报 HTTPSERVICE_NONACTIVATED,通常是总开关未开启(用 queryGateway getPrivilege 查询、enableService 开启)。purgeCache:清除域名缓存(CDN/EO,按 URL/前缀/整站),返回 TaskId 后用 queryGateway cachePurgeTask 查进度。路由级还支持 enableSafeDomain(跨域/合法域名校验)、pathRewrite(路径重写)、qpsPolicy(限频)、extension(自定义请求/响应头与缓存规则);域名级支持 protocol 与 domainExtension。updateRoute 只传要改的字段即可,未传的 CORS/重写/限频/扩展配置会保持原值。",
|
|
205678
205912
|
"verify.failWithDns": "HTTP 服务域名配置预检未通过:域名归属权校验失败。请按 data.checks 中 ownership.dnsRecords 配置 DNS TXT 记录后重试。",
|
|
205679
205913
|
"verify.fail": "HTTP 服务域名配置预检未通过。请根据 data.checks 修复问题后重试。",
|
|
205680
205914
|
"verify.failWithDnsReason": "配置 DNS TXT(主机记录/记录类型/记录值见 data.checks[].dnsRecords)后重新调用本 action",
|
|
@@ -205692,7 +205926,7 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205692
205926
|
"privilege.nonActivatedHint": ";若路由创建成功但访问报 HTTPSERVICE_NONACTIVATED(403),请先开启 HTTP 网关",
|
|
205693
205927
|
"privilege.enableServiceReason": "开启 HTTP 网关总开关(EnableService),开启后路由即可通过默认域访问",
|
|
205694
205928
|
"defaultDomain.notReady": "环境默认 HTTP 访问域名未就绪或未开通。请先在控制台开通 HTTP 访问服务,或用 queryGateway(action=\"listRoutes\") 确认 Domains 中是否存在 DomainType=HTTPSERVICE 且 IsDefault=true 的域名(形如 *.{region}.app.tcloudbase.com);不要使用静态托管域名(*.tcloudbaseapp.com)。也可以显式传入 domain 后重试 createRoute/updateRoute/deleteRoute。",
|
|
205695
|
-
"upstreamTypeRequired": "必须提供 upstreamResourceType(或 route.upstreamResourceType):WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器。禁止仅凭 targetName/serviceName 推断上游类型。",
|
|
205929
|
+
"upstreamTypeRequired": "必须提供 upstreamResourceType(或 route.upstreamResourceType):WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,STORAGE=云存储,LH=轻量应用服务器。禁止仅凭 targetName/serviceName 推断上游类型。",
|
|
205696
205930
|
"upstreamNameRequired": "必须提供 targetName 或 route.serviceName 作为上游资源名称:云函数名、云托管服务名,或静态托管实例名(常见为 staticstore)。",
|
|
205697
205931
|
"toggle.pathRequired": "action=enableRoute/disableRoute 时必须提供 path 或 route.path(例如 \"/\" 或 \"/api\")",
|
|
205698
205932
|
"toggle.notFound": "未找到路径 {path} 的路由{domainSuffix}{upstreamSuffix}。请先用 queryGateway(action=\"listRoutes\") 确认 Domain / Path,再调用 enableRoute/disableRoute。关闭静态托管默认域名(*.tcloudbaseapp.com)时,请显式传 domain=该 STATIC_STORE IsDefault 域名,并通常 path=\"/\"。",
|
|
@@ -205758,14 +205992,32 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205758
205992
|
"authSwitch.onMessage": "HTTP 访问服务鉴权开启成功",
|
|
205759
205993
|
"authSwitch.offMessage": "HTTP 访问服务鉴权关闭成功",
|
|
205760
205994
|
"authSwitch.verifyReason": "复核 HTTP 网关总开关与访问鉴权状态",
|
|
205995
|
+
"purgeCache.domainRequired": "action=purgeCache 时必须提供 domain",
|
|
205996
|
+
"purgeCache.targetsRequired": "action=purgeCache 时必须提供 targets:PURGE_URL 传完整 URL、PURGE_PREFIX 传路径前缀、PURGE_HOST 传待刷新的域名",
|
|
205997
|
+
"purgeCache.message": "已提交 {count} 个目标的缓存清除任务;CDN/EO 刷新通常数秒到数分钟,请用 queryGateway(action=\"cachePurgeTask\") 按 TaskId 查进度",
|
|
205998
|
+
"purgeCache.verifyReason": "查询缓存清除任务状态",
|
|
205999
|
+
"query.cachePurgeTask": "已获取 {count} 条缓存清除任务记录",
|
|
206000
|
+
"query.cachePurgeTaskDomainRequired": "action=cachePurgeTask 时必须提供 domain",
|
|
206001
|
+
"cache.domainNotFound": "未找到域名 {domain} 的接入配置,无法确定缓存层。请先用 queryGateway(action=\"listRoutes\") 确认域名。",
|
|
206002
|
+
"cache.notManaged": "域名 {domain} 的接入方式是 {accessType},CloudBase 侧没有该域名的 CDN/EO 缓存,缓存刷新不适用(DIRECT 直连与 CUSTOM 自有 CDN 的缓存不由平台托管)。如需刷新,请先把域名切到 CDN 或 EO 接入。",
|
|
206003
|
+
"cache.typeMismatch": "域名 {domain} 的接入方式是 {accessType},不能按 cacheType={requested} 刷新。省略 cacheType 就会按接入方式自动匹配。",
|
|
205761
206004
|
// Input schema parameter descriptions
|
|
205762
|
-
"schema.query.action": "只读操作类型:listRoutes、getRoute、listCustomDomains、getPrivilege。" +
|
|
206005
|
+
"schema.query.action": "只读操作类型:listRoutes、getRoute、listCustomDomains、getPrivilege、cachePurgeTask。" +
|
|
205763
206006
|
"getPrivilege 无需其他参数,直接返回 HTTP 网关总开关与访问鉴权状态。" +
|
|
206007
|
+
"cachePurgeTask 需要 domain(可选 cacheType/taskId/purgeType/startTime/endTime/offset/limit)。" +
|
|
205764
206008
|
"自定义域名访问场景先 listCustomDomains 确认是否已有域名可复用。",
|
|
205765
206009
|
"schema.query.targetName": "上游资源名过滤(UpstreamResourceName):云函数名、云托管服务名,或静态托管实例名(常见 staticstore)。",
|
|
205766
206010
|
"schema.query.routeId": "路由 ID。getRoute 时可选",
|
|
205767
206011
|
"schema.query.path": "路由路径。getRoute / listRoutes 过滤时可选",
|
|
205768
|
-
"schema.query.domain": "域名。getRoute / listRoutes
|
|
206012
|
+
"schema.query.domain": "域名。getRoute / listRoutes 过滤时可选;cachePurgeTask 时必填",
|
|
206013
|
+
"schema.query.cacheType": "缓存层(仅 cachePurgeTask):CDN 或 EO。省略时按域名接入方式自动匹配(EO→EO、CDN→CDN);" +
|
|
206014
|
+
"DIRECT / CUSTOM / NONE 的域没有 CloudBase 托管的缓存,会直接拒绝并说明原因。",
|
|
206015
|
+
"schema.query.taskId": "缓存清除任务 ID(仅 cachePurgeTask,可选过滤)",
|
|
206016
|
+
"schema.query.purgeType": "清除方式过滤(仅 cachePurgeTask):PURGE_URL=按 URL、PURGE_PREFIX=按前缀、PURGE_HOST=整站",
|
|
206017
|
+
"schema.query.startTime": "任务开始时间(仅 cachePurgeTask,可选)。格式 YYYY-MM-DD HH:mm:ss",
|
|
206018
|
+
"schema.query.endTime": "任务结束时间(仅 cachePurgeTask,可选)。格式 YYYY-MM-DD HH:mm:ss",
|
|
206019
|
+
"schema.query.offset": "分页偏移(仅 cachePurgeTask,可选)",
|
|
206020
|
+
"schema.query.limit": "返回数量上限(仅 cachePurgeTask,可选)",
|
|
205769
206021
|
"schema.manage.action": "写操作:createRoute/updateRoute/deleteRoute 管理路由;enableRoute/disableRoute 启用或禁用已有路由(需 path,建议显式传 domain);" +
|
|
205770
206022
|
"bindCustomDomain/deleteCustomDomain 管理自定义域名;" +
|
|
205771
206023
|
"enableService/authSwitch 开关 HTTP 网关总开关与访问鉴权(需配合 enable 参数)。" +
|
|
@@ -205775,13 +206027,15 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205775
206027
|
"已有自定义域名时优先 createRoute(domain=已有域名) 实现访问,不必再次 bindCustomDomain / 传入 certificateId;" +
|
|
205776
206028
|
"bindCustomDomain 仅用于首次绑定新域名(certificateId 可选,未传则按域名自动检索;可选 accessType=DIRECT|CDN|CUSTOM,CUSTOM 需 customCname;普通场景用默认 DIRECT)。" +
|
|
205777
206029
|
"createRoute/bindCustomDomain 创建前会 VerifyHTTPServiceRoute 预检;失败时按返回的 DNS TXT 指引配置后重试。" +
|
|
206030
|
+
"purgeCache 清除域名缓存:需 domain 与 targets(配 purgeType=PURGE_URL|PURGE_PREFIX|PURGE_HOST,可选 cacheType=CDN|EO)。" +
|
|
205778
206031
|
"接入说明:https://docs.cloudbase.net/service/custom-domain",
|
|
205779
206032
|
"schema.manage.targetName": "上游资源名称(UpstreamResourceName),与 route.serviceName 二选一(route 优先)。" +
|
|
205780
206033
|
"云函数=函数名;云托管=服务名;静态托管=实例名(常见 staticstore)。不会自动推断上游类型。",
|
|
205781
206034
|
"schema.manage.path": "触发路径(网关匹配前缀),默认 /{上游名}。例:云函数 /api/hello、云托管 /api、静态托管 / 或 /app。" +
|
|
205782
206035
|
"只建网关入口;与 enablePathTransmission 共同决定上游实际收到的路径。",
|
|
205783
206036
|
"schema.manage.upstreamResourceType": "上游类型(与 route.upstreamResourceType 二选一,route 优先)。" +
|
|
205784
|
-
"WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器。" +
|
|
206037
|
+
"WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,STORAGE=云存储,LH=轻量应用服务器。" +
|
|
206038
|
+
"STORAGE 的 UpstreamResourceName 是云存储实例名,可先用 queryStorage 查实例。" +
|
|
205785
206039
|
"createRoute/updateRoute 必填其一;勿把 manageFunctions 的 type=HTTP|Event 传到本字段。",
|
|
205786
206040
|
"schema.manage.auth": "网关路径鉴权(EnableAuth)。匿名/浏览器公网访问通常 false。" +
|
|
205787
206041
|
"只控制网关入口;云函数安全规则、云托管鉴权、静态托管权限需各自工具另行配置。",
|
|
@@ -205790,6 +206044,30 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205790
206044
|
"CBR 云托管(Express 等自管子路由)与 WEB_SCF 多路径函数常需 true;" +
|
|
205791
206045
|
"STATIC_STORE 把触发路径映射到站点根目录(如 /app → 托管 /)时通常 false;" +
|
|
205792
206046
|
"单入口/根路径处理保持 false。也可用 route.enablePathTransmission(route 优先)。",
|
|
206047
|
+
"schema.manage.enableSafeDomain": "跨域/合法域名校验(EnableSafeDomain),即控制台的「跨域设置」。true 时校验请求来源域名," +
|
|
206048
|
+
"false 时不校验(浏览器直连调用 API 的常见选择)。也可用 route.enableSafeDomain(route 优先)。",
|
|
206049
|
+
"schema.manage.pathRewrite": "路径重写(PathRewrite),形如 {prefix:\"/v1\", staticStorePrefix:\"app\"}。" +
|
|
206050
|
+
"prefix=命中路径前缀后替换为的内容;staticStorePrefix=静态托管场景下的目标前缀。" +
|
|
206051
|
+
"不需要改写就省略;也可用 route.pathRewrite(route 优先)。",
|
|
206052
|
+
"schema.manage.qpsPolicy": "限频(QPSPolicy),即控制台的「频限」。{total:总 QPS, perClient:{limitBy:\"ClientIP\"|\"UserID\", limitValue:单客户端 QPS}}。" +
|
|
206053
|
+
"不传则不限频;也可用 route.qpsPolicy(route 优先)。",
|
|
206054
|
+
"schema.manage.extension": "路由级扩展(Extension),可配自定义请求/响应头与缓存规则。" +
|
|
206055
|
+
"{headersHandler:{requestHeadersToAdd,requestHeadersToRemove,responseHeadersToAdd,responseHeadersToRemove}," +
|
|
206056
|
+
"cache:{rules:[{description,enable,condition:{target,matchType,values},actions:[{type:\"Cache\"|\"CacheKey\",cache,cacheKey}]}]}}。" +
|
|
206057
|
+
"⚠️ 默认域(*.{region}.app.tcloudbase.com)不支持自定义响应头,后端会拒绝(实测 2026-10-21),需要自定义域名才能配。" +
|
|
206058
|
+
"也可用 route.extension(route 优先)。",
|
|
206059
|
+
"schema.manage.extension.header.key": "请求/响应头名称,如 X-Frame-Options",
|
|
206060
|
+
"schema.manage.extension.header.value": "请求/响应头取值,如 SAMEORIGIN",
|
|
206061
|
+
"schema.manage.extension.header.action": "写入策略(可选):APPEND_IF_EXISTS_OR_ADD 追加;ADD_IF_ABSENT 不存在才加;" +
|
|
206062
|
+
"OVERWRITE_IF_EXISTS_OR_ADD 覆盖或新增;OVERWRITE_IF_EXISTS 仅覆盖已存在的",
|
|
206063
|
+
"schema.manage.extension.cacheCondition": "缓存规则匹配条件:target=url_path/file_extension/full_uri,matchType=prefix/suffix/contains/exact,values=匹配值数组",
|
|
206064
|
+
"schema.manage.extension.cacheActions": "缓存动作数组:type=Cache 配 cache{followOrigin,noCache,cacheTime,maxAgeTime}(三者互斥,需开启其一);" +
|
|
206065
|
+
"type=CacheKey 配 cacheKey{fullUrlCache,queryStringSwitch,queryStringAction,queryStringValues}",
|
|
206066
|
+
"schema.manage.domainExtension": "域名级扩展(Extension),作用于整个域名(含该域名下所有路径)的自定义头与缓存规则,结构同 extension。" +
|
|
206067
|
+
"缓存规则通常配在域名级;仅 createRoute/updateRoute/bindCustomDomain 生效。" +
|
|
206068
|
+
"⚠️ 同 extension:默认域不支持自定义响应头,需自定义域名。",
|
|
206069
|
+
"schema.manage.protocol": "域名协议(Protocol),仅 createRoute/updateRoute/bindCustomDomain 生效:" +
|
|
206070
|
+
"HTTP / HTTPS / HTTP_AND_HTTPS / HTTP_TO_HTTPS / HTTPS_TO_HTTP。省略则沿用域名现有配置。",
|
|
205793
206071
|
"schema.manage.route.serviceName": "上游实例名:云函数名 / 云托管服务名 / 静态托管实例名(常见 staticstore)/ LH 实例。优先于顶层 targetName。",
|
|
205794
206072
|
"schema.manage.route.upstreamResourceType": "同顶层 upstreamResourceType。route 内设置时优先于顶层。",
|
|
205795
206073
|
"schema.manage.route.enablePathTransmission": "同顶层 enablePathTransmission。route 内设置时优先于顶层。",
|
|
@@ -205797,6 +206075,10 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205797
206075
|
"enable=false 禁用该 Domain+Path(访问返回 GATEWAY_ROUTE_DISABLED);" +
|
|
205798
206076
|
"enable=true 重新启用。updateRoute 也可用顶层 enable 表达同一语义;" +
|
|
205799
206077
|
"也可用专用 action enableRoute/disableRoute。route.enable 优先于顶层 enable。",
|
|
206078
|
+
"schema.manage.route.enableSafeDomain": "同顶层 enableSafeDomain(跨域/合法域名校验)。route 内设置时优先于顶层。",
|
|
206079
|
+
"schema.manage.route.pathRewrite": "同顶层 pathRewrite。route 内设置时优先于顶层。",
|
|
206080
|
+
"schema.manage.route.qpsPolicy": "同顶层 qpsPolicy(限频)。route 内设置时优先于顶层。",
|
|
206081
|
+
"schema.manage.route.extension": "同顶层 extension(路由级自定义头与缓存规则)。route 内设置时优先于顶层。",
|
|
205800
206082
|
"schema.manage.route": "路由对象(可选写法)。例:云函数 {upstreamResourceType:\"WEB_SCF\",serviceName:\"fn\",path:\"/api\"};" +
|
|
205801
206083
|
"云托管 {upstreamResourceType:\"CBR\",serviceName:\"svc\",path:\"/api\"};" +
|
|
205802
206084
|
"静态托管 {upstreamResourceType:\"STATIC_STORE\",serviceName:\"staticstore\",path:\"/\"};" +
|
|
@@ -205821,11 +206103,15 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205821
206103
|
"updateRoute 可选:映射到 Routes[].Enable(也可用 route.enable,route 优先;" +
|
|
205822
206104
|
"也可用专用 action enableRoute/disableRoute)。" +
|
|
205823
206105
|
"省略或非布尔值在 enableService/authSwitch 会返回参数错误。",
|
|
206106
|
+
"schema.manage.cacheType": "缓存层(仅 purgeCache):CDN 或 EO。省略时按域名接入方式自动匹配(EO→EO、CDN→CDN);" +
|
|
206107
|
+
"DIRECT / CUSTOM / NONE 的域没有 CloudBase 托管的缓存,会直接拒绝并说明原因。",
|
|
206108
|
+
"schema.manage.purgeType": "清除方式(仅 purgeCache,默认 PURGE_URL):PURGE_URL=按完整 URL、PURGE_PREFIX=按路径前缀、PURGE_HOST=整个域名",
|
|
206109
|
+
"schema.manage.targets": "清除目标(仅 purgeCache,必填):PURGE_URL 传 https://域名/路径 形式;PURGE_PREFIX 传 /static/ 这样的前缀;PURGE_HOST 传域名本身",
|
|
205824
206110
|
}, {
|
|
205825
206111
|
"query.title": "Query CloudBase Gateway",
|
|
205826
|
-
"query.description": "Unified read-only entry for the CloudBase HTTP gateway (Domain/Route). Query path routes under a domain and their upstreams: WEB_SCF/SCF=cloud functions, CBR=CloudRun, STATIC_STORE=static hosting, LH=Lighthouse. The primary key is Domain + Path; listRoutes / getRoute / listCustomDomains / getPrivilege. getPrivilege queries the HTTP gateway master switch (enableService) and access auth (enableAuth) status. Before setting up custom domain access, run listCustomDomains first: if a custom domain already exists, prefer createRoute to attach a route (no certificate ID needed); use bindCustomDomain only when no usable custom domain exists.",
|
|
206112
|
+
"query.description": "Unified read-only entry for the CloudBase HTTP gateway (Domain/Route). Query path routes under a domain and their upstreams: WEB_SCF/SCF=cloud functions, CBR=CloudRun, STATIC_STORE=static hosting, STORAGE=cloud storage, LH=Lighthouse. The primary key is Domain + Path; listRoutes / getRoute / listCustomDomains / getPrivilege / cachePurgeTask. getPrivilege queries the HTTP gateway master switch (enableService) and access auth (enableAuth) status. cachePurgeTask queries cache purge tasks for a domain (use the TaskId from manageGateway purgeCache). Before setting up custom domain access, run listCustomDomains first: if a custom domain already exists, prefer createRoute to attach a route (no certificate ID needed); use bindCustomDomain only when no usable custom domain exists.",
|
|
205827
206113
|
"manage.title": "Manage CloudBase Gateway",
|
|
205828
|
-
"manage.description": "Unified write entry for the CloudBase HTTP gateway (Domain/Route). createRoute/updateRoute/deleteRoute forward a path under a domain to an upstream; enableRoute/disableRoute enable or disable existing routes (Routes[].Enable of ModifyHTTPServiceRoute underneath, not ModifyGatewayRoute). When domain is omitted, the IsDefault default HTTP domain with DomainType=HTTPSERVICE (like *.{region}.app.tcloudbase.com) is used; static-hosting CDN domains (*.tcloudbaseapp.com, DomainType=STATIC_STORE) are never used. These are path routes on the gateway default domain, not STATIC_STORE upstream bindings; a STATIC_STORE upstream must pass upstreamResourceType=STATIC_STORE explicitly. To disable the static-hosting default domain (*.tcloudbaseapp.com): first queryGateway(listRoutes) to find the domain with DomainType=STATIC_STORE and IsDefault=true, then manageGateway(action=\"disableRoute\", domain=that domain, path=\"/\"); do not use manageHosting. After creation, verify Domain / DomainType / Path / UpstreamResourceType via queryGateway(action=\"listRoutes\"). The upstream type uses a single parameter upstreamResourceType (or route.upstreamResourceType, route wins): WEB_SCF=HTTP cloud function, SCF=Event cloud function, CBR=CloudRun, STATIC_STORE=static hosting, LH=Lighthouse; together with targetName or route.serviceName (function name / CloudRun service name / static-hosting instance name, commonly staticstore). createRoute only creates the gateway entry and does not change upstream permissions. enablePathTransmission: default false strips the trigger path prefix; true forwards the full path (CBR multi-route and WEB_SCF self-managed sub-paths often need true; STATIC_STORE custom trigger path mapping to site root usually false). ⚠️ Custom domain access: if the env already has a custom domain (queryGateway listCustomDomains first), prefer createRoute with that domain explicitly, no certificateId needed; use bindCustomDomain only when binding a brand-new custom domain for the first time (certificateId optional: when omitted, certificates are auto-searched by domain — a single cert is auto-selected, multiple certs return selection guidance). createRoute / bindCustomDomain call VerifyHTTPServiceRoute for ownership pre-checks before creation (probe → create); on failure, data.checks and DNS TXT guidance are returned; configure and retry. CORS/security domains (browser cross-origin allowlist, unrelated to the gateway custom domains of this tool) use manageEnv(action=addSecurityDomain/removeSecurityDomain). enableService/authSwitch: HTTP gateway master switch and access auth switch; if access returns HTTPSERVICE_NONACTIVATED after createRoute, the master switch is usually off (query via queryGateway getPrivilege, enable via enableService).",
|
|
206114
|
+
"manage.description": "Unified write entry for the CloudBase HTTP gateway (Domain/Route). createRoute/updateRoute/deleteRoute forward a path under a domain to an upstream; enableRoute/disableRoute enable or disable existing routes (Routes[].Enable of ModifyHTTPServiceRoute underneath, not ModifyGatewayRoute). When domain is omitted, the IsDefault default HTTP domain with DomainType=HTTPSERVICE (like *.{region}.app.tcloudbase.com) is used; static-hosting CDN domains (*.tcloudbaseapp.com, DomainType=STATIC_STORE) are never used. These are path routes on the gateway default domain, not STATIC_STORE upstream bindings; a STATIC_STORE upstream must pass upstreamResourceType=STATIC_STORE explicitly. To disable the static-hosting default domain (*.tcloudbaseapp.com): first queryGateway(listRoutes) to find the domain with DomainType=STATIC_STORE and IsDefault=true, then manageGateway(action=\"disableRoute\", domain=that domain, path=\"/\"); do not use manageHosting. After creation, verify Domain / DomainType / Path / UpstreamResourceType via queryGateway(action=\"listRoutes\"). The upstream type uses a single parameter upstreamResourceType (or route.upstreamResourceType, route wins): WEB_SCF=HTTP cloud function, SCF=Event cloud function, CBR=CloudRun, STATIC_STORE=static hosting, STORAGE=cloud storage, LH=Lighthouse; together with targetName or route.serviceName (function name / CloudRun service name / static-hosting instance name, commonly staticstore / cloud storage instance name). createRoute only creates the gateway entry and does not change upstream permissions. enablePathTransmission: default false strips the trigger path prefix; true forwards the full path (CBR multi-route and WEB_SCF self-managed sub-paths often need true; STATIC_STORE custom trigger path mapping to site root usually false). ⚠️ Custom domain access: if the env already has a custom domain (queryGateway listCustomDomains first), prefer createRoute with that domain explicitly, no certificateId needed; use bindCustomDomain only when binding a brand-new custom domain for the first time (certificateId optional: when omitted, certificates are auto-searched by domain — a single cert is auto-selected, multiple certs return selection guidance). createRoute / bindCustomDomain call VerifyHTTPServiceRoute for ownership pre-checks before creation (probe → create); on failure, data.checks and DNS TXT guidance are returned; configure and retry. CORS/security domains (browser cross-origin allowlist, unrelated to the gateway custom domains of this tool) use manageEnv(action=addSecurityDomain/removeSecurityDomain). enableService/authSwitch: HTTP gateway master switch and access auth switch; if access returns HTTPSERVICE_NONACTIVATED after createRoute, the master switch is usually off (query via queryGateway getPrivilege, enable via enableService). purgeCache clears domain cache (CDN/EO by URL/prefix/host) and returns a TaskId; check progress with queryGateway cachePurgeTask. Route-level extras: enableSafeDomain (CORS / legit-domain check), pathRewrite (path rewriting), qpsPolicy (rate limiting), extension (custom request/response headers and cache rules); domain-level: protocol and domainExtension. updateRoute only needs the fields you want to change — untouched CORS/rewrite/QPS/extension settings are carried over from the live route.",
|
|
205829
206115
|
"verify.failWithDns": "HTTP service domain pre-check failed: domain ownership verification failed. Configure the DNS TXT records per ownership.dnsRecords in data.checks, then retry.",
|
|
205830
206116
|
"verify.fail": "HTTP service domain pre-check failed. Fix the issues per data.checks, then retry.",
|
|
205831
206117
|
"verify.failWithDnsReason": "Configure the DNS TXT records (host/record type/record value in data.checks[].dnsRecords), then call this action again",
|
|
@@ -205843,7 +206129,7 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205843
206129
|
"privilege.nonActivatedHint": "; if the route is created successfully but access returns HTTPSERVICE_NONACTIVATED (403), enable the HTTP gateway first",
|
|
205844
206130
|
"privilege.enableServiceReason": "Turn on the HTTP gateway master switch (EnableService); once on, routes are accessible via the default domain",
|
|
205845
206131
|
"defaultDomain.notReady": "The env default HTTP access domain is not ready or not provisioned. Enable the HTTP access service in the console first, or use queryGateway(action=\"listRoutes\") to confirm that Domains contains a domain with DomainType=HTTPSERVICE and IsDefault=true (shaped like *.{region}.app.tcloudbase.com); do not use static-hosting domains (*.tcloudbaseapp.com). You may also pass domain explicitly and retry createRoute/updateRoute/deleteRoute.",
|
|
205846
|
-
"upstreamTypeRequired": "upstreamResourceType (or route.upstreamResourceType) is required: WEB_SCF=HTTP cloud function, SCF=Event cloud function, CBR=CloudRun, STATIC_STORE=static hosting, LH=Lighthouse. Do not infer the upstream type from targetName/serviceName alone.",
|
|
206132
|
+
"upstreamTypeRequired": "upstreamResourceType (or route.upstreamResourceType) is required: WEB_SCF=HTTP cloud function, SCF=Event cloud function, CBR=CloudRun, STATIC_STORE=static hosting, STORAGE=cloud storage, LH=Lighthouse. Do not infer the upstream type from targetName/serviceName alone.",
|
|
205847
206133
|
"upstreamNameRequired": "targetName or route.serviceName is required as the upstream resource name: a cloud function name, CloudRun service name, or static-hosting instance name (commonly staticstore).",
|
|
205848
206134
|
"toggle.pathRequired": "path or route.path is required for action=enableRoute/disableRoute (e.g. \"/\" or \"/api\")",
|
|
205849
206135
|
"toggle.notFound": "No route found for path {path}{domainSuffix}{upstreamSuffix}. Use queryGateway(action=\"listRoutes\") first to confirm Domain / Path, then call enableRoute/disableRoute. When disabling the static-hosting default domain (*.tcloudbaseapp.com), pass domain=that STATIC_STORE IsDefault domain explicitly, usually with path=\"/\".",
|
|
@@ -205909,14 +206195,32 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205909
206195
|
"authSwitch.onMessage": "HTTP access service auth enabled successfully",
|
|
205910
206196
|
"authSwitch.offMessage": "HTTP access service auth disabled successfully",
|
|
205911
206197
|
"authSwitch.verifyReason": "Verify the HTTP gateway master switch and access auth status",
|
|
206198
|
+
"purgeCache.domainRequired": "domain is required for action=purgeCache",
|
|
206199
|
+
"purgeCache.targetsRequired": "targets is required for action=purgeCache: full URLs for PURGE_URL, path prefixes for PURGE_PREFIX, or the domain itself for PURGE_HOST",
|
|
206200
|
+
"purgeCache.message": "Submitted a cache purge task for {count} target(s); CDN/EO purges usually take seconds to minutes — check progress with queryGateway(action=\"cachePurgeTask\") by TaskId",
|
|
206201
|
+
"purgeCache.verifyReason": "Query the cache purge task status",
|
|
206202
|
+
"query.cachePurgeTask": "Retrieved {count} cache purge task record(s)",
|
|
206203
|
+
"query.cachePurgeTaskDomainRequired": "domain is required for action=cachePurgeTask",
|
|
206204
|
+
"cache.domainNotFound": "No access configuration found for domain {domain}, so the cache layer is undetermined. Confirm the domain with queryGateway(action=\"listRoutes\") first.",
|
|
206205
|
+
"cache.notManaged": "Domain {domain} uses access type {accessType}; CloudBase does not host a CDN/EO cache for it, so cache purging does not apply (DIRECT and CUSTOM own-CDN caches are not managed by the platform). Switch the domain to CDN or EO access first.",
|
|
206206
|
+
"cache.typeMismatch": "Domain {domain} uses access type {accessType} and cannot be purged with cacheType={requested}. Omit cacheType to match the access type automatically.",
|
|
205912
206207
|
// Input schema parameter descriptions
|
|
205913
|
-
"schema.query.action": "Read-only action: listRoutes, getRoute, listCustomDomains, getPrivilege. " +
|
|
206208
|
+
"schema.query.action": "Read-only action: listRoutes, getRoute, listCustomDomains, getPrivilege, cachePurgeTask. " +
|
|
205914
206209
|
"getPrivilege needs no other parameter and returns the HTTP gateway master switch and access auth status directly. " +
|
|
206210
|
+
"cachePurgeTask requires domain (optional cacheType/taskId/purgeType/startTime/endTime/offset/limit). " +
|
|
205915
206211
|
"For custom domain access, run listCustomDomains first to check whether an existing domain can be reused.",
|
|
205916
206212
|
"schema.query.targetName": "Upstream resource name filter (UpstreamResourceName): a cloud function name, CloudRun service name, or static-hosting instance name (commonly staticstore).",
|
|
205917
206213
|
"schema.query.routeId": "Route ID. Optional for getRoute",
|
|
205918
206214
|
"schema.query.path": "Route path. Optional as a getRoute / listRoutes filter",
|
|
205919
|
-
"schema.query.domain": "Domain. Optional as a getRoute / listRoutes filter",
|
|
206215
|
+
"schema.query.domain": "Domain. Optional as a getRoute / listRoutes filter; required for cachePurgeTask",
|
|
206216
|
+
"schema.query.cacheType": "Cache layer (cachePurgeTask only): CDN or EO. When omitted it is matched from the domain access type (EO→EO, CDN→CDN); " +
|
|
206217
|
+
"DIRECT / CUSTOM / NONE domains have no CloudBase-hosted cache and are rejected with an explanation.",
|
|
206218
|
+
"schema.query.taskId": "Cache purge task ID (cachePurgeTask only, optional filter)",
|
|
206219
|
+
"schema.query.purgeType": "Purge type filter (cachePurgeTask only): PURGE_URL=by URL, PURGE_PREFIX=by path prefix, PURGE_HOST=whole domain",
|
|
206220
|
+
"schema.query.startTime": "Task start time (cachePurgeTask only, optional). Format YYYY-MM-DD HH:mm:ss",
|
|
206221
|
+
"schema.query.endTime": "Task end time (cachePurgeTask only, optional). Format YYYY-MM-DD HH:mm:ss",
|
|
206222
|
+
"schema.query.offset": "Pagination offset (cachePurgeTask only, optional)",
|
|
206223
|
+
"schema.query.limit": "Max records to return (cachePurgeTask only, optional)",
|
|
205920
206224
|
"schema.manage.action": "Write actions: createRoute/updateRoute/deleteRoute manage routes; enableRoute/disableRoute enable or disable an existing route (path required, passing domain explicitly is recommended); " +
|
|
205921
206225
|
"bindCustomDomain/deleteCustomDomain manage custom domains; " +
|
|
205922
206226
|
"enableService/authSwitch toggle the HTTP gateway master switch and access auth (requires the enable parameter). " +
|
|
@@ -205926,13 +206230,15 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205926
206230
|
"When a custom domain already exists, prefer createRoute(domain=existing domain) for access instead of calling bindCustomDomain / passing certificateId again; " +
|
|
205927
206231
|
"bindCustomDomain is only for binding a new domain the first time (certificateId is optional — when omitted, certificates are searched by domain; optional accessType=DIRECT|CDN|CUSTOM, CUSTOM requires customCname; use the default DIRECT for normal cases). " +
|
|
205928
206232
|
"createRoute/bindCustomDomain run a VerifyHTTPServiceRoute pre-check before creation; on failure, follow the returned DNS TXT guidance and retry. " +
|
|
206233
|
+
"purgeCache clears domain cache: requires domain and targets (with purgeType=PURGE_URL|PURGE_PREFIX|PURGE_HOST, optional cacheType=CDN|EO). " +
|
|
205929
206234
|
"Setup guide: https://docs.cloudbase.net/service/custom-domain",
|
|
205930
206235
|
"schema.manage.targetName": "Upstream resource name (UpstreamResourceName); use either this or route.serviceName (route wins). " +
|
|
205931
206236
|
"Cloud function=function name; CloudRun=service name; static hosting=instance name (commonly staticstore). The upstream type is never inferred automatically.",
|
|
205932
206237
|
"schema.manage.path": "Trigger path (the gateway match prefix), defaults to /{upstream name}. Examples: cloud function /api/hello, CloudRun /api, static hosting / or /app. " +
|
|
205933
206238
|
"This only creates the gateway entry; together with enablePathTransmission it determines the path the upstream actually receives.",
|
|
205934
206239
|
"schema.manage.upstreamResourceType": "Upstream type (use either this or route.upstreamResourceType, route wins). " +
|
|
205935
|
-
"WEB_SCF=HTTP cloud function, SCF=Event cloud function, CBR=CloudRun, STATIC_STORE=static hosting, LH=Lighthouse. " +
|
|
206240
|
+
"WEB_SCF=HTTP cloud function, SCF=Event cloud function, CBR=CloudRun, STATIC_STORE=static hosting, STORAGE=cloud storage, LH=Lighthouse. " +
|
|
206241
|
+
"For STORAGE, UpstreamResourceName is the cloud storage instance name — look it up with queryStorage first. " +
|
|
205936
206242
|
"One of them is required for createRoute/updateRoute; do not pass the manageFunctions type=HTTP|Event value into this field.",
|
|
205937
206243
|
"schema.manage.auth": "Gateway path auth (EnableAuth). Usually false for anonymous/browser public access. " +
|
|
205938
206244
|
"It only controls the gateway entry; cloud function security rules, CloudRun auth, and static hosting permissions must be configured with their own tools.",
|
|
@@ -205941,6 +206247,31 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205941
206247
|
"CBR CloudRun (Express and similar self-managed sub-routes) and multi-path WEB_SCF functions often need true; " +
|
|
205942
206248
|
"STATIC_STORE mapping a trigger path to the site root (e.g. /app → hosting /) is usually false; " +
|
|
205943
206249
|
"keep false for single-entry/root-path handling. route.enablePathTransmission also works (route wins).",
|
|
206250
|
+
"schema.manage.enableSafeDomain": "CORS / legit-domain check (EnableSafeDomain), the console's \"cross-origin settings\". " +
|
|
206251
|
+
"true validates the request origin; false skips the check (common for browser-to-API calls). " +
|
|
206252
|
+
"route.enableSafeDomain also works (route wins).",
|
|
206253
|
+
"schema.manage.pathRewrite": "Path rewriting (PathRewrite), e.g. {prefix:\"/v1\", staticStorePrefix:\"app\"}. " +
|
|
206254
|
+
"prefix replaces the matched path prefix; staticStorePrefix is the target prefix for static hosting. " +
|
|
206255
|
+
"Omit when no rewriting is needed; route.pathRewrite also works (route wins).",
|
|
206256
|
+
"schema.manage.qpsPolicy": "Rate limiting (QPSPolicy), the console's \"frequency limit\". {total: total QPS, perClient:{limitBy:\"ClientIP\"|\"UserID\", limitValue: per-client QPS}}. " +
|
|
206257
|
+
"Omit for no limit; route.qpsPolicy also works (route wins).",
|
|
206258
|
+
"schema.manage.extension": "Route-level extension (Extension): custom request/response headers and cache rules. " +
|
|
206259
|
+
"{headersHandler:{requestHeadersToAdd,requestHeadersToRemove,responseHeadersToAdd,responseHeadersToRemove}," +
|
|
206260
|
+
"cache:{rules:[{description,enable,condition:{target,matchType,values},actions:[{type:\"Cache\"|\"CacheKey\",cache,cacheKey}]}]}}. " +
|
|
206261
|
+
"⚠️ The default domain (*.{region}.app.tcloudbase.com) rejects custom response headers (verified 2026-10-21); a custom domain is required. " +
|
|
206262
|
+
"route.extension also works (route wins).",
|
|
206263
|
+
"schema.manage.extension.header.key": "Header name, e.g. X-Frame-Options",
|
|
206264
|
+
"schema.manage.extension.header.value": "Header value, e.g. SAMEORIGIN",
|
|
206265
|
+
"schema.manage.extension.header.action": "Write strategy (optional): APPEND_IF_EXISTS_OR_ADD appends; ADD_IF_ABSENT only adds when missing; " +
|
|
206266
|
+
"OVERWRITE_IF_EXISTS_OR_ADD overwrites or adds; OVERWRITE_IF_EXISTS only overwrites existing",
|
|
206267
|
+
"schema.manage.extension.cacheCondition": "Cache rule match condition: target=url_path/file_extension/full_uri, matchType=prefix/suffix/contains/exact, values=match value list",
|
|
206268
|
+
"schema.manage.extension.cacheActions": "Cache action list: type=Cache with cache{followOrigin,noCache,cacheTime,maxAgeTime} (mutually exclusive — enable one); " +
|
|
206269
|
+
"type=CacheKey with cacheKey{fullUrlCache,queryStringSwitch,queryStringAction,queryStringValues}",
|
|
206270
|
+
"schema.manage.domainExtension": "Domain-level extension (Extension) applied to the whole domain (all paths): custom headers and cache rules, same shape as extension. " +
|
|
206271
|
+
"Cache rules usually belong here; only effective for createRoute/updateRoute/bindCustomDomain. " +
|
|
206272
|
+
"⚠️ Same as extension: the default domain rejects custom response headers; a custom domain is required.",
|
|
206273
|
+
"schema.manage.protocol": "Domain protocol (Protocol), effective for createRoute/updateRoute/bindCustomDomain only: " +
|
|
206274
|
+
"HTTP / HTTPS / HTTP_AND_HTTPS / HTTP_TO_HTTPS / HTTPS_TO_HTTP. Omit to keep the domain's current setting.",
|
|
205944
206275
|
"schema.manage.route.serviceName": "Upstream instance name: cloud function name / CloudRun service name / static-hosting instance name (commonly staticstore) / LH instance. Takes precedence over the top-level targetName.",
|
|
205945
206276
|
"schema.manage.route.upstreamResourceType": "Same as the top-level upstreamResourceType. When set inside route, it takes precedence over the top level.",
|
|
205946
206277
|
"schema.manage.route.enablePathTransmission": "Same as the top-level enablePathTransmission. When set inside route, it takes precedence over the top level.",
|
|
@@ -205948,6 +206279,10 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205948
206279
|
"enable=false disables this Domain+Path (access returns GATEWAY_ROUTE_DISABLED); " +
|
|
205949
206280
|
"enable=true re-enables it. updateRoute can express the same semantics with the top-level enable; " +
|
|
205950
206281
|
"the dedicated actions enableRoute/disableRoute also work. route.enable takes precedence over the top-level enable.",
|
|
206282
|
+
"schema.manage.route.enableSafeDomain": "Same as the top-level enableSafeDomain (CORS / legit-domain check). When set inside route, it takes precedence.",
|
|
206283
|
+
"schema.manage.route.pathRewrite": "Same as the top-level pathRewrite. When set inside route, it takes precedence.",
|
|
206284
|
+
"schema.manage.route.qpsPolicy": "Same as the top-level qpsPolicy (rate limiting). When set inside route, it takes precedence.",
|
|
206285
|
+
"schema.manage.route.extension": "Same as the top-level extension (route-level custom headers and cache rules). When set inside route, it takes precedence.",
|
|
205951
206286
|
"schema.manage.route": "Route object (an optional form). Examples: cloud function {upstreamResourceType:\"WEB_SCF\",serviceName:\"fn\",path:\"/api\"}; " +
|
|
205952
206287
|
"CloudRun {upstreamResourceType:\"CBR\",serviceName:\"svc\",path:\"/api\"}; " +
|
|
205953
206288
|
"static hosting {upstreamResourceType:\"STATIC_STORE\",serviceName:\"staticstore\",path:\"/\"}; " +
|
|
@@ -205972,6 +206307,10 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
205972
206307
|
"optional for updateRoute: maps to Routes[].Enable (route.enable also works and wins; " +
|
|
205973
206308
|
"the dedicated actions enableRoute/disableRoute are available too). " +
|
|
205974
206309
|
"Omitting it or passing a non-boolean returns a parameter error for enableService/authSwitch.",
|
|
206310
|
+
"schema.manage.cacheType": "Cache layer (purgeCache only): CDN or EO. When omitted it is matched from the domain access type (EO→EO, CDN→CDN); " +
|
|
206311
|
+
"DIRECT / CUSTOM / NONE domains have no CloudBase-hosted cache and are rejected with an explanation.",
|
|
206312
|
+
"schema.manage.purgeType": "Purge type (purgeCache only, default PURGE_URL): PURGE_URL=by full URL, PURGE_PREFIX=by path prefix, PURGE_HOST=whole domain",
|
|
206313
|
+
"schema.manage.targets": "Purge targets (purgeCache only, required): full https://domain/path URLs for PURGE_URL; prefixes such as /static/ for PURGE_PREFIX; the domain itself for PURGE_HOST",
|
|
205975
206314
|
});
|
|
205976
206315
|
|
|
205977
206316
|
|
|
@@ -208046,7 +208385,7 @@ function localizeZodSchemaShape(shape, lang, seen = new WeakMap()) {
|
|
|
208046
208385
|
"use strict";
|
|
208047
208386
|
|
|
208048
208387
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
208049
|
-
exports.validateTimerCron = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.formatRuntimeList = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = exports.HOSTED_CLIENT_INFO_CACHE_TTL_MS = exports.HOSTED_CLIENT_INFO_CACHE_CAPACITY = exports.handleHostedMcpRequest = exports.warmupHostedResources = exports.RAW_IDE_FILE_MAPPINGS = exports.simplifyEnvList = exports.envManager = exports.createCloudBaseManagerWithOptions = exports.resetCloudBaseManagerCache = exports.getEnvId = exports.getCloudBaseManager = exports.shouldRegisterTool = exports.getCloudModeStatus = exports.enableCloudMode = exports.isCloudMode = exports.logout = exports.getLoginState = exports.warn = exports.error = exports.info = exports.reportToolCall = exports.reportToolkitLifecycle = exports.telemetryReporter = exports.StdioServerTransport = exports.getDefaultServer = exports.createCloudBaseMcpServer = void 0;
|
|
208388
|
+
exports.validateTimerCron = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.formatRuntimeList = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = exports.HOSTED_CLIENT_INFO_CACHE_TTL_MS = exports.HOSTED_CLIENT_INFO_CACHE_CAPACITY = exports.handleHostedMcpRequest = exports.warmupHostedResources = exports.RAW_IDE_FILE_MAPPINGS = exports.simplifyEnvList = exports.envManager = exports.createCloudBaseManagerWithOptions = exports.resetCloudBaseManagerCache = exports.getEnvId = exports.getCloudBaseManager = exports.runWithEnvSlot = exports.ENV_SOURCES = exports.shouldRegisterTool = exports.getCloudModeStatus = exports.enableCloudMode = exports.isCloudMode = exports.logout = exports.getLoginState = exports.warn = exports.error = exports.info = exports.reportToolCall = exports.reportToolkitLifecycle = exports.telemetryReporter = exports.StdioServerTransport = exports.getDefaultServer = exports.createCloudBaseMcpServer = void 0;
|
|
208050
208389
|
// CloudBase MCP Server Library
|
|
208051
208390
|
var server_js_1 = __webpack_require__(46324);
|
|
208052
208391
|
Object.defineProperty(exports, "createCloudBaseMcpServer", ({ enumerable: true, get: function () { return server_js_1.createCloudBaseMcpServer; } }));
|
|
@@ -208066,6 +208405,13 @@ Object.defineProperty(exports, "isCloudMode", ({ enumerable: true, get: function
|
|
|
208066
208405
|
Object.defineProperty(exports, "enableCloudMode", ({ enumerable: true, get: function () { return cloud_mode_js_1.enableCloudMode; } }));
|
|
208067
208406
|
Object.defineProperty(exports, "getCloudModeStatus", ({ enumerable: true, get: function () { return cloud_mode_js_1.getCloudModeStatus; } }));
|
|
208068
208407
|
Object.defineProperty(exports, "shouldRegisterTool", ({ enumerable: true, get: function () { return cloud_mode_js_1.shouldRegisterTool; } }));
|
|
208408
|
+
/**
|
|
208409
|
+
* 环境绑定槽。外部宿主(自己起 transport 的那种)要上报真实的 envId,
|
|
208410
|
+
* 就得在自己的一次 run 里跑 server 的消息处理,否则上报恒为 `default`。
|
|
208411
|
+
*/
|
|
208412
|
+
var env_binding_js_1 = __webpack_require__(61498);
|
|
208413
|
+
Object.defineProperty(exports, "ENV_SOURCES", ({ enumerable: true, get: function () { return env_binding_js_1.ENV_SOURCES; } }));
|
|
208414
|
+
Object.defineProperty(exports, "runWithEnvSlot", ({ enumerable: true, get: function () { return env_binding_js_1.runWithEnvSlot; } }));
|
|
208069
208415
|
var cloudbase_manager_js_1 = __webpack_require__(33109);
|
|
208070
208416
|
Object.defineProperty(exports, "getCloudBaseManager", ({ enumerable: true, get: function () { return cloudbase_manager_js_1.getCloudBaseManager; } }));
|
|
208071
208417
|
Object.defineProperty(exports, "getEnvId", ({ enumerable: true, get: function () { return cloudbase_manager_js_1.getEnvId; } }));
|
|
@@ -209202,7 +209548,7 @@ exports.buildEnvCreditsHtml = buildEnvCreditsHtml;
|
|
|
209202
209548
|
exports.registerEnvCreditsResource = registerEnvCreditsResource;
|
|
209203
209549
|
const mcp_js_1 = __webpack_require__(55375);
|
|
209204
209550
|
const index_js_1 = __webpack_require__(24908);
|
|
209205
|
-
const
|
|
209551
|
+
const env_binding_js_1 = __webpack_require__(61498);
|
|
209206
209552
|
const site_map_js_1 = __webpack_require__(34533);
|
|
209207
209553
|
const logger_js_1 = __webpack_require__(40781);
|
|
209208
209554
|
const telemetry_js_1 = __webpack_require__(5198);
|
|
@@ -209272,17 +209618,12 @@ function buildEnvCreditsConsoleUrl(key, envId, site) {
|
|
|
209272
209618
|
return (0, site_map_js_1.getConsoleDevUrl)(envId ?? undefined, exports.ENV_CREDITS_ENV_LINK_HASH[key], site);
|
|
209273
209619
|
}
|
|
209274
209620
|
/**
|
|
209275
|
-
*
|
|
209276
|
-
*
|
|
209277
|
-
*
|
|
209278
|
-
* ① 本次工具结果携带(面板侧覆盖,见 EnvCreditsPayload)
|
|
209279
|
-
* → ② `server.cloudBaseOptions.envId` / `process.env.CLOUDBASE_ENV_ID`
|
|
209280
|
-
* → ③ 进程缓存 `getCachedEnvId()`
|
|
209281
|
-
* → ④ 降级:不显示 ID
|
|
209282
|
-
* hosted 是无状态的,进程缓存不可靠,因此 ③ 只是本地兜底;面板永远以工具结果为准。
|
|
209621
|
+
* Static fallback until a tool result arrives.
|
|
209622
|
+
* Explicit `cloudBaseOptions.envId` wins. Otherwise the current slot.
|
|
209623
|
+
* Does not read `CLOUDBASE_ENV_ID` or the process cache.
|
|
209283
209624
|
*/
|
|
209284
209625
|
function resolveEnvCreditsFallback(server) {
|
|
209285
|
-
const envId =
|
|
209626
|
+
const envId = (0, env_binding_js_1.readDisplayedEnvId)(server.cloudBaseOptions?.envId);
|
|
209286
209627
|
const { site, region } = (0, site_map_js_1.resolveSiteAndRegion)({
|
|
209287
209628
|
site: server.cloudBaseOptions?.site,
|
|
209288
209629
|
region: server.cloudBaseOptions?.region,
|
|
@@ -210443,7 +210784,7 @@ exports.registerGetStartedResource = registerGetStartedResource;
|
|
|
210443
210784
|
* 注入;`t()` 在 read 回调里求值,晚于 `setInstanceLang`,英文实例自动出英文。
|
|
210444
210785
|
* 注入分两路:HTML 文本走 `escapeHtml`,脚本里的字符串走 `jsLiteral`(JSON 转义 +
|
|
210445
210786
|
* 转义 `<`,避免 `</script>` 截断)。
|
|
210446
|
-
* 3.
|
|
210787
|
+
* 3. **只读无密钥**:环境 ID 来自这次调用槽;槽是空的才用 `server.cloudBaseOptions.envId`。不读环境变量和缓存。站点仍走站点解析。
|
|
210447
210788
|
* 读资源时不发网络请求;面板自己只会发两类调用——只读的
|
|
210448
210789
|
* `auth(action:"status")`(「重新检查」)和只改本地绑定的
|
|
210449
210790
|
* `auth(action:"set_env")`(点「可选环境」里的一行)。两者都不动云端资源,也不碰密钥。
|
|
@@ -210464,7 +210805,7 @@ exports.registerGetStartedResource = registerGetStartedResource;
|
|
|
210464
210805
|
*/
|
|
210465
210806
|
const mcp_js_1 = __webpack_require__(55375);
|
|
210466
210807
|
const index_js_1 = __webpack_require__(24908);
|
|
210467
|
-
const
|
|
210808
|
+
const env_binding_js_1 = __webpack_require__(61498);
|
|
210468
210809
|
const site_map_js_1 = __webpack_require__(34533);
|
|
210469
210810
|
const logger_js_1 = __webpack_require__(40781);
|
|
210470
210811
|
const telemetry_js_1 = __webpack_require__(5198);
|
|
@@ -210508,12 +210849,9 @@ function escapeHtml(value) {
|
|
|
210508
210849
|
function jsLiteral(value) {
|
|
210509
210850
|
return JSON.stringify(value).replace(/</g, "\\u003c");
|
|
210510
210851
|
}
|
|
210511
|
-
/**
|
|
210852
|
+
/** Static fallback for the panel. Reads the current slot, then this server's explicit envId. No network. */
|
|
210512
210853
|
function resolveGetStartedStatus(server) {
|
|
210513
|
-
const envId = server.cloudBaseOptions?.envId
|
|
210514
|
-
process.env.CLOUDBASE_ENV_ID ||
|
|
210515
|
-
(0, cloudbase_manager_js_1.getCachedEnvId)() ||
|
|
210516
|
-
null;
|
|
210854
|
+
const envId = (0, env_binding_js_1.readDisplayedEnvId)(server.cloudBaseOptions?.envId);
|
|
210517
210855
|
const { site, region } = (0, site_map_js_1.resolveSiteAndRegion)({
|
|
210518
210856
|
site: server.cloudBaseOptions?.site,
|
|
210519
210857
|
region: server.cloudBaseOptions?.region,
|
|
@@ -211522,6 +211860,7 @@ const index_js_1 = __webpack_require__(24908);
|
|
|
211522
211860
|
const schema_js_1 = __webpack_require__(56273);
|
|
211523
211861
|
const server_instructions_js_1 = __webpack_require__(81808);
|
|
211524
211862
|
const cloud_mode_js_1 = __webpack_require__(88694);
|
|
211863
|
+
const env_binding_js_1 = __webpack_require__(61498);
|
|
211525
211864
|
const logger_js_1 = __webpack_require__(40781);
|
|
211526
211865
|
const site_map_js_1 = __webpack_require__(34533);
|
|
211527
211866
|
const tool_result_js_1 = __webpack_require__(69645);
|
|
@@ -211710,6 +212049,8 @@ async function createCloudBaseMcpServer(options) {
|
|
|
211710
212049
|
});
|
|
211711
212050
|
// 初始化 toolDefs,用于外部提取工具列表(如微信 IDE)
|
|
211712
212051
|
server.toolDefs = [];
|
|
212052
|
+
const envSlot = { binding: null };
|
|
212053
|
+
server.envSlot = envSlot;
|
|
211713
212054
|
// 实例语言解析(须在工具注册前完成:registerTool 包装层按 lang 解析词典 key 形式的 description)
|
|
211714
212055
|
server.lang = instanceLang;
|
|
211715
212056
|
// 同步到 i18n 模块级 instanceLang:否则 t() 无 langOverride 时会退化成
|
|
@@ -211867,6 +212208,23 @@ async function createCloudBaseMcpServer(options) {
|
|
|
211867
212208
|
// 产物卡片:挂在三个部署类工具上,只读展示部署状态与访问地址,写意图一律交给会话。
|
|
211868
212209
|
(0, artifact_card_js_1.registerArtifactCardResource)(server);
|
|
211869
212210
|
}
|
|
212211
|
+
const originalConnect = server.connect.bind(server);
|
|
212212
|
+
server.connect = async (transport) => {
|
|
212213
|
+
await originalConnect(transport);
|
|
212214
|
+
const deliver = transport.onmessage;
|
|
212215
|
+
if (!deliver) {
|
|
212216
|
+
return;
|
|
212217
|
+
}
|
|
212218
|
+
transport.onmessage = (message, extra) => {
|
|
212219
|
+
if ((0, env_binding_js_1.hasEnvSlot)()) {
|
|
212220
|
+
deliver(message, extra);
|
|
212221
|
+
return;
|
|
212222
|
+
}
|
|
212223
|
+
(0, env_binding_js_1.runWithEnvSlot)(envSlot, () => {
|
|
212224
|
+
deliver(message, extra);
|
|
212225
|
+
});
|
|
212226
|
+
};
|
|
212227
|
+
};
|
|
211870
212228
|
return server;
|
|
211871
212229
|
}
|
|
211872
212230
|
/**
|
|
@@ -223907,6 +224265,7 @@ function buildEnvMetricsPayload(input) {
|
|
|
223907
224265
|
* - Error handling and telemetry reporting
|
|
223908
224266
|
*/
|
|
223909
224267
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
224268
|
+
exports.TCB_PURCHASE_URL = void 0;
|
|
223910
224269
|
exports.checkAndInitTcbService = checkAndInitTcbService;
|
|
223911
224270
|
exports.checkAndCreateFreeEnv = checkAndCreateFreeEnv;
|
|
223912
224271
|
exports.getUinForTelemetry = getUinForTelemetry;
|
|
@@ -223914,6 +224273,17 @@ const auth_js_1 = __webpack_require__(561);
|
|
|
223914
224273
|
const index_js_1 = __webpack_require__(24908);
|
|
223915
224274
|
const logger_js_1 = __webpack_require__(40781);
|
|
223916
224275
|
const telemetry_js_1 = __webpack_require__(5198);
|
|
224276
|
+
/**
|
|
224277
|
+
* 开通 CloudBase 环境的购买页。
|
|
224278
|
+
*
|
|
224279
|
+
* ⚠️ 别再写回 `/lowcode?buyType=tcb&channel=mcp`:那条路径现在 302 到 `/CloudBase`,
|
|
224280
|
+
* **重定向时把 query 全丢了**(实测 `location: https://buy.cloud.tencent.com/CloudBase`),
|
|
224281
|
+
* 用户会落到购买页首页、来源标记也一起丢。
|
|
224282
|
+
*
|
|
224283
|
+
* ⚠️ `region` / `sqlType` 是写死的:国内站默认 ap-shanghai + PG 版。国际站
|
|
224284
|
+
* (`buy.tencentcloud.com`)的域名与路径同构性未验证,见 `specs/site-domain-governance`。
|
|
224285
|
+
*/
|
|
224286
|
+
exports.TCB_PURCHASE_URL = "https://buy.cloud.tencent.com/CloudBase?buyType=tcb®ion=ap-shanghai&sqlType=pg";
|
|
223917
224287
|
/**
|
|
223918
224288
|
* Parse InitTcb error and extract user-friendly information
|
|
223919
224289
|
*/
|
|
@@ -223936,7 +224306,7 @@ function parseInitTcbError(err) {
|
|
|
223936
224306
|
const errorInfo = {
|
|
223937
224307
|
code: errorCode,
|
|
223938
224308
|
message: friendlyMessage,
|
|
223939
|
-
helpUrl:
|
|
224309
|
+
helpUrl: exports.TCB_PURCHASE_URL,
|
|
223940
224310
|
actionText,
|
|
223941
224311
|
requestId
|
|
223942
224312
|
};
|
|
@@ -224172,7 +224542,7 @@ async function checkAndCreateFreeEnv(cloudbase, context) {
|
|
|
224172
224542
|
newContext.createEnvError = {
|
|
224173
224543
|
code: "NoPromotionalActivity",
|
|
224174
224544
|
message: (0, index_js_1.t)("envSetup.noPromotionalActivity"),
|
|
224175
|
-
helpUrl:
|
|
224545
|
+
helpUrl: exports.TCB_PURCHASE_URL
|
|
224176
224546
|
};
|
|
224177
224547
|
return {
|
|
224178
224548
|
success: false,
|
|
@@ -224238,7 +224608,7 @@ async function checkAndCreateFreeEnv(cloudbase, context) {
|
|
|
224238
224608
|
newContext.createEnvError = {
|
|
224239
224609
|
code: "InvalidEnvId",
|
|
224240
224610
|
message: (0, index_js_1.t)("envSetup.invalidEnvId"),
|
|
224241
|
-
helpUrl:
|
|
224611
|
+
helpUrl: exports.TCB_PURCHASE_URL
|
|
224242
224612
|
};
|
|
224243
224613
|
return {
|
|
224244
224614
|
success: false,
|
|
@@ -224299,7 +224669,7 @@ async function checkAndCreateFreeEnv(cloudbase, context) {
|
|
|
224299
224669
|
newContext.createEnvError = {
|
|
224300
224670
|
code: createErr.code || createErr.Code || "UnknownError",
|
|
224301
224671
|
message: errorMessage,
|
|
224302
|
-
helpUrl:
|
|
224672
|
+
helpUrl: exports.TCB_PURCHASE_URL
|
|
224303
224673
|
};
|
|
224304
224674
|
(0, logger_js_1.debug)('[env-setup] CreateFreeEnvByActivity failed:', {
|
|
224305
224675
|
code: newContext.createEnvError.code,
|
|
@@ -224399,12 +224769,14 @@ const cloudbase_manager_js_1 = __webpack_require__(33109);
|
|
|
224399
224769
|
const logger_js_1 = __webpack_require__(40781);
|
|
224400
224770
|
const site_map_js_1 = __webpack_require__(34533);
|
|
224401
224771
|
const project_config_js_1 = __webpack_require__(39175);
|
|
224772
|
+
const describe_envs_query_js_1 = __webpack_require__(31284);
|
|
224402
224773
|
const index_js_1 = __webpack_require__(24908);
|
|
224403
224774
|
const tool_result_js_1 = __webpack_require__(69645);
|
|
224404
224775
|
const gateway_access_urls_js_1 = __webpack_require__(84173);
|
|
224405
224776
|
const env_setup_js_1 = __webpack_require__(27528);
|
|
224406
224777
|
const env_credits_payload_js_1 = __webpack_require__(63880);
|
|
224407
224778
|
const mcp_ui_js_1 = __webpack_require__(55880);
|
|
224779
|
+
const env_setup_js_2 = __webpack_require__(27528);
|
|
224408
224780
|
/**
|
|
224409
224781
|
* Resources accepted by CreateEnv. Matches Cloud API / Manager SDK contract.
|
|
224410
224782
|
* `postgresql` enables CloudBase PostgreSQL (PG mode) when supported by the package.
|
|
@@ -225193,7 +225565,7 @@ async function prepareAuthEnvironment(params) {
|
|
|
225193
225565
|
reason: "tcb_init_failed",
|
|
225194
225566
|
errorCode: "TCB_INIT_FAILED",
|
|
225195
225567
|
message: (0, index_js_1.t)("env.prepare.tcbInitFailed"),
|
|
225196
|
-
helpUrl:
|
|
225568
|
+
helpUrl: env_setup_js_2.TCB_PURCHASE_URL,
|
|
225197
225569
|
});
|
|
225198
225570
|
return {
|
|
225199
225571
|
currentEnvId: null,
|
|
@@ -225246,7 +225618,7 @@ async function prepareAuthEnvironment(params) {
|
|
|
225246
225618
|
reason: "env_creation_failed",
|
|
225247
225619
|
errorCode: "ENV_CREATION_FAILED",
|
|
225248
225620
|
message: (0, index_js_1.t)("env.prepare.envCreateFailed"),
|
|
225249
|
-
helpUrl:
|
|
225621
|
+
helpUrl: env_setup_js_2.TCB_PURCHASE_URL,
|
|
225250
225622
|
});
|
|
225251
225623
|
const failureMessage = userNotice
|
|
225252
225624
|
? `${userNotice}\n${createFailure.message}`
|
|
@@ -226345,42 +226717,68 @@ function registerEnvTools(server) {
|
|
|
226345
226717
|
// API Key mode: exchange for temporary credentials
|
|
226346
226718
|
const apiKeyFromEnv = (0, auth_js_1.getCloudBaseApiKeyFromEnv)();
|
|
226347
226719
|
if (apiKeyFromEnv && process.env.CLOUDBASE_ENV_ID) {
|
|
226720
|
+
// 项目级 key 与账号登录并存时,项目级优先——设备码/网页授权即使走完也不生效,
|
|
226721
|
+
// 所以短路段必须说清「怎么切」,否则用户会以为换号成功
|
|
226722
|
+
const removable = (0, auth_js_1.isEnvCredentialRemovableByLogout)();
|
|
226723
|
+
const apiKeyEnvId = process.env.CLOUDBASE_ENV_ID;
|
|
226724
|
+
const switchHint = "\n" +
|
|
226725
|
+
(removable
|
|
226726
|
+
? (0, index_js_1.t)("env.auth.apiKeySwitchHintRemovable", undefined, outLang)
|
|
226727
|
+
: (0, index_js_1.t)("env.auth.apiKeySwitchHintExternal", {
|
|
226728
|
+
varName: process.env.CLOUDBASE_API_KEY
|
|
226729
|
+
? "CLOUDBASE_API_KEY"
|
|
226730
|
+
: "CLOUDBASE_APIKEY",
|
|
226731
|
+
}, outLang));
|
|
226732
|
+
const logoutNextStep = removable
|
|
226733
|
+
? (0, tool_result_js_1.buildAuthNextStep)("logout", {
|
|
226734
|
+
suggestedArgs: { action: "logout", confirm: "yes" },
|
|
226735
|
+
})
|
|
226736
|
+
: undefined;
|
|
226737
|
+
// peek 发现回填的那份已失效时会把 env 清掉:那就不是「登录失败」,
|
|
226738
|
+
// 而是「旧 key 已经作废」,直接往下走正常登录流程
|
|
226739
|
+
let adoptedKeyDropped = false;
|
|
226348
226740
|
try {
|
|
226349
226741
|
const existingLoginState = await (0, auth_js_1.peekLoginState)();
|
|
226350
226742
|
if (existingLoginState) {
|
|
226351
226743
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
226352
226744
|
ok: true,
|
|
226353
226745
|
code: "AUTH_READY",
|
|
226354
|
-
message: await appendApiKeyCamWarningIfNeeded(existingLoginState, (0, index_js_1.t)("env.auth.apiKeyAutoLogin", undefined, outLang)),
|
|
226746
|
+
message: (await appendApiKeyCamWarningIfNeeded(existingLoginState, (0, index_js_1.t)("env.auth.apiKeyAutoLogin", undefined, outLang))) + switchHint,
|
|
226355
226747
|
auth_mode: "api_key",
|
|
226356
|
-
envId:
|
|
226748
|
+
envId: apiKeyEnvId,
|
|
226749
|
+
...(logoutNextStep ? { next_step: logoutNextStep } : {}),
|
|
226357
226750
|
});
|
|
226358
226751
|
}
|
|
226752
|
+
adoptedKeyDropped = !(0, auth_js_1.getCloudBaseApiKeyFromEnv)();
|
|
226359
226753
|
}
|
|
226360
226754
|
catch (e) {
|
|
226361
226755
|
// peekLoginState threw; log and fall through to diagnostic
|
|
226362
226756
|
(0, logger_js_1.debug)("start_auth: peekLoginState threw", { error: e instanceof Error ? e.message : String(e) });
|
|
226363
226757
|
}
|
|
226364
|
-
|
|
226365
|
-
|
|
226366
|
-
|
|
226367
|
-
|
|
226368
|
-
|
|
226369
|
-
(0, index_js_1.t)("env.auth.
|
|
226370
|
-
|
|
226371
|
-
|
|
226372
|
-
|
|
226373
|
-
|
|
226758
|
+
if (!adoptedKeyDropped) {
|
|
226759
|
+
// API Key exchange failed: return diagnostic details
|
|
226760
|
+
const exchangeRegion = (0, site_map_js_1.resolveApiKeyExchangeRegion)();
|
|
226761
|
+
const endpoint = process.env.CLOUDBASE_API_ENDPOINT ||
|
|
226762
|
+
`https://${apiKeyEnvId}.${exchangeRegion ?? "ap-shanghai"}.tcb-api.tencentcloudapi.com`;
|
|
226763
|
+
const diagMessage = (0, index_js_1.t)("env.auth.apiKeyEnvExchangeFailed", undefined, outLang) +
|
|
226764
|
+
(0, index_js_1.t)("env.auth.apiKeyDiagEnv", {
|
|
226765
|
+
envId: String(apiKeyEnvId),
|
|
226766
|
+
apiKeyPrefix: apiKeyFromEnv.slice(0, 20),
|
|
226767
|
+
site: process.env.TCB_SITE || (0, index_js_1.t)("env.auth.siteUnset", undefined, outLang),
|
|
226768
|
+
gatewayRegion: exchangeRegion ?? (0, index_js_1.t)("env.auth.gatewayRegionDefault", undefined, outLang),
|
|
226769
|
+
endpoint,
|
|
226770
|
+
}, outLang) +
|
|
226771
|
+
switchHint;
|
|
226772
|
+
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
226773
|
+
ok: false,
|
|
226774
|
+
code: "API_KEY_AUTH_FAILED",
|
|
226775
|
+
message: diagMessage,
|
|
226776
|
+
auth_mode: "api_key",
|
|
226777
|
+
envId: apiKeyEnvId,
|
|
226374
226778
|
endpoint,
|
|
226375
|
-
|
|
226376
|
-
|
|
226377
|
-
|
|
226378
|
-
code: "API_KEY_AUTH_FAILED",
|
|
226379
|
-
message: diagMessage,
|
|
226380
|
-
auth_mode: "api_key",
|
|
226381
|
-
envId: process.env.CLOUDBASE_ENV_ID,
|
|
226382
|
-
endpoint,
|
|
226383
|
-
});
|
|
226779
|
+
...(logoutNextStep ? { next_step: logoutNextStep } : {}),
|
|
226780
|
+
});
|
|
226781
|
+
}
|
|
226384
226782
|
}
|
|
226385
226783
|
const region = server.cloudBaseOptions?.region || process.env.TCB_REGION;
|
|
226386
226784
|
const auth = toolbox_1.AuthSupervisor.getInstance({});
|
|
@@ -226709,12 +227107,19 @@ function registerEnvTools(server) {
|
|
|
226709
227107
|
});
|
|
226710
227108
|
}
|
|
226711
227109
|
if (action === "logout") {
|
|
226712
|
-
//
|
|
226713
|
-
|
|
227110
|
+
// 用户自己在 shell / 宿主配置里设的 API Key 变量,进程内删不掉,只能提示去源头改;
|
|
227111
|
+
// 按项目保存的那一份(我们回填的,或 login_by_api_key 写下的)能清,走正常登出。
|
|
227112
|
+
if ((0, auth_js_1.getCloudBaseApiKeyFromEnv)() &&
|
|
227113
|
+
process.env.CLOUDBASE_ENV_ID &&
|
|
227114
|
+
!(0, auth_js_1.isEnvCredentialRemovableByLogout)()) {
|
|
226714
227115
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
226715
227116
|
ok: false,
|
|
226716
227117
|
code: "LOGOUT_NOT_ALLOWED",
|
|
226717
|
-
message: (0, index_js_1.t)("env.auth.logoutNotAllowedApiKey",
|
|
227118
|
+
message: (0, index_js_1.t)("env.auth.logoutNotAllowedApiKey", {
|
|
227119
|
+
varName: process.env.CLOUDBASE_API_KEY
|
|
227120
|
+
? "CLOUDBASE_API_KEY"
|
|
227121
|
+
: "CLOUDBASE_APIKEY",
|
|
227122
|
+
}, outLang),
|
|
226718
227123
|
auth_mode: "api_key",
|
|
226719
227124
|
});
|
|
226720
227125
|
}
|
|
@@ -226728,12 +227133,15 @@ function registerEnvTools(server) {
|
|
|
226728
227133
|
}),
|
|
226729
227134
|
});
|
|
226730
227135
|
}
|
|
226731
|
-
await (0, auth_js_1.logout)();
|
|
227136
|
+
const { removed } = await (0, auth_js_1.logout)();
|
|
226732
227137
|
(0, cloudbase_manager_js_1.resetCloudBaseManagerCache)();
|
|
226733
227138
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
226734
227139
|
ok: true,
|
|
226735
227140
|
code: "LOGGED_OUT",
|
|
226736
|
-
|
|
227141
|
+
removed_scopes: removed,
|
|
227142
|
+
message: removed.includes("project")
|
|
227143
|
+
? (0, index_js_1.t)("env.auth.loggedOutProject", undefined, outLang)
|
|
227144
|
+
: (0, index_js_1.t)("env.auth.loggedOut", undefined, outLang),
|
|
226737
227145
|
});
|
|
226738
227146
|
}
|
|
226739
227147
|
if (action === "get_temp_credentials") {
|
|
@@ -226890,11 +227298,8 @@ function registerEnvTools(server) {
|
|
|
226890
227298
|
// Filter parameters match the reference conditions provided by user
|
|
226891
227299
|
result = await cloudbaseList.commonService("tcb", "2018-06-08").call({
|
|
226892
227300
|
Action: "DescribeEnvs",
|
|
226893
|
-
|
|
226894
|
-
|
|
226895
|
-
IsVisible: false, // Filter out invisible environments
|
|
226896
|
-
Channels: ["dcloud", "iotenable", "tem", "scene_module"], // Filter special channels
|
|
226897
|
-
},
|
|
227301
|
+
// 过滤口径与 cloudbase-manager 共用一份,别在这里另写白名单
|
|
227302
|
+
Param: (0, describe_envs_query_js_1.buildDescribeEnvsFilter)(),
|
|
226898
227303
|
});
|
|
226899
227304
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
226900
227305
|
// Transform response format to match original listEnvs() format
|
|
@@ -229512,8 +229917,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
229512
229917
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
229513
229918
|
};
|
|
229514
229919
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
229515
|
-
exports.CUSTOM_IMAGE_RUNTIME = exports.MASKED_ENV_VALUE = exports.LAYER_SOFT_WARN = exports.DEFAULT_FUNCTION_ALIAS = exports.MANAGE_FUNCTION_ACTIONS = exports.QUERY_FUNCTION_ACTIONS = exports.TRIGGER_CONFIG_EXAMPLES = exports.SUPPORTED_TRIGGER_TYPES = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = exports.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE = void 0;
|
|
229920
|
+
exports.CUSTOM_IMAGE_RUNTIME = exports.MASKED_ENV_VALUE = exports.LAYER_SOFT_WARN = exports.FUNCTION_LOG_SERVICE_NOT_ENABLED_ERROR_CODE = exports.FUNCTION_LOG_QUERY_ERROR_CODE = exports.DEFAULT_FUNCTION_ALIAS = exports.MANAGE_FUNCTION_ACTIONS = exports.QUERY_FUNCTION_ACTIONS = exports.TRIGGER_CONFIG_EXAMPLES = exports.SUPPORTED_TRIGGER_TYPES = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = exports.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE = void 0;
|
|
229516
229921
|
exports.formatRuntimeList = formatRuntimeList;
|
|
229922
|
+
exports.formatClsTime = formatClsTime;
|
|
229923
|
+
exports.buildFunctionLogClsQuery = buildFunctionLogClsQuery;
|
|
229924
|
+
exports.resolveFunctionLogWindow = resolveFunctionLogWindow;
|
|
229925
|
+
exports.parseFunctionLogItem = parseFunctionLogItem;
|
|
229926
|
+
exports.isLogServiceNotEnabledMessage = isLogServiceNotEnabledMessage;
|
|
229517
229927
|
exports.layerNameIncludesEnvId = layerNameIncludesEnvId;
|
|
229518
229928
|
exports.buildCreateLayerNameWarning = buildCreateLayerNameWarning;
|
|
229519
229929
|
exports.maskFunctionDetailEnvValues = maskFunctionDetailEnvValues;
|
|
@@ -229677,6 +230087,125 @@ exports.MANAGE_FUNCTION_ACTIONS = [
|
|
|
229677
230087
|
];
|
|
229678
230088
|
/** Default SCF traffic alias used by CloudBase CLI `fn get-route` / `fn config-route`. */
|
|
229679
230089
|
exports.DEFAULT_FUNCTION_ALIAS = "$DEFAULT";
|
|
230090
|
+
/**
|
|
230091
|
+
* 云函数日志的 CLS 检索底座。
|
|
230092
|
+
*
|
|
230093
|
+
* 底层 `GetFunctionLogs` / `GetFunctionLogDetail` 已下线(`@cloudbase/manager-node` 5.8.8 起
|
|
230094
|
+
* `getFunctionLogsV2` / `getFunctionLogDetail` 直接抛错),云函数日志只能从 CLS 取。CLS 里每条
|
|
230095
|
+
* 云函数日志是按请求聚合的 JSON,`function_name` / `request_id` / `qualifier` / `src` 都是扁平
|
|
230096
|
+
* 字段,可以直接做检索条件,不需要再扫全量日志。
|
|
230097
|
+
*/
|
|
230098
|
+
const FUNCTION_LOG_CLS_SOURCE = "(src:app OR src:system)";
|
|
230099
|
+
/** SearchClsLog 单次返回上限。 */
|
|
230100
|
+
const FUNCTION_LOG_MAX_LIMIT = 100;
|
|
230101
|
+
const FUNCTION_LOG_DEFAULT_LIMIT = 20;
|
|
230102
|
+
const FUNCTION_LOG_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
230103
|
+
/**
|
|
230104
|
+
* CLS 的时间入参固定按北京时间理解(与返回的 `Timestamp` 一致),
|
|
230105
|
+
* 托管形态的服务进程可能是 UTC,所以这里显式加偏移,不依赖进程时区。
|
|
230106
|
+
*/
|
|
230107
|
+
const CLS_TIME_OFFSET_MS = 8 * 60 * 60 * 1000;
|
|
230108
|
+
/** CLS 检索语法里 `key:"value"` 的值需要转义反斜杠与双引号。 */
|
|
230109
|
+
function escapeClsValue(value) {
|
|
230110
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
230111
|
+
}
|
|
230112
|
+
/** CLS 入参/展示用的时间格式:YYYY-MM-DD HH:mm:ss(北京时间)。 */
|
|
230113
|
+
function formatClsTime(time) {
|
|
230114
|
+
return new Date(time + CLS_TIME_OFFSET_MS).toISOString().slice(0, 19).replace("T", " ");
|
|
230115
|
+
}
|
|
230116
|
+
function buildFunctionLogClsQuery(input) {
|
|
230117
|
+
const clauses = [FUNCTION_LOG_CLS_SOURCE];
|
|
230118
|
+
if (input.functionName) {
|
|
230119
|
+
clauses.push(`function_name:"${escapeClsValue(input.functionName)}"`);
|
|
230120
|
+
}
|
|
230121
|
+
if (input.qualifier) {
|
|
230122
|
+
clauses.push(`qualifier:"${escapeClsValue(input.qualifier)}"`);
|
|
230123
|
+
}
|
|
230124
|
+
if (input.requestId) {
|
|
230125
|
+
clauses.push(`request_id:"${escapeClsValue(input.requestId)}"`);
|
|
230126
|
+
}
|
|
230127
|
+
return clauses.join(" AND ");
|
|
230128
|
+
}
|
|
230129
|
+
/** 只传一端时把窗口收敛到 24 小时以内,CLS 与旧接口都限制单次跨度。 */
|
|
230130
|
+
function resolveFunctionLogWindow(startTime, endTime, now = Date.now()) {
|
|
230131
|
+
if (startTime && endTime) {
|
|
230132
|
+
return { StartTime: startTime, EndTime: endTime };
|
|
230133
|
+
}
|
|
230134
|
+
if (startTime) {
|
|
230135
|
+
const start = new Date(startTime).getTime();
|
|
230136
|
+
// 单一 startTime 时至少给出一分钟窗口:起止相同(或 start 在未来)时 CLS 会直接判非法。
|
|
230137
|
+
const end = Number.isFinite(start)
|
|
230138
|
+
? Math.max(start + 60_000, Math.min(now, start + FUNCTION_LOG_WINDOW_MS))
|
|
230139
|
+
: now;
|
|
230140
|
+
return { StartTime: startTime, EndTime: formatClsTime(end) };
|
|
230141
|
+
}
|
|
230142
|
+
if (endTime) {
|
|
230143
|
+
const end = new Date(endTime).getTime();
|
|
230144
|
+
const start = Number.isFinite(end) ? end - FUNCTION_LOG_WINDOW_MS : now - FUNCTION_LOG_WINDOW_MS;
|
|
230145
|
+
return { StartTime: formatClsTime(start), EndTime: endTime };
|
|
230146
|
+
}
|
|
230147
|
+
return { StartTime: formatClsTime(now - FUNCTION_LOG_WINDOW_MS), EndTime: formatClsTime(now) };
|
|
230148
|
+
}
|
|
230149
|
+
/**
|
|
230150
|
+
* 把 CLS 的日志条目还原成调用方关心的字段。
|
|
230151
|
+
*
|
|
230152
|
+
* 解析失败时(例如用户自己打的纯文本日志)保留原文放进 `log`,不让一条脏数据毁掉整页结果。
|
|
230153
|
+
*/
|
|
230154
|
+
function parseFunctionLogItem(item) {
|
|
230155
|
+
const content = typeof item.Content === "string" ? item.Content : "";
|
|
230156
|
+
let parsed = null;
|
|
230157
|
+
try {
|
|
230158
|
+
const value = JSON.parse(content);
|
|
230159
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
230160
|
+
parsed = value;
|
|
230161
|
+
}
|
|
230162
|
+
}
|
|
230163
|
+
catch {
|
|
230164
|
+
parsed = null;
|
|
230165
|
+
}
|
|
230166
|
+
const timestamp = item.Timestamp ?? "";
|
|
230167
|
+
if (!parsed) {
|
|
230168
|
+
return {
|
|
230169
|
+
requestId: "",
|
|
230170
|
+
functionName: "",
|
|
230171
|
+
qualifier: "",
|
|
230172
|
+
source: "",
|
|
230173
|
+
log: content,
|
|
230174
|
+
statusCode: "",
|
|
230175
|
+
retCode: "",
|
|
230176
|
+
durationMs: null,
|
|
230177
|
+
memoryMb: null,
|
|
230178
|
+
memUsageBytes: null,
|
|
230179
|
+
requestSource: "",
|
|
230180
|
+
timestamp,
|
|
230181
|
+
};
|
|
230182
|
+
}
|
|
230183
|
+
const str = (value) => value === undefined || value === null ? "" : String(value);
|
|
230184
|
+
const num = (value) => {
|
|
230185
|
+
const parsedNumber = Number(value);
|
|
230186
|
+
return Number.isFinite(parsedNumber) ? parsedNumber : null;
|
|
230187
|
+
};
|
|
230188
|
+
return {
|
|
230189
|
+
requestId: str(parsed.request_id),
|
|
230190
|
+
functionName: str(parsed.function_name),
|
|
230191
|
+
qualifier: str(parsed.qualifier || parsed.alias),
|
|
230192
|
+
source: str(parsed.src),
|
|
230193
|
+
log: str(parsed.log || parsed.tcb_log),
|
|
230194
|
+
statusCode: str(parsed.status_code),
|
|
230195
|
+
retCode: str(parsed.ret_code),
|
|
230196
|
+
durationMs: num(parsed.duration),
|
|
230197
|
+
memoryMb: num(parsed.memory),
|
|
230198
|
+
memUsageBytes: num(parsed.mem_usage),
|
|
230199
|
+
requestSource: str(parsed.request_source),
|
|
230200
|
+
timestamp,
|
|
230201
|
+
};
|
|
230202
|
+
}
|
|
230203
|
+
exports.FUNCTION_LOG_QUERY_ERROR_CODE = "FUNCTION_LOG_QUERY_FAILED";
|
|
230204
|
+
exports.FUNCTION_LOG_SERVICE_NOT_ENABLED_ERROR_CODE = "LOG_SERVICE_NOT_ENABLED";
|
|
230205
|
+
/** 未开通日志服务时 CLS 报的是 topic 不存在,按这个特征把它翻译成可执行的下一步。 */
|
|
230206
|
+
function isLogServiceNotEnabledMessage(message) {
|
|
230207
|
+
return /TopicNotExist|TopicIsolated|topic[\s\S]{0,20}not\s*exist|日志服务未开通/i.test(message);
|
|
230208
|
+
}
|
|
229680
230209
|
/** Layer soft-warn copy — account-scoped SCF LayerName guidance (no hard fail). */
|
|
229681
230210
|
exports.LAYER_SOFT_WARN = {
|
|
229682
230211
|
createNameFormat: (envId) => (0, index_js_1.t)("functions.layerWarn.createNameFormat", { envId }),
|
|
@@ -230144,6 +230673,81 @@ function registerFunctionTools(server) {
|
|
|
230144
230673
|
}
|
|
230145
230674
|
}
|
|
230146
230675
|
};
|
|
230676
|
+
/**
|
|
230677
|
+
* 云函数日志统一走 CLS。查询失败时分两类给出可执行的下一步:
|
|
230678
|
+
* 日志服务没开通 ⇒ 引导开通;其它失败 ⇒ 引导到 queryLogs 用同一条检索语句重试。
|
|
230679
|
+
*/
|
|
230680
|
+
const throwLogQueryError = (error, scope) => {
|
|
230681
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
230682
|
+
if (isLogServiceNotEnabledMessage(message)) {
|
|
230683
|
+
(0, tool_result_js_1.throwToolPayloadError)({
|
|
230684
|
+
success: false,
|
|
230685
|
+
errorCode: exports.FUNCTION_LOG_SERVICE_NOT_ENABLED_ERROR_CODE,
|
|
230686
|
+
data: { ...scope },
|
|
230687
|
+
message: (0, index_js_1.t)("functions.logs.serviceNotEnabled"),
|
|
230688
|
+
nextActions: [
|
|
230689
|
+
{
|
|
230690
|
+
tool: "manageLogs",
|
|
230691
|
+
action: "createLogService",
|
|
230692
|
+
reason: (0, index_js_1.t)("functions.reason.createLogService"),
|
|
230693
|
+
suggested_args: { action: "createLogService", confirm: true },
|
|
230694
|
+
},
|
|
230695
|
+
],
|
|
230696
|
+
});
|
|
230697
|
+
}
|
|
230698
|
+
(0, tool_result_js_1.throwToolPayloadError)({
|
|
230699
|
+
success: false,
|
|
230700
|
+
errorCode: exports.FUNCTION_LOG_QUERY_ERROR_CODE,
|
|
230701
|
+
data: { ...scope, rawError: message },
|
|
230702
|
+
message: (0, index_js_1.t)("functions.logs.queryFailed", { message }),
|
|
230703
|
+
nextActions: [
|
|
230704
|
+
{
|
|
230705
|
+
tool: "queryLogs",
|
|
230706
|
+
action: "searchLogs",
|
|
230707
|
+
reason: (0, index_js_1.t)("functions.reason.searchClsFallback"),
|
|
230708
|
+
suggested_args: {
|
|
230709
|
+
action: "searchLogs",
|
|
230710
|
+
service: "tcb",
|
|
230711
|
+
queryString: buildFunctionLogClsQuery({
|
|
230712
|
+
functionName: scope.functionName,
|
|
230713
|
+
requestId: scope.requestId,
|
|
230714
|
+
}),
|
|
230715
|
+
startTime: scope.window.StartTime,
|
|
230716
|
+
endTime: scope.window.EndTime,
|
|
230717
|
+
},
|
|
230718
|
+
},
|
|
230719
|
+
],
|
|
230720
|
+
});
|
|
230721
|
+
};
|
|
230722
|
+
/**
|
|
230723
|
+
* 空结果不等于「函数没被调用」:日志服务没开通时 CLS 同样返回空。
|
|
230724
|
+
* 这里只在真的查到空结果时多做一次开销很小的探活,避免把「没开通」误报成「没日志」。
|
|
230725
|
+
*/
|
|
230726
|
+
const assertLogServiceEnabled = async (logService) => {
|
|
230727
|
+
try {
|
|
230728
|
+
if (await logService.checkLogServiceEnabled()) {
|
|
230729
|
+
return;
|
|
230730
|
+
}
|
|
230731
|
+
}
|
|
230732
|
+
catch {
|
|
230733
|
+
// 探活失败不制造新的错误源:保持「该时间段没有日志」的原始结论。
|
|
230734
|
+
return;
|
|
230735
|
+
}
|
|
230736
|
+
(0, tool_result_js_1.throwToolPayloadError)({
|
|
230737
|
+
success: false,
|
|
230738
|
+
errorCode: exports.FUNCTION_LOG_SERVICE_NOT_ENABLED_ERROR_CODE,
|
|
230739
|
+
data: { enabled: false },
|
|
230740
|
+
message: (0, index_js_1.t)("functions.logs.serviceNotEnabled"),
|
|
230741
|
+
nextActions: [
|
|
230742
|
+
{
|
|
230743
|
+
tool: "manageLogs",
|
|
230744
|
+
action: "createLogService",
|
|
230745
|
+
reason: (0, index_js_1.t)("functions.reason.createLogService"),
|
|
230746
|
+
suggested_args: { action: "createLogService", confirm: true },
|
|
230747
|
+
},
|
|
230748
|
+
],
|
|
230749
|
+
});
|
|
230750
|
+
};
|
|
230147
230751
|
const normalizeManageLayers = (layers) => normalizeFunctionLayers((layers ?? []).map((layer) => ({
|
|
230148
230752
|
LayerName: layer.layerName ?? layer.LayerName,
|
|
230149
230753
|
LayerVersion: layer.layerVersion ?? layer.LayerVersion,
|
|
@@ -230265,39 +230869,86 @@ function registerFunctionTools(server) {
|
|
|
230265
230869
|
}
|
|
230266
230870
|
validateLogRange(input.startTime, input.endTime, input.offset, input.limit);
|
|
230267
230871
|
const cloudbase = await getManager();
|
|
230268
|
-
|
|
230872
|
+
const window = resolveFunctionLogWindow(input.startTime, input.endTime);
|
|
230873
|
+
const limit = Math.min(Math.max(input.limit ?? FUNCTION_LOG_DEFAULT_LIMIT, 1), FUNCTION_LOG_MAX_LIMIT);
|
|
230874
|
+
const offset = Math.max(input.offset ?? 0, 0);
|
|
230875
|
+
// SearchClsLog 单次最多 100 条且没有 offset 入参:不带游标时多取 offset+limit 再本地
|
|
230876
|
+
// 切片,带游标(context)时游标本身已经记录了偏移,直接返回当页。
|
|
230877
|
+
const fetchLimit = Math.min(offset + limit, FUNCTION_LOG_MAX_LIMIT);
|
|
230878
|
+
const queryString = buildFunctionLogClsQuery({
|
|
230879
|
+
functionName: input.functionName,
|
|
230880
|
+
requestId: input.requestId,
|
|
230881
|
+
qualifier: input.qualifier,
|
|
230882
|
+
});
|
|
230883
|
+
let logResults = {};
|
|
230269
230884
|
try {
|
|
230270
|
-
result = await cloudbase.
|
|
230271
|
-
|
|
230272
|
-
|
|
230273
|
-
|
|
230274
|
-
|
|
230275
|
-
|
|
230276
|
-
|
|
230277
|
-
|
|
230885
|
+
const result = await cloudbase.log.searchClsLog({
|
|
230886
|
+
queryString,
|
|
230887
|
+
StartTime: window.StartTime,
|
|
230888
|
+
EndTime: window.EndTime,
|
|
230889
|
+
Limit: fetchLimit,
|
|
230890
|
+
Context: input.context,
|
|
230891
|
+
Sort: "desc",
|
|
230892
|
+
service: "tcb",
|
|
230278
230893
|
});
|
|
230894
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
230895
|
+
logResults = result.LogResults ?? {};
|
|
230279
230896
|
}
|
|
230280
230897
|
catch (error) {
|
|
230281
|
-
|
|
230282
|
-
if (/invalid parameter/i.test(errMsg)) {
|
|
230283
|
-
throw new Error(`${errMsg}\n\n${(0, index_js_1.t)("functions.logsInvalidParamTips")}`);
|
|
230284
|
-
}
|
|
230285
|
-
throw error;
|
|
230898
|
+
throwLogQueryError(error, { functionName: input.functionName, window });
|
|
230286
230899
|
}
|
|
230287
|
-
|
|
230900
|
+
const entries = (logResults.Results ?? []).map(parseFunctionLogItem);
|
|
230901
|
+
const logs = input.context ? entries : entries.slice(offset, offset + limit);
|
|
230902
|
+
if (logs.length === 0) {
|
|
230903
|
+
await assertLogServiceEnabled(cloudbase.log);
|
|
230904
|
+
}
|
|
230905
|
+
const hasMore = !logResults.ListOver && Boolean(logResults.Context);
|
|
230288
230906
|
return buildEnvelope({
|
|
230289
230907
|
action: input.action,
|
|
230290
230908
|
functionName: input.functionName,
|
|
230291
|
-
|
|
230292
|
-
|
|
230293
|
-
|
|
230294
|
-
|
|
230295
|
-
|
|
230296
|
-
|
|
230297
|
-
|
|
230298
|
-
|
|
230299
|
-
|
|
230300
|
-
|
|
230909
|
+
service: "tcb",
|
|
230910
|
+
queryString,
|
|
230911
|
+
startTime: window.StartTime,
|
|
230912
|
+
endTime: window.EndTime,
|
|
230913
|
+
logs,
|
|
230914
|
+
count: logs.length,
|
|
230915
|
+
context: logResults.Context ?? null,
|
|
230916
|
+
hasMore,
|
|
230917
|
+
}, logs.length > 0
|
|
230918
|
+
? (0, index_js_1.t)("functions.gotFunctionLogs", { fnName: input.functionName })
|
|
230919
|
+
: (0, index_js_1.t)("functions.logs.emptyByFunction", {
|
|
230920
|
+
fnName: input.functionName,
|
|
230921
|
+
start: window.StartTime,
|
|
230922
|
+
end: window.EndTime,
|
|
230923
|
+
}), hasMore
|
|
230924
|
+
? [
|
|
230925
|
+
{
|
|
230926
|
+
tool: "queryFunctions",
|
|
230927
|
+
action: "listFunctionLogs",
|
|
230928
|
+
reason: (0, index_js_1.t)("functions.reason.nextLogPage"),
|
|
230929
|
+
suggested_args: {
|
|
230930
|
+
action: "listFunctionLogs",
|
|
230931
|
+
functionName: input.functionName,
|
|
230932
|
+
context: logResults.Context,
|
|
230933
|
+
startTime: window.StartTime,
|
|
230934
|
+
endTime: window.EndTime,
|
|
230935
|
+
limit,
|
|
230936
|
+
},
|
|
230937
|
+
},
|
|
230938
|
+
]
|
|
230939
|
+
: [
|
|
230940
|
+
{
|
|
230941
|
+
tool: "queryFunctions",
|
|
230942
|
+
action: "getFunctionLogDetail",
|
|
230943
|
+
reason: (0, index_js_1.t)("functions.reason.logDetail"),
|
|
230944
|
+
suggested_args: {
|
|
230945
|
+
action: "getFunctionLogDetail",
|
|
230946
|
+
requestId: logs[0]?.requestId || "<日志里的 requestId>",
|
|
230947
|
+
startTime: window.StartTime,
|
|
230948
|
+
endTime: window.EndTime,
|
|
230949
|
+
},
|
|
230950
|
+
},
|
|
230951
|
+
]);
|
|
230301
230952
|
}
|
|
230302
230953
|
case "getFunctionLogDetail": {
|
|
230303
230954
|
if (!input.requestId) {
|
|
@@ -230305,27 +230956,67 @@ function registerFunctionTools(server) {
|
|
|
230305
230956
|
}
|
|
230306
230957
|
validateLogRange(input.startTime, input.endTime);
|
|
230307
230958
|
const cloudbase = await getManager();
|
|
230308
|
-
|
|
230959
|
+
const window = resolveFunctionLogWindow(input.startTime, input.endTime);
|
|
230960
|
+
const queryString = buildFunctionLogClsQuery({
|
|
230961
|
+
functionName: input.functionName,
|
|
230962
|
+
requestId: input.requestId,
|
|
230963
|
+
qualifier: input.qualifier,
|
|
230964
|
+
});
|
|
230965
|
+
let logResults = {};
|
|
230309
230966
|
try {
|
|
230310
|
-
result = await cloudbase.
|
|
230311
|
-
|
|
230312
|
-
|
|
230313
|
-
|
|
230967
|
+
const result = await cloudbase.log.searchClsLog({
|
|
230968
|
+
queryString,
|
|
230969
|
+
StartTime: window.StartTime,
|
|
230970
|
+
EndTime: window.EndTime,
|
|
230971
|
+
Limit: FUNCTION_LOG_MAX_LIMIT,
|
|
230972
|
+
Sort: "asc",
|
|
230973
|
+
service: "tcb",
|
|
230314
230974
|
});
|
|
230975
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
230976
|
+
logResults = result.LogResults ?? {};
|
|
230315
230977
|
}
|
|
230316
230978
|
catch (error) {
|
|
230317
|
-
|
|
230318
|
-
|
|
230319
|
-
|
|
230320
|
-
|
|
230321
|
-
|
|
230979
|
+
throwLogQueryError(error, { requestId: input.requestId, window });
|
|
230980
|
+
}
|
|
230981
|
+
// 一次调用在 CLS 里是多条记录(START / 业务日志 / REPORT),按时间升序拼回完整过程。
|
|
230982
|
+
const entries = (logResults.Results ?? []).map(parseFunctionLogItem);
|
|
230983
|
+
if (entries.length === 0) {
|
|
230984
|
+
await assertLogServiceEnabled(cloudbase.log);
|
|
230985
|
+
return buildEnvelope({
|
|
230986
|
+
action: input.action,
|
|
230987
|
+
requestId: input.requestId,
|
|
230988
|
+
queryString,
|
|
230989
|
+
startTime: window.StartTime,
|
|
230990
|
+
endTime: window.EndTime,
|
|
230991
|
+
logs: [],
|
|
230992
|
+
count: 0,
|
|
230993
|
+
}, (0, index_js_1.t)("functions.logs.emptyByRequest", {
|
|
230994
|
+
requestId: input.requestId,
|
|
230995
|
+
start: window.StartTime,
|
|
230996
|
+
end: window.EndTime,
|
|
230997
|
+
}), [
|
|
230998
|
+
{
|
|
230999
|
+
tool: "queryFunctions",
|
|
231000
|
+
action: "listFunctionLogs",
|
|
231001
|
+
reason: (0, index_js_1.t)("functions.reason.widenLogRange"),
|
|
231002
|
+
suggested_args: {
|
|
231003
|
+
action: "listFunctionLogs",
|
|
231004
|
+
functionName: input.functionName || "<函数名>",
|
|
231005
|
+
startTime: window.StartTime,
|
|
231006
|
+
endTime: window.EndTime,
|
|
231007
|
+
},
|
|
231008
|
+
},
|
|
231009
|
+
]);
|
|
230322
231010
|
}
|
|
230323
|
-
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
230324
231011
|
return buildEnvelope({
|
|
230325
231012
|
action: input.action,
|
|
230326
231013
|
requestId: input.requestId,
|
|
230327
|
-
|
|
230328
|
-
|
|
231014
|
+
functionName: entries[0]?.functionName || input.functionName || null,
|
|
231015
|
+
queryString,
|
|
231016
|
+
startTime: window.StartTime,
|
|
231017
|
+
endTime: window.EndTime,
|
|
231018
|
+
logs: entries,
|
|
231019
|
+
count: entries.length,
|
|
230329
231020
|
}, (0, index_js_1.t)("functions.gotLogDetail", { requestId: input.requestId }));
|
|
230330
231021
|
}
|
|
230331
231022
|
case "listFunctionLayers": {
|
|
@@ -231701,6 +232392,7 @@ function registerFunctionTools(server) {
|
|
|
231701
232392
|
.optional()
|
|
231702
232393
|
.describe("functions.schema.query.requestId"),
|
|
231703
232394
|
qualifier: zod_1.z.string().optional().describe("functions.schema.query.qualifier"),
|
|
232395
|
+
context: zod_1.z.string().optional().describe("functions.schema.query.context"),
|
|
231704
232396
|
runtime: zod_1.z.string().optional().describe("functions.schema.query.runtime"),
|
|
231705
232397
|
searchKey: zod_1.z.string().optional().describe("functions.schema.query.searchKey"),
|
|
231706
232398
|
layerName: zod_1.z
|
|
@@ -231827,6 +232519,7 @@ const QUERY_GATEWAY_ACTIONS = [
|
|
|
231827
232519
|
"getRoute",
|
|
231828
232520
|
"listCustomDomains",
|
|
231829
232521
|
"getPrivilege",
|
|
232522
|
+
"cachePurgeTask",
|
|
231830
232523
|
];
|
|
231831
232524
|
const MANAGE_GATEWAY_ACTIONS = [
|
|
231832
232525
|
"createRoute",
|
|
@@ -231838,6 +232531,7 @@ const MANAGE_GATEWAY_ACTIONS = [
|
|
|
231838
232531
|
"deleteCustomDomain",
|
|
231839
232532
|
"enableService",
|
|
231840
232533
|
"authSwitch",
|
|
232534
|
+
"purgeCache",
|
|
231841
232535
|
];
|
|
231842
232536
|
/** DomainType of the environment default HTTP service (gateway) domain. */
|
|
231843
232537
|
const HTTP_SERVICE_DOMAIN_TYPE = "HTTPSERVICE";
|
|
@@ -231847,6 +232541,24 @@ const UPSTREAM_RESOURCE_TYPES = [
|
|
|
231847
232541
|
"CBR",
|
|
231848
232542
|
"STATIC_STORE",
|
|
231849
232543
|
"LH",
|
|
232544
|
+
"STORAGE",
|
|
232545
|
+
];
|
|
232546
|
+
/** Domain-level protocol accepted by HTTPServiceDomainParam. */
|
|
232547
|
+
const DOMAIN_PROTOCOLS = [
|
|
232548
|
+
"HTTP",
|
|
232549
|
+
"HTTPS",
|
|
232550
|
+
"HTTP_AND_HTTPS",
|
|
232551
|
+
"HTTP_TO_HTTPS",
|
|
232552
|
+
"HTTPS_TO_HTTP",
|
|
232553
|
+
];
|
|
232554
|
+
/** Cache layer that owns the purged objects (CDN vs EdgeOne). */
|
|
232555
|
+
const CACHE_TYPES = ["CDN", "EO"];
|
|
232556
|
+
const PURGE_TYPES = ["PURGE_URL", "PURGE_PREFIX", "PURGE_HOST"];
|
|
232557
|
+
const HEADER_ADD_ACTIONS = [
|
|
232558
|
+
"APPEND_IF_EXISTS_OR_ADD",
|
|
232559
|
+
"ADD_IF_ABSENT",
|
|
232560
|
+
"OVERWRITE_IF_EXISTS_OR_ADD",
|
|
232561
|
+
"OVERWRITE_IF_EXISTS",
|
|
231850
232562
|
];
|
|
231851
232563
|
function normalizeAccessPath(path) {
|
|
231852
232564
|
if (!path) {
|
|
@@ -231854,6 +232566,225 @@ function normalizeAccessPath(path) {
|
|
|
231854
232566
|
}
|
|
231855
232567
|
return path.startsWith("/") ? path : `/${path}`;
|
|
231856
232568
|
}
|
|
232569
|
+
// ---------------------------------------------------------------------------
|
|
232570
|
+
// Route/Domain extension schemas (aligned with manager-node HTTPServiceRouteParam)
|
|
232571
|
+
// ---------------------------------------------------------------------------
|
|
232572
|
+
const headerToAddSchema = zod_1.z.object({
|
|
232573
|
+
key: zod_1.z.string().describe("gateway.schema.manage.extension.header.key"),
|
|
232574
|
+
value: zod_1.z.string().describe("gateway.schema.manage.extension.header.value"),
|
|
232575
|
+
action: zod_1.z
|
|
232576
|
+
.enum(HEADER_ADD_ACTIONS)
|
|
232577
|
+
.optional()
|
|
232578
|
+
.describe("gateway.schema.manage.extension.header.action"),
|
|
232579
|
+
});
|
|
232580
|
+
const headersHandlerSchema = zod_1.z.object({
|
|
232581
|
+
requestHeadersToAdd: zod_1.z.array(headerToAddSchema).optional(),
|
|
232582
|
+
requestHeadersToRemove: zod_1.z.array(zod_1.z.string()).optional(),
|
|
232583
|
+
responseHeadersToAdd: zod_1.z.array(headerToAddSchema).optional(),
|
|
232584
|
+
responseHeadersToRemove: zod_1.z.array(zod_1.z.string()).optional(),
|
|
232585
|
+
});
|
|
232586
|
+
const cacheRuleSchema = zod_1.z.object({
|
|
232587
|
+
description: zod_1.z.string().optional(),
|
|
232588
|
+
enable: zod_1.z.boolean().optional(),
|
|
232589
|
+
condition: zod_1.z
|
|
232590
|
+
.object({
|
|
232591
|
+
target: zod_1.z.enum(["url_path", "file_extension", "full_uri"]).optional(),
|
|
232592
|
+
matchType: zod_1.z.enum(["prefix", "suffix", "contains", "exact"]).optional(),
|
|
232593
|
+
values: zod_1.z.array(zod_1.z.string()).optional(),
|
|
232594
|
+
})
|
|
232595
|
+
.describe("gateway.schema.manage.extension.cacheCondition"),
|
|
232596
|
+
actions: zod_1.z
|
|
232597
|
+
.array(zod_1.z.object({
|
|
232598
|
+
type: zod_1.z.enum(["Cache", "CacheKey"]).optional(),
|
|
232599
|
+
cache: zod_1.z
|
|
232600
|
+
.object({
|
|
232601
|
+
followOrigin: zod_1.z.boolean().optional(),
|
|
232602
|
+
noCache: zod_1.z.boolean().optional(),
|
|
232603
|
+
cacheTime: zod_1.z.number().int().min(0).optional(),
|
|
232604
|
+
maxAgeTime: zod_1.z.number().int().min(0).optional(),
|
|
232605
|
+
})
|
|
232606
|
+
.optional(),
|
|
232607
|
+
cacheKey: zod_1.z
|
|
232608
|
+
.object({
|
|
232609
|
+
fullUrlCache: zod_1.z.enum(["on", "off"]).optional(),
|
|
232610
|
+
queryStringSwitch: zod_1.z.enum(["on", "off"]).optional(),
|
|
232611
|
+
queryStringAction: zod_1.z.enum(["includeCustom", "excludeCustom"]).optional(),
|
|
232612
|
+
queryStringValues: zod_1.z.array(zod_1.z.string()).optional(),
|
|
232613
|
+
})
|
|
232614
|
+
.optional(),
|
|
232615
|
+
}))
|
|
232616
|
+
.describe("gateway.schema.manage.extension.cacheActions"),
|
|
232617
|
+
});
|
|
232618
|
+
const extensionSchema = zod_1.z.object({
|
|
232619
|
+
headersHandler: headersHandlerSchema.optional(),
|
|
232620
|
+
cache: zod_1.z.object({ rules: zod_1.z.array(cacheRuleSchema).optional() }).optional(),
|
|
232621
|
+
});
|
|
232622
|
+
const pathRewriteSchema = zod_1.z.object({
|
|
232623
|
+
prefix: zod_1.z.string().optional(),
|
|
232624
|
+
staticStorePrefix: zod_1.z.string().optional(),
|
|
232625
|
+
});
|
|
232626
|
+
const qpsPolicySchema = zod_1.z.object({
|
|
232627
|
+
total: zod_1.z.number().int().min(0).optional(),
|
|
232628
|
+
perClient: zod_1.z
|
|
232629
|
+
.object({
|
|
232630
|
+
limitBy: zod_1.z.enum(["ClientIP", "UserID"]).optional(),
|
|
232631
|
+
limitValue: zod_1.z.number().int().min(1).optional(),
|
|
232632
|
+
})
|
|
232633
|
+
.optional(),
|
|
232634
|
+
});
|
|
232635
|
+
function toHeadersHandler(input) {
|
|
232636
|
+
if (!input) {
|
|
232637
|
+
return undefined;
|
|
232638
|
+
}
|
|
232639
|
+
const output = {};
|
|
232640
|
+
const toHeader = (item) => item.action
|
|
232641
|
+
? { Key: item.key, Value: item.value, Action: item.action }
|
|
232642
|
+
: { Key: item.key, Value: item.value };
|
|
232643
|
+
if (input.requestHeadersToAdd?.length) {
|
|
232644
|
+
output.RequestHeadersToAdd = input.requestHeadersToAdd.map(toHeader);
|
|
232645
|
+
}
|
|
232646
|
+
if (input.requestHeadersToRemove?.length) {
|
|
232647
|
+
output.RequestHeadersToRemove = input.requestHeadersToRemove;
|
|
232648
|
+
}
|
|
232649
|
+
if (input.responseHeadersToAdd?.length) {
|
|
232650
|
+
output.ResponseHeadersToAdd = input.responseHeadersToAdd.map(toHeader);
|
|
232651
|
+
}
|
|
232652
|
+
if (input.responseHeadersToRemove?.length) {
|
|
232653
|
+
output.ResponseHeadersToRemove = input.responseHeadersToRemove;
|
|
232654
|
+
}
|
|
232655
|
+
return Object.keys(output).length ? output : undefined;
|
|
232656
|
+
}
|
|
232657
|
+
function toCacheSet(input) {
|
|
232658
|
+
if (!input?.rules?.length) {
|
|
232659
|
+
return undefined;
|
|
232660
|
+
}
|
|
232661
|
+
return {
|
|
232662
|
+
Rules: input.rules.map((rule) => ({
|
|
232663
|
+
...(rule.description !== undefined ? { Description: rule.description } : {}),
|
|
232664
|
+
...(rule.enable !== undefined ? { Enable: rule.enable } : {}),
|
|
232665
|
+
Condition: {
|
|
232666
|
+
...(rule.condition?.target ? { Target: rule.condition.target } : {}),
|
|
232667
|
+
...(rule.condition?.matchType ? { MatchType: rule.condition.matchType } : {}),
|
|
232668
|
+
...(rule.condition?.values ? { Values: rule.condition.values } : {}),
|
|
232669
|
+
},
|
|
232670
|
+
Actions: (rule.actions ?? []).map((action) => ({
|
|
232671
|
+
...(action.type ? { Type: action.type } : {}),
|
|
232672
|
+
...(action.cache
|
|
232673
|
+
? {
|
|
232674
|
+
Cache: {
|
|
232675
|
+
...(action.cache.followOrigin !== undefined
|
|
232676
|
+
? { FollowOrigin: action.cache.followOrigin }
|
|
232677
|
+
: {}),
|
|
232678
|
+
...(action.cache.noCache !== undefined
|
|
232679
|
+
? { NoCache: action.cache.noCache }
|
|
232680
|
+
: {}),
|
|
232681
|
+
...(action.cache.cacheTime !== undefined
|
|
232682
|
+
? { CacheTime: action.cache.cacheTime }
|
|
232683
|
+
: {}),
|
|
232684
|
+
...(action.cache.maxAgeTime !== undefined
|
|
232685
|
+
? { MaxAgeTime: action.cache.maxAgeTime }
|
|
232686
|
+
: {}),
|
|
232687
|
+
},
|
|
232688
|
+
}
|
|
232689
|
+
: {}),
|
|
232690
|
+
...(action.cacheKey
|
|
232691
|
+
? {
|
|
232692
|
+
CacheKey: {
|
|
232693
|
+
...(action.cacheKey.fullUrlCache
|
|
232694
|
+
? { FullURLCache: action.cacheKey.fullUrlCache }
|
|
232695
|
+
: {}),
|
|
232696
|
+
...(action.cacheKey.queryStringSwitch
|
|
232697
|
+
? { QueryStringSwitch: action.cacheKey.queryStringSwitch }
|
|
232698
|
+
: {}),
|
|
232699
|
+
...(action.cacheKey.queryStringAction
|
|
232700
|
+
? { QueryStringAction: action.cacheKey.queryStringAction }
|
|
232701
|
+
: {}),
|
|
232702
|
+
...(action.cacheKey.queryStringValues
|
|
232703
|
+
? { QueryStringValues: action.cacheKey.queryStringValues }
|
|
232704
|
+
: {}),
|
|
232705
|
+
},
|
|
232706
|
+
}
|
|
232707
|
+
: {}),
|
|
232708
|
+
})),
|
|
232709
|
+
})),
|
|
232710
|
+
};
|
|
232711
|
+
}
|
|
232712
|
+
function toExtension(input) {
|
|
232713
|
+
if (!input) {
|
|
232714
|
+
return undefined;
|
|
232715
|
+
}
|
|
232716
|
+
const output = {};
|
|
232717
|
+
const headersHandler = toHeadersHandler(input.headersHandler);
|
|
232718
|
+
if (headersHandler) {
|
|
232719
|
+
output.HeadersHandler = headersHandler;
|
|
232720
|
+
}
|
|
232721
|
+
const cache = toCacheSet(input.cache);
|
|
232722
|
+
if (cache) {
|
|
232723
|
+
output.Cache = cache;
|
|
232724
|
+
}
|
|
232725
|
+
return Object.keys(output).length ? output : undefined;
|
|
232726
|
+
}
|
|
232727
|
+
function toPathRewrite(input) {
|
|
232728
|
+
if (!input) {
|
|
232729
|
+
return undefined;
|
|
232730
|
+
}
|
|
232731
|
+
const output = {};
|
|
232732
|
+
if (typeof input.prefix === "string") {
|
|
232733
|
+
output.Prefix = input.prefix;
|
|
232734
|
+
}
|
|
232735
|
+
if (typeof input.staticStorePrefix === "string") {
|
|
232736
|
+
output.StaticStorePrefix = input.staticStorePrefix;
|
|
232737
|
+
}
|
|
232738
|
+
return Object.keys(output).length ? output : undefined;
|
|
232739
|
+
}
|
|
232740
|
+
function toQpsPolicy(input) {
|
|
232741
|
+
if (!input) {
|
|
232742
|
+
return undefined;
|
|
232743
|
+
}
|
|
232744
|
+
const output = {};
|
|
232745
|
+
if (typeof input.total === "number") {
|
|
232746
|
+
output.QPSTotal = input.total;
|
|
232747
|
+
}
|
|
232748
|
+
if (input.perClient) {
|
|
232749
|
+
const perClient = {};
|
|
232750
|
+
if (input.perClient.limitBy) {
|
|
232751
|
+
perClient.LimitBy = input.perClient.limitBy;
|
|
232752
|
+
}
|
|
232753
|
+
if (typeof input.perClient.limitValue === "number") {
|
|
232754
|
+
perClient.LimitValue = input.perClient.limitValue;
|
|
232755
|
+
}
|
|
232756
|
+
if (Object.keys(perClient).length) {
|
|
232757
|
+
output.QPSPerClient = perClient;
|
|
232758
|
+
}
|
|
232759
|
+
}
|
|
232760
|
+
return Object.keys(output).length ? output : undefined;
|
|
232761
|
+
}
|
|
232762
|
+
/**
|
|
232763
|
+
* Route fields that ModifyHTTPServiceRoute replaces wholesale. When an update
|
|
232764
|
+
* omits one of them, the existing value must be carried over — otherwise a
|
|
232765
|
+
* partial update (e.g. only bumping QPS) would silently wipe CORS / rewrite /
|
|
232766
|
+
* headers / cache rules.
|
|
232767
|
+
*/
|
|
232768
|
+
const PRESERVED_ROUTE_FIELDS = [
|
|
232769
|
+
"EnableAuth",
|
|
232770
|
+
"EnableSafeDomain",
|
|
232771
|
+
"EnablePathTransmission",
|
|
232772
|
+
"PathRewrite",
|
|
232773
|
+
"QPSPolicy",
|
|
232774
|
+
"Extension",
|
|
232775
|
+
"Enable",
|
|
232776
|
+
];
|
|
232777
|
+
function carryOverRouteFields(route, existing) {
|
|
232778
|
+
if (!existing) {
|
|
232779
|
+
return route;
|
|
232780
|
+
}
|
|
232781
|
+
for (const field of PRESERVED_ROUTE_FIELDS) {
|
|
232782
|
+
if (route[field] === undefined && existing[field] !== undefined) {
|
|
232783
|
+
route[field] = existing[field];
|
|
232784
|
+
}
|
|
232785
|
+
}
|
|
232786
|
+
return route;
|
|
232787
|
+
}
|
|
231857
232788
|
/**
|
|
231858
232789
|
* Collect FAIL items from VerifyHTTPServiceRoute, mapping DNS records to
|
|
231859
232790
|
* lowercase field names for MCP structured output (aligned with CLI 3.8.1).
|
|
@@ -232296,16 +233227,13 @@ function registerGatewayTools(server) {
|
|
|
232296
233227
|
});
|
|
232297
233228
|
const path = normalizeAccessPath(input.route?.path ?? input.path ?? `/${upstreamResourceName}`);
|
|
232298
233229
|
const domain = await resolveRouteDomain(input.domain);
|
|
232299
|
-
const
|
|
232300
|
-
|
|
232301
|
-
|
|
232302
|
-
|
|
232303
|
-
|
|
232304
|
-
const
|
|
232305
|
-
|
|
232306
|
-
: input.enablePathTransmission !== undefined
|
|
232307
|
-
? input.enablePathTransmission
|
|
232308
|
-
: undefined;
|
|
233230
|
+
const pick = (routeValue, topValue) => routeValue !== undefined ? routeValue : topValue;
|
|
233231
|
+
const enableAuth = pick(input.route?.auth, input.auth);
|
|
233232
|
+
const enableSafeDomain = pick(input.route?.enableSafeDomain, input.enableSafeDomain);
|
|
233233
|
+
const enablePathTransmission = pick(input.route?.enablePathTransmission, input.enablePathTransmission);
|
|
233234
|
+
const routePathRewrite = toPathRewrite(pick(input.route?.pathRewrite, input.pathRewrite));
|
|
233235
|
+
const routeQpsPolicy = toQpsPolicy(pick(input.route?.qpsPolicy, input.qpsPolicy));
|
|
233236
|
+
const routeExtension = toExtension(pick(input.route?.extension, input.extension));
|
|
232309
233237
|
// Route enable: prefer route.enable. For updateRoute only, top-level
|
|
232310
233238
|
// enable also maps to Route.Enable (enableService/authSwitch use the
|
|
232311
233239
|
// same field name but different actions).
|
|
@@ -232319,18 +233247,35 @@ function registerGatewayTools(server) {
|
|
|
232319
233247
|
Path: path,
|
|
232320
233248
|
UpstreamResourceType: upstreamResourceType,
|
|
232321
233249
|
UpstreamResourceName: upstreamResourceName,
|
|
232322
|
-
EnableAuth: enableAuth,
|
|
232323
233250
|
};
|
|
233251
|
+
if (enableAuth !== undefined) {
|
|
233252
|
+
route.EnableAuth = enableAuth;
|
|
233253
|
+
}
|
|
233254
|
+
if (enableSafeDomain !== undefined) {
|
|
233255
|
+
route.EnableSafeDomain = enableSafeDomain;
|
|
233256
|
+
}
|
|
232324
233257
|
if (enablePathTransmission !== undefined) {
|
|
232325
233258
|
route.EnablePathTransmission = enablePathTransmission;
|
|
232326
233259
|
}
|
|
233260
|
+
if (routePathRewrite) {
|
|
233261
|
+
route.PathRewrite = routePathRewrite;
|
|
233262
|
+
}
|
|
233263
|
+
if (routeQpsPolicy) {
|
|
233264
|
+
route.QPSPolicy = routeQpsPolicy;
|
|
233265
|
+
}
|
|
233266
|
+
if (routeExtension) {
|
|
233267
|
+
route.Extension = routeExtension;
|
|
233268
|
+
}
|
|
232327
233269
|
if (routeEnable !== undefined) {
|
|
232328
233270
|
route.Enable = routeEnable;
|
|
232329
233271
|
}
|
|
233272
|
+
const domainExtension = toExtension(input.domainExtension);
|
|
232330
233273
|
return {
|
|
232331
233274
|
EnvId: await resolveEnvId(),
|
|
232332
233275
|
Domain: {
|
|
232333
233276
|
Domain: domain,
|
|
233277
|
+
...(input.protocol ? { Protocol: input.protocol } : {}),
|
|
233278
|
+
...(domainExtension ? { Extension: domainExtension } : {}),
|
|
232334
233279
|
Routes: [route],
|
|
232335
233280
|
},
|
|
232336
233281
|
resolved: {
|
|
@@ -232339,6 +233284,7 @@ function registerGatewayTools(server) {
|
|
|
232339
233284
|
upstreamResourceType,
|
|
232340
233285
|
upstreamResourceName,
|
|
232341
233286
|
enableAuth,
|
|
233287
|
+
enableSafeDomain,
|
|
232342
233288
|
enablePathTransmission,
|
|
232343
233289
|
enable: routeEnable,
|
|
232344
233290
|
},
|
|
@@ -232387,6 +233333,57 @@ function registerGatewayTools(server) {
|
|
|
232387
233333
|
}
|
|
232388
233334
|
return matches[0];
|
|
232389
233335
|
};
|
|
233336
|
+
/**
|
|
233337
|
+
* Locate the live record (domain + route) so partial updates can carry over
|
|
233338
|
+
* fields the caller did not touch.
|
|
233339
|
+
*/
|
|
233340
|
+
const findExistingRouteRecord = async (domain, path) => {
|
|
233341
|
+
const result = await listHttpServiceRoutes({ domain });
|
|
233342
|
+
const domainRecord = (result.Domains ?? []).find((item) => item.Domain === domain);
|
|
233343
|
+
const route = (domainRecord?.Routes ?? []).find((item) => normalizeAccessPath(String(item.Path ?? "")) ===
|
|
233344
|
+
path);
|
|
233345
|
+
return {
|
|
233346
|
+
domainRecord,
|
|
233347
|
+
route: route,
|
|
233348
|
+
};
|
|
233349
|
+
};
|
|
233350
|
+
/** CDN vs EO is decided by the domain's access type; default to CDN. */
|
|
233351
|
+
/**
|
|
233352
|
+
* 缓存层由域名的接入方式决定,不能猜。
|
|
233353
|
+
*
|
|
233354
|
+
* - EO / CDN → 对应缓存层
|
|
233355
|
+
* - DIRECT / CUSTOM / NONE → CloudBase 侧没有托管缓存,刷新不适用。
|
|
233356
|
+
* 实测(2026-10-21)对 DIRECT 域发 CDN 刷新,PurgeHTTPServiceCache 会「成功」登记
|
|
233357
|
+
* 一个任务,而 DescribeHTTPServiceCachePurgeTask 随后抛 Third Service Error ——
|
|
233358
|
+
* 即后端对 DIRECT 域缺校验、返回不可读错误。这里提前拦住并说明原因。
|
|
233359
|
+
*/
|
|
233360
|
+
const resolveDomainCacheType = async (domain, preferred) => {
|
|
233361
|
+
const findDomain = (result) => (result.Domains ?? []).find((item) => item.Domain === domain);
|
|
233362
|
+
let record = findDomain(await listHttpServiceRoutes({ domain }));
|
|
233363
|
+
if (!record) {
|
|
233364
|
+
// 域名下暂时没有路由时,筛 Domain 可能查不到,退回全量再找一次。
|
|
233365
|
+
record = findDomain(await listHttpServiceRoutes());
|
|
233366
|
+
}
|
|
233367
|
+
if (!record) {
|
|
233368
|
+
throw new Error((0, index_js_1.t)("gateway.cache.domainNotFound", { domain }));
|
|
233369
|
+
}
|
|
233370
|
+
const accessType = String(record.AccessType ?? "");
|
|
233371
|
+
const boundCacheType = accessType === "EO" ? "EO" : accessType === "CDN" ? "CDN" : undefined;
|
|
233372
|
+
if (!boundCacheType) {
|
|
233373
|
+
throw new Error((0, index_js_1.t)("gateway.cache.notManaged", {
|
|
233374
|
+
domain,
|
|
233375
|
+
accessType: accessType || "UNKNOWN",
|
|
233376
|
+
}));
|
|
233377
|
+
}
|
|
233378
|
+
if (preferred && preferred !== boundCacheType) {
|
|
233379
|
+
throw new Error((0, index_js_1.t)("gateway.cache.typeMismatch", {
|
|
233380
|
+
domain,
|
|
233381
|
+
accessType: boundCacheType,
|
|
233382
|
+
requested: preferred,
|
|
233383
|
+
}));
|
|
233384
|
+
}
|
|
233385
|
+
return boundCacheType;
|
|
233386
|
+
};
|
|
232390
233387
|
const routeMutationNextActions = (targetName) => [
|
|
232391
233388
|
{
|
|
232392
233389
|
tool: "queryGateway",
|
|
@@ -232499,6 +233496,34 @@ function registerGatewayTools(server) {
|
|
|
232499
233496
|
},
|
|
232500
233497
|
]);
|
|
232501
233498
|
}
|
|
233499
|
+
case "cachePurgeTask": {
|
|
233500
|
+
if (!input.domain) {
|
|
233501
|
+
throw new Error((0, index_js_1.t)("gateway.query.cachePurgeTaskDomainRequired"));
|
|
233502
|
+
}
|
|
233503
|
+
const cacheType = await resolveDomainCacheType(input.domain, input.cacheType);
|
|
233504
|
+
const cloudbase = await getManager();
|
|
233505
|
+
const result = await cloudbase.env.describeHttpServiceCachePurgeTask({
|
|
233506
|
+
EnvId: await resolveEnvId(),
|
|
233507
|
+
Domain: input.domain,
|
|
233508
|
+
CacheType: cacheType,
|
|
233509
|
+
...(input.taskId ? { TaskId: input.taskId } : {}),
|
|
233510
|
+
...(input.purgeType ? { PurgeType: input.purgeType } : {}),
|
|
233511
|
+
...(input.startTime ? { StartTime: input.startTime } : {}),
|
|
233512
|
+
...(input.endTime ? { EndTime: input.endTime } : {}),
|
|
233513
|
+
...(input.offset !== undefined ? { Offset: input.offset } : {}),
|
|
233514
|
+
...(input.limit !== undefined ? { Limit: input.limit } : {}),
|
|
233515
|
+
});
|
|
233516
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
233517
|
+
const tasks = Array.isArray(result?.Tasks) ? result.Tasks : [];
|
|
233518
|
+
return buildEnvelope({
|
|
233519
|
+
action: input.action,
|
|
233520
|
+
domain: input.domain,
|
|
233521
|
+
cacheType,
|
|
233522
|
+
tasks,
|
|
233523
|
+
total: result?.TotalCount ?? tasks.length,
|
|
233524
|
+
raw: result,
|
|
233525
|
+
}, (0, index_js_1.t)("gateway.query.cachePurgeTask", { count: tasks.length }));
|
|
233526
|
+
}
|
|
232502
233527
|
default:
|
|
232503
233528
|
throw new Error((0, index_js_1.t)("gateway.error.unsupportedAction", { action: input.action }));
|
|
232504
233529
|
}
|
|
@@ -232607,6 +233632,7 @@ function registerGatewayTools(server) {
|
|
|
232607
233632
|
upstreamResourceType: payload.resolved.upstreamResourceType,
|
|
232608
233633
|
upstreamResourceName: payload.resolved.upstreamResourceName,
|
|
232609
233634
|
auth: payload.resolved.enableAuth ?? null,
|
|
233635
|
+
enableSafeDomain: payload.resolved.enableSafeDomain ?? null,
|
|
232610
233636
|
enablePathTransmission: payload.resolved.enablePathTransmission ?? null,
|
|
232611
233637
|
accessUrl: `https://${payload.resolved.domain}${payload.resolved.path}`,
|
|
232612
233638
|
accessUrls: [`https://${payload.resolved.domain}${payload.resolved.path}`],
|
|
@@ -232635,6 +233661,14 @@ function registerGatewayTools(server) {
|
|
|
232635
233661
|
case "updateRoute": {
|
|
232636
233662
|
const cloudbase = await getManager();
|
|
232637
233663
|
const payload = await normalizeRoutePayload(input);
|
|
233664
|
+
// Preserve untouched route/domain fields from the live record: the
|
|
233665
|
+
// backend replaces the whole route entry, so a partial update would
|
|
233666
|
+
// otherwise wipe CORS / rewrite / QPS / headers / cache settings.
|
|
233667
|
+
const existing = await findExistingRouteRecord(payload.resolved.domain, payload.resolved.path);
|
|
233668
|
+
carryOverRouteFields(payload.Domain.Routes[0], existing.route);
|
|
233669
|
+
if (!payload.Domain.Protocol && existing.domainRecord?.Protocol) {
|
|
233670
|
+
payload.Domain.Protocol = existing.domainRecord.Protocol;
|
|
233671
|
+
}
|
|
232638
233672
|
const result = await cloudbase.env.modifyHttpServiceRoute({
|
|
232639
233673
|
EnvId: payload.EnvId,
|
|
232640
233674
|
Domain: payload.Domain,
|
|
@@ -232652,6 +233686,7 @@ function registerGatewayTools(server) {
|
|
|
232652
233686
|
upstreamResourceType: payload.resolved.upstreamResourceType,
|
|
232653
233687
|
upstreamResourceName: payload.resolved.upstreamResourceName,
|
|
232654
233688
|
auth: payload.resolved.enableAuth ?? null,
|
|
233689
|
+
enableSafeDomain: payload.resolved.enableSafeDomain ?? null,
|
|
232655
233690
|
enablePathTransmission: payload.resolved.enablePathTransmission ?? null,
|
|
232656
233691
|
enable: payload.resolved.enable ?? null,
|
|
232657
233692
|
...(accessUrl
|
|
@@ -232733,6 +233768,11 @@ function registerGatewayTools(server) {
|
|
|
232733
233768
|
if (enablePathTransmission !== undefined) {
|
|
232734
233769
|
route.EnablePathTransmission = enablePathTransmission;
|
|
232735
233770
|
}
|
|
233771
|
+
if (input.enableSafeDomain !== undefined) {
|
|
233772
|
+
route.EnableSafeDomain = input.enableSafeDomain;
|
|
233773
|
+
}
|
|
233774
|
+
// Toggling Enable must not drop CORS / rewrite / QPS / headers / cache.
|
|
233775
|
+
carryOverRouteFields(route, existing);
|
|
232736
233776
|
const cloudbase = await getManager();
|
|
232737
233777
|
const result = await cloudbase.env.modifyHttpServiceRoute({
|
|
232738
233778
|
EnvId: await resolveEnvId(),
|
|
@@ -232827,6 +233867,7 @@ function registerGatewayTools(server) {
|
|
|
232827
233867
|
CertId: input.certificateId || "",
|
|
232828
233868
|
AccessType: accessType,
|
|
232829
233869
|
Enable: input.enable !== undefined ? input.enable : true,
|
|
233870
|
+
...(input.protocol ? { Protocol: input.protocol } : {}),
|
|
232830
233871
|
...(input.customCname ? { CustomCname: input.customCname } : {}),
|
|
232831
233872
|
};
|
|
232832
233873
|
const verifyFailure = await verifyHttpServiceRouteOrFail({
|
|
@@ -232848,6 +233889,7 @@ function registerGatewayTools(server) {
|
|
|
232848
233889
|
Domain: input.domain,
|
|
232849
233890
|
CertId: certificateId,
|
|
232850
233891
|
AccessType: accessType,
|
|
233892
|
+
...(input.protocol ? { Protocol: input.protocol } : {}),
|
|
232851
233893
|
...(input.enable !== undefined
|
|
232852
233894
|
? { Enable: input.enable }
|
|
232853
233895
|
: {}),
|
|
@@ -232978,6 +234020,43 @@ function registerGatewayTools(server) {
|
|
|
232978
234020
|
},
|
|
232979
234021
|
]);
|
|
232980
234022
|
}
|
|
234023
|
+
case "purgeCache": {
|
|
234024
|
+
if (!input.domain) {
|
|
234025
|
+
throw new Error((0, index_js_1.t)("gateway.purgeCache.domainRequired"));
|
|
234026
|
+
}
|
|
234027
|
+
const targets = (input.targets ?? [])
|
|
234028
|
+
.map((item) => (typeof item === "string" ? item.trim() : ""))
|
|
234029
|
+
.filter(Boolean);
|
|
234030
|
+
if (!targets.length) {
|
|
234031
|
+
throw new Error((0, index_js_1.t)("gateway.purgeCache.targetsRequired"));
|
|
234032
|
+
}
|
|
234033
|
+
const purgeType = input.purgeType ?? "PURGE_URL";
|
|
234034
|
+
const cacheType = await resolveDomainCacheType(input.domain, input.cacheType);
|
|
234035
|
+
const cloudbase = await getManager();
|
|
234036
|
+
const result = await cloudbase.env.purgeHttpServiceCache({
|
|
234037
|
+
EnvId: await resolveEnvId(),
|
|
234038
|
+
Domain: input.domain,
|
|
234039
|
+
CacheType: cacheType,
|
|
234040
|
+
PurgeType: purgeType,
|
|
234041
|
+
Targets: targets,
|
|
234042
|
+
});
|
|
234043
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
234044
|
+
return buildEnvelope({
|
|
234045
|
+
action: input.action,
|
|
234046
|
+
domain: input.domain,
|
|
234047
|
+
cacheType,
|
|
234048
|
+
purgeType,
|
|
234049
|
+
targets,
|
|
234050
|
+
taskId: result?.TaskId ?? null,
|
|
234051
|
+
raw: result,
|
|
234052
|
+
}, (0, index_js_1.t)("gateway.purgeCache.message", { count: targets.length }), [
|
|
234053
|
+
{
|
|
234054
|
+
tool: "queryGateway",
|
|
234055
|
+
action: "cachePurgeTask",
|
|
234056
|
+
reason: (0, index_js_1.t)("gateway.purgeCache.verifyReason"),
|
|
234057
|
+
},
|
|
234058
|
+
]);
|
|
234059
|
+
}
|
|
232981
234060
|
default:
|
|
232982
234061
|
throw new Error((0, index_js_1.t)("gateway.error.unsupportedAction", { action: input.action }));
|
|
232983
234062
|
}
|
|
@@ -232996,6 +234075,19 @@ function registerGatewayTools(server) {
|
|
|
232996
234075
|
routeId: zod_1.z.string().optional().describe("gateway.schema.query.routeId"),
|
|
232997
234076
|
path: zod_1.z.string().optional().describe("gateway.schema.query.path"),
|
|
232998
234077
|
domain: zod_1.z.string().optional().describe("gateway.schema.query.domain"),
|
|
234078
|
+
cacheType: zod_1.z
|
|
234079
|
+
.enum(CACHE_TYPES)
|
|
234080
|
+
.optional()
|
|
234081
|
+
.describe("gateway.schema.query.cacheType"),
|
|
234082
|
+
taskId: zod_1.z.string().optional().describe("gateway.schema.query.taskId"),
|
|
234083
|
+
purgeType: zod_1.z
|
|
234084
|
+
.enum(PURGE_TYPES)
|
|
234085
|
+
.optional()
|
|
234086
|
+
.describe("gateway.schema.query.purgeType"),
|
|
234087
|
+
startTime: zod_1.z.string().optional().describe("gateway.schema.query.startTime"),
|
|
234088
|
+
endTime: zod_1.z.string().optional().describe("gateway.schema.query.endTime"),
|
|
234089
|
+
offset: zod_1.z.number().int().min(0).optional().describe("gateway.schema.query.offset"),
|
|
234090
|
+
limit: zod_1.z.number().int().min(1).optional().describe("gateway.schema.query.limit"),
|
|
232999
234091
|
},
|
|
233000
234092
|
annotations: {
|
|
233001
234093
|
readOnlyHint: true,
|
|
@@ -233025,6 +234117,26 @@ function registerGatewayTools(server) {
|
|
|
233025
234117
|
.boolean()
|
|
233026
234118
|
.optional()
|
|
233027
234119
|
.describe("gateway.schema.manage.enablePathTransmission"),
|
|
234120
|
+
enableSafeDomain: zod_1.z
|
|
234121
|
+
.boolean()
|
|
234122
|
+
.optional()
|
|
234123
|
+
.describe("gateway.schema.manage.enableSafeDomain"),
|
|
234124
|
+
pathRewrite: pathRewriteSchema
|
|
234125
|
+
.optional()
|
|
234126
|
+
.describe("gateway.schema.manage.pathRewrite"),
|
|
234127
|
+
qpsPolicy: qpsPolicySchema
|
|
234128
|
+
.optional()
|
|
234129
|
+
.describe("gateway.schema.manage.qpsPolicy"),
|
|
234130
|
+
extension: extensionSchema
|
|
234131
|
+
.optional()
|
|
234132
|
+
.describe("gateway.schema.manage.extension"),
|
|
234133
|
+
domainExtension: extensionSchema
|
|
234134
|
+
.optional()
|
|
234135
|
+
.describe("gateway.schema.manage.domainExtension"),
|
|
234136
|
+
protocol: zod_1.z
|
|
234137
|
+
.enum(DOMAIN_PROTOCOLS)
|
|
234138
|
+
.optional()
|
|
234139
|
+
.describe("gateway.schema.manage.protocol"),
|
|
233028
234140
|
route: zod_1.z
|
|
233029
234141
|
.object({
|
|
233030
234142
|
path: zod_1.z.string().optional(),
|
|
@@ -233041,6 +234153,19 @@ function registerGatewayTools(server) {
|
|
|
233041
234153
|
.boolean()
|
|
233042
234154
|
.optional()
|
|
233043
234155
|
.describe("gateway.schema.manage.route.enablePathTransmission"),
|
|
234156
|
+
enableSafeDomain: zod_1.z
|
|
234157
|
+
.boolean()
|
|
234158
|
+
.optional()
|
|
234159
|
+
.describe("gateway.schema.manage.route.enableSafeDomain"),
|
|
234160
|
+
pathRewrite: pathRewriteSchema
|
|
234161
|
+
.optional()
|
|
234162
|
+
.describe("gateway.schema.manage.route.pathRewrite"),
|
|
234163
|
+
qpsPolicy: qpsPolicySchema
|
|
234164
|
+
.optional()
|
|
234165
|
+
.describe("gateway.schema.manage.route.qpsPolicy"),
|
|
234166
|
+
extension: extensionSchema
|
|
234167
|
+
.optional()
|
|
234168
|
+
.describe("gateway.schema.manage.route.extension"),
|
|
233044
234169
|
enable: zod_1.z
|
|
233045
234170
|
.boolean()
|
|
233046
234171
|
.optional()
|
|
@@ -233062,6 +234187,18 @@ function registerGatewayTools(server) {
|
|
|
233062
234187
|
.optional()
|
|
233063
234188
|
.describe("gateway.schema.manage.customCname"),
|
|
233064
234189
|
enable: zod_1.z.boolean().optional().describe("gateway.schema.manage.enable"),
|
|
234190
|
+
cacheType: zod_1.z
|
|
234191
|
+
.enum(CACHE_TYPES)
|
|
234192
|
+
.optional()
|
|
234193
|
+
.describe("gateway.schema.manage.cacheType"),
|
|
234194
|
+
purgeType: zod_1.z
|
|
234195
|
+
.enum(PURGE_TYPES)
|
|
234196
|
+
.optional()
|
|
234197
|
+
.describe("gateway.schema.manage.purgeType"),
|
|
234198
|
+
targets: zod_1.z
|
|
234199
|
+
.array(zod_1.z.string())
|
|
234200
|
+
.optional()
|
|
234201
|
+
.describe("gateway.schema.manage.targets"),
|
|
233065
234202
|
},
|
|
233066
234203
|
annotations: {
|
|
233067
234204
|
readOnlyHint: false,
|
|
@@ -239455,7 +240592,7 @@ exports.readSkipList = readSkipList;
|
|
|
239455
240592
|
exports.isSkipped = isSkipped;
|
|
239456
240593
|
exports.readAutoApprovePolicy = readAutoApprovePolicy;
|
|
239457
240594
|
exports.guardDestructiveAction = guardDestructiveAction;
|
|
239458
|
-
const
|
|
240595
|
+
const env_binding_js_1 = __webpack_require__(61498);
|
|
239459
240596
|
const index_js_1 = __webpack_require__(24908);
|
|
239460
240597
|
const elicitation_js_1 = __webpack_require__(65048);
|
|
239461
240598
|
const destructive_actions_js_1 = __webpack_require__(72827);
|
|
@@ -239524,16 +240661,7 @@ function readAutoApprovePolicy() {
|
|
|
239524
240661
|
return "allow";
|
|
239525
240662
|
}
|
|
239526
240663
|
function resolveEnvId(server) {
|
|
239527
|
-
|
|
239528
|
-
if (typeof fromOptions === "string" && fromOptions.length > 0) {
|
|
239529
|
-
return fromOptions;
|
|
239530
|
-
}
|
|
239531
|
-
try {
|
|
239532
|
-
return (0, cloudbase_manager_js_1.getCachedEnvId)() ?? (0, index_js_1.t)("confirmation.message.unknownEnv");
|
|
239533
|
-
}
|
|
239534
|
-
catch {
|
|
239535
|
-
return (0, index_js_1.t)("confirmation.message.unknownEnv");
|
|
239536
|
-
}
|
|
240664
|
+
return (0, env_binding_js_1.readDisplayedEnvId)(server.cloudBaseOptions?.envId) ?? (0, index_js_1.t)("confirmation.message.unknownEnv");
|
|
239537
240665
|
}
|
|
239538
240666
|
function blockedText(status, actionKey, targetInfo, params) {
|
|
239539
240667
|
const keyByStatus = {
|
|
@@ -239901,6 +241029,47 @@ async function guardCredentialWrite(server, params) {
|
|
|
239901
241029
|
}
|
|
239902
241030
|
|
|
239903
241031
|
|
|
241032
|
+
/***/ },
|
|
241033
|
+
|
|
241034
|
+
/***/ 31284
|
|
241035
|
+
(__unused_webpack_module, exports) {
|
|
241036
|
+
|
|
241037
|
+
"use strict";
|
|
241038
|
+
|
|
241039
|
+
/**
|
|
241040
|
+
* 账号级 DescribeEnvs 的查询口径 —— 唯一真源。
|
|
241041
|
+
*
|
|
241042
|
+
* EnvTypes 是白名单语义(不为空时以该字段为准):少写一个值不会报错,只会静默
|
|
241043
|
+
* 少一类环境。2026-10 的客户案例就是这样:平台侧代建的环境 EnvType=platform,
|
|
241044
|
+
* 控制台能列、MCP 拉不到,用户看到的是「请先创建环境」,现场没有任何错误可看。
|
|
241045
|
+
*
|
|
241046
|
+
* - baas / weda:标准云开发、微搭,MCP 工具主要面向这两类
|
|
241047
|
+
* - platform:平台侧代建的环境(site-* 一类),控制台列这类
|
|
241048
|
+
*
|
|
241049
|
+
* 未纳入 hosting / run(云托管)、tcbgw、paas:MCP 历史上就没列过,加进来会让
|
|
241050
|
+
* 用户在环境候选里看到一堆用不了的托管环境。授权页那份白名单多一个 hosting,
|
|
241051
|
+
* 是历史原因,两边差异是有意的。
|
|
241052
|
+
*/
|
|
241053
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
241054
|
+
exports.DESCRIBE_ENVS_EXCLUDED_CHANNELS = exports.DESCRIBE_ENVS_ENV_TYPES = void 0;
|
|
241055
|
+
exports.buildDescribeEnvsFilter = buildDescribeEnvsFilter;
|
|
241056
|
+
/** 允许出现在环境候选列表里的 EnvType */
|
|
241057
|
+
exports.DESCRIBE_ENVS_ENV_TYPES = ["baas", "weda", "platform"];
|
|
241058
|
+
/**
|
|
241059
|
+
* IsVisible=false 表示 Channels 是「排除列表」:
|
|
241060
|
+
* 这 4 个渠道创建的环境不参与环境候选,其余渠道(含控制台的 qc_console)正常返回。
|
|
241061
|
+
*/
|
|
241062
|
+
exports.DESCRIBE_ENVS_EXCLUDED_CHANNELS = ["dcloud", "iotenable", "tem", "scene_module"];
|
|
241063
|
+
/** 生成 DescribeEnvs 的 Param 过滤段;每次返回新数组,避免调用方改到共享常量 */
|
|
241064
|
+
function buildDescribeEnvsFilter() {
|
|
241065
|
+
return {
|
|
241066
|
+
EnvTypes: [...exports.DESCRIBE_ENVS_ENV_TYPES],
|
|
241067
|
+
IsVisible: false,
|
|
241068
|
+
Channels: [...exports.DESCRIBE_ENVS_EXCLUDED_CHANNELS],
|
|
241069
|
+
};
|
|
241070
|
+
}
|
|
241071
|
+
|
|
241072
|
+
|
|
239904
241073
|
/***/ },
|
|
239905
241074
|
|
|
239906
241075
|
/***/ 72827
|
|
@@ -240251,6 +241420,213 @@ function resolveDestructiveAction(toolName, args) {
|
|
|
240251
241420
|
}
|
|
240252
241421
|
|
|
240253
241422
|
|
|
241423
|
+
/***/ },
|
|
241424
|
+
|
|
241425
|
+
/***/ 36953
|
|
241426
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
241427
|
+
|
|
241428
|
+
"use strict";
|
|
241429
|
+
|
|
241430
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
241431
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
241432
|
+
};
|
|
241433
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
241434
|
+
exports.readSystemAnchor = readSystemAnchor;
|
|
241435
|
+
exports.physicalMacAddresses = physicalMacAddresses;
|
|
241436
|
+
exports.collectHostSignal = collectHostSignal;
|
|
241437
|
+
exports.computeDeviceId = computeDeviceId;
|
|
241438
|
+
const crypto_1 = __importDefault(__webpack_require__(55511));
|
|
241439
|
+
const child_process_1 = __webpack_require__(79646);
|
|
241440
|
+
const fs_1 = __importDefault(__webpack_require__(29021));
|
|
241441
|
+
const os_1 = __importDefault(__webpack_require__(21820));
|
|
241442
|
+
/**
|
|
241443
|
+
* 匿名设备指纹。
|
|
241444
|
+
*
|
|
241445
|
+
* 为什么要有这个文件:旧实现是 `sha256(hostname | CPU model | 全部非内部网卡 MAC)`,
|
|
241446
|
+
* 锚点选错了 —— macOS 开着「私有 Wi-Fi 地址」时每个 SSID 一个随机 MAC,`awdl0` / `llw0` /
|
|
241447
|
+
* `bridge0` 的 MAC 随系统状态漂移,容器里 hostname 和 MAC 每次重建都变。结果是同一台 Mac
|
|
241448
|
+
* 一天能上报成几十个「设备」(2026-10-26 实测:Mac 指纹 82% 只在那一天出现过,
|
|
241449
|
+
* Windows 同口径 22%)。
|
|
241450
|
+
*
|
|
241451
|
+
* 现在的取值顺序:
|
|
241452
|
+
* 1. 系统级不可变标识 —— macOS `IOPlatformUUID`、Windows `MachineGuid`、Linux `/etc/machine-id`;
|
|
241453
|
+
* 2. 取不到时退到 `hostname + CPU model + 过滤后的物理网卡 MAC`;
|
|
241454
|
+
* 3. 再取不到只留 `hostname + CPU model`。
|
|
241455
|
+
*
|
|
241456
|
+
* 三条纪律:
|
|
241457
|
+
* - **格式不变**:仍是 SHA256 前 32 位 hex,灯塔 `A2` 字段与后端都不用改。
|
|
241458
|
+
* - **绝不用随机数兜底**。旧实现取不到信息时 `crypto.randomBytes(16)`,等于每次启动都是
|
|
241459
|
+
* 一台新设备 —— 正是要消灭的行为。宁可所有机器共用一个弱指纹,也不要一堆假设备。
|
|
241460
|
+
* - **只在构造时跑一次**。锚点要起子进程(`ioreg` / `reg`),1s 超时就降级,
|
|
241461
|
+
* 绝不放进每次上报的路径。
|
|
241462
|
+
*
|
|
241463
|
+
* 口径变化(换锚点当天就会看到,报表侧要提前打招呼):
|
|
241464
|
+
* - 历史 `A2` 全部失效,老设备会以新指纹重新出现 —— 报表上「装机量跳一下」不是增长。
|
|
241465
|
+
* - 容器内多实例若共享镜像固化的 `/etc/machine-id`,会被合并成同一台设备(以前是各算一个新设备)。
|
|
241466
|
+
*/
|
|
241467
|
+
/** 取系统级锚点的子进程超时:超了直接降级,不能拖慢进程启动 */
|
|
241468
|
+
const ANCHOR_TIMEOUT_MS = 1000;
|
|
241469
|
+
/**
|
|
241470
|
+
* 虚拟 / 隧道网卡名前缀(小写比较)。这些接口的 MAC 会随系统状态漂移或每次重建都变,
|
|
241471
|
+
* 拼进指纹就等于给同一台机器发新身份。
|
|
241472
|
+
*/
|
|
241473
|
+
const VIRTUAL_NIC_PREFIXES = [
|
|
241474
|
+
'awdl', // Apple Wireless Direct Link
|
|
241475
|
+
'llw', // Apple 低延迟 WLAN
|
|
241476
|
+
'bridge', // macOS / Windows 网桥
|
|
241477
|
+
'utun', // macOS / iOS VPN 隧道
|
|
241478
|
+
'tun',
|
|
241479
|
+
'tap',
|
|
241480
|
+
'veth', // 容器 veth pair
|
|
241481
|
+
'docker',
|
|
241482
|
+
'br-', // docker bridge
|
|
241483
|
+
'vmnet', // VMware
|
|
241484
|
+
'vboxnet', // VirtualBox
|
|
241485
|
+
'vether', // Hyper-V 虚拟交换机(vEthernet)
|
|
241486
|
+
'zt', // ZeroTier
|
|
241487
|
+
'tailscale',
|
|
241488
|
+
'wg', // WireGuard
|
|
241489
|
+
'lo', // loopback(正常情况下 internal 已过滤,兜一层)
|
|
241490
|
+
];
|
|
241491
|
+
function sha256Short(input) {
|
|
241492
|
+
return crypto_1.default.createHash('sha256').update(input).digest('hex').substring(0, 32);
|
|
241493
|
+
}
|
|
241494
|
+
/** `machine-id` 合法值:16–64 位 hex,且不能是全 0(有些镜像里就是全 0 的空壳) */
|
|
241495
|
+
function isUsableMachineId(value) {
|
|
241496
|
+
if (!/^[0-9a-f]{16,64}$/i.test(value)) {
|
|
241497
|
+
return false;
|
|
241498
|
+
}
|
|
241499
|
+
return !/^0+$/.test(value);
|
|
241500
|
+
}
|
|
241501
|
+
function readFileQuietly(filePath) {
|
|
241502
|
+
try {
|
|
241503
|
+
return fs_1.default.readFileSync(filePath, 'utf8').trim();
|
|
241504
|
+
}
|
|
241505
|
+
catch {
|
|
241506
|
+
return undefined;
|
|
241507
|
+
}
|
|
241508
|
+
}
|
|
241509
|
+
/** 起一次子进程读锚点。超时 / 不存在 / 权限不足一律返回 undefined,由调用方降级。 */
|
|
241510
|
+
function execQuietly(file, args) {
|
|
241511
|
+
try {
|
|
241512
|
+
return (0, child_process_1.execFileSync)(file, args, {
|
|
241513
|
+
timeout: ANCHOR_TIMEOUT_MS,
|
|
241514
|
+
encoding: 'utf8',
|
|
241515
|
+
// 子进程的 stderr 全部吞掉:`ioreg` 在受限环境会打噪音,`reg` 在 32 位 Node
|
|
241516
|
+
// 下可能报找不到键,这些都不该出现在 MCP 的 stdout(stdio transport 上是协议流)
|
|
241517
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
241518
|
+
windowsHide: true,
|
|
241519
|
+
});
|
|
241520
|
+
}
|
|
241521
|
+
catch {
|
|
241522
|
+
return undefined;
|
|
241523
|
+
}
|
|
241524
|
+
}
|
|
241525
|
+
/**
|
|
241526
|
+
* 读系统级不可变标识。**只读一次**,失败即降级。
|
|
241527
|
+
* `platform` 参数只为测试注入,正常运行不传。
|
|
241528
|
+
*/
|
|
241529
|
+
function readSystemAnchor(platform = process.platform) {
|
|
241530
|
+
if (platform === 'darwin') {
|
|
241531
|
+
const out = execQuietly('ioreg', ['-rd1', '-c', 'IOPlatformExpertDevice']);
|
|
241532
|
+
const matched = out && /"IOPlatformUUID"\s*=\s*"([^"]+)"/.exec(out);
|
|
241533
|
+
if (matched?.[1]) {
|
|
241534
|
+
return { value: matched[1].trim(), source: 'platform-uuid' };
|
|
241535
|
+
}
|
|
241536
|
+
return undefined;
|
|
241537
|
+
}
|
|
241538
|
+
if (platform === 'win32') {
|
|
241539
|
+
const out = execQuietly('reg', [
|
|
241540
|
+
'query',
|
|
241541
|
+
'HKLM\\SOFTWARE\\Microsoft\\Cryptography',
|
|
241542
|
+
'/v',
|
|
241543
|
+
'MachineGuid',
|
|
241544
|
+
]);
|
|
241545
|
+
// 形如:` MachineGuid REG_SZ 3f2a....`(分隔符是多个空格或 tab)
|
|
241546
|
+
const matched = out && /MachineGuid\s+REG_SZ\s+([0-9a-fA-F-]{8,})/.exec(out);
|
|
241547
|
+
if (matched?.[1]) {
|
|
241548
|
+
return { value: matched[1].trim().toLowerCase(), source: 'machine-guid' };
|
|
241549
|
+
}
|
|
241550
|
+
return undefined;
|
|
241551
|
+
}
|
|
241552
|
+
// linux / openharmony / 其他类 Unix:先 /etc/machine-id,再 dbus 那份
|
|
241553
|
+
for (const candidate of ['/etc/machine-id', '/var/lib/dbus/machine-id']) {
|
|
241554
|
+
const raw = readFileQuietly(candidate);
|
|
241555
|
+
if (raw && isUsableMachineId(raw)) {
|
|
241556
|
+
return { value: raw.toLowerCase(), source: 'machine-id' };
|
|
241557
|
+
}
|
|
241558
|
+
}
|
|
241559
|
+
return undefined;
|
|
241560
|
+
}
|
|
241561
|
+
function isVirtualNic(name) {
|
|
241562
|
+
const lower = name.toLowerCase();
|
|
241563
|
+
return VIRTUAL_NIC_PREFIXES.some((prefix) => lower.startsWith(prefix));
|
|
241564
|
+
}
|
|
241565
|
+
/**
|
|
241566
|
+
* 非内部、非虚拟、MAC 不是全 0 / 广播地址的网卡 MAC,去重后排序。
|
|
241567
|
+
* 排序是为了让指纹与网卡枚举顺序无关(枚举顺序在重启后可能变)。
|
|
241568
|
+
*/
|
|
241569
|
+
function physicalMacAddresses(interfaces = os_1.default.networkInterfaces()) {
|
|
241570
|
+
const macs = new Set();
|
|
241571
|
+
for (const [name, list] of Object.entries(interfaces)) {
|
|
241572
|
+
if (!list || isVirtualNic(name)) {
|
|
241573
|
+
continue;
|
|
241574
|
+
}
|
|
241575
|
+
for (const nic of list) {
|
|
241576
|
+
const mac = nic?.mac?.toLowerCase();
|
|
241577
|
+
if (!nic || nic.internal || !mac) {
|
|
241578
|
+
continue;
|
|
241579
|
+
}
|
|
241580
|
+
if (mac === '00:00:00:00:00:00' || mac === 'ff:ff:ff:ff:ff:ff') {
|
|
241581
|
+
continue;
|
|
241582
|
+
}
|
|
241583
|
+
macs.add(mac);
|
|
241584
|
+
}
|
|
241585
|
+
}
|
|
241586
|
+
return [...macs].sort();
|
|
241587
|
+
}
|
|
241588
|
+
/** 取不到系统锚点时的兜底信号:**不含虚拟网卡**,主机名与 CPU 型号足够稳。 */
|
|
241589
|
+
function collectHostSignal() {
|
|
241590
|
+
let hostname = 'unknown-host';
|
|
241591
|
+
try {
|
|
241592
|
+
hostname = os_1.default.hostname() || hostname;
|
|
241593
|
+
}
|
|
241594
|
+
catch {
|
|
241595
|
+
// 主机名读不到不影响降级:CPU + MAC 仍可用
|
|
241596
|
+
}
|
|
241597
|
+
let cpu = '';
|
|
241598
|
+
try {
|
|
241599
|
+
cpu = os_1.default
|
|
241600
|
+
.cpus()
|
|
241601
|
+
.map((item) => item.model)
|
|
241602
|
+
.join(',');
|
|
241603
|
+
}
|
|
241604
|
+
catch {
|
|
241605
|
+
// 同上
|
|
241606
|
+
}
|
|
241607
|
+
let macs = [];
|
|
241608
|
+
try {
|
|
241609
|
+
macs = physicalMacAddresses();
|
|
241610
|
+
}
|
|
241611
|
+
catch {
|
|
241612
|
+
// 同上
|
|
241613
|
+
}
|
|
241614
|
+
const parts = [hostname, cpu, ...macs].filter((part) => Boolean(part));
|
|
241615
|
+
return {
|
|
241616
|
+
value: parts.join('|'),
|
|
241617
|
+
source: macs.length > 0 ? 'host-fallback' : 'host-only',
|
|
241618
|
+
};
|
|
241619
|
+
}
|
|
241620
|
+
/**
|
|
241621
|
+
* 计算匿名设备指纹(SHA256 前 32 位 hex),并返回这次用的锚点来源 ——
|
|
241622
|
+
* 来源只进 debug 日志,用于上线后确认「到底有多少机器走到了兜底」。
|
|
241623
|
+
*/
|
|
241624
|
+
function computeDeviceId(platform = process.platform) {
|
|
241625
|
+
const anchor = readSystemAnchor(platform) ?? collectHostSignal();
|
|
241626
|
+
return { deviceId: sha256Short(anchor.value), source: anchor.source };
|
|
241627
|
+
}
|
|
241628
|
+
|
|
241629
|
+
|
|
240254
241630
|
/***/ },
|
|
240255
241631
|
|
|
240256
241632
|
/***/ 65048
|
|
@@ -240391,6 +241767,113 @@ async function requestChoiceElicitation(server, params) {
|
|
|
240391
241767
|
}
|
|
240392
241768
|
|
|
240393
241769
|
|
|
241770
|
+
/***/ },
|
|
241771
|
+
|
|
241772
|
+
/***/ 61498
|
|
241773
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
241774
|
+
|
|
241775
|
+
"use strict";
|
|
241776
|
+
|
|
241777
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
241778
|
+
exports.ENV_SOURCES = void 0;
|
|
241779
|
+
exports.noteEnvBinding = noteEnvBinding;
|
|
241780
|
+
exports.clearEnvBinding = clearEnvBinding;
|
|
241781
|
+
exports.hasEnvSlot = hasEnvSlot;
|
|
241782
|
+
exports.readReportedEnv = readReportedEnv;
|
|
241783
|
+
exports.readDisplayedEnvId = readDisplayedEnvId;
|
|
241784
|
+
exports.runWithEnvSlot = runWithEnvSlot;
|
|
241785
|
+
exports.runInEnvSlot = runInEnvSlot;
|
|
241786
|
+
exports.peekLocalEnvBinding = peekLocalEnvBinding;
|
|
241787
|
+
const node_async_hooks_1 = __webpack_require__(18667);
|
|
241788
|
+
const project_config_js_1 = __webpack_require__(39175);
|
|
241789
|
+
/**
|
|
241790
|
+
* Where this resolution got its env id.
|
|
241791
|
+
* The first four values are already in shipped queries. Do not rename them.
|
|
241792
|
+
* `default` stays `default` (an empty result, not a rename to `unresolved`).
|
|
241793
|
+
*/
|
|
241794
|
+
exports.ENV_SOURCES = [
|
|
241795
|
+
"cloudBaseOptions",
|
|
241796
|
+
"process.env.CLOUDBASE_ENV_ID",
|
|
241797
|
+
"envManager.cachedEnvId",
|
|
241798
|
+
"project",
|
|
241799
|
+
"login_state",
|
|
241800
|
+
"auto_bound",
|
|
241801
|
+
"default",
|
|
241802
|
+
];
|
|
241803
|
+
const envCall = new node_async_hooks_1.AsyncLocalStorage();
|
|
241804
|
+
function isReportableEnvId(envId) {
|
|
241805
|
+
return !!envId && envId !== "local" && envId !== "unknown";
|
|
241806
|
+
}
|
|
241807
|
+
/** Write into the current slot. Outside a slot this is a no-op and does not touch process globals. */
|
|
241808
|
+
function noteEnvBinding(binding) {
|
|
241809
|
+
const slot = envCall.getStore();
|
|
241810
|
+
if (!slot || binding.source === "default" || !isReportableEnvId(binding.envId)) {
|
|
241811
|
+
return;
|
|
241812
|
+
}
|
|
241813
|
+
slot.binding = { envId: binding.envId, source: binding.source };
|
|
241814
|
+
}
|
|
241815
|
+
function clearEnvBinding() {
|
|
241816
|
+
const slot = envCall.getStore();
|
|
241817
|
+
if (slot) {
|
|
241818
|
+
slot.binding = null;
|
|
241819
|
+
}
|
|
241820
|
+
}
|
|
241821
|
+
function hasEnvSlot() {
|
|
241822
|
+
return envCall.getStore() !== undefined;
|
|
241823
|
+
}
|
|
241824
|
+
function readReportedEnv() {
|
|
241825
|
+
const binding = envCall.getStore()?.binding;
|
|
241826
|
+
if (!binding || binding.source === "default" || !isReportableEnvId(binding.envId)) {
|
|
241827
|
+
return { envId: "unknown", envIdSource: "default" };
|
|
241828
|
+
}
|
|
241829
|
+
return { envId: binding.envId, envIdSource: binding.source };
|
|
241830
|
+
}
|
|
241831
|
+
/**
|
|
241832
|
+
* Env id shown on the start page, the usage card, and confirmation text.
|
|
241833
|
+
* An explicit envId on this call wins, matching the resolver ladder.
|
|
241834
|
+
* Otherwise the current slot (login state, project, cache, or env var already noted).
|
|
241835
|
+
* Does not read process.env or the manager cache: on a hosted request those belong to the server machine.
|
|
241836
|
+
*/
|
|
241837
|
+
function readDisplayedEnvId(explicitEnvId) {
|
|
241838
|
+
if (isReportableEnvId(explicitEnvId)) {
|
|
241839
|
+
return explicitEnvId;
|
|
241840
|
+
}
|
|
241841
|
+
const reported = readReportedEnv();
|
|
241842
|
+
if (reported.envIdSource !== "default") {
|
|
241843
|
+
return reported.envId;
|
|
241844
|
+
}
|
|
241845
|
+
return null;
|
|
241846
|
+
}
|
|
241847
|
+
function runWithEnvSlot(slot, fn) {
|
|
241848
|
+
return envCall.run(slot, fn);
|
|
241849
|
+
}
|
|
241850
|
+
/** One fresh slot. Tests and any caller that must not share another request's binding. */
|
|
241851
|
+
function runInEnvSlot(fn) {
|
|
241852
|
+
return envCall.run({ binding: null }, fn);
|
|
241853
|
+
}
|
|
241854
|
+
/**
|
|
241855
|
+
* Read-only snapshot for process start. Does not call setEnvId and does not list envs.
|
|
241856
|
+
* `cachedEnvId` is passed in so this module does not import the manager (that import cycles).
|
|
241857
|
+
*/
|
|
241858
|
+
function peekLocalEnvBinding(input) {
|
|
241859
|
+
if (isReportableEnvId(input.cachedEnvId)) {
|
|
241860
|
+
return { envId: input.cachedEnvId, source: "envManager.cachedEnvId" };
|
|
241861
|
+
}
|
|
241862
|
+
const fromEnv = process.env.CLOUDBASE_ENV_ID;
|
|
241863
|
+
if (isReportableEnvId(fromEnv)) {
|
|
241864
|
+
return { envId: fromEnv, source: "process.env.CLOUDBASE_ENV_ID" };
|
|
241865
|
+
}
|
|
241866
|
+
const projectEnvId = (0, project_config_js_1.readProjectEnvId)();
|
|
241867
|
+
if (isReportableEnvId(projectEnvId)) {
|
|
241868
|
+
return { envId: projectEnvId, source: "project" };
|
|
241869
|
+
}
|
|
241870
|
+
if (isReportableEnvId(input.loginEnvId)) {
|
|
241871
|
+
return { envId: input.loginEnvId, source: "login_state" };
|
|
241872
|
+
}
|
|
241873
|
+
return { envId: null, source: "default" };
|
|
241874
|
+
}
|
|
241875
|
+
|
|
241876
|
+
|
|
240394
241877
|
/***/ },
|
|
240395
241878
|
|
|
240396
241879
|
/***/ 81194
|
|
@@ -242069,6 +243552,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
242069
243552
|
};
|
|
242070
243553
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
242071
243554
|
exports.reportToolkitSessionInitialized = exports.reportToolkitLifecycle = exports.reportResourceRead = exports.reportElicitationResult = exports.reportToolCall = exports.MCP_UI_EXTENSION = exports.telemetryReporter = void 0;
|
|
243555
|
+
exports.seedStdioEnvBinding = seedStdioEnvBinding;
|
|
242072
243556
|
exports.extractMcpClientInfo = extractMcpClientInfo;
|
|
242073
243557
|
exports.readMcpClientInfoFromServer = readMcpClientInfoFromServer;
|
|
242074
243558
|
exports.normalizeClientName = normalizeClientName;
|
|
@@ -242082,6 +243566,8 @@ const os_1 = __importDefault(__webpack_require__(21820));
|
|
|
242082
243566
|
const auth_js_1 = __webpack_require__(561);
|
|
242083
243567
|
const cloudbase_manager_js_1 = __webpack_require__(33109);
|
|
242084
243568
|
const cloud_mode_js_1 = __webpack_require__(88694);
|
|
243569
|
+
const env_binding_js_1 = __webpack_require__(61498);
|
|
243570
|
+
const device_id_js_1 = __webpack_require__(36953);
|
|
242085
243571
|
const logger_js_1 = __webpack_require__(40781);
|
|
242086
243572
|
const site_map_js_1 = __webpack_require__(34533);
|
|
242087
243573
|
/**
|
|
@@ -242137,7 +243623,7 @@ class TelemetryReporter {
|
|
|
242137
243623
|
const arch = os_1.default.arch(); // 系统架构
|
|
242138
243624
|
// Build-time injected version; guard for vitest / non-webpack runtimes.
|
|
242139
243625
|
const mcpVersion = process.env.npm_package_version ||
|
|
242140
|
-
( true ? "2.36.
|
|
243626
|
+
( true ? "2.36.2" : 0);
|
|
242141
243627
|
return {
|
|
242142
243628
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
242143
243629
|
deviceId: this.deviceId,
|
|
@@ -242150,26 +243636,25 @@ class TelemetryReporter {
|
|
|
242150
243636
|
}
|
|
242151
243637
|
/**
|
|
242152
243638
|
* 获取设备唯一标识
|
|
242153
|
-
*
|
|
243639
|
+
*
|
|
243640
|
+
* 锚点与降级顺序见 `utils/device-id.ts`:优先系统级不可变标识(IOPlatformUUID /
|
|
243641
|
+
* MachineGuid / machine-id),取不到才退到 hostname + CPU + 过滤后的物理网卡 MAC。
|
|
243642
|
+
* 容器里 hostname 每次重建都变、macOS 私有 Wi-Fi 地址让 MAC 随 SSID 漂移,
|
|
243643
|
+
* 两者都不能当锚点 —— 旧实现把它们全拼进去,同一台 Mac 一天能上报成几十个设备。
|
|
243644
|
+
*
|
|
243645
|
+
* 子进程(ioreg / reg)只在这里跑一次(构造时),1s 超时即降级。
|
|
242154
243646
|
*/
|
|
242155
243647
|
getDeviceId() {
|
|
242156
243648
|
try {
|
|
242157
|
-
|
|
242158
|
-
|
|
242159
|
-
|
|
242160
|
-
os_1.default.cpus().map((cpu) => cpu.model).join(','),
|
|
242161
|
-
Object.values(os_1.default.networkInterfaces())
|
|
242162
|
-
.reduce((acc, val) => acc.concat(val || []), [])
|
|
242163
|
-
.filter((nic) => nic && !nic.internal && nic.mac)
|
|
242164
|
-
.map((nic) => nic.mac)
|
|
242165
|
-
.join(',')
|
|
242166
|
-
].join('|');
|
|
242167
|
-
// 生成SHA256哈希作为设备ID
|
|
242168
|
-
return crypto_1.default.createHash('sha256').update(deviceInfo).digest('hex').substring(0, 32);
|
|
243649
|
+
const { deviceId, source } = (0, device_id_js_1.computeDeviceId)();
|
|
243650
|
+
(0, logger_js_1.debug)('device_id_resolved', { source, deviceId: deviceId.substring(0, 8) + '...' });
|
|
243651
|
+
return deviceId;
|
|
242169
243652
|
}
|
|
242170
243653
|
catch (err) {
|
|
242171
|
-
//
|
|
242172
|
-
|
|
243654
|
+
// 走到这里说明连 hostname / CPU 都读不到:用固定串兜底,**绝不能**用随机数
|
|
243655
|
+
// (随机数等于每次启动都是一台新设备,正是这次要消灭的行为)。
|
|
243656
|
+
(0, logger_js_1.debug)('获取设备标识失败,回落到固定串', err instanceof Error ? err : new Error(String(err)));
|
|
243657
|
+
return crypto_1.default.createHash('sha256').update('cloudbase-mcp|no-device-signal').digest('hex').substring(0, 32);
|
|
242173
243658
|
}
|
|
242174
243659
|
}
|
|
242175
243660
|
/**
|
|
@@ -242285,39 +243770,40 @@ class TelemetryReporter {
|
|
|
242285
243770
|
// 创建全局实例
|
|
242286
243771
|
exports.telemetryReporter = new TelemetryReporter();
|
|
242287
243772
|
/**
|
|
242288
|
-
*
|
|
242289
|
-
*
|
|
243773
|
+
* Reports read the current AsyncLocalStorage slot.
|
|
243774
|
+
* They do not re-read envManager or CLOUDBASE_ENV_ID.
|
|
243775
|
+
* An explicit envId on this call is only used when the slot is still empty
|
|
243776
|
+
* (hosted initialized, before a resolver runs, when the request already carried one).
|
|
243777
|
+
*
|
|
243778
|
+
* The source list lives in `env-binding.ts` (`ENV_SOURCES`) — one definition only.
|
|
242290
243779
|
*/
|
|
242291
243780
|
function resolveEnvId(cloudBaseOptions) {
|
|
242292
|
-
|
|
242293
|
-
|
|
242294
|
-
|
|
242295
|
-
if (cloudBaseOptions?.envId) {
|
|
242296
|
-
envId = cloudBaseOptions.envId;
|
|
242297
|
-
envIdSource = 'cloudBaseOptions';
|
|
242298
|
-
}
|
|
242299
|
-
else {
|
|
242300
|
-
const cachedEnvId = (0, cloudbase_manager_js_1.getCachedEnvId)();
|
|
242301
|
-
if (cachedEnvId) {
|
|
242302
|
-
envId = cachedEnvId;
|
|
242303
|
-
envIdSource = 'envManager.cachedEnvId';
|
|
242304
|
-
}
|
|
242305
|
-
else if (process.env.CLOUDBASE_ENV_ID) {
|
|
242306
|
-
envId = process.env.CLOUDBASE_ENV_ID;
|
|
242307
|
-
envIdSource = 'process.env.CLOUDBASE_ENV_ID';
|
|
242308
|
-
}
|
|
242309
|
-
else {
|
|
242310
|
-
envId = 'unknown';
|
|
242311
|
-
envIdSource = 'default';
|
|
242312
|
-
}
|
|
242313
|
-
}
|
|
243781
|
+
const reported = (0, env_binding_js_1.readReportedEnv)();
|
|
243782
|
+
if (reported.envIdSource !== "default") {
|
|
243783
|
+
return reported;
|
|
242314
243784
|
}
|
|
242315
|
-
|
|
242316
|
-
|
|
242317
|
-
|
|
242318
|
-
|
|
243785
|
+
if (cloudBaseOptions?.envId) {
|
|
243786
|
+
return { envId: cloudBaseOptions.envId, envIdSource: "cloudBaseOptions" };
|
|
243787
|
+
}
|
|
243788
|
+
return { envId: "unknown", envIdSource: "default" };
|
|
243789
|
+
}
|
|
243790
|
+
/**
|
|
243791
|
+
* Stdio start: reuse the login warm (one peekLoginState per process) and one project-file read.
|
|
243792
|
+
* Does not call setEnvId and does not list environments. Cloud mode does not read local files.
|
|
243793
|
+
*/
|
|
243794
|
+
async function seedStdioEnvBinding(slot) {
|
|
243795
|
+
if ((0, cloud_mode_js_1.isCloudMode)()) {
|
|
243796
|
+
return;
|
|
243797
|
+
}
|
|
243798
|
+
await warmLocalLoginState();
|
|
243799
|
+
const loginEnvId = typeof localLoginState?.envId === "string" ? localLoginState.envId : null;
|
|
243800
|
+
const binding = (0, env_binding_js_1.peekLocalEnvBinding)({
|
|
243801
|
+
cachedEnvId: (0, cloudbase_manager_js_1.getCachedEnvId)(),
|
|
243802
|
+
loginEnvId,
|
|
243803
|
+
});
|
|
243804
|
+
if (binding.envId && binding.source !== "default") {
|
|
243805
|
+
slot.binding = binding;
|
|
242319
243806
|
}
|
|
242320
|
-
return { envId, envIdSource };
|
|
242321
243807
|
}
|
|
242322
243808
|
/**
|
|
242323
243809
|
* Normalize SDK Implementation / clientInfo into telemetry-safe fields.
|
|
@@ -242624,6 +244110,9 @@ const reportToolCall = async (params) => {
|
|
|
242624
244110
|
duration: params.duration !== undefined ? String(params.duration) : undefined,
|
|
242625
244111
|
error: params.error ? params.error.substring(0, 200) : undefined, // 限制错误信息长度
|
|
242626
244112
|
envId: envId || 'unknown',
|
|
244113
|
+
// 取值来源(cloudBaseOptions / envManager.cachedEnvId / process.env / default):
|
|
244114
|
+
// 这一列就是「envId 为什么是 unknown」的判据,别再靠猜
|
|
244115
|
+
envIdSource,
|
|
242627
244116
|
region: siteRegion.region,
|
|
242628
244117
|
site: siteRegion.site,
|
|
242629
244118
|
login_uin: loginUin,
|
|
@@ -242637,6 +244126,13 @@ const reportToolCall = async (params) => {
|
|
|
242637
244126
|
if (params.action !== undefined) {
|
|
242638
244127
|
eventData.action = params.action;
|
|
242639
244128
|
}
|
|
244129
|
+
// 环境准备结果:拿不到就不占列(与能力字段同一纪律,不写 unknown 假值)
|
|
244130
|
+
if (params.envSetupStatus !== undefined) {
|
|
244131
|
+
eventData.envSetupStatus = params.envSetupStatus;
|
|
244132
|
+
}
|
|
244133
|
+
if (params.envSetupFailReason !== undefined) {
|
|
244134
|
+
eventData.envSetupFailReason = params.envSetupFailReason;
|
|
244135
|
+
}
|
|
242640
244136
|
// 添加入参信息(如果提供)
|
|
242641
244137
|
if (params.inputParams !== undefined) {
|
|
242642
244138
|
try {
|
|
@@ -242758,7 +244254,15 @@ const reportToolkitLifecycle = async (params) => {
|
|
|
242758
244254
|
// 安全获取环境ID,优先使用传入的配置
|
|
242759
244255
|
const { envId, envIdSource } = resolveEnvId(params.cloudBaseOptions);
|
|
242760
244256
|
const siteRegion = resolveTelemetrySiteRegion(params.cloudBaseOptions);
|
|
242761
|
-
|
|
244257
|
+
// `start` 在进程最早期发出:此时既没有宿主注入的 uin,也还没人 warm 过本地登录态。
|
|
244258
|
+
// 卡死 `allowResolve: false` 就只能读到空缓存 → 恒 'unknown'(2026-10-26 实测:这一列
|
|
244259
|
+
// 有真实 uin 的行是 0)。start 允许解析:`warmLocalLoginState()` 进程内只跑一次
|
|
244260
|
+
// (读本地 auth.json;临时密钥过期时可能续期一次,与工具调用本来就要付的开销同源),
|
|
244261
|
+
// 不会挂到每次上报上。
|
|
244262
|
+
// `exit` 仍保持不允许 —— 退出路径不能等,拿不到就是 unknown,`start` 那次已经把值带出去了。
|
|
244263
|
+
const loginUin = await resolveLoginUin(params.cloudBaseOptions, {
|
|
244264
|
+
allowResolve: params.event !== 'exit',
|
|
244265
|
+
});
|
|
242762
244266
|
(0, logger_js_1.debug)('[telemetry] 生命周期事件 envId 获取结果', {
|
|
242763
244267
|
event: params.event,
|
|
242764
244268
|
envId,
|
|
@@ -242773,6 +244277,9 @@ const reportToolkitLifecycle = async (params) => {
|
|
|
242773
244277
|
exitCode: params.exitCode !== undefined ? String(params.exitCode) : undefined,
|
|
242774
244278
|
error: params.error ? params.error.substring(0, 200) : undefined, // 限制错误信息长度
|
|
242775
244279
|
envId: envId || 'unknown',
|
|
244280
|
+
// 取值来源(cloudBaseOptions / envManager.cachedEnvId / process.env / default):
|
|
244281
|
+
// 这一列就是「envId 为什么是 unknown」的判据,别再靠猜
|
|
244282
|
+
envIdSource,
|
|
242776
244283
|
region: siteRegion.region,
|
|
242777
244284
|
site: siteRegion.site,
|
|
242778
244285
|
login_uin: loginUin,
|
|
@@ -242829,12 +244336,15 @@ exports.reportToolkitLifecycle = reportToolkitLifecycle;
|
|
|
242829
244336
|
*/
|
|
242830
244337
|
const reportToolkitSessionInitialized = async (params) => {
|
|
242831
244338
|
const { nodeVersion, osType, osRelease, arch, mcpVersion } = exports.telemetryReporter.getUserAgent();
|
|
242832
|
-
const { envId } = resolveEnvId(params.cloudBaseOptions);
|
|
244339
|
+
const { envId, envIdSource } = resolveEnvId(params.cloudBaseOptions);
|
|
242833
244340
|
const siteRegion = resolveTelemetrySiteRegion(params.cloudBaseOptions);
|
|
242834
|
-
|
|
244341
|
+
// 与 `start` 同理:`initialized` 紧跟在 `start` 之后,也是不允许等的分支就会白报一条 unknown。
|
|
244342
|
+
// 这里放开解析;若 `start` 已经 warm 过,这一句直接命中进程内缓存,零额外成本。
|
|
244343
|
+
const loginUin = await resolveLoginUin(params.cloudBaseOptions);
|
|
242835
244344
|
const eventData = {
|
|
242836
244345
|
event: 'initialized',
|
|
242837
244346
|
envId: envId || 'unknown',
|
|
244347
|
+
envIdSource,
|
|
242838
244348
|
region: siteRegion.region,
|
|
242839
244349
|
site: siteRegion.site,
|
|
242840
244350
|
login_uin: loginUin,
|
|
@@ -243008,7 +244518,6 @@ function throwToolPayloadError(payload) {
|
|
|
243008
244518
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
243009
244519
|
exports.applyCategoryAnnotationMeta = applyCategoryAnnotationMeta;
|
|
243010
244520
|
exports.wrapServerWithTelemetry = wrapServerWithTelemetry;
|
|
243011
|
-
const cloudbase_manager_js_1 = __webpack_require__(33109);
|
|
243012
244521
|
const cloud_mode_js_1 = __webpack_require__(88694);
|
|
243013
244522
|
const logger_js_1 = __webpack_require__(40781);
|
|
243014
244523
|
const telemetry_js_1 = __webpack_require__(5198);
|
|
@@ -243071,8 +244580,56 @@ function contributionHint(server) {
|
|
|
243071
244580
|
].join("\n");
|
|
243072
244581
|
}
|
|
243073
244582
|
/**
|
|
243074
|
-
*
|
|
244583
|
+
* 从 `auth` 的返回里取出「环境准备」的结果,供遥测上报。
|
|
244584
|
+
*
|
|
244585
|
+
* 为什么要从返回体里抠:`env_setup_status` / `env_setup_failure.reason` 只存在于
|
|
244586
|
+
* `auth` 的 payload 里,不是 `reportToolCall` 的入参。而工具 wrapper 是唯一同时
|
|
244587
|
+
* 看得见 args 和 result 的地方。
|
|
244588
|
+
*
|
|
244589
|
+
* 现状(2026-10-27):这两项只回给模型、没进埋点,于是「无环境的用户卡在购买页、
|
|
244590
|
+
* 实名、还是 CAM 授权」在数据里长得一模一样,加文案也无法验收。
|
|
243075
244591
|
*/
|
|
244592
|
+
function readEnvSetupOutcome(result) {
|
|
244593
|
+
const rec = result;
|
|
244594
|
+
if (!rec || typeof rec !== 'object')
|
|
244595
|
+
return undefined;
|
|
244596
|
+
// 优先 structuredContent(MCP 规范位),退到 content[0].text 里的 JSON
|
|
244597
|
+
const candidates = [];
|
|
244598
|
+
if (rec.structuredContent)
|
|
244599
|
+
candidates.push(rec.structuredContent);
|
|
244600
|
+
const content = Array.isArray(rec.content) ? rec.content : [];
|
|
244601
|
+
for (const item of content) {
|
|
244602
|
+
const text = item?.text;
|
|
244603
|
+
if (typeof text === 'string' && text.trim().startsWith('{')) {
|
|
244604
|
+
try {
|
|
244605
|
+
candidates.push(JSON.parse(text));
|
|
244606
|
+
}
|
|
244607
|
+
catch {
|
|
244608
|
+
/* 不是 JSON 就跳过,不要因为解析失败影响正常返回 */
|
|
244609
|
+
}
|
|
244610
|
+
}
|
|
244611
|
+
}
|
|
244612
|
+
for (const payload of candidates) {
|
|
244613
|
+
const p = payload;
|
|
244614
|
+
const status = typeof p?.env_setup_status === 'string' ? p.env_setup_status : undefined;
|
|
244615
|
+
if (!status)
|
|
244616
|
+
continue;
|
|
244617
|
+
const failure = p?.env_setup_failure;
|
|
244618
|
+
const reason = typeof failure?.reason === 'string' ? failure.reason : undefined;
|
|
244619
|
+
// 把两个布尔压进 reason 的后缀:一列就能看清「卡在哪」,
|
|
244620
|
+
// 单看 reason 只知道「建环境失败」,不知道是实名还是 CAM 授权拦住的
|
|
244621
|
+
const gates = [];
|
|
244622
|
+
if (failure?.need_real_name_auth === true)
|
|
244623
|
+
gates.push('realname');
|
|
244624
|
+
if (failure?.need_cam_auth === true)
|
|
244625
|
+
gates.push('cam');
|
|
244626
|
+
return {
|
|
244627
|
+
status,
|
|
244628
|
+
reason: reason ? (gates.length ? `${reason}+${gates.join('+')}` : reason) : undefined,
|
|
244629
|
+
};
|
|
244630
|
+
}
|
|
244631
|
+
return undefined;
|
|
244632
|
+
}
|
|
243076
244633
|
/**
|
|
243077
244634
|
* 工具自己返回的失败:结构化 `{ success: false }`(`isBusinessFailureToolResult` 已覆盖
|
|
243078
244635
|
* 顶层 / structuredContent / JSON 文本三种挂法),**或**已经显式带 `isError: true` 的回执。
|
|
@@ -243092,7 +244649,7 @@ function isReturnedFailureResult(result) {
|
|
|
243092
244649
|
* 所以两条路径对同一个底层错误得到的文本逐字相同(🆔 RequestId + 📦 版本页脚都在这里)。
|
|
243093
244650
|
*/
|
|
243094
244651
|
function buildFailureClientText(errorMessage, requestId, server) {
|
|
243095
|
-
const mcpVersion = true ? "2.36.
|
|
244652
|
+
const mcpVersion = true ? "2.36.2" : 0;
|
|
243096
244653
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
243097
244654
|
return `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n${contributionHint(server)}`;
|
|
243098
244655
|
}
|
|
@@ -243152,12 +244709,18 @@ function withEnhancedFailureText(result, errorMessage, requestId, server) {
|
|
|
243152
244709
|
}
|
|
243153
244710
|
return result;
|
|
243154
244711
|
}
|
|
244712
|
+
/**
|
|
244713
|
+
* 创建包装后的处理函数,添加数据上报功能
|
|
244714
|
+
*/
|
|
243155
244715
|
function createWrappedHandler(name, handler, server) {
|
|
243156
244716
|
return async (args, extra) => {
|
|
243157
244717
|
const startTime = Date.now();
|
|
243158
244718
|
let success = false;
|
|
243159
244719
|
let errorMessage;
|
|
243160
244720
|
let requestId;
|
|
244721
|
+
// 提到 try 外:finally 里要读 auth 的环境准备结果(env_setup_status / failure.reason)。
|
|
244722
|
+
// 护栏拦截的早退路径不会赋值,finally 里按 undefined 处理。
|
|
244723
|
+
let result;
|
|
243161
244724
|
try {
|
|
243162
244725
|
(0, logger_js_1.debug)(`开始执行工具: ${name}`, { args: sanitizeArgs(args) });
|
|
243163
244726
|
// In test environment, skip logger to avoid potential blocking
|
|
@@ -243189,7 +244752,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
243189
244752
|
return guardDecision.result;
|
|
243190
244753
|
}
|
|
243191
244754
|
// 执行原始处理函数(extra 一并透传,工具可据此拿到在途请求 id)
|
|
243192
|
-
|
|
244755
|
+
result = await handler(args, extra);
|
|
243193
244756
|
// 工具**自己返回**的失败(`{ success: false }` 结构化载荷,或已经带 `isError: true` 的
|
|
243194
244757
|
// 失败回执)与"抛错"是同一件事:遥测要按失败记,文案要吃同一套收尾(增强 + RequestId +
|
|
243195
244758
|
// 版本页脚)。护栏拦截的返回走不到这里——它在上面就 return 了,且它的载荷既没有
|
|
@@ -243270,24 +244833,19 @@ function createWrappedHandler(name, handler, server) {
|
|
|
243270
244833
|
const isTestEnvironment = false || process.env.VITEST === "true";
|
|
243271
244834
|
if (!isTestEnvironment) {
|
|
243272
244835
|
const duration = Date.now() - startTime;
|
|
243273
|
-
|
|
243274
|
-
let cloudBaseOptions = server.cloudBaseOptions;
|
|
243275
|
-
if (!cloudBaseOptions?.envId) {
|
|
243276
|
-
const cachedEnvId = (0, cloudbase_manager_js_1.getCachedEnvId)();
|
|
243277
|
-
if (cachedEnvId) {
|
|
243278
|
-
cloudBaseOptions = { ...cloudBaseOptions, envId: cachedEnvId };
|
|
243279
|
-
}
|
|
243280
|
-
}
|
|
244836
|
+
const envSetup = name === 'auth' ? readEnvSetupOutcome(result) : undefined;
|
|
243281
244837
|
// 异步上报,不阻塞工具返回
|
|
243282
244838
|
(0, telemetry_js_1.reportToolCall)({
|
|
243283
244839
|
toolName: name,
|
|
244840
|
+
envSetupStatus: envSetup?.status,
|
|
244841
|
+
envSetupFailReason: envSetup?.reason,
|
|
243284
244842
|
success,
|
|
243285
244843
|
requestId,
|
|
243286
244844
|
duration,
|
|
243287
244845
|
error: errorMessage,
|
|
243288
244846
|
inputParams: sanitizeArgs(args), // 添加入参上报
|
|
243289
244847
|
action: args?.action, // 工具级 action(如 auth 的 status/set_env)
|
|
243290
|
-
cloudBaseOptions: cloudBaseOptions,
|
|
244848
|
+
cloudBaseOptions: server.cloudBaseOptions,
|
|
243291
244849
|
ide: server.ide || process.env.INTEGRATION_IDE, // 传递集成IDE信息
|
|
243292
244850
|
client: server.client || process.env.CLOUDBASE_MCP_CLIENT, // 传递 MCP client 来源标识
|
|
243293
244851
|
mcpClientInfo: (0, telemetry_js_1.readMcpClientInfoFromServer)(server),
|
|
@@ -263601,6 +265159,14 @@ module.exports = require("net");
|
|
|
263601
265159
|
|
|
263602
265160
|
/***/ },
|
|
263603
265161
|
|
|
265162
|
+
/***/ 18667
|
|
265163
|
+
(module) {
|
|
265164
|
+
|
|
265165
|
+
"use strict";
|
|
265166
|
+
module.exports = require("node:async_hooks");
|
|
265167
|
+
|
|
265168
|
+
/***/ },
|
|
265169
|
+
|
|
263604
265170
|
/***/ 75305
|
|
263605
265171
|
(module) {
|
|
263606
265172
|
|