@cloudbase/manager-node 5.5.7 → 5.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +88 -0
- package/lib/environment.js +5 -0
- package/lib/index.js +11 -0
- package/lib/integration/constants.js +10 -0
- package/lib/integration/crypto.js +102 -0
- package/lib/integration/fields.js +69 -0
- package/lib/integration/index.js +310 -0
- package/lib/integration/secretKey.js +92 -0
- package/lib/integration/types.js +18 -0
- package/lib/interfaces/index.js +1 -0
- package/lib/interfaces/integration.interface.js +20 -0
- package/package.json +1 -1
- package/types/environment.d.ts +3 -0
- package/types/index.d.ts +10 -0
- package/types/integration/constants.d.ts +7 -0
- package/types/integration/crypto.d.ts +16 -0
- package/types/integration/fields.d.ts +17 -0
- package/types/integration/index.d.ts +62 -0
- package/types/integration/secretKey.d.ts +15 -0
- package/types/integration/types.d.ts +200 -0
- package/types/interfaces/index.d.ts +1 -0
- package/types/interfaces/integration.interface.d.ts +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,91 @@
|
|
|
1
|
+
## @cloudbase/manager-node v5.5.7 版本发布 🚀(2026-06-30)
|
|
2
|
+
|
|
3
|
+
- 优化云存储上传逻辑,解决 socket hang up 问题
|
|
4
|
+
- 修复 添加 onFileFinish 回调的 file 空值检查
|
|
5
|
+
- 修复 跳过 enduser 相关测试用例
|
|
6
|
+
- 修复 generate-changelog 及更新函数类型
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## @cloudbase/manager-node v5.5.6 版本发布 🚀(2026-06-24)
|
|
11
|
+
|
|
12
|
+
- 新增 补全 getEnvInfo 返回字段并新增 isPostgresqlEnv 判断方法
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## @cloudbase/manager-node v5.5.4 版本发布 🚀(2026-06-12)
|
|
17
|
+
|
|
18
|
+
- 修复 X-Metadata和X-upsert统一改成x-metadata 和x-upsert
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## @cloudbase/manager-node v5.5.1 版本发布 🚀(2026-06-01)
|
|
23
|
+
|
|
24
|
+
- 新增 switch ListFunctions from scf to tcb service
|
|
25
|
+
- 新增 createFunction 检测 CREATE_FAILED 残留并自动清理重建
|
|
26
|
+
- 新增 PG 存储能力
|
|
27
|
+
- 新增 aiModel 新增 AI 模型管理能力
|
|
28
|
+
- 新增 修复静态托管部署多并发中断问题
|
|
29
|
+
- 新增 登陆配置相关接口
|
|
30
|
+
- 新增 更新获取appid的方式
|
|
31
|
+
- 新增 修复测试用例
|
|
32
|
+
- 新增 修复app测试
|
|
33
|
+
- 新增 修复storage 获取权限兼容问题
|
|
34
|
+
- 新增更新函数配置TopicId参数
|
|
35
|
+
- 新增 云函数参数处理优化+切scf
|
|
36
|
+
- 新增 支持通过镜像部署云函数
|
|
37
|
+
- 新增 cos地域更新
|
|
38
|
+
- 新增 cloudrun features
|
|
39
|
+
- 新增 cloudrun 接口
|
|
40
|
+
- 新增 cos上传方式更新
|
|
41
|
+
- 新增 云托管支持灰度发布
|
|
42
|
+
- 新增 更新 flexdb 调用文档和单测
|
|
43
|
+
- 新增 更新文件大小限制为1.5M
|
|
44
|
+
- 新增 部署web云函数
|
|
45
|
+
- 新增 cloudrun deploy params update
|
|
46
|
+
- 新增 request join env
|
|
47
|
+
- 新增 增加云函数层管理及触发器逻辑
|
|
48
|
+
- 新增云函数管理相关逻辑
|
|
49
|
+
- 新增 add agentService
|
|
50
|
+
- 新增 add cloudrun deploy api
|
|
51
|
+
- 新增 cloudrun
|
|
52
|
+
- 新增 support disable cos sdk keepalive
|
|
53
|
+
- 新增 support COS intranet endpoint
|
|
54
|
+
- 新增 remove createEnv
|
|
55
|
+
- 新增 add intranet endpoint for all services
|
|
56
|
+
- 新增 support set Concurrent And Flow
|
|
57
|
+
- 新增 增加下载重试与并发个数
|
|
58
|
+
- 新增 增加dirupload retry与parallel功能
|
|
59
|
+
- 优化 更新cos以解决tough-cookie漏洞;并解决build时的ts报错
|
|
60
|
+
- 优化 update https-proxy-agent
|
|
61
|
+
- 修复 use tcb service with EnvId for table-level APIs
|
|
62
|
+
- 修复 generate-changelog 脚本修复及优化
|
|
63
|
+
- 修复 remove .claude/setting.local
|
|
64
|
+
- 修复 deleteCustomDomain修复路由检测。env下新增gw模块的测试用例。
|
|
65
|
+
- 修复删除云函数入参及返回逻辑
|
|
66
|
+
- 修复 更新错误码
|
|
67
|
+
- 修复 fix config
|
|
68
|
+
- 修复 internal endpoint
|
|
69
|
+
- 修复 fix
|
|
70
|
+
- 修复 fix v
|
|
71
|
+
- 修复 fix bug
|
|
72
|
+
- 修复 增加函数创建失败错误信息
|
|
73
|
+
- 修复 test API
|
|
74
|
+
- 修复 修改checkFullAccess逻辑
|
|
75
|
+
- 修复 处理大文件删除堆栈超出问题
|
|
76
|
+
- 修复 update updateFunctionConfig
|
|
77
|
+
- 修复 getFunctionLogs 传参自动补齐时间区间问题
|
|
78
|
+
- 修复 解决 downloadAndExtractRemoteZip 丢失文件的问题
|
|
79
|
+
- 修复 get stream from download file
|
|
80
|
+
- 修复 fix
|
|
81
|
+
- 修复 fix env Type bug
|
|
82
|
+
- 修复 fix
|
|
83
|
+
- 解压文件过滤__MACOSX文件夹
|
|
84
|
+
- 增加函数创建失败错误信息
|
|
85
|
+
- migrate func log api
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
1
89
|
# 4.0.0
|
|
2
90
|
- 升级 https-proxy-agent 3->5 修复 https://github.com/TencentCloud/tencentcloud-sdk-nodejs/issues/47
|
|
3
91
|
|
package/lib/environment.js
CHANGED
|
@@ -23,6 +23,7 @@ const permission_1 = require("./permission");
|
|
|
23
23
|
const sandbox_1 = require("./sandbox");
|
|
24
24
|
const aiModel_1 = require("./aiModel");
|
|
25
25
|
const monitor_1 = require("./monitor");
|
|
26
|
+
const integration_1 = require("./integration");
|
|
26
27
|
class Environment {
|
|
27
28
|
constructor(context, envId) {
|
|
28
29
|
this.inited = false;
|
|
@@ -49,6 +50,7 @@ class Environment {
|
|
|
49
50
|
this.sandboxService = new sandbox_1.SandboxService(this);
|
|
50
51
|
this.aiModelService = new aiModel_1.AiModelService(this);
|
|
51
52
|
this.monitorService = new monitor_1.MonitorService(this);
|
|
53
|
+
this.integrationService = new integration_1.IntegrationService(this);
|
|
52
54
|
}
|
|
53
55
|
async lazyInit() {
|
|
54
56
|
if (!this.inited) {
|
|
@@ -126,6 +128,9 @@ class Environment {
|
|
|
126
128
|
getMonitorService() {
|
|
127
129
|
return this.monitorService;
|
|
128
130
|
}
|
|
131
|
+
getIntegrationService() {
|
|
132
|
+
return this.integrationService;
|
|
133
|
+
}
|
|
129
134
|
getCommonService(serviceType = 'tcb', serviceVersion) {
|
|
130
135
|
return new common_1.CommonService(this, serviceType, serviceVersion);
|
|
131
136
|
}
|
package/lib/index.js
CHANGED
|
@@ -122,6 +122,17 @@ class CloudBase {
|
|
|
122
122
|
get aiModel() {
|
|
123
123
|
return this.currentEnvironment().getAiModelService();
|
|
124
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* 集成中心服务(UserKey)
|
|
127
|
+
* 提供集成模板/实例的增删改查与绑定云函数能力
|
|
128
|
+
*/
|
|
129
|
+
get integration() {
|
|
130
|
+
return this.currentEnvironment().getIntegrationService();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 监控服务
|
|
134
|
+
* 提供指标查询能力
|
|
135
|
+
*/
|
|
125
136
|
get monitor() {
|
|
126
137
|
return this.currentEnvironment().getMonitorService();
|
|
127
138
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 集成中心常量定义(与 dev-platform 对齐)
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MIN_AES_CIPHERTEXT_LENGTH = exports.USER_KEY_BUSINESS = void 0;
|
|
7
|
+
/** 业务类型标识:集成中心来源的密钥对 */
|
|
8
|
+
exports.USER_KEY_BUSINESS = 'integration';
|
|
9
|
+
/** 密文最小长度(小于该长度视为非密文,解密时原样返回) */
|
|
10
|
+
exports.MIN_AES_CIPHERTEXT_LENGTH = 24;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.AESCrypto = void 0;
|
|
37
|
+
exports.aesEncryptWithIv = aesEncryptWithIv;
|
|
38
|
+
/**
|
|
39
|
+
* 集成中心 AES 加解密
|
|
40
|
+
*
|
|
41
|
+
* 与 dev-platform 的 AESCrypto(crypto-js)完全对齐,保证密文可互相解出:
|
|
42
|
+
* - 算法:AES-256-CBC
|
|
43
|
+
* - key:32 字节(按 UTF-8 解析)
|
|
44
|
+
* - IV:每次随机 16 字节
|
|
45
|
+
* - padding:PKCS7
|
|
46
|
+
* - 密文格式:base64(IV) + base64(ciphertext)
|
|
47
|
+
* (IV 固定 16 字节 → base64 长度恒为 24,前 24 字符即 IV)
|
|
48
|
+
*
|
|
49
|
+
* 使用 Node 内置 crypto 复刻,无需引入额外依赖。
|
|
50
|
+
*/
|
|
51
|
+
const crypto = __importStar(require("crypto"));
|
|
52
|
+
const ALGORITHM = 'aes-256-cbc';
|
|
53
|
+
const KEY_BYTE_LENGTH = 32;
|
|
54
|
+
const IV_BYTE_LENGTH = 16;
|
|
55
|
+
/** base64(16 字节) 的固定长度 */
|
|
56
|
+
const IV_BASE64_LENGTH = 24;
|
|
57
|
+
function assertKey(key) {
|
|
58
|
+
if (Buffer.byteLength(key, 'utf8') !== KEY_BYTE_LENGTH) {
|
|
59
|
+
throw new Error('密钥必须是 32 字节长度');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 使用指定 IV 加密(供测试与内部使用,保证可重现)
|
|
64
|
+
*/
|
|
65
|
+
function aesEncryptWithIv(plaintext, key, iv) {
|
|
66
|
+
assertKey(key);
|
|
67
|
+
if (iv.length !== IV_BYTE_LENGTH) {
|
|
68
|
+
throw new Error('IV 必须是 16 字节长度');
|
|
69
|
+
}
|
|
70
|
+
const cipher = crypto.createCipheriv(ALGORITHM, Buffer.from(key, 'utf8'), iv);
|
|
71
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
|
|
72
|
+
return iv.toString('base64') + encrypted.toString('base64');
|
|
73
|
+
}
|
|
74
|
+
class AESCryptoImpl {
|
|
75
|
+
/**
|
|
76
|
+
* AES-256-CBC 加密,返回 base64(IV)+base64(密文)
|
|
77
|
+
*/
|
|
78
|
+
encrypt(plaintext, key) {
|
|
79
|
+
assertKey(key);
|
|
80
|
+
const iv = crypto.randomBytes(IV_BYTE_LENGTH);
|
|
81
|
+
return aesEncryptWithIv(plaintext, key, iv);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 解密 base64(IV)+base64(密文) 格式的密文
|
|
85
|
+
*/
|
|
86
|
+
decrypt(encryptedData, key) {
|
|
87
|
+
assertKey(key);
|
|
88
|
+
const ivBase64 = encryptedData.slice(0, IV_BASE64_LENGTH);
|
|
89
|
+
const ciphertextBase64 = encryptedData.slice(IV_BASE64_LENGTH);
|
|
90
|
+
const iv = Buffer.from(ivBase64, 'base64');
|
|
91
|
+
if (iv.length !== IV_BYTE_LENGTH) {
|
|
92
|
+
throw new Error('密文格式错误:IV 长度非法');
|
|
93
|
+
}
|
|
94
|
+
const decipher = crypto.createDecipheriv(ALGORITHM, Buffer.from(key, 'utf8'), iv);
|
|
95
|
+
const decrypted = Buffer.concat([
|
|
96
|
+
decipher.update(Buffer.from(ciphertextBase64, 'base64')),
|
|
97
|
+
decipher.final()
|
|
98
|
+
]);
|
|
99
|
+
return decrypted.toString('utf8');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.AESCrypto = new AESCryptoImpl();
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parsePasswordFieldNames = parsePasswordFieldNames;
|
|
4
|
+
exports.encryptPasswordFields = encryptPasswordFields;
|
|
5
|
+
exports.decryptPasswordFields = decryptPasswordFields;
|
|
6
|
+
/**
|
|
7
|
+
* 集成中心敏感字段处理(与 dev-platform 对齐)
|
|
8
|
+
*
|
|
9
|
+
* - 实例 Ext 为扁平对象 `{ [fieldName]: value }`
|
|
10
|
+
* - 模板 Ext 为 `{ fields: [{ name, type }] }`,type === 'password' 即敏感字段
|
|
11
|
+
* - 加密:仅加密有值的 password 字段(create / update 同一逻辑,后端对未改动 password 做保留)
|
|
12
|
+
* - 解密:长度 > MIN_AES_CIPHERTEXT_LENGTH 才尝试解密,失败保留原值不中断
|
|
13
|
+
*/
|
|
14
|
+
const crypto_1 = require("./crypto");
|
|
15
|
+
const constants_1 = require("./constants");
|
|
16
|
+
/**
|
|
17
|
+
* 从模板 Ext(JSON:`{ fields: [{ name, type }] }`)解析出 password 字段名集合。
|
|
18
|
+
* 解析失败或无 fields 时返回空数组。
|
|
19
|
+
*/
|
|
20
|
+
function parsePasswordFieldNames(templateExt) {
|
|
21
|
+
if (!templateExt)
|
|
22
|
+
return [];
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(templateExt);
|
|
25
|
+
const fields = (parsed === null || parsed === void 0 ? void 0 : parsed.fields) || [];
|
|
26
|
+
return fields
|
|
27
|
+
.filter(f => (f === null || f === void 0 ? void 0 : f.type) === 'password' && (f === null || f === void 0 ? void 0 : f.name))
|
|
28
|
+
.map(f => f.name);
|
|
29
|
+
}
|
|
30
|
+
catch (_a) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 加密 ext 对象中的 password 字段(仅加密有值的字段)。
|
|
36
|
+
* 返回新对象,不修改入参。
|
|
37
|
+
*/
|
|
38
|
+
function encryptPasswordFields(extObj, passwordFieldNames, aesKey) {
|
|
39
|
+
const result = Object.assign({}, extObj);
|
|
40
|
+
passwordFieldNames.forEach(name => {
|
|
41
|
+
const value = result[name];
|
|
42
|
+
if (name && value) {
|
|
43
|
+
result[name] = crypto_1.AESCrypto.encrypt(value, aesKey);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 解密 ext 对象中的 password 字段。
|
|
50
|
+
* - 仅处理长度 > MIN_AES_CIPHERTEXT_LENGTH 的字符串(规避明显非密文的噪音)
|
|
51
|
+
* - 解密失败保留原值,不中断流程
|
|
52
|
+
* 返回新对象,不修改入参。
|
|
53
|
+
*/
|
|
54
|
+
function decryptPasswordFields(extObj, passwordFieldNames, aesKey) {
|
|
55
|
+
const result = Object.assign({}, extObj);
|
|
56
|
+
passwordFieldNames.forEach(name => {
|
|
57
|
+
const encrypted = result[name];
|
|
58
|
+
if (typeof encrypted !== 'string' || encrypted.length <= constants_1.MIN_AES_CIPHERTEXT_LENGTH) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
result[name] = crypto_1.AESCrypto.decrypt(encrypted, aesKey);
|
|
63
|
+
}
|
|
64
|
+
catch (_a) {
|
|
65
|
+
// 解密失败保留原值,不打断主流程
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
14
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
15
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
16
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
17
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
18
|
+
};
|
|
19
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
20
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.IntegrationService = void 0;
|
|
24
|
+
const error_1 = require("../error");
|
|
25
|
+
const utils_1 = require("../utils");
|
|
26
|
+
const secretKey_1 = require("./secretKey");
|
|
27
|
+
const fields_1 = require("./fields");
|
|
28
|
+
__exportStar(require("./types"), exports);
|
|
29
|
+
/**
|
|
30
|
+
* 集成中心(UserKey)服务
|
|
31
|
+
*
|
|
32
|
+
* 复用现有 tcb 云 API(version 2018-06-08),统一携带 Business='integration'。
|
|
33
|
+
* 敏感字段加解密、bindFunction 编排在后续模块叠加。
|
|
34
|
+
*/
|
|
35
|
+
class IntegrationService {
|
|
36
|
+
constructor(environment) {
|
|
37
|
+
this.environment = environment;
|
|
38
|
+
this.tcbService = new utils_1.CloudService(environment.cloudBaseContext, 'tcb', '2018-06-08');
|
|
39
|
+
}
|
|
40
|
+
// =========== 只读 API ===========
|
|
41
|
+
/** 列出集成模板(密钥对模版列表) */
|
|
42
|
+
async listTemplates(params = {}) {
|
|
43
|
+
var _a, _b;
|
|
44
|
+
const { envId } = this.getEnvInfo();
|
|
45
|
+
return this.tcbService.request('GetUserKeyTemplateList', {
|
|
46
|
+
EnvId: envId,
|
|
47
|
+
Offset: (_a = params.offset) !== null && _a !== void 0 ? _a : 0,
|
|
48
|
+
Limit: (_b = params.limit) !== null && _b !== void 0 ? _b : 100,
|
|
49
|
+
AuthTypeCode: params.authTypeCode,
|
|
50
|
+
AuthTypeName: params.authTypeName
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** 列出集成实例(密钥对列表) */
|
|
54
|
+
async listUserKeys(params = {}) {
|
|
55
|
+
var _a, _b;
|
|
56
|
+
const { envId } = this.getEnvInfo();
|
|
57
|
+
return this.tcbService.request('GetUserKeyList', {
|
|
58
|
+
EnvId: envId,
|
|
59
|
+
Offset: (_a = params.offset) !== null && _a !== void 0 ? _a : 0,
|
|
60
|
+
Limit: (_b = params.limit) !== null && _b !== void 0 ? _b : 100,
|
|
61
|
+
Name: params.name,
|
|
62
|
+
AuthTypeCode: params.authTypeCode,
|
|
63
|
+
Business: params.business // ✅ 新增:业务类型
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/** 查询单个集成实例详情 */
|
|
67
|
+
async getUserKey(params) {
|
|
68
|
+
var _a;
|
|
69
|
+
this.validateRequiredParams(params, ['keyId']);
|
|
70
|
+
const { envId } = this.getEnvInfo();
|
|
71
|
+
return this.tcbService.request('GetOneUserKey', {
|
|
72
|
+
EnvId: envId,
|
|
73
|
+
KeyID: params.keyId,
|
|
74
|
+
NeedPwd: (_a = params.needPwd) !== null && _a !== void 0 ? _a : false,
|
|
75
|
+
Business: params.business // ✅ 新增:业务类型
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
// =========== 写 API ===========
|
|
79
|
+
/** 创建集成实例 */
|
|
80
|
+
async createUserKey(params) {
|
|
81
|
+
this.validateRequiredParams(params, ['name', 'authTypeCode']);
|
|
82
|
+
const { envId } = this.getEnvInfo();
|
|
83
|
+
const ext = await this.buildExt({
|
|
84
|
+
authTypeCode: params.authTypeCode,
|
|
85
|
+
envVariables: params.envVariables,
|
|
86
|
+
ext: params.ext
|
|
87
|
+
});
|
|
88
|
+
return this.tcbService.request('CreateUserKey', {
|
|
89
|
+
EnvId: envId,
|
|
90
|
+
Name: params.name,
|
|
91
|
+
KeyID: params.keyId,
|
|
92
|
+
AuthTypeCode: params.authTypeCode,
|
|
93
|
+
Description: params.description,
|
|
94
|
+
Ext: ext,
|
|
95
|
+
TicketID: params.ticketId,
|
|
96
|
+
Business: params.business, // ✅ 新增:业务类型
|
|
97
|
+
DemoCodeFunctionName: params.demoCodeFunctionName, // ✅ 新增:示例代码云函数名称
|
|
98
|
+
RuntimeConfig: params.runtimeConfig // ✅ 新增:Agent 云函数配置
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/** 更新集成实例 */
|
|
102
|
+
async updateUserKey(params) {
|
|
103
|
+
var _a, _b;
|
|
104
|
+
this.validateRequiredParams(params, ['keyId']);
|
|
105
|
+
const { envId } = this.getEnvInfo();
|
|
106
|
+
// 传入 envVariables 时需回查现有实例:用于合并 Ext(保留未改动字段)并兜底 authTypeCode
|
|
107
|
+
let authTypeCode = params.authTypeCode;
|
|
108
|
+
let existingExt;
|
|
109
|
+
if (params.envVariables) {
|
|
110
|
+
const existing = await this.getUserKey({ keyId: params.keyId });
|
|
111
|
+
existingExt = (_a = existing.UserKeyInfo) === null || _a === void 0 ? void 0 : _a.Ext;
|
|
112
|
+
if (!authTypeCode) {
|
|
113
|
+
authTypeCode = (_b = existing.UserKeyInfo) === null || _b === void 0 ? void 0 : _b.AuthTypeCode;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const ext = await this.buildExt({
|
|
117
|
+
authTypeCode,
|
|
118
|
+
envVariables: params.envVariables,
|
|
119
|
+
ext: params.ext,
|
|
120
|
+
existingExt
|
|
121
|
+
});
|
|
122
|
+
const requestParams = {
|
|
123
|
+
EnvId: envId,
|
|
124
|
+
KeyID: params.keyId,
|
|
125
|
+
Name: params.name,
|
|
126
|
+
AuthTypeCode: authTypeCode,
|
|
127
|
+
Description: params.description,
|
|
128
|
+
Ext: ext,
|
|
129
|
+
DemoCodeFunctionName: params.demoCodeFunctionName,
|
|
130
|
+
Business: params.business,
|
|
131
|
+
RuntimeConfig: params.runtimeConfig
|
|
132
|
+
};
|
|
133
|
+
return this.tcbService.request('UpdateUserKey', requestParams);
|
|
134
|
+
}
|
|
135
|
+
/** 删除集成实例 */
|
|
136
|
+
async deleteUserKey(params) {
|
|
137
|
+
this.validateRequiredParams(params, ['keyId']);
|
|
138
|
+
const { envId } = this.getEnvInfo();
|
|
139
|
+
return this.tcbService.request('DeleteUserKey', {
|
|
140
|
+
EnvId: envId,
|
|
141
|
+
KeyID: params.keyId
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
// =========== 编排 API ===========
|
|
145
|
+
/**
|
|
146
|
+
* 将集成实例绑定到云函数(口径 A)。
|
|
147
|
+
*
|
|
148
|
+
* 绑定载体为 `DemoCodeFunctionName`:调 `UpdateUserKey` 设置该字段,
|
|
149
|
+
* 后端负责把集成配置注入函数运行时;CLI 不读写函数环境变量。
|
|
150
|
+
*
|
|
151
|
+
* - 集成与云函数一对一:已绑定到不同函数且未传 `force` 时报错;
|
|
152
|
+
* - 幂等:已绑定到同一函数时直接返回,不发送请求;
|
|
153
|
+
* - 不携带 `Ext`,保留集成原有配置。
|
|
154
|
+
*/
|
|
155
|
+
async bindFunction(params) {
|
|
156
|
+
this.validateRequiredParams(params, ['keyId', 'functionName']);
|
|
157
|
+
const { keyId, functionName, force } = params;
|
|
158
|
+
const { UserKeyInfo } = await this.getUserKey({ keyId, business: 'integration' });
|
|
159
|
+
if (!UserKeyInfo) {
|
|
160
|
+
throw new error_1.CloudBaseError(`集成实例不存在: ${keyId}`);
|
|
161
|
+
}
|
|
162
|
+
const previousFunctionName = UserKeyInfo.DemoCodeFunctionName;
|
|
163
|
+
// 已绑定到同一函数:幂等返回
|
|
164
|
+
if (previousFunctionName === functionName) {
|
|
165
|
+
return {
|
|
166
|
+
keyId,
|
|
167
|
+
functionName,
|
|
168
|
+
previousFunctionName,
|
|
169
|
+
overwritten: false,
|
|
170
|
+
alreadyBound: true
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// 已绑定到不同函数:需 force 覆盖
|
|
174
|
+
const overwritten = Boolean(previousFunctionName);
|
|
175
|
+
if (overwritten && !force) {
|
|
176
|
+
throw new error_1.CloudBaseError(`集成实例 ${keyId} 已绑定云函数 ${previousFunctionName},如需改绑请使用 force 覆盖`);
|
|
177
|
+
}
|
|
178
|
+
// 与控制台对齐:传递完整参数,business: 'integration' 标记来源
|
|
179
|
+
const result = await this.updateUserKey({
|
|
180
|
+
keyId,
|
|
181
|
+
name: UserKeyInfo.Name,
|
|
182
|
+
authTypeCode: UserKeyInfo.AuthTypeCode,
|
|
183
|
+
description: UserKeyInfo.Description,
|
|
184
|
+
ext: UserKeyInfo.Ext,
|
|
185
|
+
demoCodeFunctionName: functionName,
|
|
186
|
+
business: 'integration'
|
|
187
|
+
});
|
|
188
|
+
return {
|
|
189
|
+
keyId,
|
|
190
|
+
functionName,
|
|
191
|
+
previousFunctionName,
|
|
192
|
+
overwritten,
|
|
193
|
+
alreadyBound: false
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 解密集成实例 Ext 中的 password 字段,返回扁平明文对象。
|
|
198
|
+
* 供 bind-resource / 详情展示使用;解密失败的字段保留原值。
|
|
199
|
+
*/
|
|
200
|
+
async decryptUserKeyExt(userKeyInfo) {
|
|
201
|
+
const extObj = this.safeParseExt(userKeyInfo.Ext);
|
|
202
|
+
const passwordFieldNames = await this.resolvePasswordFieldNames(userKeyInfo.AuthTypeCode);
|
|
203
|
+
if (!passwordFieldNames.length) {
|
|
204
|
+
return extObj;
|
|
205
|
+
}
|
|
206
|
+
const { envId } = this.getEnvInfo();
|
|
207
|
+
const aesKey = await (0, secretKey_1.getAesKey)({ envId });
|
|
208
|
+
return (0, fields_1.decryptPasswordFields)(extObj, passwordFieldNames, aesKey);
|
|
209
|
+
}
|
|
210
|
+
// =========== 辅助方法 ===========
|
|
211
|
+
/**
|
|
212
|
+
* 构建最终写入的 Ext(JSON 字符串)。
|
|
213
|
+
*
|
|
214
|
+
* - 显式传入 `ext` 时优先使用(不做额外处理);
|
|
215
|
+
* - 传入 `envVariables` 时:
|
|
216
|
+
* - 提供 `existingExt`(update 场景)时与现有 Ext **合并**,仅加密本次传入(变更)
|
|
217
|
+
* 的 password 字段,未传入的 password 字段保留现有密文、非 password 字段保留原值;
|
|
218
|
+
* - **编辑模式下空值删除字段**(与控制台对齐:空值表示不更新);
|
|
219
|
+
* - 未提供 `existingExt`(create 场景)时按模板识别 password 字段并加密有值字段;
|
|
220
|
+
* - 两者均未传时返回 undefined(保持原有 Ext 不变)。
|
|
221
|
+
*/
|
|
222
|
+
async buildExt(params) {
|
|
223
|
+
if (params.ext !== undefined) {
|
|
224
|
+
return params.ext;
|
|
225
|
+
}
|
|
226
|
+
if (!params.envVariables) {
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
const passwordFieldNames = await this.resolvePasswordFieldNames(params.authTypeCode);
|
|
230
|
+
let changedObj = Object.assign({}, params.envVariables);
|
|
231
|
+
// 编辑模式(existingExt 存在):删除空值字段(表示不更新,与控制台对齐)
|
|
232
|
+
if (params.existingExt) {
|
|
233
|
+
for (const [name, value] of Object.entries(changedObj)) {
|
|
234
|
+
if (value === '' || value === null || value === undefined) {
|
|
235
|
+
delete changedObj[name];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// 仅加密本次传入(变更)的 password 字段,避免对现有密文二次加密
|
|
240
|
+
const changedPasswordNames = passwordFieldNames.filter(name => name in changedObj);
|
|
241
|
+
if (changedPasswordNames.length) {
|
|
242
|
+
const { envId } = this.getEnvInfo();
|
|
243
|
+
// 注:manager-node 暂以国内七彩石为默认;国际站由上层透传后扩展
|
|
244
|
+
const aesKey = await (0, secretKey_1.getAesKey)({ envId });
|
|
245
|
+
changedObj = (0, fields_1.encryptPasswordFields)(changedObj, changedPasswordNames, aesKey);
|
|
246
|
+
}
|
|
247
|
+
// 合并现有 Ext(update):现有字段打底,变更字段覆盖
|
|
248
|
+
const existingObj = params.existingExt ? this.safeParseExt(params.existingExt) : {};
|
|
249
|
+
const merged = Object.assign(Object.assign({}, existingObj), changedObj);
|
|
250
|
+
return JSON.stringify(merged);
|
|
251
|
+
}
|
|
252
|
+
/** 按 authTypeCode 拉取模板并解析 password 字段名集合 */
|
|
253
|
+
async resolvePasswordFieldNames(authTypeCode) {
|
|
254
|
+
var _a, _b;
|
|
255
|
+
if (!authTypeCode)
|
|
256
|
+
return [];
|
|
257
|
+
const res = await this.listTemplates({ authTypeCode, limit: 1 });
|
|
258
|
+
const templateExt = (_b = (_a = res.KeyTemplateList) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.Ext;
|
|
259
|
+
return (0, fields_1.parsePasswordFieldNames)(templateExt);
|
|
260
|
+
}
|
|
261
|
+
/** 安全解析实例 Ext(扁平对象),失败返回空对象 */
|
|
262
|
+
safeParseExt(ext) {
|
|
263
|
+
if (!ext)
|
|
264
|
+
return {};
|
|
265
|
+
try {
|
|
266
|
+
const parsed = JSON.parse(ext);
|
|
267
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
268
|
+
}
|
|
269
|
+
catch (_a) {
|
|
270
|
+
return {};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/** 获取环境信息 */
|
|
274
|
+
getEnvInfo() {
|
|
275
|
+
const envConfig = this.environment.lazyEnvironmentConfig;
|
|
276
|
+
return {
|
|
277
|
+
envId: envConfig.EnvId
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/** 校验必填参数 */
|
|
281
|
+
validateRequiredParams(params, fields) {
|
|
282
|
+
for (const field of fields) {
|
|
283
|
+
if (!params[field]) {
|
|
284
|
+
throw new error_1.CloudBaseError(`${field} 是必填参数`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
exports.IntegrationService = IntegrationService;
|
|
290
|
+
__decorate([
|
|
291
|
+
(0, utils_1.preLazy)()
|
|
292
|
+
], IntegrationService.prototype, "listTemplates", null);
|
|
293
|
+
__decorate([
|
|
294
|
+
(0, utils_1.preLazy)()
|
|
295
|
+
], IntegrationService.prototype, "listUserKeys", null);
|
|
296
|
+
__decorate([
|
|
297
|
+
(0, utils_1.preLazy)()
|
|
298
|
+
], IntegrationService.prototype, "getUserKey", null);
|
|
299
|
+
__decorate([
|
|
300
|
+
(0, utils_1.preLazy)()
|
|
301
|
+
], IntegrationService.prototype, "createUserKey", null);
|
|
302
|
+
__decorate([
|
|
303
|
+
(0, utils_1.preLazy)()
|
|
304
|
+
], IntegrationService.prototype, "updateUserKey", null);
|
|
305
|
+
__decorate([
|
|
306
|
+
(0, utils_1.preLazy)()
|
|
307
|
+
], IntegrationService.prototype, "deleteUserKey", null);
|
|
308
|
+
__decorate([
|
|
309
|
+
(0, utils_1.preLazy)()
|
|
310
|
+
], IntegrationService.prototype, "bindFunction", null);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAesKey = getAesKey;
|
|
4
|
+
exports.__clearAesKeyCache = __clearAesKeyCache;
|
|
5
|
+
/**
|
|
6
|
+
* 集成中心 AES key 获取(七彩石)
|
|
7
|
+
*
|
|
8
|
+
* 与 dev-platform 一致:通过 QueryRainbowConfig 拉取 group=tcb-config(国内)/
|
|
9
|
+
* frontend.tcb-config(国际)下字段 dev-platform-apis 的值作为 AES-256-CBC 密钥。
|
|
10
|
+
*
|
|
11
|
+
* 安全约束:
|
|
12
|
+
* - key 仅在进程内存使用,按 group 维度缓存;
|
|
13
|
+
* - 绝不写入任何本地文件、绝不打印日志。
|
|
14
|
+
*/
|
|
15
|
+
const http_request_1 = require("../utils/http-request");
|
|
16
|
+
const error_1 = require("../error");
|
|
17
|
+
/** 七彩石配置(与 dev-platform constants 对齐) */
|
|
18
|
+
const RAINBOW_CONFIG = {
|
|
19
|
+
ENV_TYPE: 'Default',
|
|
20
|
+
GROUP_CN: 'tcb-config',
|
|
21
|
+
GROUP_INTL: 'frontend.tcb-config',
|
|
22
|
+
/** AES key 在 kvs 中的字段名 */
|
|
23
|
+
CRYPTO_KEY_FIELD: 'dev-platform-apis'
|
|
24
|
+
};
|
|
25
|
+
const RAINBOW_HOST_CN = 'wedaapi.tcbautomation.cn';
|
|
26
|
+
const RAINBOW_HOST_INTL = 'gray.decisiontcb.tencentcloud.com';
|
|
27
|
+
/** 无 EnvId 时的占位 Uin(与 dev-platform 行为一致) */
|
|
28
|
+
const FALLBACK_UIN = '3309033';
|
|
29
|
+
/** 进程内缓存(按 group 维度),key 不落盘、不打印 */
|
|
30
|
+
const keyCache = {};
|
|
31
|
+
/**
|
|
32
|
+
* 获取集成中心 AES key(进程内缓存)
|
|
33
|
+
* @throws CloudBaseError 拉取或解析失败
|
|
34
|
+
*/
|
|
35
|
+
async function getAesKey(params = {}) {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
const { envId, isIntl = false, proxy } = params;
|
|
38
|
+
const group = isIntl ? RAINBOW_CONFIG.GROUP_INTL : RAINBOW_CONFIG.GROUP_CN;
|
|
39
|
+
if (keyCache[group]) {
|
|
40
|
+
return keyCache[group];
|
|
41
|
+
}
|
|
42
|
+
const host = isIntl ? RAINBOW_HOST_INTL : RAINBOW_HOST_CN;
|
|
43
|
+
const url = `https://${host}/Graydecision/V1/QueryRainbowConfig?group=${group}`;
|
|
44
|
+
const payload = {
|
|
45
|
+
EnvType: RAINBOW_CONFIG.ENV_TYPE,
|
|
46
|
+
Group: group
|
|
47
|
+
};
|
|
48
|
+
if (envId) {
|
|
49
|
+
payload.EnvId = envId;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
payload.Uin = FALLBACK_UIN;
|
|
53
|
+
}
|
|
54
|
+
let resJson;
|
|
55
|
+
try {
|
|
56
|
+
resJson = await (0, http_request_1.fetch)(url, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: { 'content-type': 'application/json' },
|
|
59
|
+
body: JSON.stringify(payload)
|
|
60
|
+
}, proxy);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
throw new error_1.CloudBaseError('获取集成加解密密钥失败:七彩石配置拉取请求异常,请检查网络连接或代理设置', {
|
|
64
|
+
original: e
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const data = (_a = resJson === null || resJson === void 0 ? void 0 : resJson.Response) === null || _a === void 0 ? void 0 : _a.Data;
|
|
68
|
+
if (!data || data.ErrorCode !== '0') {
|
|
69
|
+
throw new error_1.CloudBaseError(`获取集成加解密密钥失败:七彩石返回异常(ErrorCode=${data === null || data === void 0 ? void 0 : data.ErrorCode})。请确认当前环境已开通集成中心能力`);
|
|
70
|
+
}
|
|
71
|
+
let config;
|
|
72
|
+
try {
|
|
73
|
+
config = JSON.parse(data.ConfigValue)[0];
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
throw new error_1.CloudBaseError('获取集成加解密密钥失败:七彩石配置内容解析失败', {
|
|
77
|
+
original: e
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const kvs = ((_b = config === null || config === void 0 ? void 0 : config.kvs) === null || _b === void 0 ? void 0 : _b.kvs) || [];
|
|
81
|
+
const target = kvs.find(kv => kv.key === RAINBOW_CONFIG.CRYPTO_KEY_FIELD);
|
|
82
|
+
const key = target === null || target === void 0 ? void 0 : target.value;
|
|
83
|
+
if (!key) {
|
|
84
|
+
throw new error_1.CloudBaseError(`获取集成加解密密钥失败:七彩石配置中缺少 ${RAINBOW_CONFIG.CRYPTO_KEY_FIELD} 字段`);
|
|
85
|
+
}
|
|
86
|
+
keyCache[group] = key;
|
|
87
|
+
return key;
|
|
88
|
+
}
|
|
89
|
+
/** 清空进程内缓存(仅供测试使用) */
|
|
90
|
+
function __clearAesKeyCache() {
|
|
91
|
+
Object.keys(keyCache).forEach(k => delete keyCache[k]);
|
|
92
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 集成中心(UserKey)类型定义
|
|
4
|
+
*
|
|
5
|
+
* 字段与 dev-platform(weda-alternative/apps/dev-platform)对齐:
|
|
6
|
+
* - 云 API 出入参为 PascalCase(EnvId / KeyID / AuthTypeCode / Ext / NeedPwd 等)
|
|
7
|
+
* - Ext 为 JSON 字符串,承载动态配置字段(含加密后的敏感值)
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.UserKeyBindServiceType = void 0;
|
|
11
|
+
/** 密钥对绑定的服务类型 */
|
|
12
|
+
var UserKeyBindServiceType;
|
|
13
|
+
(function (UserKeyBindServiceType) {
|
|
14
|
+
UserKeyBindServiceType["MCP"] = "Mcp";
|
|
15
|
+
UserKeyBindServiceType["APIS"] = "Apis";
|
|
16
|
+
UserKeyBindServiceType["OTHER"] = "Other";
|
|
17
|
+
UserKeyBindServiceType["CLOUD_FUNCTION"] = "CloudFunction";
|
|
18
|
+
})(UserKeyBindServiceType || (exports.UserKeyBindServiceType = UserKeyBindServiceType = {}));
|
package/lib/interfaces/index.js
CHANGED
|
@@ -22,3 +22,4 @@ __exportStar(require("./storage.interface"), exports);
|
|
|
22
22
|
__exportStar(require("./cam.interface"), exports);
|
|
23
23
|
__exportStar(require("./billing.interface"), exports);
|
|
24
24
|
__exportStar(require("./cloudApp.interface"), exports);
|
|
25
|
+
__exportStar(require("./integration.interface"), exports);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* 集成中心(UserKey)服务接口导出
|
|
19
|
+
*/
|
|
20
|
+
__exportStar(require("../integration/types"), exports);
|
package/package.json
CHANGED
package/types/environment.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { PermissionService } from './permission';
|
|
|
19
19
|
import { SandboxService } from './sandbox';
|
|
20
20
|
import { AiModelService } from './aiModel';
|
|
21
21
|
import { MonitorService } from './monitor';
|
|
22
|
+
import { IntegrationService } from './integration';
|
|
22
23
|
export declare class Environment {
|
|
23
24
|
inited: boolean;
|
|
24
25
|
cloudBaseContext: CloudBaseContext;
|
|
@@ -43,6 +44,7 @@ export declare class Environment {
|
|
|
43
44
|
private sandboxService;
|
|
44
45
|
private aiModelService;
|
|
45
46
|
private monitorService;
|
|
47
|
+
private integrationService;
|
|
46
48
|
constructor(context: CloudBaseContext, envId: string);
|
|
47
49
|
lazyInit(): Promise<any>;
|
|
48
50
|
getEnvId(): string;
|
|
@@ -65,6 +67,7 @@ export declare class Environment {
|
|
|
65
67
|
getSandboxService(): SandboxService;
|
|
66
68
|
getAiModelService(): AiModelService;
|
|
67
69
|
getMonitorService(): MonitorService;
|
|
70
|
+
getIntegrationService(): IntegrationService;
|
|
68
71
|
getCommonService(serviceType: string, serviceVersion: any): CommonService;
|
|
69
72
|
getServicesEnvInfo(): Promise<any>;
|
|
70
73
|
getAuthConfig(): {
|
package/types/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { PermissionService } from './permission';
|
|
|
19
19
|
import { SandboxService } from './sandbox';
|
|
20
20
|
import { CloudAppService } from './cloudApp';
|
|
21
21
|
import { AiModelService } from './aiModel';
|
|
22
|
+
import { IntegrationService } from './integration';
|
|
22
23
|
import { MonitorService } from './monitor';
|
|
23
24
|
interface CloudBaseConfig {
|
|
24
25
|
secretId?: string;
|
|
@@ -85,6 +86,15 @@ declare class CloudBase {
|
|
|
85
86
|
get permission(): PermissionService;
|
|
86
87
|
get sandbox(): SandboxService;
|
|
87
88
|
get aiModel(): AiModelService;
|
|
89
|
+
/**
|
|
90
|
+
* 集成中心服务(UserKey)
|
|
91
|
+
* 提供集成模板/实例的增删改查与绑定云函数能力
|
|
92
|
+
*/
|
|
93
|
+
get integration(): IntegrationService;
|
|
94
|
+
/**
|
|
95
|
+
* 监控服务
|
|
96
|
+
* 提供指标查询能力
|
|
97
|
+
*/
|
|
88
98
|
get monitor(): MonitorService;
|
|
89
99
|
get docs(): DocsService;
|
|
90
100
|
getEnvironmentManager(): EnvironmentManager;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 使用指定 IV 加密(供测试与内部使用,保证可重现)
|
|
3
|
+
*/
|
|
4
|
+
export declare function aesEncryptWithIv(plaintext: string, key: string, iv: Buffer): string;
|
|
5
|
+
declare class AESCryptoImpl {
|
|
6
|
+
/**
|
|
7
|
+
* AES-256-CBC 加密,返回 base64(IV)+base64(密文)
|
|
8
|
+
*/
|
|
9
|
+
encrypt(plaintext: string, key: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* 解密 base64(IV)+base64(密文) 格式的密文
|
|
12
|
+
*/
|
|
13
|
+
decrypt(encryptedData: string, key: string): string;
|
|
14
|
+
}
|
|
15
|
+
export declare const AESCrypto: AESCryptoImpl;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 从模板 Ext(JSON:`{ fields: [{ name, type }] }`)解析出 password 字段名集合。
|
|
3
|
+
* 解析失败或无 fields 时返回空数组。
|
|
4
|
+
*/
|
|
5
|
+
export declare function parsePasswordFieldNames(templateExt?: string): string[];
|
|
6
|
+
/**
|
|
7
|
+
* 加密 ext 对象中的 password 字段(仅加密有值的字段)。
|
|
8
|
+
* 返回新对象,不修改入参。
|
|
9
|
+
*/
|
|
10
|
+
export declare function encryptPasswordFields(extObj: Record<string, string>, passwordFieldNames: string[], aesKey: string): Record<string, string>;
|
|
11
|
+
/**
|
|
12
|
+
* 解密 ext 对象中的 password 字段。
|
|
13
|
+
* - 仅处理长度 > MIN_AES_CIPHERTEXT_LENGTH 的字符串(规避明显非密文的噪音)
|
|
14
|
+
* - 解密失败保留原值,不中断流程
|
|
15
|
+
* 返回新对象,不修改入参。
|
|
16
|
+
*/
|
|
17
|
+
export declare function decryptPasswordFields(extObj: Record<string, string>, passwordFieldNames: string[], aesKey: string): Record<string, string>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Environment } from '../environment';
|
|
2
|
+
import { IListTemplatesParams, IListUserKeysParams, IGetUserKeyParams, ICreateUserKeyParams, IUpdateUserKeyParams, IDeleteUserKeyParams, IGetUserKeyTemplateListResult, IGetUserKeyListResult, IGetOneUserKeyResult, ICreateUserKeyResult, IUpdateUserKeyResult, IDeleteUserKeyResult, IUserKeyInfo, IBindFunctionParams, IBindResult } from './types';
|
|
3
|
+
export * from './types';
|
|
4
|
+
/**
|
|
5
|
+
* 集成中心(UserKey)服务
|
|
6
|
+
*
|
|
7
|
+
* 复用现有 tcb 云 API(version 2018-06-08),统一携带 Business='integration'。
|
|
8
|
+
* 敏感字段加解密、bindFunction 编排在后续模块叠加。
|
|
9
|
+
*/
|
|
10
|
+
export declare class IntegrationService {
|
|
11
|
+
private tcbService;
|
|
12
|
+
private environment;
|
|
13
|
+
constructor(environment: Environment);
|
|
14
|
+
/** 列出集成模板(密钥对模版列表) */
|
|
15
|
+
listTemplates(params?: IListTemplatesParams): Promise<IGetUserKeyTemplateListResult>;
|
|
16
|
+
/** 列出集成实例(密钥对列表) */
|
|
17
|
+
listUserKeys(params?: IListUserKeysParams): Promise<IGetUserKeyListResult>;
|
|
18
|
+
/** 查询单个集成实例详情 */
|
|
19
|
+
getUserKey(params: IGetUserKeyParams): Promise<IGetOneUserKeyResult>;
|
|
20
|
+
/** 创建集成实例 */
|
|
21
|
+
createUserKey(params: ICreateUserKeyParams): Promise<ICreateUserKeyResult>;
|
|
22
|
+
/** 更新集成实例 */
|
|
23
|
+
updateUserKey(params: IUpdateUserKeyParams): Promise<IUpdateUserKeyResult>;
|
|
24
|
+
/** 删除集成实例 */
|
|
25
|
+
deleteUserKey(params: IDeleteUserKeyParams): Promise<IDeleteUserKeyResult>;
|
|
26
|
+
/**
|
|
27
|
+
* 将集成实例绑定到云函数(口径 A)。
|
|
28
|
+
*
|
|
29
|
+
* 绑定载体为 `DemoCodeFunctionName`:调 `UpdateUserKey` 设置该字段,
|
|
30
|
+
* 后端负责把集成配置注入函数运行时;CLI 不读写函数环境变量。
|
|
31
|
+
*
|
|
32
|
+
* - 集成与云函数一对一:已绑定到不同函数且未传 `force` 时报错;
|
|
33
|
+
* - 幂等:已绑定到同一函数时直接返回,不发送请求;
|
|
34
|
+
* - 不携带 `Ext`,保留集成原有配置。
|
|
35
|
+
*/
|
|
36
|
+
bindFunction(params: IBindFunctionParams): Promise<IBindResult>;
|
|
37
|
+
/**
|
|
38
|
+
* 解密集成实例 Ext 中的 password 字段,返回扁平明文对象。
|
|
39
|
+
* 供 bind-resource / 详情展示使用;解密失败的字段保留原值。
|
|
40
|
+
*/
|
|
41
|
+
decryptUserKeyExt(userKeyInfo: IUserKeyInfo): Promise<Record<string, string>>;
|
|
42
|
+
/**
|
|
43
|
+
* 构建最终写入的 Ext(JSON 字符串)。
|
|
44
|
+
*
|
|
45
|
+
* - 显式传入 `ext` 时优先使用(不做额外处理);
|
|
46
|
+
* - 传入 `envVariables` 时:
|
|
47
|
+
* - 提供 `existingExt`(update 场景)时与现有 Ext **合并**,仅加密本次传入(变更)
|
|
48
|
+
* 的 password 字段,未传入的 password 字段保留现有密文、非 password 字段保留原值;
|
|
49
|
+
* - **编辑模式下空值删除字段**(与控制台对齐:空值表示不更新);
|
|
50
|
+
* - 未提供 `existingExt`(create 场景)时按模板识别 password 字段并加密有值字段;
|
|
51
|
+
* - 两者均未传时返回 undefined(保持原有 Ext 不变)。
|
|
52
|
+
*/
|
|
53
|
+
private buildExt;
|
|
54
|
+
/** 按 authTypeCode 拉取模板并解析 password 字段名集合 */
|
|
55
|
+
private resolvePasswordFieldNames;
|
|
56
|
+
/** 安全解析实例 Ext(扁平对象),失败返回空对象 */
|
|
57
|
+
private safeParseExt;
|
|
58
|
+
/** 获取环境信息 */
|
|
59
|
+
private getEnvInfo;
|
|
60
|
+
/** 校验必填参数 */
|
|
61
|
+
private validateRequiredParams;
|
|
62
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface IGetAesKeyParams {
|
|
2
|
+
/** 环境 Id(用于灰度命中,无则用占位 Uin) */
|
|
3
|
+
envId?: string;
|
|
4
|
+
/** 是否国际站 */
|
|
5
|
+
isIntl?: boolean;
|
|
6
|
+
/** 代理 */
|
|
7
|
+
proxy?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 获取集成中心 AES key(进程内缓存)
|
|
11
|
+
* @throws CloudBaseError 拉取或解析失败
|
|
12
|
+
*/
|
|
13
|
+
export declare function getAesKey(params?: IGetAesKeyParams): Promise<string>;
|
|
14
|
+
/** 清空进程内缓存(仅供测试使用) */
|
|
15
|
+
export declare function __clearAesKeyCache(): void;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 集成中心(UserKey)类型定义
|
|
3
|
+
*
|
|
4
|
+
* 字段与 dev-platform(weda-alternative/apps/dev-platform)对齐:
|
|
5
|
+
* - 云 API 出入参为 PascalCase(EnvId / KeyID / AuthTypeCode / Ext / NeedPwd 等)
|
|
6
|
+
* - Ext 为 JSON 字符串,承载动态配置字段(含加密后的敏感值)
|
|
7
|
+
*/
|
|
8
|
+
/** Ext 中单个配置字段描述(模板与实例通用) */
|
|
9
|
+
export interface IUserKeyExtField {
|
|
10
|
+
/** 字段名 */
|
|
11
|
+
name: string;
|
|
12
|
+
/** 字段类型,type === 'password' 视为敏感字段 */
|
|
13
|
+
type: string;
|
|
14
|
+
/** 字段展示名 */
|
|
15
|
+
label?: string;
|
|
16
|
+
/** 字段值(实例中为用户填写值,敏感字段为密文) */
|
|
17
|
+
value?: string;
|
|
18
|
+
/** 是否必填 */
|
|
19
|
+
required?: boolean;
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}
|
|
22
|
+
/** Ext 反序列化后的结构 */
|
|
23
|
+
export interface IUserKeyExt {
|
|
24
|
+
/** 动态字段集合 */
|
|
25
|
+
fields?: IUserKeyExtField[];
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
}
|
|
28
|
+
/** 集成模板(密钥对模版) */
|
|
29
|
+
export interface IUserKeyTemplate {
|
|
30
|
+
/** 授权类型码(模板 Key) */
|
|
31
|
+
AuthTypeCode: string;
|
|
32
|
+
/** 授权类型名称(模板中文名) */
|
|
33
|
+
AuthTypeName: string;
|
|
34
|
+
/** 模板原始动态信息,JSON 字符串,含 fields 定义 */
|
|
35
|
+
Ext: string;
|
|
36
|
+
/** 授权 URL(OAuth 类模板) */
|
|
37
|
+
AuthURL?: string;
|
|
38
|
+
/** 模板图标 */
|
|
39
|
+
Icon?: string;
|
|
40
|
+
State?: string;
|
|
41
|
+
RedirectURI?: string;
|
|
42
|
+
}
|
|
43
|
+
/** 密钥对绑定的服务类型 */
|
|
44
|
+
export declare enum UserKeyBindServiceType {
|
|
45
|
+
MCP = "Mcp",
|
|
46
|
+
APIS = "Apis",
|
|
47
|
+
OTHER = "Other",
|
|
48
|
+
CLOUD_FUNCTION = "CloudFunction"
|
|
49
|
+
}
|
|
50
|
+
/** 密钥对绑定的服务信息 */
|
|
51
|
+
export interface IUserKeyBindService {
|
|
52
|
+
/** 引用的服务标识 */
|
|
53
|
+
ID: string;
|
|
54
|
+
/** 引用的服务名称 */
|
|
55
|
+
Name: string;
|
|
56
|
+
/** 引用的服务类型 */
|
|
57
|
+
_type?: UserKeyBindServiceType;
|
|
58
|
+
/** 绑定场景 */
|
|
59
|
+
Scene?: string;
|
|
60
|
+
}
|
|
61
|
+
/** 集成实例(一个 UserKey = 一个集成实例) */
|
|
62
|
+
export interface IUserKeyInfo {
|
|
63
|
+
/** 用户密钥对名称 */
|
|
64
|
+
Name: string;
|
|
65
|
+
/** 用户密钥对标识 */
|
|
66
|
+
KeyID: string;
|
|
67
|
+
/** 描述 */
|
|
68
|
+
Description?: string;
|
|
69
|
+
/** 授权类型码 */
|
|
70
|
+
AuthTypeCode: string;
|
|
71
|
+
/** 授权类型名称 */
|
|
72
|
+
AuthTypeName: string;
|
|
73
|
+
/** 额外信息,JSON 字符串(含加密敏感值) */
|
|
74
|
+
Ext: string;
|
|
75
|
+
/** 已绑定的服务列表 */
|
|
76
|
+
BindServiceList?: {
|
|
77
|
+
Mcp?: IUserKeyBindService[];
|
|
78
|
+
Apis?: IUserKeyBindService[];
|
|
79
|
+
Other?: IUserKeyBindService[];
|
|
80
|
+
[key: string]: IUserKeyBindService[] | undefined;
|
|
81
|
+
};
|
|
82
|
+
/** 状态 */
|
|
83
|
+
Status?: string;
|
|
84
|
+
/** OAuth 类授权 ticket id */
|
|
85
|
+
TicketID?: string;
|
|
86
|
+
/** 绑定的示例代码云函数名称(集成与云函数一对一关联的载体) */
|
|
87
|
+
DemoCodeFunctionName?: string;
|
|
88
|
+
/** 创建时间(ISO 8601 字符串,如 2026-07-01T10:00:00+08:00) */
|
|
89
|
+
CreateAt?: string;
|
|
90
|
+
/** 更新时间(ISO 8601 字符串,如 2026-07-01T10:00:00+08:00) */
|
|
91
|
+
UpdateAt?: string;
|
|
92
|
+
}
|
|
93
|
+
/** 列出模板入参 */
|
|
94
|
+
export interface IListTemplatesParams {
|
|
95
|
+
offset?: number;
|
|
96
|
+
limit?: number;
|
|
97
|
+
authTypeCode?: string;
|
|
98
|
+
authTypeName?: string;
|
|
99
|
+
}
|
|
100
|
+
/** 列出集成实例入参 */
|
|
101
|
+
export interface IListUserKeysParams {
|
|
102
|
+
name?: string;
|
|
103
|
+
authTypeCode?: string;
|
|
104
|
+
offset?: number;
|
|
105
|
+
limit?: number;
|
|
106
|
+
/** 业务类型,integration:从集成中心来的,默认为空,表示是从授权管理中心来的 */
|
|
107
|
+
business?: string;
|
|
108
|
+
}
|
|
109
|
+
/** 查询集成实例详情入参 */
|
|
110
|
+
export interface IGetUserKeyParams {
|
|
111
|
+
keyId: string;
|
|
112
|
+
/** 为 true 时返回加密字段的密文值 */
|
|
113
|
+
needPwd?: boolean;
|
|
114
|
+
/** 业务类型,integration:从集成中心来的,默认为空,表示是从授权管理中心来的 */
|
|
115
|
+
business?: string;
|
|
116
|
+
}
|
|
117
|
+
/** 创建集成实例入参 */
|
|
118
|
+
export interface ICreateUserKeyParams {
|
|
119
|
+
name: string;
|
|
120
|
+
authTypeCode: string;
|
|
121
|
+
description?: string;
|
|
122
|
+
/** 环境变量键值对(敏感字段传明文,内部加密后写入 Ext) */
|
|
123
|
+
envVariables?: Record<string, string>;
|
|
124
|
+
/** 直接传入 Ext JSON 字符串(与 envVariables 二选一,envVariables 优先) */
|
|
125
|
+
ext?: string;
|
|
126
|
+
keyId?: string;
|
|
127
|
+
ticketId?: string;
|
|
128
|
+
/** 业务类型,integration:从集成中心来的,默认为空,表示是从授权管理中心来的 */
|
|
129
|
+
business?: string;
|
|
130
|
+
/** 示例代码云函数名称 */
|
|
131
|
+
demoCodeFunctionName?: string;
|
|
132
|
+
/** Agent 云函数配置 */
|
|
133
|
+
runtimeConfig?: Record<string, any>;
|
|
134
|
+
}
|
|
135
|
+
/** 更新集成实例入参 */
|
|
136
|
+
export interface IUpdateUserKeyParams {
|
|
137
|
+
keyId: string;
|
|
138
|
+
name?: string;
|
|
139
|
+
authTypeCode?: string;
|
|
140
|
+
description?: string;
|
|
141
|
+
/** 待变更的环境变量键值对(仅传需要改动的字段,敏感字段传明文) */
|
|
142
|
+
envVariables?: Record<string, string>;
|
|
143
|
+
/** 直接传入 Ext JSON 字符串(与 envVariables 二选一,envVariables 优先) */
|
|
144
|
+
ext?: string;
|
|
145
|
+
/** 绑定的示例代码云函数名称(bind-resource 使用) */
|
|
146
|
+
demoCodeFunctionName?: string;
|
|
147
|
+
/** 业务类型,integration:从集成中心来的,默认为空,表示是从授权管理中心来的 */
|
|
148
|
+
business?: string;
|
|
149
|
+
/** Agent 云函数配置 */
|
|
150
|
+
runtimeConfig?: Record<string, any>;
|
|
151
|
+
}
|
|
152
|
+
/** 删除集成实例入参 */
|
|
153
|
+
export interface IDeleteUserKeyParams {
|
|
154
|
+
keyId: string;
|
|
155
|
+
}
|
|
156
|
+
/** 绑定集成到云函数入参 */
|
|
157
|
+
export interface IBindFunctionParams {
|
|
158
|
+
keyId: string;
|
|
159
|
+
functionName: string;
|
|
160
|
+
/** 已绑定到其它函数时是否强制覆盖 */
|
|
161
|
+
force?: boolean;
|
|
162
|
+
}
|
|
163
|
+
/** 绑定结果摘要 */
|
|
164
|
+
export interface IBindResult {
|
|
165
|
+
keyId: string;
|
|
166
|
+
functionName: string;
|
|
167
|
+
/** 先前绑定的云函数名(无则 undefined) */
|
|
168
|
+
previousFunctionName?: string;
|
|
169
|
+
/** 是否覆盖了已有的不同绑定 */
|
|
170
|
+
overwritten: boolean;
|
|
171
|
+
/** 已绑定到同一函数、无需变更时为 true(幂等) */
|
|
172
|
+
alreadyBound: boolean;
|
|
173
|
+
}
|
|
174
|
+
export interface IGetUserKeyTemplateListResult {
|
|
175
|
+
KeyTemplateList: IUserKeyTemplate[];
|
|
176
|
+
TotalCount: number;
|
|
177
|
+
RequestId?: string;
|
|
178
|
+
}
|
|
179
|
+
export interface IGetUserKeyListResult {
|
|
180
|
+
UserKeyList: IUserKeyInfo[];
|
|
181
|
+
TotalCount: number;
|
|
182
|
+
RequestId?: string;
|
|
183
|
+
}
|
|
184
|
+
export interface IGetOneUserKeyResult {
|
|
185
|
+
UserKeyInfo: IUserKeyInfo;
|
|
186
|
+
RequestId?: string;
|
|
187
|
+
}
|
|
188
|
+
export interface ICreateUserKeyResult {
|
|
189
|
+
CreateResult: number;
|
|
190
|
+
DemoCodeFunctionName?: string;
|
|
191
|
+
RequestId?: string;
|
|
192
|
+
}
|
|
193
|
+
export interface IUpdateUserKeyResult {
|
|
194
|
+
UpdateResult: number;
|
|
195
|
+
RequestId?: string;
|
|
196
|
+
}
|
|
197
|
+
export interface IDeleteUserKeyResult {
|
|
198
|
+
DeleteResult: number;
|
|
199
|
+
RequestId?: string;
|
|
200
|
+
}
|