@cloudbase/manager-node 4.11.0-alpha.2 → 4.11.0-alpha.4

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.
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,19 @@
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
+ __exportStar(require("./base"), exports);
18
+ __exportStar(require("./account"), exports);
19
+ __exportStar(require("./backup"), exports);
@@ -617,21 +617,17 @@ class StorageService {
617
617
  Error
618
618
  };
619
619
  }
620
- /**
621
- * 获取文件存储权限
622
- * READONLY:所有用户可读,仅创建者和管理员可写
623
- * PRIVATE:仅创建者及管理员可读写
624
- * ADMINWRITE:所有用户可读,仅管理员可写
625
- * ADMINONLY:仅管理员可读写
626
- * CUSTOM:自定义安全规则
627
- * @returns {Promise<{ acl: AclType, rule?: IStorageAclRule }>}
628
- */
629
- async getStorageAcl() {
620
+ async getStorageAcl(options) {
630
621
  const { bucket, env } = this.getStorageConfig();
631
622
  const res = await this.tcbService.request('DescribeStorageSafeRule', {
632
623
  EnvId: env,
633
624
  Bucket: bucket
634
625
  });
626
+ // 默认行为:返回简单的 AclType(向后兼容)
627
+ if (!(options === null || options === void 0 ? void 0 : options.withRule)) {
628
+ return res.AclTag;
629
+ }
630
+ // 带规则模式:返回对象
635
631
  const result = { acl: res.AclTag };
636
632
  if (res.AclTag === 'CUSTOM' && res.Rule) {
637
633
  try {
@@ -730,6 +726,56 @@ class StorageService {
730
726
  }
731
727
  return fileList;
732
728
  }
729
+ /**
730
+ * 列出指定目录下的文件和子目录(不递归,只列当前层)
731
+ * 使用 COS Delimiter 参数实现
732
+ * @param {string} dirPath 目录路径,空字符串表示根目录
733
+ * @returns {Promise<{ files: IListFileInfo[], directories: string[] }>}
734
+ */
735
+ async listCurrentDirectory(dirPath = '') {
736
+ const { bucket, region } = this.getStorageConfig();
737
+ const cos = this.getCos();
738
+ const getBucket = util_1.default.promisify(cos.getBucket).bind(cos);
739
+ // 确保目录路径以 / 结尾(除了根目录)
740
+ let prefix = dirPath;
741
+ if (prefix && !prefix.endsWith('/')) {
742
+ prefix = prefix + '/';
743
+ }
744
+ const files = [];
745
+ const directories = [];
746
+ let marker = '';
747
+ let isTruncated = true;
748
+ while (isTruncated) {
749
+ const res = await getBucket({
750
+ Bucket: bucket,
751
+ Region: region,
752
+ Prefix: prefix,
753
+ Delimiter: '/', // 关键:使用分隔符,不递归子目录
754
+ MaxKeys: 1000,
755
+ Marker: marker
756
+ });
757
+ // 文件列表(不包含子目录)
758
+ if (res.Contents) {
759
+ // 过滤掉目录本身(Key === prefix 的情况)
760
+ const fileItems = res.Contents.filter((item) => item.Key !== prefix);
761
+ files.push(...fileItems);
762
+ }
763
+ // 子目录列表(CommonPrefixes)
764
+ if (res.CommonPrefixes) {
765
+ const dirs = res.CommonPrefixes.map((item) => item.Prefix);
766
+ directories.push(...dirs);
767
+ }
768
+ isTruncated = res.IsTruncated === 'true' || res.IsTruncated === true;
769
+ if (isTruncated) {
770
+ // 防止无限循环:如果 IsTruncated 为 true 但 NextMarker 为空,则跳出循环
771
+ if (!res.NextMarker) {
772
+ break;
773
+ }
774
+ marker = res.NextMarker;
775
+ }
776
+ }
777
+ return { files, directories };
778
+ }
733
779
  /**
734
780
  * 遍历本地文件夹
735
781
  * 忽略不包含 dir 路径,即如果 ignore 匹配 dir,dir 也不会被忽略
@@ -862,6 +908,356 @@ class StorageService {
862
908
  });
863
909
  return res;
864
910
  }
911
+ // ===== 复制/移动/搜索方法 =====
912
+ /**
913
+ * 复制单个文件
914
+ * @param options.sourcePath 源文件路径(云端路径,如 images/a.jpg)
915
+ * @param options.destPath 目标文件路径(云端路径,如 backup/a.jpg)
916
+ * @param options.force 是否强制覆盖
917
+ * @param options.skipExisting 是否跳过已存在的文件
918
+ * @returns 复制结果
919
+ */
920
+ async copyFile(options) {
921
+ const { sourcePath, destPath, force = false, skipExisting = false } = options;
922
+ const { bucket, region } = this.getStorageConfig();
923
+ // 1. 检查源文件是否存在
924
+ let sourceFileInfo;
925
+ try {
926
+ sourceFileInfo = await this.getFileInfo(sourcePath);
927
+ }
928
+ catch (e) {
929
+ if (e.statusCode === 404 || e.code === 'NoSuchKey') {
930
+ throw new error_1.CloudBaseError(`源文件不存在: ${sourcePath}`, {
931
+ code: 'SOURCE_NOT_FOUND'
932
+ });
933
+ }
934
+ throw e;
935
+ }
936
+ // 2. 检查目标文件是否存在
937
+ let destExists = false;
938
+ let destFileInfo = null;
939
+ try {
940
+ destFileInfo = await this.getFileInfo(destPath);
941
+ destExists = true;
942
+ }
943
+ catch (e) {
944
+ if (e.statusCode !== 404 && e.code !== 'NoSuchKey') {
945
+ throw e;
946
+ }
947
+ }
948
+ if (destExists) {
949
+ if (skipExisting) {
950
+ return {
951
+ success: true,
952
+ sourcePath,
953
+ destPath,
954
+ status: 'skipped',
955
+ // COS SDK 返回的 Size 单位已经是 bytes
956
+ size: (destFileInfo === null || destFileInfo === void 0 ? void 0 : destFileInfo.Size) ? parseInt(destFileInfo.Size, 10) : undefined
957
+ };
958
+ }
959
+ if (!force) {
960
+ throw new error_1.CloudBaseError(`目标文件已存在: ${destPath}`, {
961
+ code: 'DEST_EXISTS'
962
+ });
963
+ }
964
+ }
965
+ // 3. 执行复制(使用 COS SDK putObjectCopy)
966
+ const cos = this.getCos();
967
+ const putObjectCopy = util_1.default.promisify(cos.putObjectCopy).bind(cos);
968
+ // CopySource 格式: {bucket}.cos.{region}.myqcloud.com/{key}
969
+ // 注意: key 需要 URL 编码
970
+ // cspell:ignore myqcloud
971
+ const copySource = `${bucket}.cos.${region}.myqcloud.com/${encodeURIComponent(sourcePath)}`;
972
+ const res = await putObjectCopy({
973
+ Bucket: bucket,
974
+ Region: region,
975
+ Key: destPath,
976
+ CopySource: copySource
977
+ });
978
+ if (res.statusCode !== 200) {
979
+ throw new error_1.CloudBaseError(`复制文件失败:${JSON.stringify(res)}`);
980
+ }
981
+ // 4. 返回复制结果
982
+ return {
983
+ success: true,
984
+ sourcePath,
985
+ destPath,
986
+ status: 'copied',
987
+ // COS SDK 返回的 Size 单位已经是 bytes
988
+ size: (sourceFileInfo === null || sourceFileInfo === void 0 ? void 0 : sourceFileInfo.Size) ? parseInt(sourceFileInfo.Size, 10) : undefined
989
+ };
990
+ }
991
+ /**
992
+ * 复制目录
993
+ * 遍历源目录下的所有文件,并行复制到目标目录
994
+ * @param options.sourcePath 源目录路径
995
+ * @param options.destPath 目标目录路径
996
+ * @param options.include 包含模式(glob 格式)
997
+ * @param options.exclude 排除模式(glob 格式)
998
+ * @param options.force 是否强制覆盖
999
+ * @param options.skipExisting 是否跳过已存在的文件
1000
+ * @param options.parallel 并发数,默认 20
1001
+ * @param options.onProgress 进度回调
1002
+ * @returns 复制结果数组
1003
+ */
1004
+ async copyDirectory(options) {
1005
+ const { sourcePath, destPath, include, exclude, force = false, skipExisting = false, parallel = 20, onProgress } = options;
1006
+ // 1. 列出源目录所有文件
1007
+ const sourceKey = this.getCloudKey(sourcePath);
1008
+ const files = await this.walkCloudDir(sourceKey);
1009
+ if (!files || !files.length) {
1010
+ // 进一步检查目录是否存在(通过 listCurrentDirectory)
1011
+ // 如果目录存在但为空,listCurrentDirectory 会返回空的 files 和 directories
1012
+ // 如果目录不存在,COS 仍然返回成功但结果为空
1013
+ // 这里通过检查源路径的父目录来判断
1014
+ const parentPath = sourcePath.includes('/')
1015
+ ? sourcePath.substring(0, sourcePath.lastIndexOf('/'))
1016
+ : '';
1017
+ const { directories } = await this.listCurrentDirectory(parentPath);
1018
+ const dirExists = directories.some(d => {
1019
+ const normalizedDir = d.endsWith('/') ? d.slice(0, -1) : d;
1020
+ return normalizedDir === sourceKey.slice(0, -1) || normalizedDir === sourcePath;
1021
+ });
1022
+ if (dirExists) {
1023
+ throw new error_1.CloudBaseError(`源目录为空: ${sourcePath}`, {
1024
+ code: 'SOURCE_EMPTY'
1025
+ });
1026
+ }
1027
+ else {
1028
+ throw new error_1.CloudBaseError(`源目录不存在: ${sourcePath}`, {
1029
+ code: 'SOURCE_NOT_FOUND'
1030
+ });
1031
+ }
1032
+ }
1033
+ // 2. 过滤文件(使用 micromatch)
1034
+ let filteredFiles = files.filter(f => !f.Key.endsWith('/')); // 排除目录
1035
+ if (include) {
1036
+ const patterns = Array.isArray(include) ? include : [include];
1037
+ filteredFiles = filteredFiles.filter(f => {
1038
+ const relativePath = f.Key.replace(sourceKey, '');
1039
+ return micromatch_1.default.isMatch(relativePath, patterns);
1040
+ });
1041
+ }
1042
+ if (exclude) {
1043
+ const patterns = Array.isArray(exclude) ? exclude : [exclude];
1044
+ filteredFiles = filteredFiles.filter(f => {
1045
+ const relativePath = f.Key.replace(sourceKey, '');
1046
+ return !micromatch_1.default.isMatch(relativePath, patterns);
1047
+ });
1048
+ }
1049
+ if (!filteredFiles.length) {
1050
+ return [];
1051
+ }
1052
+ // 3. 构建复制任务
1053
+ let copiedCount = 0;
1054
+ let skippedCount = 0;
1055
+ const destKey = destPath.endsWith('/') ? destPath : destPath + '/';
1056
+ const tasks = filteredFiles.map(file => async () => {
1057
+ const relativePath = file.Key.replace(sourceKey, '');
1058
+ const targetPath = destKey + relativePath;
1059
+ try {
1060
+ const result = await this.copyFile({
1061
+ sourcePath: file.Key,
1062
+ destPath: targetPath,
1063
+ force,
1064
+ skipExisting
1065
+ });
1066
+ if (result.status === 'copied')
1067
+ copiedCount++;
1068
+ if (result.status === 'skipped')
1069
+ skippedCount++;
1070
+ onProgress === null || onProgress === void 0 ? void 0 : onProgress({
1071
+ copied: copiedCount,
1072
+ skipped: skippedCount,
1073
+ total: filteredFiles.length,
1074
+ currentFile: file.Key
1075
+ });
1076
+ return result;
1077
+ }
1078
+ catch (e) {
1079
+ return {
1080
+ success: false,
1081
+ sourcePath: file.Key,
1082
+ destPath: targetPath,
1083
+ status: 'failed',
1084
+ error: e.message
1085
+ };
1086
+ }
1087
+ });
1088
+ // 4. 使用 AsyncTaskParallelController 并发执行
1089
+ const controller = new parallel_1.AsyncTaskParallelController(parallel, 50);
1090
+ controller.loadTasks(tasks);
1091
+ return controller.run();
1092
+ }
1093
+ /**
1094
+ * 移动文件(复制后删除源文件)
1095
+ * 注意:移动操作是「复制 + 删除」的两步操作,如果删除失败,文件会同时存在于源和目标位置
1096
+ * @param options 与 copyFile 相同的选项
1097
+ * @returns 移动结果,如果删除源文件失败会在 error 字段说明
1098
+ */
1099
+ async moveFile(options) {
1100
+ const result = await this.copyFile(options);
1101
+ if (result.status === 'copied') {
1102
+ // 复制成功后使用 COS SDK 直接删除源文件
1103
+ const { bucket, region } = this.getStorageConfig();
1104
+ const cos = this.getCos();
1105
+ const deleteObject = util_1.default.promisify(cos.deleteObject).bind(cos);
1106
+ // 注意:文件路径不需要用 getCloudKey(),getCloudKey() 会在末尾加 /,用于目录
1107
+ const sourceKey = options.sourcePath;
1108
+ try {
1109
+ await deleteObject({
1110
+ Bucket: bucket,
1111
+ Region: region,
1112
+ Key: sourceKey
1113
+ });
1114
+ }
1115
+ catch (e) {
1116
+ // 删除失败时,文件已复制成功,返回结果但附带错误信息
1117
+ return Object.assign(Object.assign({}, result), { error: `文件已复制但删除源文件失败: ${e.message}` });
1118
+ }
1119
+ }
1120
+ return result;
1121
+ }
1122
+ /**
1123
+ * 移动目录(复制后删除源目录)
1124
+ * 注意:移动操作是「复制 + 删除」的两步操作,如果部分删除失败,文件会同时存在于源和目标位置
1125
+ * @param options 与 copyDirectory 相同的选项
1126
+ * @returns 移动结果数组,删除失败的文件会在对应结果的 error 字段说明
1127
+ */
1128
+ async moveDirectory(options) {
1129
+ const results = await this.copyDirectory(options);
1130
+ // 只删除复制成功的文件
1131
+ const copiedFiles = results
1132
+ .filter(r => r.status === 'copied')
1133
+ .map(r => r.sourcePath);
1134
+ if (copiedFiles.length > 0) {
1135
+ // 使用 COS SDK deleteMultipleObject 批量删除源文件
1136
+ const { bucket, region } = this.getStorageConfig();
1137
+ const cos = this.getCos();
1138
+ const deleteMultipleObject = util_1.default.promisify(cos.deleteMultipleObject).bind(cos);
1139
+ // COS deleteMultipleObject 单次最多删除 1000 个对象,这里按 500 分片
1140
+ const files = [...copiedFiles];
1141
+ const total = Math.ceil(files.length / 500);
1142
+ const sliceGroup = [];
1143
+ for (let i = 0; i < total; i++) {
1144
+ sliceGroup.push(files.splice(0, 500));
1145
+ }
1146
+ // 收集删除失败的文件
1147
+ const deleteFailedFiles = new Map();
1148
+ const tasks = sliceGroup.map(async (group) => {
1149
+ try {
1150
+ const res = await deleteMultipleObject({
1151
+ Bucket: bucket,
1152
+ Region: region,
1153
+ Objects: group.map(file => ({ Key: file }))
1154
+ });
1155
+ // 检查部分删除失败的情况
1156
+ if (res.Error && res.Error.length > 0) {
1157
+ for (const err of res.Error) {
1158
+ deleteFailedFiles.set(err.Key, err.Message || 'Unknown error');
1159
+ }
1160
+ }
1161
+ }
1162
+ catch (e) {
1163
+ // 整批删除失败,记录所有文件
1164
+ for (const file of group) {
1165
+ deleteFailedFiles.set(file, e.message);
1166
+ }
1167
+ }
1168
+ });
1169
+ await Promise.all(tasks);
1170
+ // 将删除失败信息附加到对应的结果中
1171
+ if (deleteFailedFiles.size > 0) {
1172
+ for (const result of results) {
1173
+ if (result.status === 'copied' && deleteFailedFiles.has(result.sourcePath)) {
1174
+ result.error = `文件已复制但删除源文件失败: ${deleteFailedFiles.get(result.sourcePath)}`;
1175
+ }
1176
+ }
1177
+ }
1178
+ }
1179
+ return results;
1180
+ }
1181
+ /**
1182
+ * 搜索文件和目录(只搜索当前目录,不递归)
1183
+ * @param options.pattern 搜索模式(支持 glob 或正则表达式)
1184
+ * @param options.path 搜索目录路径(不指定则搜索根目录)
1185
+ * @param options.isRegex 是否为正则表达式模式
1186
+ * @param options.fileType 文件类型过滤
1187
+ * @param options.limit 限制返回数量,默认 100
1188
+ * @param options.includeDetails 是否包含详细信息(大小、修改时间)
1189
+ * @returns 搜索结果数组(包含文件和目录)
1190
+ */
1191
+ async searchFiles(options) {
1192
+ const { pattern, path: searchPath = '', isRegex = false, fileType, limit = 100, includeDetails = true } = options;
1193
+ // 构建匹配器
1194
+ let matcher;
1195
+ if (isRegex) {
1196
+ // 正则表达式模式
1197
+ // 安全检查:限制正则表达式长度和复杂度,防止 ReDoS 攻击
1198
+ const MAX_REGEX_LENGTH = 200;
1199
+ if (pattern.length > MAX_REGEX_LENGTH) {
1200
+ throw new error_1.CloudBaseError(`正则表达式过长,最大允许 ${MAX_REGEX_LENGTH} 字符`, {
1201
+ code: 'PATTERN_TOO_LONG'
1202
+ });
1203
+ }
1204
+ // 检测潜在的危险模式(嵌套量词)
1205
+ const dangerousPatterns = /(\+|\*|\{[0-9,]+\})\s*(\+|\*|\?|\{[0-9,]+\})/;
1206
+ if (dangerousPatterns.test(pattern)) {
1207
+ throw new error_1.CloudBaseError('正则表达式包含潜在的危险模式(嵌套量词),可能导致性能问题', {
1208
+ code: 'PATTERN_DANGEROUS'
1209
+ });
1210
+ }
1211
+ try {
1212
+ const regex = new RegExp(pattern);
1213
+ matcher = (name) => regex.test(name);
1214
+ }
1215
+ catch (e) {
1216
+ throw new error_1.CloudBaseError(`正则表达式语法错误: ${e.message}`, {
1217
+ code: 'PATTERN_SYNTAX_ERROR'
1218
+ });
1219
+ }
1220
+ }
1221
+ else {
1222
+ // Glob 模式 - 使用 micromatch
1223
+ matcher = (name) => micromatch_1.default.isMatch(name, pattern);
1224
+ }
1225
+ const results = [];
1226
+ // 只列出当前目录(使用 Delimiter,不递归)
1227
+ const { files, directories } = await this.listCurrentDirectory(searchPath);
1228
+ // 处理目录
1229
+ for (const dir of directories) {
1230
+ // 获取目录名(去掉末尾的 / 和前缀)
1231
+ const dirPath = dir.endsWith('/') ? dir.slice(0, -1) : dir;
1232
+ const dirName = dirPath.split('/').pop() || dirPath;
1233
+ if (matcher(dirName)) {
1234
+ results.push({
1235
+ key: dir,
1236
+ type: 'directory'
1237
+ });
1238
+ }
1239
+ }
1240
+ // 处理文件
1241
+ let matchedFiles = files.filter(f => {
1242
+ const basename = f.Key.split('/').pop() || f.Key;
1243
+ return matcher(basename);
1244
+ });
1245
+ // 文件类型过滤
1246
+ if (fileType) {
1247
+ const ext = fileType.startsWith('.') ? fileType : `.${fileType}`;
1248
+ matchedFiles = matchedFiles.filter(f => f.Key.toLowerCase().endsWith(ext.toLowerCase()));
1249
+ }
1250
+ for (const f of matchedFiles) {
1251
+ results.push({
1252
+ key: f.Key,
1253
+ type: 'file',
1254
+ size: includeDetails ? parseInt(f.Size, 10) : undefined,
1255
+ lastModified: includeDetails ? new Date(f.LastModified).toISOString() : undefined
1256
+ });
1257
+ }
1258
+ // 限制总数量
1259
+ return results.slice(0, limit);
1260
+ }
865
1261
  /**
866
1262
  * 获取 COS 配置
867
1263
  */
@@ -1074,9 +1470,27 @@ __decorate([
1074
1470
  __decorate([
1075
1471
  (0, utils_1.preLazy)()
1076
1472
  ], StorageService.prototype, "walkCloudDirCustom", null);
1473
+ __decorate([
1474
+ (0, utils_1.preLazy)()
1475
+ ], StorageService.prototype, "listCurrentDirectory", null);
1077
1476
  __decorate([
1078
1477
  (0, utils_1.preLazy)()
1079
1478
  ], StorageService.prototype, "putBucketWebsite", null);
1080
1479
  __decorate([
1081
1480
  (0, utils_1.preLazy)()
1082
1481
  ], StorageService.prototype, "getBucket", null);
1482
+ __decorate([
1483
+ (0, utils_1.preLazy)()
1484
+ ], StorageService.prototype, "copyFile", null);
1485
+ __decorate([
1486
+ (0, utils_1.preLazy)()
1487
+ ], StorageService.prototype, "copyDirectory", null);
1488
+ __decorate([
1489
+ (0, utils_1.preLazy)()
1490
+ ], StorageService.prototype, "moveFile", null);
1491
+ __decorate([
1492
+ (0, utils_1.preLazy)()
1493
+ ], StorageService.prototype, "moveDirectory", null);
1494
+ __decorate([
1495
+ (0, utils_1.preLazy)()
1496
+ ], StorageService.prototype, "searchFiles", null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/manager-node",
3
- "version": "4.11.0-alpha.2",
3
+ "version": "4.11.0-alpha.4",
4
4
  "description": "The node manage service api for cloudbase.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -15,6 +15,38 @@ interface IMgoQueryInfo {
15
15
  MgoLimit?: number;
16
16
  MgoOffset?: number;
17
17
  }
18
+ /** 待执行命令参数 */
19
+ interface IMgoCommandParam {
20
+ /** 表名 */
21
+ TableName: string;
22
+ /** 操作类型:UPDATE / QUERY / INSERT / DELETE / COMMAND */
23
+ CommandType: string;
24
+ /** 待执行命令(JSON 字符串) */
25
+ Command: string;
26
+ }
27
+ /** MongoDB 连接器配置 */
28
+ interface IMongoConnector {
29
+ /** 连接器实例 ID */
30
+ InstanceId?: string;
31
+ /** MongoDB 数据库名 */
32
+ DatabaseName?: string;
33
+ }
34
+ /** RunCommands 请求参数 */
35
+ interface IRunCommandsOptions {
36
+ /** 待执行命令列表 */
37
+ MgoCommands: IMgoCommandParam[];
38
+ /** 实例 ID,如 tnt-xxxx。不传则自动使用当前环境的数据库实例 ID */
39
+ Tag?: string;
40
+ /** 环境 ID。不传则自动使用当前环境 ID */
41
+ EnvId?: string;
42
+ /** Mongo 连接器实例信息 */
43
+ MongoConnector?: IMongoConnector;
44
+ }
45
+ /** RunCommands 返回结果 */
46
+ interface IRunCommandsResult extends IResponseInfo {
47
+ /** 返回结果,每个元素是一个 JSON 字符串 */
48
+ Data: string[];
49
+ }
18
50
  interface ICollectionInfo extends IResponseInfo {
19
51
  Collections: Array<TableInfo>;
20
52
  Pager: Pager;
@@ -38,6 +70,52 @@ interface IDatabaseMigrateQueryInfo extends IResponseInfo {
38
70
  interface IDatabaseImportAndExportInfo extends IResponseInfo {
39
71
  JobId: number;
40
72
  }
73
+ /** 回档表格名称映射信息 */
74
+ interface IModifyTableNamesInfo {
75
+ /** 原表名 */
76
+ OldTableName: string;
77
+ /** 新表名 */
78
+ NewTableName: string;
79
+ }
80
+ /** 回档任务信息 */
81
+ interface IRestoreTask {
82
+ /** 恢复任务ID */
83
+ TaskId?: string;
84
+ /** 任务状态 */
85
+ Status?: string;
86
+ /** 任务创建时间 */
87
+ Time?: string;
88
+ /** 环境ID */
89
+ EnvId?: string;
90
+ /** 恢复类型 */
91
+ Type?: string;
92
+ }
93
+ /** 任意时间回档范围 */
94
+ interface IRestoreTableTimeRange {
95
+ [key: string]: any;
96
+ }
97
+ /** 获取可回档表格返回结果 */
98
+ interface IDescribeRestoreTablesResult extends IResponseInfo {
99
+ /** 可回档表格列表 */
100
+ Tables: string[];
101
+ }
102
+ /** 获取回档任务返回结果 */
103
+ interface IDescribeRestoreTaskResult extends IResponseInfo {
104
+ /** 回档任务列表 */
105
+ Tasks: IRestoreTask[];
106
+ }
107
+ /** 获取可回档时间返回结果 */
108
+ interface IDescribeRestoreTimeResult extends IResponseInfo {
109
+ /** 可回档时间列表 */
110
+ RestoreTimes: string[];
111
+ /** 任意时间回档列表 */
112
+ RestoreTimeRanges: IRestoreTableTimeRange[];
113
+ }
114
+ /** 实例表格回档返回结果 */
115
+ interface IRestoreTCBTablesResult extends IResponseInfo {
116
+ /** 流程ID */
117
+ FlowId: number;
118
+ }
41
119
  export declare class DatabaseService {
42
120
  static tcbServiceVersion: IServiceVersion;
43
121
  static flexdbServiceVersion: IServiceVersion;
@@ -62,5 +140,39 @@ export declare class DatabaseService {
62
140
  migrateStatus(jobId: number): Promise<IDatabaseMigrateQueryInfo>;
63
141
  import(collectionName: string, file: any, options: any): Promise<IDatabaseImportAndExportInfo>;
64
142
  export(collectionName: string, file: any, options: any): Promise<IDatabaseImportAndExportInfo>;
143
+ /**
144
+ * 获取可回档表格
145
+ * @param time 回档时间,格式 YYYY-MM-DD HH:MM:SS
146
+ * @param filters 过滤器(可选)
147
+ * @param instanceId 实例ID(可选,不传则自动使用当前环境的数据库实例 ID)
148
+ * @returns 可回档表格列表
149
+ */
150
+ describeRestoreTables(time: string, filters?: string[], instanceId?: string): Promise<IDescribeRestoreTablesResult>;
151
+ /**
152
+ * 获取回档任务
153
+ * @param instanceId 实例ID(可选,不传则自动使用当前环境的数据库实例 ID)
154
+ * @returns 回档任务列表
155
+ */
156
+ describeRestoreTask(instanceId?: string): Promise<IDescribeRestoreTaskResult>;
157
+ /**
158
+ * 获取可回档时间
159
+ * @param instanceId 实例ID(可选,不传则自动使用当前环境的数据库实例 ID)
160
+ * @returns 可回档时间列表及任意时间回档列表
161
+ */
162
+ describeRestoreTime(instanceId?: string): Promise<IDescribeRestoreTimeResult>;
163
+ /**
164
+ * 实例表格回档
165
+ * @param time 回档时间,格式 YYYY-MM-DD HH:MM:SS
166
+ * @param modifyTableNamesInfo 回档表格信息(原表名 → 新表名映射)
167
+ * @param instanceId 实例ID(可选,不传则自动使用当前环境的数据库实例 ID)
168
+ * @returns 流程ID
169
+ */
170
+ restoreTables(time: string, modifyTableNamesInfo: IModifyTableNamesInfo[], instanceId?: string): Promise<IRestoreTCBTablesResult>;
171
+ /**
172
+ * 执行文档型数据库命令
173
+ * @param options 命令参数(命令列表、可选的 Tag/EnvId/MongoConnector)
174
+ * @returns 执行结果,Data 为 JSON 字符串数组
175
+ */
176
+ runCommands(options: IRunCommandsOptions): Promise<IRunCommandsResult>;
65
177
  }
66
178
  export {};
@@ -11,6 +11,7 @@ import { ThirdService } from './third';
11
11
  import { AccessService } from './access';
12
12
  import { UserService } from './user';
13
13
  import { CloudBaseRunService } from './cloudBaseRun';
14
+ import { MysqlService } from './mysql';
14
15
  import { EnvInfo } from './interfaces';
15
16
  export declare class Environment {
16
17
  inited: boolean;
@@ -29,6 +30,7 @@ export declare class Environment {
29
30
  private accessService;
30
31
  private userService;
31
32
  private cloudBaseRunService;
33
+ private mysqlService;
32
34
  constructor(context: CloudBaseContext, envId: string);
33
35
  lazyInit(): Promise<any>;
34
36
  getEnvId(): string;
@@ -44,6 +46,7 @@ export declare class Environment {
44
46
  getAccessService(): AccessService;
45
47
  getUserService(): UserService;
46
48
  getCloudBaseRunService(): CloudBaseRunService;
49
+ getMysqlService(): MysqlService;
47
50
  getCommonService(serviceType: string, serviceVersion: any): CommonService;
48
51
  getServicesEnvInfo(): Promise<any>;
49
52
  getAuthConfig(): {
package/types/index.d.ts CHANGED
@@ -12,6 +12,7 @@ import { ThirdService } from './third';
12
12
  import { AccessService } from './access';
13
13
  import { UserService } from './user';
14
14
  import { CloudBaseRunService } from './cloudBaseRun';
15
+ import { MysqlService } from './mysql';
15
16
  import { DocsService } from './docs';
16
17
  interface CloudBaseConfig {
17
18
  secretId?: string;
@@ -49,6 +50,7 @@ declare class CloudBase {
49
50
  get database(): DatabaseService;
50
51
  get hosting(): HostingService;
51
52
  get access(): AccessService;
53
+ get mysql(): MysqlService;
52
54
  get cloudApp(): CloudBaseRunService;
53
55
  commonService(service?: string, version?: string): CommonService;
54
56
  get env(): EnvService;