dpu-cloud-sdk 1.0.0 → 1.0.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/README.md ADDED
@@ -0,0 +1,403 @@
1
+ # DPU Cloud SDK
2
+
3
+ A comprehensive TypeScript SDK for interacting with DPU (Data Processing Unit) storage services. This package provides upload, download, compression, and translation capabilities for file management in cloud environments.
4
+
5
+ ## Features
6
+
7
+ - 📁 **File Upload & Download** - Support for single and multi-part uploads with progress tracking
8
+ - 🗜️ **Compression** - Compress folders and monitor compression status
9
+ - 🌐 **Translation** - Translate files between different formats
10
+ - ⚙️ **Configurable Base URL** - Customize domain for different environments
11
+ - 🔐 **Token Management** - Built-in token refresh support
12
+ - 🚀 **Worker Threads** - Parallel file processing with automatic worker management
13
+ - ♻️ **Retry Logic** - Automatic retry with exponential backoff
14
+ - 📊 **Progress Tracking** - Real-time upload/download progress callbacks
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install dpu-cloud-sdk
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### Basic Setup
25
+
26
+ ```typescript
27
+ import { DPUClient } from 'dpu-cloud-sdk';
28
+
29
+ const client = new DPUClient(
30
+ accessToken,
31
+ refreshTokenCallback
32
+ );
33
+ ```
34
+
35
+ ### With Custom Base URL
36
+
37
+ ```typescript
38
+ import { DPUClient } from 'dpu-cloud-sdk';
39
+
40
+ const client = new DPUClient(
41
+ accessToken,
42
+ refreshTokenCallback,
43
+ 3, // maxRetry
44
+ 'https://your-custom-domain.com' // Custom base URL
45
+ );
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ ### Setting Base URL
51
+
52
+ There are multiple ways to configure the base URL:
53
+
54
+ #### 1. Via Constructor (Recommended)
55
+ ```typescript
56
+ const client = new DPUClient(
57
+ accessToken,
58
+ refreshTokenCallback,
59
+ maxRetry,
60
+ 'https://api.yourdomain.com'
61
+ );
62
+ ```
63
+
64
+ #### 2. Via dpuConfig (Global)
65
+ ```typescript
66
+ import { dpuConfig, DPUClient } from 'dpu-cloud-sdk';
67
+
68
+ // Set globally before creating client
69
+ dpuConfig.setBaseURL('https://api.yourdomain.com');
70
+
71
+ const client = new DPUClient(accessToken, refreshTokenCallback);
72
+ ```
73
+
74
+ #### 3. Via setConfig
75
+ ```typescript
76
+ import { dpuConfig } from 'dpu-cloud-sdk';
77
+
78
+ dpuConfig.setConfig({
79
+ baseURL: 'https://api.yourdomain.com'
80
+ });
81
+ ```
82
+
83
+ ### Environment-based Configuration
84
+
85
+ ```typescript
86
+ // For development
87
+ dpuConfig.setBaseURL(process.env.REACT_APP_API_URL || 'https://dev-api.yourdomain.com');
88
+
89
+ // For production
90
+ dpuConfig.setBaseURL('https://api.yourdomain.com');
91
+ ```
92
+
93
+ ## Usage Examples
94
+
95
+ ### File Upload
96
+
97
+ #### Single File Upload with Progress
98
+ ```typescript
99
+ import { DPUClient } from 'dpu-cloud-sdk';
100
+
101
+ const client = new DPUClient(accessToken, refreshTokenCallback);
102
+
103
+ const uploadedId = await client.uploadSingleFile(
104
+ bucketName,
105
+ fileKey,
106
+ file,
107
+ {
108
+ onProgress: (percentage) => {
109
+ console.log(`Upload progress: ${percentage}%`);
110
+ }
111
+ }
112
+ );
113
+ ```
114
+
115
+ #### Multiple Files Upload
116
+ ```typescript
117
+ const fileMap = new Map([
118
+ [fileKey1, file1],
119
+ [fileKey2, file2],
120
+ [fileKey3, file3]
121
+ ]);
122
+
123
+ const results = await client.uploadMultipleFiles(
124
+ bucketName,
125
+ fileMap,
126
+ {
127
+ onProgress: (fileKey, percentage) => {
128
+ console.log(`${fileKey}: ${percentage}%`);
129
+ }
130
+ }
131
+ );
132
+ ```
133
+
134
+ ### File Download
135
+
136
+ ```typescript
137
+ const downloadUrl = await client.getUrlToDownload(
138
+ bucketName,
139
+ fileName
140
+ );
141
+
142
+ // Download the file
143
+ window.location.href = downloadUrl;
144
+ ```
145
+
146
+ ### Compression
147
+
148
+ #### Compress Folder
149
+ ```typescript
150
+ const compressResult = await client.compressFolder(
151
+ bucketName,
152
+ folderPath,
153
+ {
154
+ onProgress: (status) => {
155
+ console.log('Compression status:', status);
156
+ }
157
+ }
158
+ );
159
+
160
+ console.log('Compression ID:', compressResult.dataId);
161
+ ```
162
+
163
+ #### Get Compression Status
164
+ ```typescript
165
+ const status = await client.getStatusCompress(compressionId);
166
+ console.log('Compression status:', status);
167
+ ```
168
+
169
+ ### Translation
170
+
171
+ #### Translate File
172
+ ```typescript
173
+ const translateRequest = {
174
+ bucketName: 'my-bucket',
175
+ fileName: 'document.pdf',
176
+ targetFormat: 'docx'
177
+ };
178
+
179
+ const translateResult = await client.translateFile(translateRequest);
180
+ console.log('Translation ID:', translateResult.dataId);
181
+ ```
182
+
183
+ #### Get Translation Status
184
+ ```typescript
185
+ const status = await client.getStatusTranslate(translateId);
186
+ console.log('Translation progress:', status.percentage);
187
+ ```
188
+
189
+ #### Get Translation Status for Specific File
190
+ ```typescript
191
+ const fileStatus = await client.getStatusTranslateFile(
192
+ translateId,
193
+ fileName
194
+ );
195
+ ```
196
+
197
+ ## API Methods
198
+
199
+ ### DPUClient Methods
200
+
201
+ #### Upload Methods
202
+ - `uploadSingleFile(bucketName, fileKey, file, options?)` - Upload a single file
203
+ - `uploadMultipleFiles(bucketName, fileMap, options?)` - Upload multiple files
204
+ - `uploadSingleFileWithCustomFileName(bucketName, customName, file, options?)` - Upload with custom name
205
+ - `uploadSingleFileWithInitUpload(bucketName, fileKey, file, options?)` - Upload with init upload
206
+
207
+ #### Download Methods
208
+ - `getUrlToDownload(bucketName, fileName)` - Get download URL
209
+ - `downloadSingleFile(bucketName, fileName, options?)` - Download file directly
210
+ - `downloadMultipleFiles(bucketName, fileNames, options?)` - Download multiple files
211
+
212
+ #### Compression Methods
213
+ - `compressFolder(bucketName, folderPath, options?)` - Compress a folder
214
+ - `getStatusCompress(compressionId)` - Check compression status
215
+ - `cancelCompressionDownload(compressionId)` - Cancel compression
216
+
217
+ #### Translation Methods
218
+ - `translateFile(request, options?)` - Start file translation
219
+ - `getStatusTranslate(translateId)` - Get translation status
220
+ - `getStatusTranslateFile(translateId, fileName)` - Get specific file translation status
221
+ - `getEPSGRegionCode(region)` - Get EPSG code for region
222
+ - `getFileTileSet(translateId)` - Get file tile set
223
+
224
+ #### Object Methods
225
+ - `getObjectDetail(bucketName, fileName)` - Get object details
226
+ - `getObjects(bucketName)` - List objects in bucket
227
+ - `applyPermissionToObjects(data)` - Apply permissions to objects
228
+
229
+ ## Configuration Options
230
+
231
+ ### DPUClient Constructor
232
+
233
+ ```typescript
234
+ new DPUClient(
235
+ accessToken?: string, // JWT access token
236
+ reFreshToken?: () => Promise<string>, // Callback to refresh token
237
+ maxRetry?: number, // Max retry attempts (default: 3)
238
+ baseURL?: string // Custom API base URL
239
+ )
240
+ ```
241
+
242
+ ### Upload Options
243
+
244
+ ```typescript
245
+ interface UploadOptions {
246
+ onProgress?: (percentage: number) => void;
247
+ cancellationToken?: AbortController;
248
+ fileKey?: string;
249
+ dataUploadId?: string;
250
+ }
251
+ ```
252
+
253
+ ### Download Options
254
+
255
+ ```typescript
256
+ interface DownloadOptions {
257
+ onProgress?: (loadedBytes: number, totalBytes: number) => void;
258
+ cancellationToken?: AbortController;
259
+ }
260
+ ```
261
+
262
+ ## Error Handling
263
+
264
+ The SDK includes built-in error handling with automatic retries for transient failures:
265
+
266
+ ```typescript
267
+ try {
268
+ const result = await client.uploadSingleFile(bucketName, fileKey, file);
269
+ console.log('Upload successful:', result);
270
+ } catch (error) {
271
+ console.error('Upload failed:', error.message);
272
+ // Handle error appropriately
273
+ }
274
+ ```
275
+
276
+ ### Common Error Status Codes
277
+
278
+ - `200` - Success
279
+ - `400` - Bad Request
280
+ - `401` - Unauthorized (Token expired or invalid)
281
+ - `403` - Forbidden (Insufficient permissions)
282
+ - `404` - Not Found (Resource doesn't exist)
283
+ - `500` - Internal Server Error
284
+
285
+ ## Token Management
286
+
287
+ ### Automatic Token Refresh
288
+
289
+ Provide a refresh token callback to automatically refresh tokens when they expire:
290
+
291
+ ```typescript
292
+ const refreshTokenCallback = async () => {
293
+ const response = await fetch('/api/refresh-token', {
294
+ method: 'POST',
295
+ headers: { 'Content-Type': 'application/json' }
296
+ });
297
+ const { token } = await response.json();
298
+ return token;
299
+ };
300
+
301
+ const client = new DPUClient(
302
+ initialAccessToken,
303
+ refreshTokenCallback
304
+ );
305
+ ```
306
+
307
+ ## Advanced Usage
308
+
309
+ ### Cancelling Operations
310
+
311
+ Use `AbortController` to cancel ongoing operations:
312
+
313
+ ```typescript
314
+ const cancellationToken = new AbortController();
315
+
316
+ setTimeout(() => {
317
+ cancellationToken.abort(); // Cancel after 5 seconds
318
+ }, 5000);
319
+
320
+ try {
321
+ await client.uploadSingleFile(
322
+ bucketName,
323
+ fileKey,
324
+ largeFile,
325
+ { cancellationToken }
326
+ );
327
+ } catch (error) {
328
+ if (error.name === 'AbortError') {
329
+ console.log('Upload cancelled');
330
+ }
331
+ }
332
+ ```
333
+
334
+ ### Parallel Uploads with Progress
335
+
336
+ ```typescript
337
+ const files = [file1, file2, file3];
338
+
339
+ const promises = files.map((file, index) =>
340
+ client.uploadSingleFile(
341
+ bucketName,
342
+ `file-${index}`,
343
+ file,
344
+ {
345
+ onProgress: (percentage) => {
346
+ console.log(`File ${index}: ${percentage}%`);
347
+ }
348
+ }
349
+ )
350
+ );
351
+
352
+ const results = await Promise.all(promises);
353
+ ```
354
+
355
+ ## Performance Tips
356
+
357
+ 1. **Use Multiple Files Upload** - More efficient for batch operations than individual uploads
358
+ 2. **Monitor Progress** - Implement progress callbacks for better UX
359
+ 3. **Optimize Chunk Size** - Default is 5MB per chunk (configurable)
360
+ 4. **Limit Concurrent Workers** - Default max 20 workers (adjust based on system resources)
361
+ 5. **Handle Token Refresh** - Implement token refresh callback to avoid interruptions
362
+
363
+ ## Browser Compatibility
364
+
365
+ - Chrome 90+
366
+ - Firefox 88+
367
+ - Safari 14+
368
+ - Edge 90+
369
+
370
+ ## TypeScript Support
371
+
372
+ This package is fully typed with TypeScript. All models and interfaces are exported:
373
+
374
+ ```typescript
375
+ import {
376
+ DPUClient,
377
+ dpuConfig,
378
+ InitUploadResponse,
379
+ PresignURLResponse,
380
+ TranslateInfo,
381
+ CompressStatus
382
+ } from 'dpu-cloud-sdk';
383
+ ```
384
+
385
+ ## Support & Documentation
386
+
387
+ For issues, questions, or contributions, please contact the development team or check the internal documentation.
388
+
389
+ ## License
390
+
391
+ ISC
392
+
393
+ ## Changelog
394
+
395
+ ### v1.0.0
396
+ - Initial release
397
+ - File upload/download functionality
398
+ - Compression support
399
+ - Translation support
400
+ - Configurable base URL
401
+ - Token refresh support
402
+ - Progress tracking
403
+ - Retry logic
@@ -43,7 +43,7 @@ export declare class DPUClient {
43
43
  uploadFileRetry(bucketName: string, file: File, cancellationToken: AbortController, onProgress?: (chunkUploaded: number) => void, maxWebWorker?: number, prefix?: string, initUpload?: InitUploadResponse, customFileName?: string, worker?: Worker, dataUploadId?: string): Promise<unknown>;
44
44
  uploadFile(bucketName: string, file: File, cancellationToken: AbortController, onProgress?: (chunkUploaded: number) => void, maxWebWorker?: number, prefix?: string, initUpload?: InitUploadResponse, customFileName?: string, worker?: Worker, dataUploadId?: string): Promise<unknown>;
45
45
  private runOnWorker;
46
- uploadFolderAferInit(filesInitiated: {
46
+ uploadFolderAfterInit(filesInitiated: {
47
47
  file: File;
48
48
  fileKey: string;
49
49
  path: string;
package/dist/DPUClient.js CHANGED
@@ -185,7 +185,7 @@ export class DPUClient {
185
185
  for (let index = 0; index < maxWorker; index++) {
186
186
  const channel = new MessageChannel();
187
187
  const worker = new Worker(new URL("workerUploadChildFile", import.meta.url));
188
- worker.postMessage({ port: channel.port2 }, [channel.port2]);
188
+ worker.postMessage({ port: channel.port2, baseURL: dpuConfig.getBaseURL() }, [channel.port2]);
189
189
  workerPorts.push(channel.port1);
190
190
  this.workersStatus.push({
191
191
  worker: worker,
@@ -346,7 +346,7 @@ export class DPUClient {
346
346
  for (let index = 0; index < maxWorker; index++) {
347
347
  const channel = new MessageChannel();
348
348
  const worker = new Worker(new URL("workerUploadChildFile", import.meta.url));
349
- worker.postMessage({ port: channel.port2 }, [channel.port2]);
349
+ worker.postMessage({ port: channel.port2, baseURL: dpuConfig.getBaseURL() }, [channel.port2]);
350
350
  workerPorts.push(channel.port1);
351
351
  this.workersStatus.push({
352
352
  worker: worker,
@@ -463,6 +463,7 @@ export class DPUClient {
463
463
  requestId: data.requestId,
464
464
  dataUploadId: data.dataUploadId,
465
465
  fileName: data.fileName,
466
+ baseURL: dpuConfig.getBaseURL(),
466
467
  };
467
468
  worker.postMessage(newData, [data.arrayBuffer]);
468
469
  // Cleanup abort handler when promise resolves or rejects
@@ -478,7 +479,7 @@ export class DPUClient {
478
479
  }
479
480
  //#endregion
480
481
  //#region Upload folder
481
- async uploadFolderAferInit(filesInitiated, cancellationToken, worker, dataUploadId, onProgress, maxWebWorker) {
482
+ async uploadFolderAfterInit(filesInitiated, cancellationToken, worker, dataUploadId, onProgress, maxWebWorker) {
482
483
  const bucketName = filesInitiated[0].path.split("/").at(0);
483
484
  if (!bucketName)
484
485
  return new Promise((resolve, reject) => {
@@ -690,7 +691,7 @@ export class DPUClient {
690
691
  for (let index = 0; index < maxWorker; index++) {
691
692
  const channel = new MessageChannel();
692
693
  const worker = new Worker(new URL("workerUploadSingleFile", import.meta.url));
693
- worker.postMessage({ port: channel.port2 }, [channel.port2]);
694
+ worker.postMessage({ port: channel.port2, baseURL: dpuConfig.getBaseURL() }, [channel.port2]);
694
695
  workerPorts.push(channel.port1);
695
696
  this.workersStatus.push({
696
697
  worker: worker,
@@ -821,6 +822,7 @@ export class DPUClient {
821
822
  isGetInfo: request.isGetInfo,
822
823
  preSignUrl: request.preSignUrl,
823
824
  dataUploadId: request.dataUploadId,
825
+ baseURL: dpuConfig.getBaseURL(),
824
826
  };
825
827
  worker.postMessage(newData, [request.arrayBuffer]);
826
828
  // Cleanup abort handler when promise resolves or rejects
@@ -1,12 +1,17 @@
1
1
  import { ApiStatus } from "./utils/Constants";
2
2
  import { Buffer } from "buffer";
3
3
  import { StatusWorker } from "./utils/Enum";
4
+ import { dpuConfig } from "./utils/Config";
4
5
  let abortController = null;
5
6
  let workerPortRoot = null;
6
7
  self.onmessage = async (message) => {
7
8
  const { data } = message;
8
9
  if (data.port) {
9
10
  workerPortRoot = data.port;
11
+ // Set baseURL if provided
12
+ if (data.baseURL) {
13
+ dpuConfig.setBaseURL(data.baseURL);
14
+ }
10
15
  }
11
16
  else {
12
17
  // Handle abort message
@@ -2,6 +2,7 @@ import { ConfigFileRules } from "./utils/Constants";
2
2
  import { Buffer } from "buffer";
3
3
  import { StatusWorker } from "./utils/Enum";
4
4
  import { ServiceIntegration } from "./ServiceIntegration";
5
+ import { dpuConfig } from "./utils/Config";
5
6
  let abortController = null;
6
7
  let workerPortRoot = null;
7
8
  // tạm thời chưa làm phần token
@@ -9,6 +10,10 @@ self.onmessage = async (message) => {
9
10
  const { data } = message;
10
11
  if (data.port) {
11
12
  workerPortRoot = data.port;
13
+ // Set baseURL if provided
14
+ if (data.baseURL) {
15
+ dpuConfig.setBaseURL(data.baseURL);
16
+ }
12
17
  }
13
18
  else {
14
19
  // Handle abort message
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dpu-cloud-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "main": "dist/index",
5
5
  "types": "dist/index",
6
6
  "scripts": {
package/src/DPUClient.ts CHANGED
@@ -343,7 +343,7 @@ export class DPUClient {
343
343
  const worker = new Worker(
344
344
  new URL("workerUploadChildFile", import.meta.url)
345
345
  );
346
- worker.postMessage({ port: channel.port2 }, [channel.port2]);
346
+ worker.postMessage({ port: channel.port2, baseURL: dpuConfig.getBaseURL() }, [channel.port2]);
347
347
  workerPorts.push(channel.port1);
348
348
  this.workersStatus.push({
349
349
  worker: worker,
@@ -585,7 +585,7 @@ export class DPUClient {
585
585
  const worker = new Worker(
586
586
  new URL("workerUploadChildFile", import.meta.url)
587
587
  );
588
- worker.postMessage({ port: channel.port2 }, [channel.port2]);
588
+ worker.postMessage({ port: channel.port2, baseURL: dpuConfig.getBaseURL() }, [channel.port2]);
589
589
  workerPorts.push(channel.port1);
590
590
  this.workersStatus.push({
591
591
  worker: worker,
@@ -728,6 +728,7 @@ export class DPUClient {
728
728
  requestId: data.requestId,
729
729
  dataUploadId: data.dataUploadId,
730
730
  fileName: data.fileName,
731
+ baseURL: dpuConfig.getBaseURL(),
731
732
  };
732
733
  worker.postMessage(newData, [data.arrayBuffer]);
733
734
 
@@ -746,7 +747,7 @@ export class DPUClient {
746
747
  }
747
748
  //#endregion
748
749
  //#region Upload folder
749
- public async uploadFolderAferInit(
750
+ public async uploadFolderAfterInit(
750
751
  filesInitiated: {
751
752
  file: File;
752
753
  fileKey: string;
@@ -1096,7 +1097,7 @@ export class DPUClient {
1096
1097
  const worker = new Worker(
1097
1098
  new URL("workerUploadSingleFile", import.meta.url)
1098
1099
  );
1099
- worker.postMessage({ port: channel.port2 }, [channel.port2]);
1100
+ worker.postMessage({ port: channel.port2, baseURL: dpuConfig.getBaseURL() }, [channel.port2]);
1100
1101
  workerPorts.push(channel.port1);
1101
1102
  this.workersStatus.push({
1102
1103
  worker: worker,
@@ -1254,6 +1255,7 @@ export class DPUClient {
1254
1255
  isGetInfo: request.isGetInfo,
1255
1256
  preSignUrl: request.preSignUrl,
1256
1257
  dataUploadId: request.dataUploadId,
1258
+ baseURL: dpuConfig.getBaseURL(),
1257
1259
  };
1258
1260
  worker.postMessage(newData, [request.arrayBuffer]);
1259
1261
 
@@ -1,6 +1,7 @@
1
1
  import { ApiStatus } from "./utils/Constants";
2
2
  import { Buffer } from "buffer";
3
3
  import { StatusWorker } from "./utils/Enum";
4
+ import { dpuConfig } from "./utils/Config";
4
5
 
5
6
  let abortController: AbortController | null = null;
6
7
  let workerPortRoot: MessagePort | null = null;
@@ -9,6 +10,10 @@ self.onmessage = async (message) => {
9
10
  const { data } = message;
10
11
  if (data.port) {
11
12
  workerPortRoot = data.port;
13
+ // Set baseURL if provided
14
+ if (data.baseURL) {
15
+ dpuConfig.setBaseURL(data.baseURL);
16
+ }
12
17
  } else {
13
18
  // Handle abort message
14
19
  if (data.type === "abort") {
@@ -2,6 +2,7 @@ import { ConfigFileRules, ApiStatus } from "./utils/Constants";
2
2
  import { Buffer } from "buffer";
3
3
  import { StatusWorker } from "./utils/Enum";
4
4
  import { ServiceIntegration } from "./ServiceIntegration";
5
+ import { dpuConfig } from "./utils/Config";
5
6
 
6
7
  let abortController: AbortController | null = null;
7
8
  let workerPortRoot: MessagePort | null = null;
@@ -11,6 +12,10 @@ self.onmessage = async (message) => {
11
12
  const { data } = message;
12
13
  if (data.port) {
13
14
  workerPortRoot = data.port;
15
+ // Set baseURL if provided
16
+ if (data.baseURL) {
17
+ dpuConfig.setBaseURL(data.baseURL);
18
+ }
14
19
  } else {
15
20
  // Handle abort message
16
21
  if (data.type === "abort") {