@seaverse/utils-sdk 0.1.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/dist/client.js ADDED
@@ -0,0 +1,255 @@
1
+ /**
2
+ * SeaVerse Utils SDK Client
3
+ */
4
+ import axios from 'axios';
5
+ import { UtilsAPIError, ErrorCode, } from './models.js';
6
+ import { compressImage, shouldCompress } from './compress.js';
7
+ import { validateFile, isImageFile, handleAxiosError, createUploadError, ProgressTracker, } from './utils.js';
8
+ /**
9
+ * SeaVerse Utils API Client
10
+ *
11
+ * 提供文件上传、图片压缩等功能,支持多租户隔离。
12
+ * 自动处理预签名 URL 上传流程:
13
+ * 1. 获取预签名 URL
14
+ * 2. 直接上传到 GCS
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const client = new UtilsClient({
19
+ * token: 'your-bearer-token'
20
+ * });
21
+ *
22
+ * const file = document.querySelector('input[type="file"]').files[0];
23
+ * const result = await client.uploadFile(file, {
24
+ * onProgress: (progress) => {
25
+ * console.log(`${progress.percent}% - ${progress.stage}`);
26
+ * }
27
+ * });
28
+ *
29
+ * console.log('CDN URL:', result.cdnUrl);
30
+ * ```
31
+ */
32
+ export class UtilsClient {
33
+ constructor(options) {
34
+ // 初始化 axios 实例
35
+ this.axios = axios.create({
36
+ baseURL: options.baseURL || 'https://resource.seaverse.ai',
37
+ timeout: options.timeout || 60000,
38
+ headers: {
39
+ 'Content-Type': 'application/json',
40
+ Authorization: `Bearer ${options.token}`,
41
+ },
42
+ });
43
+ // 初始化压缩配置
44
+ this.compressionConfig = {
45
+ enabled: options.compress?.enabled ?? true,
46
+ maxWidth: options.compress?.maxWidth ?? 1080,
47
+ maxHeight: options.compress?.maxHeight ?? 1080,
48
+ quality: options.compress?.quality ?? 0.8,
49
+ };
50
+ // 响应拦截器:统一错误处理
51
+ this.axios.interceptors.response.use((response) => response, (error) => {
52
+ throw handleAxiosError(error);
53
+ });
54
+ }
55
+ /**
56
+ * 上传文件
57
+ *
58
+ * 自动处理完整的上传流程:
59
+ * 1. 文件验证
60
+ * 2. 图片压缩(如果启用)
61
+ * 3. 获取预签名 URL
62
+ * 4. 上传到 GCS
63
+ *
64
+ * @param file - 要上传的文件
65
+ * @param options - 上传选项
66
+ * @returns 上传结果
67
+ * @throws {UtilsAPIError} 上传失败时抛出错误
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * const result = await client.uploadFile(file, {
72
+ * onProgress: (progress) => {
73
+ * console.log(`上传进度: ${progress.percent}%`);
74
+ * },
75
+ * compress: true
76
+ * });
77
+ * ```
78
+ */
79
+ async uploadFile(file, options) {
80
+ const startTime = Date.now();
81
+ const originalSize = file.size;
82
+ let processedFile = file;
83
+ let compressed = false;
84
+ try {
85
+ // 步骤 1: 准备阶段
86
+ options?.onProgress?.({
87
+ loaded: 0,
88
+ total: file.size,
89
+ percent: 0,
90
+ stage: 'preparing',
91
+ });
92
+ // 步骤 2: 文件验证
93
+ const validationResult = validateFile(file);
94
+ if (!validationResult.valid) {
95
+ throw createUploadError(ErrorCode.VALIDATION_FAILED, validationResult.errors.join('; '));
96
+ }
97
+ // 步骤 3: 图片压缩(如果需要)
98
+ const shouldCompressFile = options?.compress !== false &&
99
+ shouldCompress(file, this.compressionConfig);
100
+ if (shouldCompressFile && isImageFile(file)) {
101
+ options?.onProgress?.({
102
+ loaded: 0,
103
+ total: file.size,
104
+ percent: 5,
105
+ stage: 'compressing',
106
+ });
107
+ const compressionResult = await compressImage(file, this.compressionConfig);
108
+ processedFile = compressionResult.compressedFile;
109
+ compressed = true;
110
+ }
111
+ // 步骤 4: 获取预签名 URL
112
+ const presignedData = await this.getPresignedUrl(processedFile.type);
113
+ // 步骤 5: 上传到 GCS
114
+ options?.onProgress?.({
115
+ loaded: 0,
116
+ total: processedFile.size,
117
+ percent: 10,
118
+ stage: 'uploading',
119
+ });
120
+ await this.uploadToPresignedUrl(presignedData.data.upload_url, processedFile, options?.onProgress);
121
+ // 步骤 6: 返回结果
122
+ const duration = Date.now() - startTime;
123
+ const result = {
124
+ fileName: file.name,
125
+ originalFileName: file.name,
126
+ cdnUrl: presignedData.data.cdn_url,
127
+ objectPath: presignedData.data.object_path,
128
+ fileSize: processedFile.size,
129
+ originalSize,
130
+ compressed,
131
+ contentType: processedFile.type,
132
+ duration,
133
+ expiresAt: presignedData.data.expires_at,
134
+ };
135
+ options?.onProgress?.({
136
+ loaded: processedFile.size,
137
+ total: processedFile.size,
138
+ percent: 100,
139
+ stage: 'complete',
140
+ });
141
+ return result;
142
+ }
143
+ catch (error) {
144
+ if (error instanceof UtilsAPIError) {
145
+ throw error;
146
+ }
147
+ throw createUploadError(ErrorCode.UPLOAD_FAILED, `上传失败: ${error instanceof Error ? error.message : '未知错误'}`);
148
+ }
149
+ }
150
+ /**
151
+ * 获取预签名 URL
152
+ *
153
+ * @param contentType - 文件 MIME 类型
154
+ * @returns 预签名 URL 响应
155
+ * @throws {UtilsAPIError} 请求失败时抛出错误
156
+ */
157
+ async getPresignedUrl(contentType) {
158
+ try {
159
+ const request = {
160
+ content_type: contentType,
161
+ };
162
+ const response = await this.axios.post('/api/v1/resources/presign-upload', request);
163
+ if (response.data.code !== 0) {
164
+ throw createUploadError(ErrorCode.PRESIGNED_URL_FAILED, response.data.message || '获取预签名 URL 失败', response.status, response.data);
165
+ }
166
+ return response.data;
167
+ }
168
+ catch (error) {
169
+ if (error instanceof UtilsAPIError) {
170
+ throw error;
171
+ }
172
+ throw createUploadError(ErrorCode.PRESIGNED_URL_FAILED, `获取预签名 URL 失败: ${error instanceof Error ? error.message : '未知错误'}`);
173
+ }
174
+ }
175
+ /**
176
+ * 上传文件到预签名 URL
177
+ *
178
+ * 使用 XMLHttpRequest 实现,以支持上传进度回调
179
+ *
180
+ * @param uploadUrl - 预签名 URL
181
+ * @param file - 要上传的文件
182
+ * @param onProgress - 进度回调函数
183
+ * @throws {UtilsAPIError} 上传失败时抛出错误
184
+ */
185
+ async uploadToPresignedUrl(uploadUrl, file, onProgress) {
186
+ return new Promise((resolve, reject) => {
187
+ const xhr = new XMLHttpRequest();
188
+ const tracker = new ProgressTracker();
189
+ // 进度事件
190
+ xhr.upload.addEventListener('progress', (e) => {
191
+ if (e.lengthComputable && onProgress) {
192
+ const { speed, remainingTime } = tracker.calculate(e.loaded, e.total);
193
+ onProgress({
194
+ loaded: e.loaded,
195
+ total: e.total,
196
+ percent: Math.round((e.loaded / e.total) * 100),
197
+ stage: 'uploading',
198
+ speed,
199
+ remainingTime,
200
+ });
201
+ }
202
+ });
203
+ // 成功
204
+ xhr.addEventListener('load', () => {
205
+ if (xhr.status >= 200 && xhr.status < 300) {
206
+ resolve();
207
+ }
208
+ else {
209
+ reject(createUploadError(ErrorCode.UPLOAD_FAILED, `上传失败,HTTP 状态码: ${xhr.status}`, xhr.status));
210
+ }
211
+ });
212
+ // 错误
213
+ xhr.addEventListener('error', () => {
214
+ reject(createUploadError(ErrorCode.NETWORK_ERROR, '网络错误,上传失败'));
215
+ });
216
+ // 超时
217
+ xhr.addEventListener('timeout', () => {
218
+ reject(createUploadError(ErrorCode.TIMEOUT, '上传超时'));
219
+ });
220
+ // 发送请求
221
+ xhr.open('PUT', uploadUrl);
222
+ xhr.setRequestHeader('Content-Type', file.type);
223
+ xhr.timeout = this.axios.defaults.timeout;
224
+ xhr.send(file);
225
+ });
226
+ }
227
+ /**
228
+ * 更新 Bearer Token
229
+ *
230
+ * @param token - 新的 Bearer Token
231
+ */
232
+ setToken(token) {
233
+ this.axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
234
+ }
235
+ /**
236
+ * 更新基础 URL
237
+ *
238
+ * @param baseURL - 新的基础 URL
239
+ */
240
+ setBaseURL(baseURL) {
241
+ this.axios.defaults.baseURL = baseURL;
242
+ }
243
+ /**
244
+ * 更新压缩配置
245
+ *
246
+ * @param config - 新的压缩配置
247
+ */
248
+ updateCompressionConfig(config) {
249
+ this.compressionConfig = {
250
+ ...this.compressionConfig,
251
+ ...config,
252
+ };
253
+ }
254
+ }
255
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Image compression utilities for SeaVerse Utils SDK
3
+ */
4
+ import { CompressionConfig, CompressionResult } from './models.js';
5
+ /**
6
+ * 压缩图片文件
7
+ * @param file - 要压缩的图片文件
8
+ * @param config - 压缩配置
9
+ * @returns 压缩结果
10
+ */
11
+ export declare function compressImage(file: File, config?: CompressionConfig): Promise<CompressionResult>;
12
+ /**
13
+ * 检查是否需要压缩
14
+ * @param file - 文件对象
15
+ * @param config - 压缩配置
16
+ * @returns 是否需要压缩
17
+ */
18
+ export declare function shouldCompress(file: File, config?: CompressionConfig): boolean;
19
+ //# sourceMappingURL=compress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAa,MAAM,aAAa,CAAC;AAG9E;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,iBAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAwC5B;AA+HD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,iBAAiB,GACzB,OAAO,CAoBT"}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Image compression utilities for SeaVerse Utils SDK
3
+ */
4
+ import { ErrorCode } from './models.js';
5
+ import { createUploadError, isImageFile } from './utils.js';
6
+ /**
7
+ * 压缩图片文件
8
+ * @param file - 要压缩的图片文件
9
+ * @param config - 压缩配置
10
+ * @returns 压缩结果
11
+ */
12
+ export async function compressImage(file, config) {
13
+ // 验证是否为图片
14
+ if (!isImageFile(file)) {
15
+ throw createUploadError(ErrorCode.COMPRESSION_FAILED, `无法压缩非图片文件: ${file.type}`);
16
+ }
17
+ // 默认配置
18
+ const defaultConfig = {
19
+ enabled: true,
20
+ maxWidth: 1080,
21
+ maxHeight: 1080,
22
+ quality: 0.8,
23
+ };
24
+ const finalConfig = { ...defaultConfig, ...config };
25
+ // 如果禁用压缩,直接返回原文件
26
+ if (!finalConfig.enabled) {
27
+ return {
28
+ originalFile: file,
29
+ compressedFile: file,
30
+ originalSize: file.size,
31
+ compressedSize: file.size,
32
+ compressionRatio: 1,
33
+ width: 0,
34
+ height: 0,
35
+ };
36
+ }
37
+ try {
38
+ return await performCompression(file, finalConfig);
39
+ }
40
+ catch (error) {
41
+ throw createUploadError(ErrorCode.COMPRESSION_FAILED, `图片压缩失败: ${error instanceof Error ? error.message : '未知错误'}`);
42
+ }
43
+ }
44
+ /**
45
+ * 执行图片压缩
46
+ * @param file - 原始文件
47
+ * @param config - 压缩配置
48
+ * @returns 压缩结果
49
+ */
50
+ async function performCompression(file, config) {
51
+ return new Promise((resolve, reject) => {
52
+ const reader = new FileReader();
53
+ reader.onload = (e) => {
54
+ const img = new Image();
55
+ img.onload = () => {
56
+ try {
57
+ // 检查浏览器是否支持 Canvas
58
+ if (typeof document === 'undefined' || !document.createElement) {
59
+ reject(new Error('当前环境不支持图片压缩功能(需要浏览器环境)'));
60
+ return;
61
+ }
62
+ const { width, height } = calculateDimensions(img.width, img.height, config.maxWidth, config.maxHeight);
63
+ // 创建 Canvas
64
+ const canvas = document.createElement('canvas');
65
+ const ctx = canvas.getContext('2d');
66
+ if (!ctx) {
67
+ reject(new Error('无法创建 Canvas 2D 上下文,您的浏览器可能不支持此功能'));
68
+ return;
69
+ }
70
+ canvas.width = width;
71
+ canvas.height = height;
72
+ // 绘制缩放后的图片
73
+ ctx.drawImage(img, 0, 0, width, height);
74
+ // 转换为 Blob
75
+ canvas.toBlob((blob) => {
76
+ if (!blob) {
77
+ reject(new Error('图片转换为 Blob 失败'));
78
+ return;
79
+ }
80
+ const compressedFile = new File([blob], file.name, {
81
+ type: file.type,
82
+ lastModified: Date.now(),
83
+ });
84
+ resolve({
85
+ originalFile: file,
86
+ compressedFile,
87
+ originalSize: file.size,
88
+ compressedSize: compressedFile.size,
89
+ compressionRatio: compressedFile.size / file.size,
90
+ width,
91
+ height,
92
+ });
93
+ }, file.type, config.quality);
94
+ }
95
+ catch (error) {
96
+ reject(error);
97
+ }
98
+ };
99
+ img.onerror = () => {
100
+ reject(new Error('图片加载失败'));
101
+ };
102
+ img.src = e.target?.result;
103
+ };
104
+ reader.onerror = () => {
105
+ reject(new Error('文件读取失败'));
106
+ };
107
+ reader.readAsDataURL(file);
108
+ });
109
+ }
110
+ /**
111
+ * 计算缩放后的尺寸(保持宽高比)
112
+ * @param originalWidth - 原始宽度
113
+ * @param originalHeight - 原始高度
114
+ * @param maxWidth - 最大宽度
115
+ * @param maxHeight - 最大高度
116
+ * @returns 缩放后的尺寸
117
+ */
118
+ function calculateDimensions(originalWidth, originalHeight, maxWidth, maxHeight) {
119
+ let width = originalWidth;
120
+ let height = originalHeight;
121
+ // 如果尺寸在限制内,不需要缩放
122
+ if (width <= maxWidth && height <= maxHeight) {
123
+ return { width, height };
124
+ }
125
+ // 计算缩放比例
126
+ const widthRatio = maxWidth / width;
127
+ const heightRatio = maxHeight / height;
128
+ const ratio = Math.min(widthRatio, heightRatio);
129
+ width = Math.round(width * ratio);
130
+ height = Math.round(height * ratio);
131
+ return { width, height };
132
+ }
133
+ /**
134
+ * 检查是否需要压缩
135
+ * @param file - 文件对象
136
+ * @param config - 压缩配置
137
+ * @returns 是否需要压缩
138
+ */
139
+ export function shouldCompress(file, config) {
140
+ const defaultConfig = {
141
+ enabled: true,
142
+ maxWidth: 1080,
143
+ maxHeight: 1080,
144
+ };
145
+ const finalConfig = { ...defaultConfig, ...config };
146
+ // 如果禁用压缩或不是图片,不压缩
147
+ if (!finalConfig.enabled || !isImageFile(file)) {
148
+ return false;
149
+ }
150
+ // 可以添加更多判断逻辑,例如:
151
+ // - 文件大小超过阈值
152
+ // - 文件尺寸超过最大值
153
+ // 目前简单返回 true,让 compressImage 内部判断
154
+ return true;
155
+ }
156
+ //# sourceMappingURL=compress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress.js","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * SeaVerse Utils SDK
3
+ *
4
+ * 通用工具集合,包含文件上传、图片压缩等功能
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export { UtilsClient } from './client.js';
9
+ export type { UtilsClientOptions, CompressionConfig, UploadOptions, UploadProgress, UploadResult, PresignUploadRequest, PresignUploadData, PresignUploadResponse, ValidationResult, ValidationRules, CompressionResult, ErrorCodeType, } from './models.js';
10
+ export { UtilsAPIError, ErrorCode } from './models.js';
11
+ export { validateFile, formatBytes, isImageFile, getFileExtension, } from './utils.js';
12
+ export { compressImage, shouldCompress } from './compress.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,aAAa,GACd,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGvD,OAAO,EACL,YAAY,EACZ,WAAW,EACX,WAAW,EACX,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * SeaVerse Utils SDK
3
+ *
4
+ * 通用工具集合,包含文件上传、图片压缩等功能
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ // 导出核心客户端
9
+ export { UtilsClient } from './client.js';
10
+ // 导出错误类和错误码
11
+ export { UtilsAPIError, ErrorCode } from './models.js';
12
+ // 导出工具函数
13
+ export { validateFile, formatBytes, isImageFile, getFileExtension, } from './utils.js';
14
+ // 导出压缩函数
15
+ export { compressImage, shouldCompress } from './compress.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,UAAU;AACV,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkB1C,YAAY;AACZ,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvD,SAAS;AACT,OAAO,EACL,YAAY,EACZ,WAAW,EACX,WAAW,EACX,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAEpB,SAAS;AACT,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}