ai-yuca 1.0.8 → 1.1.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/.cdn.cache.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "lastUploadVersion": "mfhlsh6u",
3
- "lastDeployTime": "2025-09-13T02:50:24.958Z",
4
- "lastDeployVersion": "mfho5760"
3
+ "lastDeployTime": "2025-09-15T06:15:45.798Z",
4
+ "lastDeployVersion": "mfkqd0es"
5
5
  }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-yuca",
3
- "version": "1.0.8",
3
+ "version": "1.1.1",
4
4
  "description": "一个实用的AI辅助工具",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -50,15 +50,32 @@ const uploadWithConfig_1 = require("./uploadWithConfig");
50
50
  const cache_1 = require("./cache");
51
51
  const child_process_1 = require("child_process");
52
52
  /**
53
- * 获取环境配置文件
53
+ * 从GCP存储读取环境配置文件
54
54
  */
55
- const getConfigFiles = (env, config) => {
55
+ const getConfigFiles = (env, config, keyFile) => {
56
56
  return new Promise(async (resolve) => {
57
57
  try {
58
- const { data: sitemap = { projects: [] } } = await axios_1.default.get(`${config.aws.HostName}/${config.aws.prefix}/static/config/${env}.config.json`);
58
+ // 继承原来的权限文件,创建GCP存储客户端
59
+ const storageClient = keyFile
60
+ ? (0, upload_1.createStorageClient)({ keyFilename: keyFile })
61
+ : (0, upload_1.createStorageClient)();
62
+ const bucket = storageClient.bucket(config.aws.Bucket);
63
+ const configPath = `${config.aws.prefix}/static/config/${env}.config.json`;
64
+ const file = bucket.file(configPath);
65
+ // 检查文件是否存在
66
+ const [exists] = await file.exists();
67
+ if (!exists) {
68
+ console.log(`配置文件不存在: ${configPath}`);
69
+ resolve({ data: { projects: [] } });
70
+ return;
71
+ }
72
+ // 直接读取文件内容到内存,不下载到本地
73
+ const [contents] = await file.download();
74
+ const sitemap = JSON.parse(contents.toString());
59
75
  resolve({ data: sitemap });
60
76
  }
61
77
  catch (e) {
78
+ console.log(`读取配置文件失败: ${e instanceof Error ? e.message : String(e)}`);
62
79
  resolve({ data: { projects: [] } });
63
80
  }
64
81
  });
@@ -176,7 +193,7 @@ async function uploadToGcp(filePath, bucketName, destination, keyFile) {
176
193
  async function updateEnvironmentConfig(env, projectName, versionInfo, config, keyFile) {
177
194
  try {
178
195
  // 获取当前环境配置
179
- const { data: envConfig } = await getConfigFiles(env, config);
196
+ const { data: envConfig } = await getConfigFiles(env, config, keyFile);
180
197
  // 查找或创建项目配置
181
198
  let projectConfig = envConfig.projects.find((p) => p.name === projectName);
182
199
  if (!projectConfig) {
@@ -198,11 +215,14 @@ async function updateEnvironmentConfig(env, projectName, versionInfo, config, ke
198
215
  const configPath = `${config.aws.prefix}/static/config/${env}.config.json`;
199
216
  const tempFile = path.join(process.cwd(), `temp-${env}-config.json`);
200
217
  fs.writeFileSync(tempFile, JSON.stringify(envConfig, null, 2));
201
- const result = await uploadToGcp(tempFile, config.bucketName, configPath, keyFile);
218
+ console.log("更新线上配置:", JSON.stringify(envConfig));
219
+ const result = await uploadToGcp(tempFile, config.aws.Bucket, configPath, keyFile);
202
220
  fs.unlinkSync(tempFile);
221
+ console.log('更新环境配置状态:', JSON.stringify(result.error) || result.url);
203
222
  return result.success;
204
223
  }
205
- catch (_a) {
224
+ catch (e) {
225
+ console.log('更新环境配置失败:', e);
206
226
  return false;
207
227
  }
208
228
  }
@@ -218,23 +238,11 @@ async function deployFiles(options) {
218
238
  // 2. 执行upload-config阶段
219
239
  console.log('📤 执行upload-config上传配置文件...');
220
240
  try {
221
- const uploadResult = await (0, uploadWithConfig_1.uploadFilesWithConfig)({
241
+ await (0, uploadWithConfig_1.uploadFilesWithConfig)({
222
242
  configPath: options.config,
223
243
  storageClientOptions: options.keyFile ? { keyFilename: options.keyFile } : {},
224
244
  enableCache: true
225
245
  });
226
- if (uploadResult.success.length > 0) {
227
- console.log(chalk_1.default.green(`✅ upload-config成功: ${uploadResult.success.length}个文件`));
228
- uploadResult.success.forEach(file => {
229
- console.log(chalk_1.default.green(` ✅ ${file.file}: ${file.url}`));
230
- });
231
- }
232
- if (uploadResult.failed.length > 0) {
233
- console.log(chalk_1.default.red(`❌ upload-config失败: ${uploadResult.failed.length}个文件`));
234
- uploadResult.failed.forEach(file => {
235
- console.log(chalk_1.default.red(` ❌ ${file.file}: ${file.error}`));
236
- });
237
- }
238
246
  }
239
247
  catch (error) {
240
248
  console.warn(`⚠️ upload-config执行失败: ${error instanceof Error ? error.message : String(error)}`);
@@ -260,17 +268,22 @@ async function deployFiles(options) {
260
268
  // 5. 文件处理与上传阶段
261
269
  console.log('📤 上传原始HTML文件...');
262
270
  const uploadedFiles = [];
263
- for (const file of files) {
271
+ // 使用Promise.all并行上传文件
272
+ const uploadPromises = files.map(file => {
264
273
  const relativePath = path.relative(sourcePath, file);
265
274
  const destination = `${prefix}/${cdnKey}/${relativePath}`;
266
275
  console.log(` 上传: ${relativePath}`);
267
- const result = await (0, upload_1.uploadFile)({
276
+ return (0, upload_1.uploadFile)({
268
277
  bucketName: uploadConfig.bucketName,
269
278
  filePath: file,
270
279
  destination,
271
280
  storageClient: (0, upload_1.createStorageClient)(options.keyFile ? { keyFilename: options.keyFile } : {}),
272
281
  enableCompression: true
273
- });
282
+ }).then(result => ({ result, relativePath, destination }));
283
+ });
284
+ const uploadResults = await Promise.all(uploadPromises);
285
+ // 同步打印上传结果
286
+ for (const { result, relativePath, destination } of uploadResults) {
274
287
  if (result.success) {
275
288
  uploadedFiles.push(relativePath);
276
289
  console.log(chalk_1.default.green(` ✅ ${relativePath}: ${result.url || destination}`));
@@ -346,7 +359,8 @@ async function deployFiles(options) {
346
359
  // 7. 环境配置同步阶段
347
360
  console.log('🔄 同步环境配置...');
348
361
  // 检查项目是否存在
349
- const { data: envConfig } = await getConfigFiles(options.env, config);
362
+ const { data: envConfig } = await getConfigFiles(options.env, config, options.keyFile);
363
+ console.log('当前环境配置:', JSON.stringify(envConfig));
350
364
  const existingProject = envConfig.projects.find((p) => p.name === projectInfo.name);
351
365
  if (!existingProject) {
352
366
  if (options.force) {
@@ -375,7 +389,11 @@ async function deployFiles(options) {
375
389
  timestamp: Date.now(),
376
390
  files: obj.links
377
391
  };
378
- await updateEnvironmentConfig(options.env, projectInfo.name, versionInfo, config, options.keyFile);
392
+ const projectConfigUpdate = await updateEnvironmentConfig(options.env, projectInfo.name, versionInfo, config, options.keyFile);
393
+ console.log('项目配置信息上传结果:', JSON.stringify(projectConfigUpdate));
394
+ if (!projectConfigUpdate) {
395
+ throw new Error('更新项目配置失败,发布失败!');
396
+ }
379
397
  // 8. 发布完成阶段
380
398
  console.log('💾 记录发布版本...');
381
399
  (0, cache_1.writeLastDeployVersion)(cdnKey);
@@ -61,7 +61,7 @@ export interface DeployResult {
61
61
  message: string;
62
62
  }
63
63
  export interface GetConfigFilesFunction {
64
- (env: string, config: Record<string, any>): Promise<{
64
+ (env: string, config: Record<string, any>, keyFile?: string): Promise<{
65
65
  data: {
66
66
  projects: Array<any>;
67
67
  };
@@ -120,6 +120,7 @@ async function uploadFile(options) {
120
120
  }
121
121
  }
122
122
  // 上传文件
123
+ // @ts-ignore
123
124
  const [file] = await bucket.upload(fileToUpload, {
124
125
  destination: destPath,
125
126
  // 设置元数据
@@ -128,9 +129,6 @@ async function uploadFile(options) {
128
129
  cacheControl: contentType === 'application/json' ? 'public, max-age=0' : 'public, max-age=31536000',
129
130
  contentEncoding,
130
131
  contentType
131
- },
132
- preconditionOpts: {
133
- ifGenerationMatch: 0 // 0表示如果文件存在则覆盖
134
132
  }
135
133
  });
136
134
  // 如果上传了压缩文件,删除临时文件
@@ -150,7 +148,7 @@ async function uploadFile(options) {
150
148
  };
151
149
  }
152
150
  catch (error) {
153
- console.log('上传文件时出错:', JSON.stringify(error));
151
+ console.log('上传文件时出错:', filePath, JSON.stringify(error));
154
152
  return {
155
153
  success: false,
156
154
  file: filePath,
@@ -176,14 +174,15 @@ async function uploadFiles(options) {
176
174
  try {
177
175
  // 如果sourcePath是数组,批量上传多个文件
178
176
  if (Array.isArray(sourcePath)) {
179
- for (const filePath of sourcePath) {
180
- const result = await uploadFile({
181
- bucketName,
182
- filePath,
183
- destination: destination ? `${destination}/${path.basename(filePath)}` : undefined,
184
- storageClient,
185
- enableCompression
186
- });
177
+ const uploadPromises = sourcePath.map(filePath => uploadFile({
178
+ bucketName,
179
+ filePath,
180
+ destination: destination ? `${destination}/${path.basename(filePath)}` : undefined,
181
+ storageClient,
182
+ enableCompression
183
+ }));
184
+ const uploadResults = await Promise.all(uploadPromises);
185
+ for (const result of uploadResults) {
187
186
  if (result.success) {
188
187
  results.success.push(result);
189
188
  }
@@ -214,37 +213,52 @@ async function uploadFiles(options) {
214
213
  else if (stats.isDirectory()) {
215
214
  // 上传目录中的文件
216
215
  const files = await readdir(sourcePath);
216
+ // 分离文件和目录
217
+ const filePromises = [];
218
+ const dirPromises = [];
217
219
  for (const file of files) {
218
220
  const filePath = path.join(sourcePath, file);
219
221
  const fileStats = await stat(filePath);
220
222
  if (fileStats.isFile()) {
221
- // 上传文件
223
+ // 准备文件上传Promise
222
224
  const destPath = destination ? `${destination}/${file}` : file;
223
- const result = await uploadFile({
225
+ filePromises.push(uploadFile({
224
226
  bucketName,
225
227
  filePath,
226
228
  destination: destPath,
227
229
  storageClient,
228
230
  enableCompression
229
- });
230
- if (result.success) {
231
- results.success.push(result);
232
- }
233
- else {
234
- results.failed.push(result);
235
- }
231
+ }));
236
232
  }
237
233
  else if (recursive && fileStats.isDirectory()) {
238
- // 递归上传子目录
234
+ // 准备递归目录上传Promise
239
235
  const subDestination = destination ? `${destination}/${file}` : file;
240
- const subResults = await uploadFiles({
236
+ dirPromises.push(uploadFiles({
241
237
  bucketName,
242
238
  sourcePath: filePath,
243
239
  destination: subDestination,
244
240
  storageClient,
245
241
  recursive,
246
242
  enableCompression
247
- });
243
+ }));
244
+ }
245
+ }
246
+ // 并行上传所有文件
247
+ if (filePromises.length > 0) {
248
+ const fileResults = await Promise.all(filePromises);
249
+ for (const result of fileResults) {
250
+ if (result.success) {
251
+ results.success.push(result);
252
+ }
253
+ else {
254
+ results.failed.push(result);
255
+ }
256
+ }
257
+ }
258
+ // 并行处理所有子目录
259
+ if (dirPromises.length > 0) {
260
+ const dirResults = await Promise.all(dirPromises);
261
+ for (const subResults of dirResults) {
248
262
  results.success = results.success.concat(subResults.success);
249
263
  results.failed = results.failed.concat(subResults.failed);
250
264
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-yuca",
3
- "version": "1.0.8",
3
+ "version": "1.1.1",
4
4
  "description": "一个实用的AI辅助工具",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
package/src/deploy.ts CHANGED
@@ -16,23 +16,38 @@ import {
16
16
  DeployConfig,
17
17
  ProjectInfo,
18
18
  DeployVersionInfo,
19
- EnvironmentConfig,
20
- ProjectConfig,
21
19
  DeployResult,
22
20
  GetConfigFilesFunction
23
21
  } from './types/deploy';
24
22
 
25
23
  /**
26
- * 获取环境配置文件
24
+ * 从GCP存储读取环境配置文件
27
25
  */
28
- const getConfigFiles: GetConfigFilesFunction = (env, config) => {
26
+ const getConfigFiles: GetConfigFilesFunction = (env, config, keyFile) => {
29
27
  return new Promise(async resolve => {
30
28
  try {
31
- const { data: sitemap = { projects: [] } } = await axios.get(
32
- `${config.aws.HostName}/${config.aws.prefix}/static/config/${env}.config.json`
33
- );
29
+ // 继承原来的权限文件,创建GCP存储客户端
30
+ const storageClient = keyFile
31
+ ? createStorageClient({ keyFilename: keyFile })
32
+ : createStorageClient();
33
+ const bucket = storageClient.bucket(config.aws.Bucket);
34
+ const configPath = `${config.aws.prefix}/static/config/${env}.config.json`;
35
+ const file = bucket.file(configPath);
36
+
37
+ // 检查文件是否存在
38
+ const [exists] = await file.exists();
39
+ if (!exists) {
40
+ console.log(`配置文件不存在: ${configPath}`);
41
+ resolve({ data: { projects: [] } });
42
+ return;
43
+ }
44
+
45
+ // 直接读取文件内容到内存,不下载到本地
46
+ const [contents] = await file.download();
47
+ const sitemap = JSON.parse(contents.toString());
34
48
  resolve({ data: sitemap });
35
49
  } catch (e) {
50
+ console.log(`读取配置文件失败: ${e instanceof Error ? e.message : String(e)}`);
36
51
  resolve({ data: { projects: [] } });
37
52
  }
38
53
  });
@@ -156,7 +171,7 @@ async function uploadToGcp(
156
171
  storageClient: client,
157
172
  enableCompression: true
158
173
  });
159
-
174
+
160
175
  if (result.success) {
161
176
  return { success: true, url: result.url };
162
177
  } else {
@@ -183,7 +198,7 @@ async function updateEnvironmentConfig(
183
198
  ): Promise<boolean> {
184
199
  try {
185
200
  // 获取当前环境配置
186
- const { data: envConfig } = await getConfigFiles(env, config);
201
+ const { data: envConfig } = await getConfigFiles(env, config, keyFile);
187
202
 
188
203
  // 查找或创建项目配置
189
204
  let projectConfig = envConfig.projects.find((p: any) => p.name === projectName);
@@ -208,13 +223,16 @@ async function updateEnvironmentConfig(
208
223
  const tempFile = path.join(process.cwd(), `temp-${env}-config.json`);
209
224
 
210
225
  fs.writeFileSync(tempFile, JSON.stringify(envConfig, null, 2));
226
+
227
+ console.log("更新线上配置:", JSON.stringify(envConfig));
211
228
 
212
- const result = await uploadToGcp(tempFile, config.bucketName, configPath, keyFile);
229
+ const result = await uploadToGcp(tempFile, config.aws.Bucket, configPath, keyFile);
213
230
 
214
231
  fs.unlinkSync(tempFile);
215
-
232
+ console.log('更新环境配置状态:', JSON.stringify(result.error) || result.url);
216
233
  return result.success;
217
- } catch {
234
+ } catch(e) {
235
+ console.log('更新环境配置失败:', e);
218
236
  return false;
219
237
  }
220
238
  }
@@ -235,23 +253,11 @@ export async function deployFiles(options: DeployCommandOptions): Promise<Deploy
235
253
  // 2. 执行upload-config阶段
236
254
  console.log('📤 执行upload-config上传配置文件...');
237
255
  try {
238
- const uploadResult = await uploadFilesWithConfig({
256
+ await uploadFilesWithConfig({
239
257
  configPath: options.config,
240
258
  storageClientOptions: options.keyFile ? { keyFilename: options.keyFile } : {},
241
259
  enableCache: true
242
260
  });
243
- if (uploadResult.success.length > 0) {
244
- console.log(chalk.green(`✅ upload-config成功: ${uploadResult.success.length}个文件`));
245
- uploadResult.success.forEach(file => {
246
- console.log(chalk.green(` ✅ ${file.file}: ${file.url}`));
247
- });
248
- }
249
- if (uploadResult.failed.length > 0) {
250
- console.log(chalk.red(`❌ upload-config失败: ${uploadResult.failed.length}个文件`));
251
- uploadResult.failed.forEach(file => {
252
- console.log(chalk.red(` ❌ ${file.file}: ${file.error}`));
253
- });
254
- }
255
261
  } catch (error) {
256
262
  console.warn(`⚠️ upload-config执行失败: ${error instanceof Error ? error.message : String(error)}`);
257
263
  }
@@ -284,19 +290,25 @@ export async function deployFiles(options: DeployCommandOptions): Promise<Deploy
284
290
  console.log('📤 上传原始HTML文件...');
285
291
  const uploadedFiles: string[] = [];
286
292
 
287
- for (const file of files) {
293
+ // 使用Promise.all并行上传文件
294
+ const uploadPromises = files.map(file => {
288
295
  const relativePath = path.relative(sourcePath, file);
289
296
  const destination = `${prefix}/${cdnKey}/${relativePath}`;
290
297
 
291
298
  console.log(` 上传: ${relativePath}`);
292
- const result = await uploadFile({
299
+ return uploadFile({
293
300
  bucketName: uploadConfig.bucketName,
294
301
  filePath: file,
295
302
  destination,
296
303
  storageClient: createStorageClient(options.keyFile ? { keyFilename: options.keyFile } : {}),
297
304
  enableCompression: true
298
- });
299
-
305
+ }).then(result => ({ result, relativePath, destination }));
306
+ });
307
+
308
+ const uploadResults = await Promise.all(uploadPromises);
309
+
310
+ // 同步打印上传结果
311
+ for (const { result, relativePath, destination } of uploadResults) {
300
312
  if (result.success) {
301
313
  uploadedFiles.push(relativePath);
302
314
  console.log(chalk.green(` ✅ ${relativePath}: ${result.url || destination}`));
@@ -378,7 +390,10 @@ export async function deployFiles(options: DeployCommandOptions): Promise<Deploy
378
390
  console.log('🔄 同步环境配置...');
379
391
 
380
392
  // 检查项目是否存在
381
- const { data: envConfig } = await getConfigFiles(options.env, config);
393
+ const { data: envConfig } = await getConfigFiles(options.env, config, options.keyFile);
394
+
395
+ console.log('当前环境配置:', JSON.stringify(envConfig));
396
+
382
397
  const existingProject = envConfig.projects.find((p: any) => p.name === projectInfo.name);
383
398
 
384
399
  if (!existingProject) {
@@ -410,8 +425,11 @@ export async function deployFiles(options: DeployCommandOptions): Promise<Deploy
410
425
  files: obj.links
411
426
  };
412
427
 
413
- await updateEnvironmentConfig(options.env, projectInfo.name, versionInfo, config, options.keyFile);
414
-
428
+ const projectConfigUpdate = await updateEnvironmentConfig(options.env, projectInfo.name, versionInfo, config, options.keyFile);
429
+ console.log('项目配置信息上传结果:',JSON.stringify(projectConfigUpdate));
430
+ if (!projectConfigUpdate) {
431
+ throw new Error('更新项目配置失败,发布失败!');
432
+ }
415
433
  // 8. 发布完成阶段
416
434
  console.log('💾 记录发布版本...');
417
435
  writeLastDeployVersion(cdnKey);
@@ -70,5 +70,5 @@ export interface DeployResult {
70
70
  }
71
71
 
72
72
  export interface GetConfigFilesFunction {
73
- (env: string, config: Record<string, any>): Promise<{ data: { projects: Array<any> } }>;
73
+ (env: string, config: Record<string, any>, keyFile?: string): Promise<{ data: { projects: Array<any> } }>;
74
74
  }
package/src/upload.ts CHANGED
@@ -52,7 +52,7 @@ function createStorageClient(options: Partial<StorageClientOptions> = {}): Stora
52
52
  * @param options - 上传选项
53
53
  * @returns 上传结果
54
54
  */
55
- async function uploadFile(options: UploadFileOptions): Promise<UploadResult> {
55
+ async function uploadFile(options: UploadFileOptions): Promise<UploadResult> {
56
56
  const { bucketName, filePath, destination, storageClient, enableCompression = true } = options;
57
57
 
58
58
  if (!bucketName || !filePath || !storageClient) {
@@ -105,6 +105,7 @@ async function uploadFile(options: UploadFileOptions): Promise<UploadResult> {
105
105
  }
106
106
 
107
107
  // 上传文件
108
+ // @ts-ignore
108
109
  const [file] = await bucket.upload(fileToUpload, {
109
110
  destination: destPath,
110
111
  // 设置元数据
@@ -113,9 +114,6 @@ async function uploadFile(options: UploadFileOptions): Promise<UploadResult> {
113
114
  cacheControl: contentType === 'application/json' ? 'public, max-age=0' : 'public, max-age=31536000',
114
115
  contentEncoding,
115
116
  contentType
116
- },
117
- preconditionOpts: {
118
- ifGenerationMatch: 0 // 0表示如果文件存在则覆盖
119
117
  }
120
118
  });
121
119
 
@@ -137,7 +135,7 @@ async function uploadFile(options: UploadFileOptions): Promise<UploadResult> {
137
135
  url: `https://storage.googleapis.com/${bucketName}/${metadata.name || path.basename(filePath)}`
138
136
  };
139
137
  } catch (error) {
140
- console.log('上传文件时出错:', JSON.stringify(error));
138
+ console.log('上传文件时出错:', filePath, JSON.stringify(error));
141
139
  return {
142
140
  success: false,
143
141
  file: filePath,
@@ -169,15 +167,19 @@ async function uploadFiles(options: UploadFilesOptions): Promise<UploadFilesResu
169
167
  try {
170
168
  // 如果sourcePath是数组,批量上传多个文件
171
169
  if (Array.isArray(sourcePath)) {
172
- for (const filePath of sourcePath) {
173
- const result = await uploadFile({
170
+ const uploadPromises = sourcePath.map(filePath =>
171
+ uploadFile({
174
172
  bucketName,
175
173
  filePath,
176
174
  destination: destination ? `${destination}/${path.basename(filePath)}` : undefined,
177
175
  storageClient,
178
176
  enableCompression
179
- });
180
-
177
+ })
178
+ );
179
+
180
+ const uploadResults = await Promise.all(uploadPromises);
181
+
182
+ for (const result of uploadResults) {
181
183
  if (result.success) {
182
184
  results.success.push(result);
183
185
  } else {
@@ -209,40 +211,60 @@ async function uploadFiles(options: UploadFilesOptions): Promise<UploadFilesResu
209
211
  // 上传目录中的文件
210
212
  const files = await readdir(sourcePath);
211
213
 
214
+ // 分离文件和目录
215
+ const filePromises: Promise<any>[] = [];
216
+ const dirPromises: Promise<any>[] = [];
217
+
212
218
  for (const file of files) {
213
219
  const filePath = path.join(sourcePath, file);
214
220
  const fileStats = await stat(filePath);
215
221
 
216
222
  if (fileStats.isFile()) {
217
- // 上传文件
223
+ // 准备文件上传Promise
218
224
  const destPath = destination ? `${destination}/${file}` : file;
219
225
 
220
- const result = await uploadFile({
221
- bucketName,
222
- filePath,
223
- destination: destPath,
224
- storageClient,
225
- enableCompression
226
- });
226
+ filePromises.push(
227
+ uploadFile({
228
+ bucketName,
229
+ filePath,
230
+ destination: destPath,
231
+ storageClient,
232
+ enableCompression
233
+ })
234
+ );
235
+ } else if (recursive && fileStats.isDirectory()) {
236
+ // 准备递归目录上传Promise
237
+ const subDestination = destination ? `${destination}/${file}` : file;
227
238
 
239
+ dirPromises.push(
240
+ uploadFiles({
241
+ bucketName,
242
+ sourcePath: filePath,
243
+ destination: subDestination,
244
+ storageClient,
245
+ recursive,
246
+ enableCompression
247
+ })
248
+ );
249
+ }
250
+ }
251
+
252
+ // 并行上传所有文件
253
+ if (filePromises.length > 0) {
254
+ const fileResults = await Promise.all(filePromises);
255
+ for (const result of fileResults) {
228
256
  if (result.success) {
229
257
  results.success.push(result);
230
258
  } else {
231
259
  results.failed.push(result);
232
260
  }
233
- } else if (recursive && fileStats.isDirectory()) {
234
- // 递归上传子目录
235
- const subDestination = destination ? `${destination}/${file}` : file;
236
-
237
- const subResults = await uploadFiles({
238
- bucketName,
239
- sourcePath: filePath,
240
- destination: subDestination,
241
- storageClient,
242
- recursive,
243
- enableCompression
244
- });
245
-
261
+ }
262
+ }
263
+
264
+ // 并行处理所有子目录
265
+ if (dirPromises.length > 0) {
266
+ const dirResults = await Promise.all(dirPromises);
267
+ for (const subResults of dirResults) {
246
268
  results.success = results.success.concat(subResults.success);
247
269
  results.failed = results.failed.concat(subResults.failed);
248
270
  }