ai-yuca 1.0.0
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/.eslintrc.js +25 -0
- package/CONFIG_UPLOAD.md +154 -0
- package/CONTRIBUTING.md +58 -0
- package/INSTALLATION.md +192 -0
- package/README.md +80 -0
- package/bin/cli.js +85 -0
- package/bin/cli.ts +302 -0
- package/dist/bin/cli.d.ts +2 -0
- package/dist/bin/cli.js +297 -0
- package/dist/package.json +51 -0
- package/dist/src/config.d.ts +56 -0
- package/dist/src/config.js +101 -0
- package/dist/src/download.d.ts +30 -0
- package/dist/src/download.js +214 -0
- package/dist/src/index.d.ts +18 -0
- package/dist/src/index.js +126 -0
- package/dist/src/types/analyze.d.ts +33 -0
- package/dist/src/types/analyze.js +5 -0
- package/dist/src/types/download.d.ts +60 -0
- package/dist/src/types/download.js +2 -0
- package/dist/src/types/index.d.ts +8 -0
- package/dist/src/types/index.js +28 -0
- package/dist/src/types/upload.d.ts +89 -0
- package/dist/src/types/upload.js +2 -0
- package/dist/src/upload.d.ts +24 -0
- package/dist/src/upload.js +252 -0
- package/dist/src/uploadWithConfig.d.ts +34 -0
- package/dist/src/uploadWithConfig.js +82 -0
- package/dist/src/utils/compression.d.ts +16 -0
- package/dist/src/utils/compression.js +85 -0
- package/dist/test/compression.test.d.ts +1 -0
- package/dist/test/compression.test.js +109 -0
- package/dist/test/download.test.d.ts +1 -0
- package/dist/test/download.test.js +168 -0
- package/dist/test/index.test.d.ts +1 -0
- package/dist/test/index.test.js +33 -0
- package/dist/test/upload.test.d.ts +1 -0
- package/dist/test/upload.test.js +140 -0
- package/docs/usage.md +223 -0
- package/examples/sample.txt +7 -0
- package/examples/upload-example.js +53 -0
- package/out/test.txt +1 -0
- package/package.json +51 -0
- package/src/config.ts +104 -0
- package/src/download.ts +216 -0
- package/src/index.js +88 -0
- package/src/index.ts +98 -0
- package/src/types/analyze.ts +37 -0
- package/src/types/download.ts +67 -0
- package/src/types/index.ts +16 -0
- package/src/types/upload.ts +97 -0
- package/src/upload.js +197 -0
- package/src/upload.ts +254 -0
- package/src/uploadWithConfig.ts +122 -0
- package/src/utils/compression.ts +61 -0
- package/test/compression.test.ts +88 -0
- package/test/download.test.ts +162 -0
- package/test/index.test.js +38 -0
- package/test/index.test.ts +39 -0
- package/test/upload.test.ts +131 -0
- package/tsconfig.json +17 -0
- package/vs.config.json +42 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 上传功能相关类型定义
|
|
3
|
+
*/
|
|
4
|
+
import { Storage } from '@google-cloud/storage';
|
|
5
|
+
/**
|
|
6
|
+
* 存储客户端选项接口
|
|
7
|
+
*/
|
|
8
|
+
export interface StorageClientOptions {
|
|
9
|
+
keyFilename?: string;
|
|
10
|
+
projectId?: string;
|
|
11
|
+
credentials?: {
|
|
12
|
+
client_email?: string;
|
|
13
|
+
private_key?: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 文件上传选项接口
|
|
18
|
+
*/
|
|
19
|
+
export interface UploadFileOptions {
|
|
20
|
+
bucketName: string;
|
|
21
|
+
filePath: string;
|
|
22
|
+
destination?: string;
|
|
23
|
+
storageClient: Storage;
|
|
24
|
+
/**
|
|
25
|
+
* 是否启用GZIP压缩(对js、css、json、html、woff文件类型)
|
|
26
|
+
* @default true
|
|
27
|
+
*/
|
|
28
|
+
enableCompression?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 批量上传选项接口
|
|
32
|
+
*/
|
|
33
|
+
export interface UploadFilesOptions {
|
|
34
|
+
bucketName: string;
|
|
35
|
+
sourcePath: string | string[];
|
|
36
|
+
destination?: string;
|
|
37
|
+
storageClient: Storage;
|
|
38
|
+
recursive?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* 是否启用GZIP压缩(对js、css、json、html、woff文件类型)
|
|
41
|
+
* @default true
|
|
42
|
+
*/
|
|
43
|
+
enableCompression?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 上传成功结果接口
|
|
47
|
+
*/
|
|
48
|
+
export interface UploadSuccessResult {
|
|
49
|
+
success: true;
|
|
50
|
+
file: string;
|
|
51
|
+
size: string | number;
|
|
52
|
+
contentType: string;
|
|
53
|
+
timeCreated: string;
|
|
54
|
+
url: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 上传失败结果接口
|
|
58
|
+
*/
|
|
59
|
+
export interface UploadFailedResult {
|
|
60
|
+
success: false;
|
|
61
|
+
file: string;
|
|
62
|
+
error: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 上传结果类型
|
|
66
|
+
*/
|
|
67
|
+
export type UploadResult = UploadSuccessResult | UploadFailedResult;
|
|
68
|
+
/**
|
|
69
|
+
* 批量上传结果接口
|
|
70
|
+
*/
|
|
71
|
+
export interface UploadFilesResult {
|
|
72
|
+
success: UploadSuccessResult[];
|
|
73
|
+
failed: UploadFailedResult[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* CLI上传命令选项接口
|
|
77
|
+
*/
|
|
78
|
+
export interface UploadCommandOptions {
|
|
79
|
+
source: string[];
|
|
80
|
+
bucket: string;
|
|
81
|
+
destination?: string;
|
|
82
|
+
keyFile?: string;
|
|
83
|
+
recursive: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* 是否启用GZIP压缩(对js、css、json、html、woff文件类型)
|
|
86
|
+
* @default true
|
|
87
|
+
*/
|
|
88
|
+
compression?: boolean;
|
|
89
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GCP上传功能模块
|
|
3
|
+
*/
|
|
4
|
+
import { Storage } from '@google-cloud/storage';
|
|
5
|
+
import { StorageClientOptions, UploadFileOptions, UploadFilesOptions, UploadResult, UploadFilesResult } from './types/upload';
|
|
6
|
+
/**
|
|
7
|
+
* 创建GCP存储客户端
|
|
8
|
+
* @param options - 配置选项
|
|
9
|
+
* @returns GCP存储客户端实例
|
|
10
|
+
*/
|
|
11
|
+
declare function createStorageClient(options?: Partial<StorageClientOptions>): Storage;
|
|
12
|
+
/**
|
|
13
|
+
* 上传单个文件到GCP存储桶
|
|
14
|
+
* @param options - 上传选项
|
|
15
|
+
* @returns 上传结果
|
|
16
|
+
*/
|
|
17
|
+
declare function uploadFile(options: UploadFileOptions): Promise<UploadResult>;
|
|
18
|
+
/**
|
|
19
|
+
* 批量上传文件到GCP存储桶
|
|
20
|
+
* @param options - 上传选项
|
|
21
|
+
* @returns 上传结果
|
|
22
|
+
*/
|
|
23
|
+
declare function uploadFiles(options: UploadFilesOptions): Promise<UploadFilesResult>;
|
|
24
|
+
export { createStorageClient, uploadFile, uploadFiles };
|
|
@@ -0,0 +1,252 @@
|
|
|
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.createStorageClient = createStorageClient;
|
|
37
|
+
exports.uploadFile = uploadFile;
|
|
38
|
+
exports.uploadFiles = uploadFiles;
|
|
39
|
+
/**
|
|
40
|
+
* GCP上传功能模块
|
|
41
|
+
*/
|
|
42
|
+
const storage_1 = require("@google-cloud/storage");
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const util = __importStar(require("util"));
|
|
46
|
+
const compression_1 = require("./utils/compression");
|
|
47
|
+
const readdir = util.promisify(fs.readdir);
|
|
48
|
+
const stat = util.promisify(fs.stat);
|
|
49
|
+
/**
|
|
50
|
+
* 创建GCP存储客户端
|
|
51
|
+
* @param options - 配置选项
|
|
52
|
+
* @returns GCP存储客户端实例
|
|
53
|
+
*/
|
|
54
|
+
function createStorageClient(options = {}) {
|
|
55
|
+
const { keyFilename, projectId, credentials } = options;
|
|
56
|
+
// 如果提供了keyFilename,使用密钥文件认证
|
|
57
|
+
if (keyFilename) {
|
|
58
|
+
return new storage_1.Storage({
|
|
59
|
+
keyFilename
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// 如果提供了credentials,使用凭证对象认证
|
|
63
|
+
if (credentials) {
|
|
64
|
+
return new storage_1.Storage({
|
|
65
|
+
projectId,
|
|
66
|
+
credentials
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// 使用应用默认凭证(ADC)进行免密认证
|
|
70
|
+
// 这将使用环境变量GOOGLE_APPLICATION_CREDENTIALS或默认服务账号
|
|
71
|
+
return new storage_1.Storage();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 上传单个文件到GCP存储桶
|
|
75
|
+
* @param options - 上传选项
|
|
76
|
+
* @returns 上传结果
|
|
77
|
+
*/
|
|
78
|
+
async function uploadFile(options) {
|
|
79
|
+
const { bucketName, filePath, destination, storageClient, enableCompression = true } = options;
|
|
80
|
+
if (!bucketName || !filePath || !storageClient) {
|
|
81
|
+
throw new Error('缺少必要的上传参数');
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
// 检查文件是否存在
|
|
85
|
+
if (!fs.existsSync(filePath)) {
|
|
86
|
+
throw new Error(`文件不存在: ${filePath}`);
|
|
87
|
+
}
|
|
88
|
+
// 获取存储桶
|
|
89
|
+
const bucket = storageClient.bucket(bucketName);
|
|
90
|
+
// 确定目标路径
|
|
91
|
+
const destPath = destination || path.basename(filePath);
|
|
92
|
+
// 检查是否需要压缩
|
|
93
|
+
let fileToUpload = filePath;
|
|
94
|
+
let contentEncoding;
|
|
95
|
+
let contentType;
|
|
96
|
+
if (enableCompression && (0, compression_1.shouldCompressFile)(filePath)) {
|
|
97
|
+
// 压缩文件
|
|
98
|
+
fileToUpload = await (0, compression_1.compressFile)(filePath);
|
|
99
|
+
contentEncoding = 'gzip';
|
|
100
|
+
// 根据文件扩展名设置正确的Content-Type
|
|
101
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
102
|
+
switch (ext) {
|
|
103
|
+
case '.js':
|
|
104
|
+
contentType = 'application/javascript';
|
|
105
|
+
break;
|
|
106
|
+
case '.css':
|
|
107
|
+
contentType = 'text/css';
|
|
108
|
+
break;
|
|
109
|
+
case '.json':
|
|
110
|
+
contentType = 'application/json';
|
|
111
|
+
break;
|
|
112
|
+
case '.html':
|
|
113
|
+
contentType = 'text/html';
|
|
114
|
+
break;
|
|
115
|
+
case '.woff':
|
|
116
|
+
contentType = 'font/woff';
|
|
117
|
+
break;
|
|
118
|
+
default:
|
|
119
|
+
contentType = 'application/octet-stream';
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// 上传文件
|
|
123
|
+
const [file] = await bucket.upload(fileToUpload, {
|
|
124
|
+
destination: destPath,
|
|
125
|
+
// 设置元数据
|
|
126
|
+
metadata: {
|
|
127
|
+
// 为.json文件设置缓存时间为0,其他文件保持一年缓存
|
|
128
|
+
cacheControl: path.extname(filePath).toLowerCase() === '.json' ? 'public, max-age=0' : 'public, max-age=31536000',
|
|
129
|
+
contentEncoding,
|
|
130
|
+
contentType
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
// 如果上传了压缩文件,删除临时文件
|
|
134
|
+
if (fileToUpload !== filePath && fs.existsSync(fileToUpload)) {
|
|
135
|
+
fs.unlinkSync(fileToUpload);
|
|
136
|
+
}
|
|
137
|
+
// 获取文件公共URL
|
|
138
|
+
const [metadata] = await file.getMetadata();
|
|
139
|
+
return {
|
|
140
|
+
success: true,
|
|
141
|
+
file: metadata.name || path.basename(filePath),
|
|
142
|
+
size: metadata.size || 0,
|
|
143
|
+
contentType: metadata.contentType || 'application/octet-stream',
|
|
144
|
+
timeCreated: metadata.timeCreated || new Date().toISOString(),
|
|
145
|
+
url: `https://storage.googleapis.com/${bucketName}/${metadata.name || path.basename(filePath)}`
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return {
|
|
150
|
+
success: false,
|
|
151
|
+
file: filePath,
|
|
152
|
+
error: error instanceof Error ? error.message : String(error)
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 批量上传文件到GCP存储桶
|
|
158
|
+
* @param options - 上传选项
|
|
159
|
+
* @returns 上传结果
|
|
160
|
+
*/
|
|
161
|
+
async function uploadFiles(options) {
|
|
162
|
+
const { bucketName, sourcePath, destination, storageClient, recursive = false, enableCompression = true } = options;
|
|
163
|
+
if (!bucketName || !sourcePath || !storageClient) {
|
|
164
|
+
throw new Error('缺少必要的上传参数');
|
|
165
|
+
}
|
|
166
|
+
const results = {
|
|
167
|
+
success: [],
|
|
168
|
+
failed: []
|
|
169
|
+
};
|
|
170
|
+
try {
|
|
171
|
+
// 如果sourcePath是数组,批量上传多个文件
|
|
172
|
+
if (Array.isArray(sourcePath)) {
|
|
173
|
+
for (const filePath of sourcePath) {
|
|
174
|
+
const result = await uploadFile({
|
|
175
|
+
bucketName,
|
|
176
|
+
filePath,
|
|
177
|
+
destination: destination ? `${destination}/${path.basename(filePath)}` : undefined,
|
|
178
|
+
storageClient,
|
|
179
|
+
enableCompression
|
|
180
|
+
});
|
|
181
|
+
if (result.success) {
|
|
182
|
+
results.success.push(result);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
results.failed.push(result);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return results;
|
|
189
|
+
}
|
|
190
|
+
// 检查sourcePath是文件还是目录
|
|
191
|
+
const stats = await stat(sourcePath);
|
|
192
|
+
if (stats.isFile()) {
|
|
193
|
+
// 上传单个文件
|
|
194
|
+
const result = await uploadFile({
|
|
195
|
+
bucketName,
|
|
196
|
+
filePath: sourcePath,
|
|
197
|
+
destination,
|
|
198
|
+
storageClient,
|
|
199
|
+
enableCompression
|
|
200
|
+
});
|
|
201
|
+
if (result.success) {
|
|
202
|
+
results.success.push(result);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
results.failed.push(result);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else if (stats.isDirectory()) {
|
|
209
|
+
// 上传目录中的文件
|
|
210
|
+
const files = await readdir(sourcePath);
|
|
211
|
+
for (const file of files) {
|
|
212
|
+
const filePath = path.join(sourcePath, file);
|
|
213
|
+
const fileStats = await stat(filePath);
|
|
214
|
+
if (fileStats.isFile()) {
|
|
215
|
+
// 上传文件
|
|
216
|
+
const destPath = destination ? `${destination}/${file}` : file;
|
|
217
|
+
const result = await uploadFile({
|
|
218
|
+
bucketName,
|
|
219
|
+
filePath,
|
|
220
|
+
destination: destPath,
|
|
221
|
+
storageClient,
|
|
222
|
+
enableCompression
|
|
223
|
+
});
|
|
224
|
+
if (result.success) {
|
|
225
|
+
results.success.push(result);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
results.failed.push(result);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else if (recursive && fileStats.isDirectory()) {
|
|
232
|
+
// 递归上传子目录
|
|
233
|
+
const subDestination = destination ? `${destination}/${file}` : file;
|
|
234
|
+
const subResults = await uploadFiles({
|
|
235
|
+
bucketName,
|
|
236
|
+
sourcePath: filePath,
|
|
237
|
+
destination: subDestination,
|
|
238
|
+
storageClient,
|
|
239
|
+
recursive,
|
|
240
|
+
enableCompression
|
|
241
|
+
});
|
|
242
|
+
results.success = results.success.concat(subResults.success);
|
|
243
|
+
results.failed = results.failed.concat(subResults.failed);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return results;
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
throw new Error(`上传文件失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { StorageClientOptions, UploadFilesResult } from './types/upload';
|
|
2
|
+
/**
|
|
3
|
+
* 基于配置文件的上传选项
|
|
4
|
+
*/
|
|
5
|
+
export interface UploadWithConfigOptions {
|
|
6
|
+
/** 存储客户端配置选项 */
|
|
7
|
+
storageClientOptions?: Partial<StorageClientOptions>;
|
|
8
|
+
/** 配置文件路径,默认为项目根目录下的vs.config.json */
|
|
9
|
+
configPath?: string;
|
|
10
|
+
/** 是否递归上传子目录,默认为true */
|
|
11
|
+
recursive?: boolean;
|
|
12
|
+
/** 是否启用压缩,默认为true */
|
|
13
|
+
enableCompression?: boolean;
|
|
14
|
+
/** 自定义源路径,如果提供则覆盖配置文件中的uploadPath */
|
|
15
|
+
customSourcePath?: string;
|
|
16
|
+
/** 自定义目标路径,如果提供则覆盖配置文件中的目标路径 */
|
|
17
|
+
customDestination?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 基于配置文件批量上传文件
|
|
21
|
+
* @param options - 上传选项
|
|
22
|
+
* @returns 上传结果
|
|
23
|
+
*/
|
|
24
|
+
export declare function uploadFilesWithConfig(options?: UploadWithConfigOptions): Promise<UploadFilesResult>;
|
|
25
|
+
/**
|
|
26
|
+
* 获取配置信息(用于调试或显示)
|
|
27
|
+
* @param configPath - 配置文件路径
|
|
28
|
+
* @returns 配置信息摘要
|
|
29
|
+
*/
|
|
30
|
+
export declare function getConfigSummary(configPath?: string): {
|
|
31
|
+
bucketName: string;
|
|
32
|
+
sourcePath: string;
|
|
33
|
+
destination: string;
|
|
34
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uploadFilesWithConfig = uploadFilesWithConfig;
|
|
4
|
+
exports.getConfigSummary = getConfigSummary;
|
|
5
|
+
/**
|
|
6
|
+
* 基于配置文件的GCP上传功能模块
|
|
7
|
+
*/
|
|
8
|
+
const storage_1 = require("@google-cloud/storage");
|
|
9
|
+
const upload_1 = require("./upload");
|
|
10
|
+
const config_1 = require("./config");
|
|
11
|
+
/**
|
|
12
|
+
* 创建存储客户端
|
|
13
|
+
* @param options - 客户端配置选项
|
|
14
|
+
* @returns GCP存储客户端实例
|
|
15
|
+
*/
|
|
16
|
+
function createStorageClientFromConfig(options = {}) {
|
|
17
|
+
const { keyFilename, projectId, credentials } = options;
|
|
18
|
+
// 如果提供了keyFilename,使用密钥文件认证
|
|
19
|
+
if (keyFilename) {
|
|
20
|
+
return new storage_1.Storage({
|
|
21
|
+
keyFilename
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
// 如果提供了credentials,使用凭证对象认证
|
|
25
|
+
if (credentials) {
|
|
26
|
+
return new storage_1.Storage({
|
|
27
|
+
projectId,
|
|
28
|
+
credentials
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// 使用应用默认凭证(ADC)进行免密认证
|
|
32
|
+
return new storage_1.Storage();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 基于配置文件批量上传文件
|
|
36
|
+
* @param options - 上传选项
|
|
37
|
+
* @returns 上传结果
|
|
38
|
+
*/
|
|
39
|
+
async function uploadFilesWithConfig(options = {}) {
|
|
40
|
+
const { storageClientOptions = {}, configPath, recursive = true, enableCompression = true, customSourcePath, customDestination } = options;
|
|
41
|
+
try {
|
|
42
|
+
// 加载配置文件
|
|
43
|
+
const config = (0, config_1.loadConfig)(configPath);
|
|
44
|
+
// 创建存储客户端
|
|
45
|
+
const storageClient = createStorageClientFromConfig(storageClientOptions);
|
|
46
|
+
// 获取配置信息
|
|
47
|
+
const bucketName = (0, config_1.getBucketName)(config);
|
|
48
|
+
const sourcePath = customSourcePath || (0, config_1.getUploadSourcePath)(config);
|
|
49
|
+
const destination = customDestination || (0, config_1.getUploadDestination)(config);
|
|
50
|
+
console.log(`开始上传文件...`);
|
|
51
|
+
console.log(`源路径: ${sourcePath}`);
|
|
52
|
+
console.log(`目标桶: ${bucketName}`);
|
|
53
|
+
console.log(`目标路径: ${destination}`);
|
|
54
|
+
// 执行批量上传
|
|
55
|
+
const result = await (0, upload_1.uploadFiles)({
|
|
56
|
+
bucketName,
|
|
57
|
+
sourcePath,
|
|
58
|
+
destination,
|
|
59
|
+
storageClient,
|
|
60
|
+
recursive,
|
|
61
|
+
enableCompression
|
|
62
|
+
});
|
|
63
|
+
console.log(`上传完成! 成功: ${result.success.length}, 失败: ${result.failed.length}`);
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
throw new Error(`基于配置文件的上传失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 获取配置信息(用于调试或显示)
|
|
72
|
+
* @param configPath - 配置文件路径
|
|
73
|
+
* @returns 配置信息摘要
|
|
74
|
+
*/
|
|
75
|
+
function getConfigSummary(configPath) {
|
|
76
|
+
const config = (0, config_1.loadConfig)(configPath);
|
|
77
|
+
return {
|
|
78
|
+
bucketName: (0, config_1.getBucketName)(config),
|
|
79
|
+
sourcePath: (0, config_1.getUploadSourcePath)(config),
|
|
80
|
+
destination: (0, config_1.getUploadDestination)(config)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 需要进行GZIP压缩的文件扩展名
|
|
3
|
+
*/
|
|
4
|
+
export declare const COMPRESSIBLE_EXTENSIONS: string[];
|
|
5
|
+
/**
|
|
6
|
+
* 检查文件是否需要压缩
|
|
7
|
+
* @param filePath - 文件路径
|
|
8
|
+
* @returns 是否需要压缩
|
|
9
|
+
*/
|
|
10
|
+
export declare function shouldCompressFile(filePath: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* 使用GZIP压缩文件
|
|
13
|
+
* @param inputPath - 输入文件路径
|
|
14
|
+
* @returns 压缩后的临时文件路径
|
|
15
|
+
*/
|
|
16
|
+
export declare function compressFile(inputPath: string): Promise<string>;
|
|
@@ -0,0 +1,85 @@
|
|
|
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.COMPRESSIBLE_EXTENSIONS = void 0;
|
|
37
|
+
exports.shouldCompressFile = shouldCompressFile;
|
|
38
|
+
exports.compressFile = compressFile;
|
|
39
|
+
const fs_1 = require("fs");
|
|
40
|
+
const zlib = __importStar(require("zlib"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const util = __importStar(require("util"));
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
const stream_1 = require("stream");
|
|
45
|
+
const pipeline = util.promisify(stream_1.pipeline);
|
|
46
|
+
/**
|
|
47
|
+
* 需要进行GZIP压缩的文件扩展名
|
|
48
|
+
*/
|
|
49
|
+
exports.COMPRESSIBLE_EXTENSIONS = [
|
|
50
|
+
'.js',
|
|
51
|
+
'.css',
|
|
52
|
+
'.json',
|
|
53
|
+
'.html',
|
|
54
|
+
'.woff'
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* 检查文件是否需要压缩
|
|
58
|
+
* @param filePath - 文件路径
|
|
59
|
+
* @returns 是否需要压缩
|
|
60
|
+
*/
|
|
61
|
+
function shouldCompressFile(filePath) {
|
|
62
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
63
|
+
return exports.COMPRESSIBLE_EXTENSIONS.includes(ext);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 使用GZIP压缩文件
|
|
67
|
+
* @param inputPath - 输入文件路径
|
|
68
|
+
* @returns 压缩后的临时文件路径
|
|
69
|
+
*/
|
|
70
|
+
async function compressFile(inputPath) {
|
|
71
|
+
// 创建临时文件路径
|
|
72
|
+
const tempDir = os.tmpdir();
|
|
73
|
+
const fileName = path.basename(inputPath);
|
|
74
|
+
const outputPath = path.join(tempDir, `${fileName}.gz`);
|
|
75
|
+
// 创建读取流、GZIP压缩流和写入流
|
|
76
|
+
const gzip = zlib.createGzip();
|
|
77
|
+
try {
|
|
78
|
+
// 使用pipeline进行流处理
|
|
79
|
+
await pipeline((0, fs_1.createReadStream)(inputPath), gzip, (0, fs_1.createWriteStream)(outputPath));
|
|
80
|
+
return outputPath;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw new Error(`压缩文件失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|