@wlindabla/file_uploader 2.0.0 → 2.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 +3 -8
- package/dist/cjs/core/index.d.ts +7 -3
- package/dist/cjs/core/index.js +20 -11
- package/dist/cjs/core/index.js.map +1 -1
- package/dist/cjs/events/complete/index.d.ts +2 -1
- package/dist/cjs/events/complete/index.js.map +1 -1
- package/dist/cjs/events/index.d.ts +1 -0
- package/dist/cjs/events/initialize/index.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/subscribers/index.d.ts +1 -0
- package/dist/cjs/subscribers/index.js.map +1 -1
- package/dist/esm/{chunk-DN5B6PRW.js → chunk-3JTTZCSQ.js} +2 -2
- package/dist/esm/{chunk-DN5B6PRW.js.map → chunk-3JTTZCSQ.js.map} +1 -1
- package/dist/esm/{chunk-LTYMA4U4.js → chunk-BNMI7DW3.js} +2 -2
- package/dist/esm/chunk-BNMI7DW3.js.map +1 -0
- package/dist/esm/{chunk-332NNKOW.js → chunk-HYNJBWW5.js} +4 -4
- package/dist/esm/chunk-HYNJBWW5.js.map +1 -0
- package/dist/esm/{chunk-6DIKDA6J.js → chunk-TONVXBLH.js} +22 -13
- package/dist/esm/chunk-TONVXBLH.js.map +1 -0
- package/dist/esm/core/index.d.mts +7 -3
- package/dist/esm/core/index.js +3 -3
- package/dist/esm/events/complete/index.d.mts +2 -1
- package/dist/esm/events/complete/index.js +1 -1
- package/dist/esm/events/index.d.mts +1 -0
- package/dist/esm/events/index.js +2 -2
- package/dist/esm/events/initialize/index.js +1 -1
- package/dist/esm/index.d.mts +1 -0
- package/dist/esm/index.js +4 -4
- package/dist/esm/subscribers/index.d.mts +1 -0
- package/dist/esm/subscribers/index.js +3 -3
- package/package.json +10 -10
- package/dist/esm/chunk-332NNKOW.js.map +0 -1
- package/dist/esm/chunk-6DIKDA6J.js.map +0 -1
- package/dist/esm/chunk-LTYMA4U4.js.map +0 -1
package/README.md
CHANGED
|
@@ -319,8 +319,7 @@ The main class. Implements `ChunkedFileUploaderInterface`.
|
|
|
319
319
|
new ChunkedFileUploader(
|
|
320
320
|
uploadEventDispatcher: EventDispatcherInterface,
|
|
321
321
|
uploadResumeData: UploadResumeCacheInterface,
|
|
322
|
-
options: UploadOptions
|
|
323
|
-
logger?: LoggerInterface
|
|
322
|
+
options: UploadOptions
|
|
324
323
|
)
|
|
325
324
|
```
|
|
326
325
|
|
|
@@ -329,7 +328,6 @@ new ChunkedFileUploader(
|
|
|
329
328
|
| `uploadEventDispatcher` | `EventDispatcherInterface` | ✅ | Dispatcher for upload lifecycle events |
|
|
330
329
|
| `uploadResumeData` | `UploadResumeCacheInterface` | ✅ | Cache implementation for resumable uploads |
|
|
331
330
|
| `options` | `UploadOptions` | ✅ | Upload configuration options |
|
|
332
|
-
| `logger` | `LoggerInterface` | ❌ | Custom logger (default: `NoopLogger`) |
|
|
333
331
|
|
|
334
332
|
#### Methods
|
|
335
333
|
|
|
@@ -1758,8 +1756,7 @@ class MonitoringLogger implements LoggerInterface {
|
|
|
1758
1756
|
const uploader = new ChunkedFileUploader(
|
|
1759
1757
|
dispatcher,
|
|
1760
1758
|
cache,
|
|
1761
|
-
options
|
|
1762
|
-
new MonitoringLogger()
|
|
1759
|
+
options
|
|
1763
1760
|
);
|
|
1764
1761
|
```
|
|
1765
1762
|
|
|
@@ -1869,8 +1866,7 @@ const uploader = new ChunkedFileUploader(
|
|
|
1869
1866
|
maxRetries: 3,
|
|
1870
1867
|
autoSave: true,
|
|
1871
1868
|
timeout: 60000
|
|
1872
|
-
}
|
|
1873
|
-
new ConsoleLogger()
|
|
1869
|
+
}
|
|
1874
1870
|
);
|
|
1875
1871
|
|
|
1876
1872
|
// Wire up DOM
|
|
@@ -1912,7 +1908,6 @@ import {
|
|
|
1912
1908
|
HttpFileUploaderEvents,
|
|
1913
1909
|
UploadProgressEvent,
|
|
1914
1910
|
UploadMediaCompleteEvent,
|
|
1915
|
-
ConsoleLogger
|
|
1916
1911
|
} from '@wlindabla/file_uploader/events';
|
|
1917
1912
|
|
|
1918
1913
|
import {
|
package/dist/cjs/core/index.d.ts
CHANGED
|
@@ -151,7 +151,7 @@ import '@wlindabla/http_client';
|
|
|
151
151
|
* @linkedin https://www.linkedin.com/in/internationales-web-apps-services-120520193/
|
|
152
152
|
* @github https://github.com/Agbokoudjo/file_uploader
|
|
153
153
|
*
|
|
154
|
-
* @version
|
|
154
|
+
* @version 2.0.1
|
|
155
155
|
* @since 1.0.0
|
|
156
156
|
* @license MIT
|
|
157
157
|
*
|
|
@@ -177,8 +177,12 @@ declare class ChunkedFileUploader {
|
|
|
177
177
|
private percentage;
|
|
178
178
|
private uploadedChunks;
|
|
179
179
|
private lastUploadedChunkIndex;
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
/**
|
|
181
|
+
* @param _uploadEventDispatcher: new BrowserEventDispatcher(), //or new NodeJSEventDispatcher() if you have an environment NodeJs
|
|
182
|
+
* @param uploadResumeData: UploadResumeCacheInterface
|
|
183
|
+
* @param options: UploadOptions
|
|
184
|
+
*/
|
|
185
|
+
constructor(_uploadEventDispatcher: EventDispatcherInterface, uploadResumeData: UploadResumeCacheInterface, options: UploadOptions);
|
|
182
186
|
/**
|
|
183
187
|
* Starts the chunked file upload process.
|
|
184
188
|
*
|
package/dist/cjs/core/index.js
CHANGED
|
@@ -32,8 +32,7 @@ __export(core_exports, {
|
|
|
32
32
|
ChunkedFileUploader: () => ChunkedFileUploader
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(core_exports);
|
|
35
|
-
var
|
|
36
|
-
var import_http_client = require("@wlindabla/http_client");
|
|
35
|
+
var import_core = require("@wlindabla/http_client/core");
|
|
37
36
|
var import_types = require("../types");
|
|
38
37
|
var import_utils = require("../utils");
|
|
39
38
|
var import_events = require("../events");
|
|
@@ -187,7 +186,7 @@ var import_p_limit = __toESM(require("p-limit"));
|
|
|
187
186
|
* @linkedin https://www.linkedin.com/in/internationales-web-apps-services-120520193/
|
|
188
187
|
* @github https://github.com/Agbokoudjo/file_uploader
|
|
189
188
|
*
|
|
190
|
-
* @version
|
|
189
|
+
* @version 2.0.1
|
|
191
190
|
* @since 1.0.0
|
|
192
191
|
* @license MIT
|
|
193
192
|
*
|
|
@@ -199,7 +198,12 @@ var import_p_limit = __toESM(require("p-limit"));
|
|
|
199
198
|
* @see {@link https://github.com/Agbokoudjo/file_uploader | GitHub Repository}
|
|
200
199
|
*/
|
|
201
200
|
class ChunkedFileUploader {
|
|
202
|
-
|
|
201
|
+
/**
|
|
202
|
+
* @param _uploadEventDispatcher: new BrowserEventDispatcher(), //or new NodeJSEventDispatcher() if you have an environment NodeJs
|
|
203
|
+
* @param uploadResumeData: UploadResumeCacheInterface
|
|
204
|
+
* @param options: UploadOptions
|
|
205
|
+
*/
|
|
206
|
+
constructor(_uploadEventDispatcher, uploadResumeData, options) {
|
|
203
207
|
this._uploadEventDispatcher = _uploadEventDispatcher;
|
|
204
208
|
this.uploadResumeData = uploadResumeData;
|
|
205
209
|
this.options = options;
|
|
@@ -260,17 +264,22 @@ class ChunkedFileUploader {
|
|
|
260
264
|
headerInitialzingUpload,
|
|
261
265
|
concurrency = 3
|
|
262
266
|
} = this.options;
|
|
263
|
-
|
|
264
|
-
|
|
267
|
+
let file;
|
|
268
|
+
try {
|
|
269
|
+
file = this.file;
|
|
270
|
+
} catch (error) {
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
const fileHash = await import_utils.FileUtils.generateFileHash(this.file);
|
|
265
274
|
let fileId;
|
|
266
275
|
try {
|
|
267
276
|
const initializationEvent = await this._uploadEventDispatcher.dispatchAsync(
|
|
268
277
|
new import_events.InitializingUploadEvent(
|
|
269
278
|
{
|
|
270
279
|
fileHash,
|
|
271
|
-
fileName:
|
|
272
|
-
fileSize:
|
|
273
|
-
fileType:
|
|
280
|
+
fileName: file.name,
|
|
281
|
+
fileSize: file.size,
|
|
282
|
+
fileType: file.type,
|
|
274
283
|
metadata,
|
|
275
284
|
endpointInit: this.endPointOptions.init,
|
|
276
285
|
headers: headerInitialzingUpload
|
|
@@ -474,7 +483,7 @@ class ChunkedFileUploader {
|
|
|
474
483
|
attempt: attempt + 1,
|
|
475
484
|
willRetry: attempt < maxRetries - 1
|
|
476
485
|
};
|
|
477
|
-
if (error instanceof
|
|
486
|
+
if (error instanceof import_core.HttpFetchError) {
|
|
478
487
|
this._uploadEventDispatcher.dispatch(chunkError, import_events.HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_FAILED);
|
|
479
488
|
}
|
|
480
489
|
if (attempt < maxRetries - 1) {
|
|
@@ -515,7 +524,7 @@ class ChunkedFileUploader {
|
|
|
515
524
|
}
|
|
516
525
|
);
|
|
517
526
|
try {
|
|
518
|
-
const response_of_server = await (0,
|
|
527
|
+
const response_of_server = await (0, import_core.safeFetch)({
|
|
519
528
|
url: this.endPointOptions.upload,
|
|
520
529
|
headers: this.options.headers,
|
|
521
530
|
data: chunkFormData,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/index.ts"],"sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n BrowserEventDispatcher,\n EventDispatcherInterface\n} from \"@wlindabla/event_dispatcher\";\n\nimport {\n FetchResponseInterface,\n safeFetch,\n HttpFetchError\n} from \"@wlindabla/http_client\";\n\nimport {\n ChunkError,\n ChunkInfo,\n ResumeData,\n UploadEndpoints,\n UploadOptions,\n UploadProgress,\n UploadResult,\n UploadState\n} from \"../types\";\n\nimport { UploadResumeCacheInterface } from \"../cache\";\nimport {\n FileUtils,\n createChunkFormData\n} from \"../utils\";\n\nimport {\n ChunkUploadHttpErrorResponseEvent,\n HttpFileUploaderEvents,\n InitializingUploadEvent,\n UploadCancelledEvent,\n UploadProgressEvent,\n UploadStateChangedEvent,\n UploadChunkStartedEvent,\n UploadPausedEvent,\n UploadResumedEvent,\n ResumeUploadEvent,\n FinalizeUploadEvent,\n UploadMediaCompleteEvent\n} from \"../events\";\n\nimport { ChunkUploadHttpErrorException, FileUploadChunkError } from \"../exceptions\";\n\nimport pLimit from 'p-limit';\n\n\n/**\n * ChunkedFileUploader\n *\n * A production-ready, event-driven chunked file upload engine for Browser and Node.js.\n *\n * Designed and developed by **AGBOKOUDJO Franck** at\n * **INTERNATIONALES WEB APPS & SERVICES**, this class provides a robust,\n * framework-agnostic solution for uploading large files to a remote server\n * by splitting them into smaller chunks and sending them in parallel with\n * configurable concurrency control.\n *\n * ---\n *\n * ### How It Works\n *\n * The upload process follows a strict three-phase lifecycle:\n *\n * 1. **Initialization** — A session is opened with the server via the `init` endpoint.\n * The file is identified by its name, size, type, and a SHA-256 hash of its\n * first megabyte. The server returns a unique `mediaId` that identifies the session.\n *\n * 2. **Chunk Upload** — The file is sliced into fixed-size chunks and uploaded\n * concurrently using `p-limit`. Each chunk carries its index, the total number\n * of chunks, and the session `mediaId`. Failed chunks are retried automatically\n * with exponential backoff up to `maxRetries` attempts.\n *\n * 3. **Finalization** — Once all chunks are successfully uploaded, the `finalize`\n * endpoint is called to instruct the server to assemble the chunks into the\n * final file.\n *\n * ---\n *\n * ### Event-Driven Architecture\n *\n * This class follows the **Symfony EventDispatcher pattern** via\n * `@wlindabla/event_dispatcher`. Every meaningful moment in the upload\n * lifecycle emits a typed event that your application can listen to:\n *\n * ```\n * IDLE → INITIALIZING → UPLOADING → FINALIZING → COMPLETED\n * ↓ ↓\n * FAILED PAUSED ↔ UPLOADING\n * ↓\n * CANCELLED\n * ```\n *\n * All event name constants are centralized in {@link HttpFileUploaderEvents}.\n *\n * ---\n *\n * ### Subscriber Registration (Required)\n *\n * Before calling `.upload()`, you **must** register the two built-in subscribers\n * on your dispatcher. They handle the HTTP communication for the init and finalize phases:\n *\n * ```typescript\n * // Browser\n * const dispatcher = new BrowserEventDispatcher(document);\n * dispatcher.addSubscriber(new InitializeUploadSubscriber(dispatcher));\n * dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));\n *\n * // Node.js\n * const dispatcher = new NodeEventDispatcher();\n * dispatcher.addSubscriber(new InitializeUploadSubscriber(dispatcher));\n * dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));\n * ```\n *\n * ---\n *\n * ### Fluent Builder API\n *\n * The class exposes a fluent API to configure the upload before starting:\n *\n * ```typescript\n * const uploader = new ChunkedFileUploader(dispatcher, cache, options);\n *\n * await uploader\n * .withFile(file)\n * .withEndpoints({\n * init: 'https://api.example.com/upload/init',\n * upload: 'https://api.example.com/upload/chunk',\n * finalize: 'https://api.example.com/upload/finalize'\n * })\n * .upload();\n * ```\n *\n * ---\n *\n * ### Resumable Uploads\n *\n * When `autoSave: true` is set in options, the upload progress is persisted\n * after each successful chunk via the {@link UploadResumeCacheInterface}.\n * A failed or interrupted upload can be resumed later:\n *\n * ```typescript\n * const resumeData = await uploader.loadResumeData(file.name);\n *\n * if (resumeData) {\n * await uploader\n * .withFile(file)\n * .withEndpoints(endpoints)\n * .resumeUpload(resumeData);\n * }\n * ```\n *\n * ---\n *\n * ### Concurrency\n *\n * Multiple chunks can be uploaded simultaneously. The `concurrency` option\n * controls how many parallel uploads are active at any given time.\n * The default value is `3`, which provides a good balance between speed\n * and server/network load:\n *\n * ```typescript\n * // Upload 5 chunks in parallel\n * new ChunkedFileUploader(dispatcher, cache, { concurrency: 5 });\n * ```\n *\n * ---\n *\n * ### Pause, Resume and Cancel\n *\n * The upload can be paused, resumed, or cancelled at any time:\n *\n * ```typescript\n * uploader.pause(); // Pauses after the current chunk finishes\n * uploader.resume(); // Resumes from where it was paused\n * uploader.cancel(); // Aborts immediately via AbortController\n * ```\n *\n * ---\n *\n * ### Cache\n *\n * The library does **not** provide a built-in cache implementation to stay\n * lightweight and environment-agnostic. You must implement\n * {@link UploadResumeCacheInterface} with your preferred storage backend\n * (localStorage, IndexedDB, Redis, filesystem, etc.).\n *\n * ---\n *\n * @author AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * @company INTERNATIONALES WEB APPS & SERVICES\n * @phone +229 0167 25 18 86\n * @linkedin https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * @github https://github.com/Agbokoudjo/file_uploader\n *\n * @version 1.0.0\n * @since 1.0.0\n * @license MIT\n *\n * @see {@link HttpFileUploaderEvents} All event name constants\n * @see {@link UploadResumeCacheInterface} Cache interface to implement\n * @see {@link InitializeUploadSubscriber} Handles the init HTTP phase\n * @see {@link FinalizeUploadSubscriber} Handles the finalize HTTP phase\n * @see {@link UploadOptions} Full configuration reference\n * @see {@link https://github.com/Agbokoudjo/file_uploader | GitHub Repository}\n */\nexport class ChunkedFileUploader {\n private _file: File |null;\n private _endpoints: UploadEndpoints|null;\n \n private isPaused: boolean;\n private startTime: number;\n private uploadedBytes: number;\n private abortController: AbortController;\n private state: UploadState;\n private totalChunks: number;\n private percentage: number;\n private uploadedChunks: number;\n private lastUploadedChunkIndex: number; \n\n public constructor(\n private readonly _uploadEventDispatcher: EventDispatcherInterface = new BrowserEventDispatcher(), //or new NodeJSEventDispatcher() if you have an environment NodeJs\n private readonly uploadResumeData: UploadResumeCacheInterface,\n private options: UploadOptions\n ) {\n \n this._file = null;\n this._endpoints = null;\n this.isPaused = false;\n this.startTime = 0;\n this.uploadedBytes = 0;\n this.abortController = new AbortController();\n this.state = UploadState.IDLE;\n this.totalChunks = 0;\n this.percentage = 0;\n this.uploadedChunks = 0;\n this.lastUploadedChunkIndex = -1; \n }\n\n /**\n * Starts the chunked file upload process.\n * \n * @throws {Error} If file or endpoints are not set\n * @throws {InitializeUploadFailureException} If server initialization fails\n * @throws {FileUploadChunkError} If a chunk fails after all retries\n * \n * @example\n * ```typescript\n * const uploader = new ChunkedFileUploader(dispatcher, cache, options);\n * \n * uploader\n * .withFile(file)\n * .withEndpoints({ init, upload, finalize });\n * \n * await uploader.upload();\n * ```\n */\n public async upload(): Promise<void>{\n this.setState(UploadState.INITIALIZING);\n\n const { maxRetries = 3, config, speedMbps, metadata,\n headerInitialzingUpload, concurrency = 3\n } = this.options;\n\n const file = this.file;\n // Generate file hash for integrity check\n const fileHash = await FileUtils.generateFileHash(file) ;\n let fileId: string;\n\n try {\n const initializationEvent = await this._uploadEventDispatcher.dispatchAsync(\n new InitializingUploadEvent(\n {\n fileHash: fileHash,\n fileName: this.file.name,\n fileSize: this.file.size,\n fileType: this.file.type,\n metadata: metadata,\n endpointInit: this.endPointOptions.init,\n headers: headerInitialzingUpload\n }),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD\n )\n\n fileId = initializationEvent.mediaId;\n } catch (error) {\n this.setState(UploadState.FAILED);\n throw error;\n }\n\n this.setState(UploadState.UPLOADING);\n this.startTime = Date.now();\n this.uploadedBytes = 0;\n this.uploadedChunks = 0;\n this.lastUploadedChunkIndex = -1;\n\n const chunkSize = this.options.chunkSize || FileUtils.calculateChunkSize(file.size, speedMbps, config);\n this.totalChunks = Math.ceil(file.size / chunkSize);\n try {\n await this.uploadChunksWithConcurrency(\n file,\n chunkSize,\n fileId,\n fileHash,\n maxRetries,\n concurrency,\n 0\n );\n\n await this.finalizeUpload(fileId, fileHash);\n \n } catch (error) {\n this.handleUploadFailure(error as Error);\n throw error;\n }\n }\n\n public withFile(file: File): this {\n if (!file) {\n throw new Error('File is required');\n }\n if (file.size === 0) {\n throw new Error('Cannot upload empty file');\n }\n if (!(file instanceof File) || !(file instanceof Blob)) {\n throw new TypeError('Expected File or Blob instance');\n }\n this._file = file;\n return this;\n }\n\n public withEndpoints(endpoints: UploadEndpoints): this {\n if (!endpoints.init || !endpoints.upload || !endpoints.finalize) {\n throw new Error('All endpoints (init, upload, finalize) are required');\n }\n this._endpoints = endpoints;\n return this;\n }\n\n private get endPointOptions():UploadEndpoints {\n if (!this._endpoints) {\n throw new Error('Endpoint URL is required');\n }\n\n return this._endpoints;\n }\n\n private get file(): File{ \n if (!this._file) {\n throw new Error(`\n This operation requires a mandatory file.Did you forget to upload the file? \n Use the withFile(file: File|Blob) function of the ChunkedFileUploader ${this} class that you instantiated.\n `)\n }\n\n return this._file;\n }\n\n /**\n * Upload all chunks with concurrency control using p-limit\n * \n * @param file - File to upload\n * @param chunkSize - Size of each chunk\n * @param fileId - Server file ID\n * @param fileHash - File hash\n * @param maxRetries - Max retry attempts per chunk\n * @param concurrency - Number of concurrent uploads (default: 3)\n */\n private async uploadChunksWithConcurrency(\n file: File,\n chunkSize: number,\n fileId: string,\n fileHash: string,\n maxRetries: number,\n concurrency: number,\n startIndex:number=0\n ): Promise<void> {\n try {\n const limit = pLimit(concurrency);\n\n // Créer toutes les promesses avec limite\n const uploadPromises: Promise<void>[] = [];\n\n for (let chunkIndex = startIndex; chunkIndex < this.totalChunks; chunkIndex++) {\n // Wrapper chaque upload dans le limiteur\n const limitedUpload = limit(() =>\n this.processChunk(\n file,\n chunkIndex,\n chunkSize,\n fileId,\n fileHash,\n maxRetries\n )\n );\n\n uploadPromises.push(limitedUpload);\n }\n\n // Attendre que tous les chunks soient uploadés\n await Promise.all(uploadPromises);\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Process a single chunk: slice, upload with retry, and save progress.\n * \n * @param file - The file being uploaded\n * @param currentChunkIndex - Index of the current chunk (0-based)\n * @param chunkSize - Size of each chunk in bytes\n * @param fileId - Server-provided file/session ID\n * @param fileHash - SHA-256 hash of the file\n * @param maxRetries - Maximum number of retry attempts\n * \n * @throws {UploadCancelledException} If upload is cancelled\n * @throws {FileUploadChunkError} If chunk upload fails after all retries\n */\n private async processChunk(\n file:File,\n currentChunkIndex: number,\n chunkSize:number,\n fileId: string,\n fileHash:string,\n maxRetries:number\n ): Promise<void>{\n try {\n if (this.abortController.signal.aborted) {\n this._uploadEventDispatcher.dispatch(\n new UploadCancelledEvent(\n file.name,\n this.totalChunks,\n this.uploadedBytes,\n this.percentage,\n currentChunkIndex,\n 'Upload cancelled by user',\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_CANCELLED\n )\n \n return;\n }\n\n while (this.isPaused) {\n await this.sleep(100);\n }\n // Calcule où commencer dans le fichier\n const start = currentChunkIndex * chunkSize;\n // chunkIndex=0 → start=0\n // chunkIndex=1 → start=300\n // chunkIndex=2 → start=600\n // chunkIndex=3 → start=900\n\n // Calcule où finir (sans depasser la fin du fichier)\n const end = Math.min(file.size, start + chunkSize);\n // chunkIndex=0 → end=min(1000, 300)=300\n // chunkIndex=1 → end=min(1000, 600)=600\n // chunkIndex=2 → end=min(1000, 900)=900\n // chunkIndex=3 → end=min(1000, 1200)=1000 ← Limité !\n\n // Découpe le morceau\n const chunk = file.slice(start, end);\n // chunkIndex=0 → slice(0, 300) → 300 bytes\n // chunkIndex=1 → slice(300, 600) → 300 bytes\n // chunkIndex=2 → slice(600, 900) → 300 bytes\n // chunkIndex=3 → slice(900, 1000)→ 100 bytes ← Plus petit !\n const chunkInfo: ChunkInfo = {\n index: currentChunkIndex,\n start,\n end,\n size: chunk.size,\n attempt: 0,\n status: 'pending'\n };\n\n this._uploadEventDispatcher.dispatch(\n new UploadChunkStartedEvent(chunkInfo),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_STARTED\n );\n // Upload with retry\n await this.uploadChunkWithRetry(\n chunk,\n chunkInfo,\n fileId,\n fileHash,\n this.totalChunks,\n maxRetries\n );\n\n // Auto-save progress\n if (this.options.autoSave) {\n await this.saveResumeData(fileId,chunkSize);\n }\n } catch (error) {\n throw error;\n \n }\n }\n\n private async uploadChunkWithRetry(\n chunk: Blob,\n chunkInfo: ChunkInfo,\n fileId: string,\n fileHash: string,\n totalChunks: number,\n maxRetries: number\n ): Promise<void> {\n let success = false;\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxRetries && !success; attempt++) {\n chunkInfo.attempt = attempt + 1;\n chunkInfo.status = 'uploading';\n\n try {\n const response = await this.uploadChunk(chunk, chunkInfo, fileId, fileHash, totalChunks);\n success = true;\n chunkInfo.status = 'success';\n\n this.updateProgress(chunk.size, chunkInfo.index)\n\n this.notifyProgress(\n this.uploadedChunks,\n totalChunks,\n this.file.size,\n response\n );\n return;\n } catch (error) {\n if (error instanceof ChunkUploadHttpErrorException) {\n this._uploadEventDispatcher.dispatch(\n new ChunkUploadHttpErrorResponseEvent(\n error.errorPayload,\n error.statusResponse,\n this.endPointOptions.upload,\n chunkInfo),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_HTTP_ERROR_RESPONSE\n )\n }\n\n lastError = error as Error;\n chunkInfo.status = 'error';\n\n const chunkError: ChunkError= {\n chunk: chunkInfo,\n error: lastError,\n attempt: attempt + 1,\n willRetry: attempt < maxRetries - 1\n };\n\n if(error instanceof HttpFetchError){\n this._uploadEventDispatcher.dispatch(chunkError,HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_FAILED)\n }\n\n if (attempt < maxRetries - 1) {\n const delay = Math.pow(2, attempt) * 1000;\n await this.sleep(delay);\n\n console.info(`Retry #${attempt + 2} in ${delay / 1000}s...`);\n }\n }\n }\n\n if (!success) {\n const fileUploadChunkError = new FileUploadChunkError(\n `Failed to upload chunk ${chunkInfo.index} after ${maxRetries} attempts`,\n {\n chunk: chunkInfo,\n error: lastError!,\n attempt: maxRetries,\n willRetry: false\n }\n );\n\n this._uploadEventDispatcher.dispatch(\n fileUploadChunkError,\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_MAXRETRY_EXPIRE\n )\n throw fileUploadChunkError;\n }\n\n }\n\n private async uploadChunk(\n chunk: Blob,\n chunkInfo: ChunkInfo,\n mediaIdFromServer: string,\n fileHash: string,\n totalChunks: number\n ): Promise<FetchResponseInterface> {\n const media = this.file;\n const chunkFormData = createChunkFormData(\n chunk,\n {\n chunkIndex: chunkInfo.index,\n mediaId: mediaIdFromServer,\n fileSize: media.size,\n fileName: media.name,\n fileHash: fileHash,\n totalChunks: totalChunks\n }\n );\n\n try {\n const response_of_server = await safeFetch({\n url: this.endPointOptions.upload,\n headers: this.options.headers,\n data: chunkFormData,\n methodSend: \"POST\",\n responseType: \"json\",\n timeout: this.options.timeout ?? 60000,\n retryCount: 2,\n retryOnStatusCode: false,\n signal: this.createChunkAbortSignal()\n })\n const statusResponse = response_of_server.status;\n //if the server send a response which not success with status code(>=4XX ou >=5XX)\n if (response_of_server.failed) {\n throw new ChunkUploadHttpErrorException(response_of_server.data, statusResponse)\n }\n\n return response_of_server;\n } catch (error) {\n throw error;\n }\n\n }\n\n private createChunkAbortSignal(): AbortSignal {\n const chunkController = new AbortController();\n\n this.abortController.signal.addEventListener('abort', () => {\n chunkController.abort();\n });\n\n return chunkController.signal;\n }\n\n private notifyProgress(\n uploadedChunks: number,\n totalChunks: number,\n totalBytes: number,\n httpResponse: FetchResponseInterface): void {\n // Temps écoulé (minimum 0.1s pour éviter division par zéro)\n const elapsed = Math.max((Date.now() - this.startTime) / 1000, 0.1);\n const speed = this.uploadedBytes / elapsed; // Vitesse instantanée\n const remainingBytes = totalBytes - this.uploadedBytes; // Bytes restants\n // Temps restant (null si pas assez de données)\n const estimatedTimeRemaining = uploadedChunks < 2 ? null : remainingBytes / speed;\n\n this.percentage = Math.round((this.uploadedBytes / totalBytes) * 100);\n\n const progress: UploadProgress = {\n uploadedChunks,\n totalChunks,\n uploadedBytes: this.uploadedBytes,\n totalBytes,\n percentage: this.percentage,\n currentChunk: uploadedChunks,\n speed, // bytes/seconde\n estimatedTimeRemaining, // secondes (ou null)\n elapsed // secondes écoulées\n };\n\n this._uploadEventDispatcher.dispatch(\n new UploadProgressEvent(\n progress,\n httpResponse.data,\n httpResponse.status\n )\n )\n \n console.info(\n `Progress: ${this.percentage}% | ` +\n `Speed: ${FileUtils.formatBytes(speed)}/s | ` +\n `ETA: ${estimatedTimeRemaining ? FileUtils.formatDuration(estimatedTimeRemaining) : 'Calculating...'}`\n );\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n /**\n * Save current upload progress to cache for resume capability\n * \n * @param fileId - Server-provided file/session ID\n * @param chunkSize - Size of each chunk in bytes\n * @returns Saved resume data\n */\n private async saveResumeData(fileId: string, chunkSize: number): Promise<ResumeData> {\n const data: ResumeData = {\n fileId: fileId,\n fileName: this.file.name,\n fileSize: this.file.size,\n uploadedChunks: this.uploadedChunks,\n lastChunkIndex: this.lastUploadedChunkIndex,\n lastBytePosition: this.uploadedBytes,\n chunkSize: chunkSize,\n concurrency:this.options.concurrency || 3\n };\n\n await this.uploadResumeData.setItem(`upload_${this.file.name}`, data);\n\n console.info(\n `Resume data saved: ${this.uploadedChunks}/${Math.ceil(this.file.size / chunkSize)} chunks, ` +\n `last chunk index: ${this.lastUploadedChunkIndex}`\n );\n\n return data;\n }\n\n private setState(newState: UploadState): void {\n const oldState = this.state;\n this.state = newState;\n\n this._uploadEventDispatcher.dispatch(\n new UploadStateChangedEvent(\n oldState,\n newState,\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_STATE_CHANGED\n )\n \n }\n\n public getState(): UploadState {\n return this.state;\n }\n\n private handleUploadFailure(error: Error): void {\n this.setState(UploadState.FAILED);\n\n this._uploadEventDispatcher.dispatch(error, HttpFileUploaderEvents.DOWNLOAD_MEDIA_FAILURE);\n console.error('Upload failed:', error);\n }\n\n public cancel(): void {\n this.abortController.abort();\n this.setState(UploadState.CANCELLED);\n }\n\n public pause(): void {\n this.isPaused = true;\n this.setState(UploadState.PAUSED);\n this._uploadEventDispatcher.dispatch(\n new UploadPausedEvent(\n this.file.name,\n this.totalChunks,\n this.uploadedBytes,\n this.percentage,\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_PAUSED\n );\n }\n\n\n public resume(): void {\n this.isPaused = false;\n this.setState(UploadState.UPLOADING);\n this._uploadEventDispatcher.dispatch(\n new UploadResumedEvent(\n this.file.name,\n this.totalChunks,\n this.uploadedBytes, \n this.percentage),\n HttpFileUploaderEvents.UPLOAD_RESUMED,\n );\n }\n\n /**\n * Load previously saved resume data\n * \n * @param fileName - Name of the file to resume\n * @returns Resume data or null if not found\n */\n async loadResumeData(fileName: string): Promise<ResumeData | null> {\n try {\n const data = await this.uploadResumeData.getItem(`upload_${fileName}`);\n\n if (data) {\n console.info(\n `Resume data loaded: ${data.uploadedChunks} chunks uploaded, ` +\n `last index: ${data.lastChunkIndex}`\n );\n }\n return data;\n } catch (error) {\n console.warn(`No resume data found for ${fileName}`);\n return null;\n }\n }\n\n /**\n * Resume upload from saved state\n * \n * @param resumeData - Previously saved resume data\n * @returns Upload result\n */\n public async resumeUpload(resumeData: ResumeData): Promise<void> {\n const __message = `Resuming upload from chunk ${resumeData.lastChunkIndex + 1} ` +\n `(${resumeData.uploadedChunks} chunks already uploaded)`;\n\n // Restore state\n this.uploadedBytes = resumeData.lastBytePosition;\n this.uploadedChunks = resumeData.uploadedChunks;\n this.lastUploadedChunkIndex = resumeData.lastChunkIndex;\n\n // Calculate adjusted start time for accurate speed calculation\n const assumedSpeed = 500000; // 500 KB/s assumed\n const timeAlreadySpent = resumeData.lastBytePosition / assumedSpeed;\n this.startTime = Date.now() - (timeAlreadySpent * 1000);\n\n const { maxRetries = 3 } = this.options;\n const fileHash = await FileUtils.generateFileHash(this.file);\n const chunkSize = resumeData.chunkSize;\n this.totalChunks = Math.ceil(this.file.size / chunkSize);\n\n try {\n this._uploadEventDispatcher.dispatch(\n new ResumeUploadEvent(resumeData,__message),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_RESUME\n )\n await this.uploadChunksWithConcurrency(\n this.file,\n chunkSize,\n resumeData.fileId,\n fileHash,\n maxRetries,\n resumeData.concurrency,\n resumeData.lastChunkIndex + 1\n )\n ;\n await this.finalizeUpload(resumeData.fileId, fileHash);\n\n } catch (error) {\n this.handleUploadFailure(error as Error);\n throw error;\n }\n }\n\n private updateProgress(chunkSize: number, chunkIndex: number): void {\n this.uploadedBytes += chunkSize;\n this.uploadedChunks++;\n this.lastUploadedChunkIndex = Math.max(this.lastUploadedChunkIndex,chunkIndex);\n }\n \n private async finalizeUpload(mediaId: string, fileHash: string): Promise<void> {\n try {\n \n const finalizeUploadEvent = await this._uploadEventDispatcher.dispatchAsync(\n new FinalizeUploadEvent(\n this.endPointOptions.finalize,\n mediaId,\n fileHash,\n this.options.headerFinalezingUpload)\n ,\n HttpFileUploaderEvents.FINALIZE_UPLOAD\n )\n\n this.setState(UploadState.FINALIZING);\n\n\n const duration = (Date.now() - this.startTime) / 1000;\n\n const uploadResult: UploadResult = {\n success: true,\n finalizeUploadResponse: finalizeUploadEvent.hasResponse() ? finalizeUploadEvent.getResponse() : null ,\n totalChunks: this.totalChunks,\n totalBytes: this.file.size,\n duration,\n averageSpeed: this.file.size / duration,\n fileId: mediaId\n };\n\n this.setState(UploadState.COMPLETED);\n\n this._uploadEventDispatcher.dispatch(\n new UploadMediaCompleteEvent(uploadResult),HttpFileUploaderEvents.DOWNLOAD_MEDIA_COMPLETE\n )\n\n } catch (error) {\n throw error;\n }\n }\n}"],"mappings":"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","names":["pLimit"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/index.ts"],"sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n EventDispatcherInterface\n} from \"@wlindabla/event_dispatcher\";\n\nimport {\n FetchResponseInterface\n} from \"@wlindabla/http_client/contracts\";\n\nimport {\n safeFetch,\n HttpFetchError\n} from \"@wlindabla/http_client/core\";\n\nimport {\n ChunkError,\n ChunkInfo,\n ResumeData,\n UploadEndpoints,\n UploadOptions,\n UploadProgress,\n UploadResult,\n UploadState\n} from \"../types\";\n\nimport { UploadResumeCacheInterface } from \"../cache\";\nimport {\n FileUtils,\n createChunkFormData\n} from \"../utils\";\n\nimport {\n ChunkUploadHttpErrorResponseEvent,\n HttpFileUploaderEvents,\n InitializingUploadEvent,\n UploadCancelledEvent,\n UploadProgressEvent,\n UploadStateChangedEvent,\n UploadChunkStartedEvent,\n UploadPausedEvent,\n UploadResumedEvent,\n ResumeUploadEvent,\n FinalizeUploadEvent,\n UploadMediaCompleteEvent\n} from \"../events\";\n\nimport { ChunkUploadHttpErrorException, FileUploadChunkError } from \"../exceptions\";\n\nimport pLimit from 'p-limit';\n\n\n/**\n * ChunkedFileUploader\n *\n * A production-ready, event-driven chunked file upload engine for Browser and Node.js.\n *\n * Designed and developed by **AGBOKOUDJO Franck** at\n * **INTERNATIONALES WEB APPS & SERVICES**, this class provides a robust,\n * framework-agnostic solution for uploading large files to a remote server\n * by splitting them into smaller chunks and sending them in parallel with\n * configurable concurrency control.\n *\n * ---\n *\n * ### How It Works\n *\n * The upload process follows a strict three-phase lifecycle:\n *\n * 1. **Initialization** — A session is opened with the server via the `init` endpoint.\n * The file is identified by its name, size, type, and a SHA-256 hash of its\n * first megabyte. The server returns a unique `mediaId` that identifies the session.\n *\n * 2. **Chunk Upload** — The file is sliced into fixed-size chunks and uploaded\n * concurrently using `p-limit`. Each chunk carries its index, the total number\n * of chunks, and the session `mediaId`. Failed chunks are retried automatically\n * with exponential backoff up to `maxRetries` attempts.\n *\n * 3. **Finalization** — Once all chunks are successfully uploaded, the `finalize`\n * endpoint is called to instruct the server to assemble the chunks into the\n * final file.\n *\n * ---\n *\n * ### Event-Driven Architecture\n *\n * This class follows the **Symfony EventDispatcher pattern** via\n * `@wlindabla/event_dispatcher`. Every meaningful moment in the upload\n * lifecycle emits a typed event that your application can listen to:\n *\n * ```\n * IDLE → INITIALIZING → UPLOADING → FINALIZING → COMPLETED\n * ↓ ↓\n * FAILED PAUSED ↔ UPLOADING\n * ↓\n * CANCELLED\n * ```\n *\n * All event name constants are centralized in {@link HttpFileUploaderEvents}.\n *\n * ---\n *\n * ### Subscriber Registration (Required)\n *\n * Before calling `.upload()`, you **must** register the two built-in subscribers\n * on your dispatcher. They handle the HTTP communication for the init and finalize phases:\n *\n * ```typescript\n * // Browser\n * const dispatcher = new BrowserEventDispatcher(document);\n * dispatcher.addSubscriber(new InitializeUploadSubscriber(dispatcher));\n * dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));\n *\n * // Node.js\n * const dispatcher = new NodeEventDispatcher();\n * dispatcher.addSubscriber(new InitializeUploadSubscriber(dispatcher));\n * dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));\n * ```\n *\n * ---\n *\n * ### Fluent Builder API\n *\n * The class exposes a fluent API to configure the upload before starting:\n *\n * ```typescript\n * const uploader = new ChunkedFileUploader(dispatcher, cache, options);\n *\n * await uploader\n * .withFile(file)\n * .withEndpoints({\n * init: 'https://api.example.com/upload/init',\n * upload: 'https://api.example.com/upload/chunk',\n * finalize: 'https://api.example.com/upload/finalize'\n * })\n * .upload();\n * ```\n *\n * ---\n *\n * ### Resumable Uploads\n *\n * When `autoSave: true` is set in options, the upload progress is persisted\n * after each successful chunk via the {@link UploadResumeCacheInterface}.\n * A failed or interrupted upload can be resumed later:\n *\n * ```typescript\n * const resumeData = await uploader.loadResumeData(file.name);\n *\n * if (resumeData) {\n * await uploader\n * .withFile(file)\n * .withEndpoints(endpoints)\n * .resumeUpload(resumeData);\n * }\n * ```\n *\n * ---\n *\n * ### Concurrency\n *\n * Multiple chunks can be uploaded simultaneously. The `concurrency` option\n * controls how many parallel uploads are active at any given time.\n * The default value is `3`, which provides a good balance between speed\n * and server/network load:\n *\n * ```typescript\n * // Upload 5 chunks in parallel\n * new ChunkedFileUploader(dispatcher, cache, { concurrency: 5 });\n * ```\n *\n * ---\n *\n * ### Pause, Resume and Cancel\n *\n * The upload can be paused, resumed, or cancelled at any time:\n *\n * ```typescript\n * uploader.pause(); // Pauses after the current chunk finishes\n * uploader.resume(); // Resumes from where it was paused\n * uploader.cancel(); // Aborts immediately via AbortController\n * ```\n *\n * ---\n *\n * ### Cache\n *\n * The library does **not** provide a built-in cache implementation to stay\n * lightweight and environment-agnostic. You must implement\n * {@link UploadResumeCacheInterface} with your preferred storage backend\n * (localStorage, IndexedDB, Redis, filesystem, etc.).\n *\n * ---\n *\n * @author AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * @company INTERNATIONALES WEB APPS & SERVICES\n * @phone +229 0167 25 18 86\n * @linkedin https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * @github https://github.com/Agbokoudjo/file_uploader\n *\n * @version 2.0.1\n * @since 1.0.0\n * @license MIT\n *\n * @see {@link HttpFileUploaderEvents} All event name constants\n * @see {@link UploadResumeCacheInterface} Cache interface to implement\n * @see {@link InitializeUploadSubscriber} Handles the init HTTP phase\n * @see {@link FinalizeUploadSubscriber} Handles the finalize HTTP phase\n * @see {@link UploadOptions} Full configuration reference\n * @see {@link https://github.com/Agbokoudjo/file_uploader | GitHub Repository}\n */\nexport class ChunkedFileUploader {\n private _file: File |null;\n private _endpoints: UploadEndpoints|null;\n \n private isPaused: boolean;\n private startTime: number;\n private uploadedBytes: number;\n private abortController: AbortController;\n private state: UploadState;\n private totalChunks: number;\n private percentage: number;\n private uploadedChunks: number;\n private lastUploadedChunkIndex: number; \n\n /**\n * @param _uploadEventDispatcher: new BrowserEventDispatcher(), //or new NodeJSEventDispatcher() if you have an environment NodeJs\n * @param uploadResumeData: UploadResumeCacheInterface\n * @param options: UploadOptions\n */\n public constructor(\n private readonly _uploadEventDispatcher: EventDispatcherInterface,\n private readonly uploadResumeData: UploadResumeCacheInterface,\n private options: UploadOptions\n ) {\n \n this._file = null;\n this._endpoints = null;\n this.isPaused = false;\n this.startTime = 0;\n this.uploadedBytes = 0;\n this.abortController = new AbortController();\n this.state = UploadState.IDLE;\n this.totalChunks = 0;\n this.percentage = 0;\n this.uploadedChunks = 0;\n this.lastUploadedChunkIndex = -1; \n }\n\n /**\n * Starts the chunked file upload process.\n * \n * @throws {Error} If file or endpoints are not set\n * @throws {InitializeUploadFailureException} If server initialization fails\n * @throws {FileUploadChunkError} If a chunk fails after all retries\n * \n * @example\n * ```typescript\n * const uploader = new ChunkedFileUploader(dispatcher, cache, options);\n * \n * uploader\n * .withFile(file)\n * .withEndpoints({ init, upload, finalize });\n * \n * await uploader.upload();\n * ```\n */\n public async upload(): Promise<void>{\n this.setState(UploadState.INITIALIZING);\n\n const { maxRetries = 3, config, speedMbps, metadata,\n headerInitialzingUpload, concurrency = 3\n } = this.options;\n\n let file: File;\n try {\n file = this.file;\n } catch (error) {\n throw error;\n }\n \n // Generate file hash for integrity check\n const fileHash = await FileUtils.generateFileHash(this.file); \n let fileId: string;\n try {\n const initializationEvent = await this._uploadEventDispatcher.dispatchAsync(\n new InitializingUploadEvent(\n {\n fileHash: fileHash,\n fileName: file.name,\n fileSize: file.size,\n fileType: file.type,\n metadata: metadata,\n endpointInit: this.endPointOptions.init,\n headers: headerInitialzingUpload\n }),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD\n )\n\n fileId = initializationEvent.mediaId;\n } catch (error) {\n this.setState(UploadState.FAILED);\n throw error;\n }\n\n this.setState(UploadState.UPLOADING);\n this.startTime = Date.now();\n this.uploadedBytes = 0;\n this.uploadedChunks = 0;\n this.lastUploadedChunkIndex = -1;\n\n const chunkSize = this.options.chunkSize || FileUtils.calculateChunkSize(file.size, speedMbps, config);\n this.totalChunks = Math.ceil(file.size / chunkSize);\n try {\n await this.uploadChunksWithConcurrency(\n file,\n chunkSize,\n fileId,\n fileHash,\n maxRetries,\n concurrency,\n 0\n );\n\n await this.finalizeUpload(fileId, fileHash);\n \n } catch (error) {\n this.handleUploadFailure(error as Error);\n throw error;\n }\n }\n\n public withFile(file: File): this {\n if (!file) {\n throw new Error('File is required');\n }\n if (file.size === 0) {\n throw new Error('Cannot upload empty file');\n }\n if (!(file instanceof File) || !(file instanceof Blob)) {\n throw new TypeError('Expected File or Blob instance');\n }\n this._file = file;\n return this;\n }\n\n public withEndpoints(endpoints: UploadEndpoints): this {\n if (!endpoints.init || !endpoints.upload || !endpoints.finalize) {\n throw new Error('All endpoints (init, upload, finalize) are required');\n }\n this._endpoints = endpoints;\n return this;\n }\n\n private get endPointOptions():UploadEndpoints {\n if (!this._endpoints) {\n throw new Error('Endpoint URL is required');\n }\n\n return this._endpoints;\n }\n\n private get file(): File{ \n if (!this._file) {\n throw new Error(`\n This operation requires a mandatory file.Did you forget to upload the file? \n Use the withFile(file: File|Blob) function of the ChunkedFileUploader ${this} class that you instantiated.\n `)\n }\n\n return this._file;\n }\n\n /**\n * Upload all chunks with concurrency control using p-limit\n * \n * @param file - File to upload\n * @param chunkSize - Size of each chunk\n * @param fileId - Server file ID\n * @param fileHash - File hash\n * @param maxRetries - Max retry attempts per chunk\n * @param concurrency - Number of concurrent uploads (default: 3)\n */\n private async uploadChunksWithConcurrency(\n file: File,\n chunkSize: number,\n fileId: string,\n fileHash: string,\n maxRetries: number,\n concurrency: number,\n startIndex:number=0\n ): Promise<void> {\n try {\n const limit = pLimit(concurrency);\n\n // Créer toutes les promesses avec limite\n const uploadPromises: Promise<void>[] = [];\n\n for (let chunkIndex = startIndex; chunkIndex < this.totalChunks; chunkIndex++) {\n // Wrapper chaque upload dans le limiteur\n const limitedUpload = limit(() =>\n this.processChunk(\n file,\n chunkIndex,\n chunkSize,\n fileId,\n fileHash,\n maxRetries\n )\n );\n\n uploadPromises.push(limitedUpload);\n }\n\n // Attendre que tous les chunks soient uploadés\n await Promise.all(uploadPromises);\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Process a single chunk: slice, upload with retry, and save progress.\n * \n * @param file - The file being uploaded\n * @param currentChunkIndex - Index of the current chunk (0-based)\n * @param chunkSize - Size of each chunk in bytes\n * @param fileId - Server-provided file/session ID\n * @param fileHash - SHA-256 hash of the file\n * @param maxRetries - Maximum number of retry attempts\n * \n * @throws {UploadCancelledException} If upload is cancelled\n * @throws {FileUploadChunkError} If chunk upload fails after all retries\n */\n private async processChunk(\n file:File,\n currentChunkIndex: number,\n chunkSize:number,\n fileId: string,\n fileHash:string,\n maxRetries:number\n ): Promise<void>{\n try {\n if (this.abortController.signal.aborted) {\n this._uploadEventDispatcher.dispatch(\n new UploadCancelledEvent(\n file.name,\n this.totalChunks,\n this.uploadedBytes,\n this.percentage,\n currentChunkIndex,\n 'Upload cancelled by user',\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_CANCELLED\n )\n \n return;\n }\n\n while (this.isPaused) {\n await this.sleep(100);\n }\n // Calcule où commencer dans le fichier\n const start = currentChunkIndex * chunkSize;\n // chunkIndex=0 → start=0\n // chunkIndex=1 → start=300\n // chunkIndex=2 → start=600\n // chunkIndex=3 → start=900\n\n // Calcule où finir (sans depasser la fin du fichier)\n const end = Math.min(file.size, start + chunkSize);\n // chunkIndex=0 → end=min(1000, 300)=300\n // chunkIndex=1 → end=min(1000, 600)=600\n // chunkIndex=2 → end=min(1000, 900)=900\n // chunkIndex=3 → end=min(1000, 1200)=1000 ← Limité !\n\n // Découpe le morceau\n const chunk = file.slice(start, end);\n // chunkIndex=0 → slice(0, 300) → 300 bytes\n // chunkIndex=1 → slice(300, 600) → 300 bytes\n // chunkIndex=2 → slice(600, 900) → 300 bytes\n // chunkIndex=3 → slice(900, 1000)→ 100 bytes ← Plus petit !\n const chunkInfo: ChunkInfo = {\n index: currentChunkIndex,\n start,\n end,\n size: chunk.size,\n attempt: 0,\n status: 'pending'\n };\n\n this._uploadEventDispatcher.dispatch(\n new UploadChunkStartedEvent(chunkInfo),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_STARTED\n );\n // Upload with retry\n await this.uploadChunkWithRetry(\n chunk,\n chunkInfo,\n fileId,\n fileHash,\n this.totalChunks,\n maxRetries\n );\n\n // Auto-save progress\n if (this.options.autoSave) {\n await this.saveResumeData(fileId,chunkSize);\n }\n } catch (error) {\n throw error;\n \n }\n }\n\n private async uploadChunkWithRetry(\n chunk: Blob,\n chunkInfo: ChunkInfo,\n fileId: string,\n fileHash: string,\n totalChunks: number,\n maxRetries: number\n ): Promise<void> {\n let success = false;\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxRetries && !success; attempt++) {\n chunkInfo.attempt = attempt + 1;\n chunkInfo.status = 'uploading';\n\n try {\n const response = await this.uploadChunk(chunk, chunkInfo, fileId, fileHash, totalChunks);\n success = true;\n chunkInfo.status = 'success';\n\n this.updateProgress(chunk.size, chunkInfo.index)\n\n this.notifyProgress(\n this.uploadedChunks,\n totalChunks,\n this.file.size,\n response\n );\n return;\n } catch (error) {\n if (error instanceof ChunkUploadHttpErrorException) {\n this._uploadEventDispatcher.dispatch(\n new ChunkUploadHttpErrorResponseEvent(\n error.errorPayload,\n error.statusResponse,\n this.endPointOptions.upload,\n chunkInfo),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_HTTP_ERROR_RESPONSE\n )\n }\n\n lastError = error as Error;\n chunkInfo.status = 'error';\n\n const chunkError: ChunkError= {\n chunk: chunkInfo,\n error: lastError,\n attempt: attempt + 1,\n willRetry: attempt < maxRetries - 1\n };\n\n if(error instanceof HttpFetchError){\n this._uploadEventDispatcher.dispatch(chunkError,HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_FAILED)\n }\n\n if (attempt < maxRetries - 1) {\n const delay = Math.pow(2, attempt) * 1000;\n await this.sleep(delay);\n\n console.info(`Retry #${attempt + 2} in ${delay / 1000}s...`);\n }\n }\n }\n\n if (!success) {\n const fileUploadChunkError = new FileUploadChunkError(\n `Failed to upload chunk ${chunkInfo.index} after ${maxRetries} attempts`,\n {\n chunk: chunkInfo,\n error: lastError!,\n attempt: maxRetries,\n willRetry: false\n }\n );\n\n this._uploadEventDispatcher.dispatch(\n fileUploadChunkError,\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_MAXRETRY_EXPIRE\n )\n \n throw fileUploadChunkError;\n }\n\n }\n\n private async uploadChunk(\n chunk: Blob,\n chunkInfo: ChunkInfo,\n mediaIdFromServer: string,\n fileHash: string,\n totalChunks: number\n ): Promise<FetchResponseInterface> {\n const media = this.file;\n const chunkFormData = createChunkFormData(\n chunk,\n {\n chunkIndex: chunkInfo.index,\n mediaId: mediaIdFromServer,\n fileSize: media.size,\n fileName: media.name,\n fileHash: fileHash,\n totalChunks: totalChunks\n }\n );\n\n try {\n const response_of_server = await safeFetch({\n url: this.endPointOptions.upload,\n headers: this.options.headers,\n data: chunkFormData,\n methodSend: \"POST\",\n responseType: \"json\",\n timeout: this.options.timeout ?? 60000,\n retryCount: 2,\n retryOnStatusCode: false,\n signal: this.createChunkAbortSignal()\n })\n const statusResponse = response_of_server.status;\n //if the server send a response which not success with status code(>=4XX ou >=5XX)\n if (response_of_server.failed) {\n throw new ChunkUploadHttpErrorException(response_of_server.data, statusResponse)\n }\n\n return response_of_server;\n } catch (error) {\n throw error;\n }\n\n }\n\n private createChunkAbortSignal(): AbortSignal {\n const chunkController = new AbortController();\n\n this.abortController.signal.addEventListener('abort', () => {\n chunkController.abort();\n });\n\n return chunkController.signal;\n }\n\n private notifyProgress(\n uploadedChunks: number,\n totalChunks: number,\n totalBytes: number,\n httpResponse: FetchResponseInterface): void {\n // Temps écoulé (minimum 0.1s pour éviter division par zéro)\n const elapsed = Math.max((Date.now() - this.startTime) / 1000, 0.1);\n const speed = this.uploadedBytes / elapsed; // Vitesse instantanée\n const remainingBytes = totalBytes - this.uploadedBytes; // Bytes restants\n // Temps restant (null si pas assez de données)\n const estimatedTimeRemaining = uploadedChunks < 2 ? null : remainingBytes / speed;\n\n this.percentage = Math.round((this.uploadedBytes / totalBytes) * 100);\n\n const progress: UploadProgress = {\n uploadedChunks,\n totalChunks,\n uploadedBytes: this.uploadedBytes,\n totalBytes,\n percentage: this.percentage,\n currentChunk: uploadedChunks,\n speed, // bytes/seconde\n estimatedTimeRemaining, // secondes (ou null)\n elapsed // secondes écoulées\n };\n\n this._uploadEventDispatcher.dispatch(\n new UploadProgressEvent(\n progress,\n httpResponse.data,\n httpResponse.status\n )\n )\n \n console.info(\n `Progress: ${this.percentage}% | ` +\n `Speed: ${FileUtils.formatBytes(speed)}/s | ` +\n `ETA: ${estimatedTimeRemaining ? FileUtils.formatDuration(estimatedTimeRemaining) : 'Calculating...'}`\n );\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n /**\n * Save current upload progress to cache for resume capability\n * \n * @param fileId - Server-provided file/session ID\n * @param chunkSize - Size of each chunk in bytes\n * @returns Saved resume data\n */\n private async saveResumeData(fileId: string, chunkSize: number): Promise<ResumeData> {\n const data: ResumeData = {\n fileId: fileId,\n fileName: this.file.name,\n fileSize: this.file.size,\n uploadedChunks: this.uploadedChunks,\n lastChunkIndex: this.lastUploadedChunkIndex,\n lastBytePosition: this.uploadedBytes,\n chunkSize: chunkSize,\n concurrency:this.options.concurrency || 3\n };\n\n await this.uploadResumeData.setItem(`upload_${this.file.name}`, data);\n\n console.info(\n `Resume data saved: ${this.uploadedChunks}/${Math.ceil(this.file.size / chunkSize)} chunks, ` +\n `last chunk index: ${this.lastUploadedChunkIndex}`\n );\n\n return data;\n }\n\n private setState(newState: UploadState): void {\n const oldState = this.state;\n this.state = newState;\n\n this._uploadEventDispatcher.dispatch(\n new UploadStateChangedEvent(\n oldState,\n newState,\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_STATE_CHANGED\n )\n \n }\n\n public getState(): UploadState {\n return this.state;\n }\n\n private handleUploadFailure(error: Error): void {\n this.setState(UploadState.FAILED);\n\n this._uploadEventDispatcher.dispatch(error, HttpFileUploaderEvents.DOWNLOAD_MEDIA_FAILURE);\n console.error('Upload failed:', error);\n }\n\n public cancel(): void {\n this.abortController.abort();\n this.setState(UploadState.CANCELLED);\n }\n\n public pause(): void {\n this.isPaused = true;\n this.setState(UploadState.PAUSED);\n this._uploadEventDispatcher.dispatch(\n new UploadPausedEvent(\n this.file.name,\n this.totalChunks,\n this.uploadedBytes,\n this.percentage,\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_PAUSED\n );\n }\n\n\n public resume(): void {\n this.isPaused = false;\n this.setState(UploadState.UPLOADING);\n this._uploadEventDispatcher.dispatch(\n new UploadResumedEvent(\n this.file.name,\n this.totalChunks,\n this.uploadedBytes, \n this.percentage),\n HttpFileUploaderEvents.UPLOAD_RESUMED,\n );\n }\n\n /**\n * Load previously saved resume data\n * \n * @param fileName - Name of the file to resume\n * @returns Resume data or null if not found\n */\n async loadResumeData(fileName: string): Promise<ResumeData | null> {\n try {\n const data = await this.uploadResumeData.getItem(`upload_${fileName}`);\n\n if (data) {\n console.info(\n `Resume data loaded: ${data.uploadedChunks} chunks uploaded, ` +\n `last index: ${data.lastChunkIndex}`\n );\n }\n return data;\n } catch (error) {\n console.warn(`No resume data found for ${fileName}`);\n return null;\n }\n }\n\n /**\n * Resume upload from saved state\n * \n * @param resumeData - Previously saved resume data\n * @returns Upload result\n */\n public async resumeUpload(resumeData: ResumeData): Promise<void> {\n const __message = `Resuming upload from chunk ${resumeData.lastChunkIndex + 1} ` +\n `(${resumeData.uploadedChunks} chunks already uploaded)`;\n\n // Restore state\n this.uploadedBytes = resumeData.lastBytePosition;\n this.uploadedChunks = resumeData.uploadedChunks;\n this.lastUploadedChunkIndex = resumeData.lastChunkIndex;\n\n // Calculate adjusted start time for accurate speed calculation\n const assumedSpeed = 500000; // 500 KB/s assumed\n const timeAlreadySpent = resumeData.lastBytePosition / assumedSpeed;\n this.startTime = Date.now() - (timeAlreadySpent * 1000);\n\n const { maxRetries = 3 } = this.options;\n const fileHash = await FileUtils.generateFileHash(this.file);\n const chunkSize = resumeData.chunkSize;\n this.totalChunks = Math.ceil(this.file.size / chunkSize);\n\n try {\n this._uploadEventDispatcher.dispatch(\n new ResumeUploadEvent(resumeData,__message),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_RESUME\n )\n await this.uploadChunksWithConcurrency(\n this.file,\n chunkSize,\n resumeData.fileId,\n fileHash,\n maxRetries,\n resumeData.concurrency,\n resumeData.lastChunkIndex + 1\n )\n ;\n await this.finalizeUpload(resumeData.fileId, fileHash);\n\n } catch (error) {\n this.handleUploadFailure(error as Error);\n throw error;\n }\n }\n\n private updateProgress(chunkSize: number, chunkIndex: number): void {\n this.uploadedBytes += chunkSize;\n this.uploadedChunks++;\n this.lastUploadedChunkIndex = Math.max(this.lastUploadedChunkIndex,chunkIndex);\n }\n \n private async finalizeUpload(mediaId: string, fileHash: string): Promise<void> {\n try {\n \n const finalizeUploadEvent = await this._uploadEventDispatcher.dispatchAsync(\n new FinalizeUploadEvent(\n this.endPointOptions.finalize,\n mediaId,\n fileHash,\n this.options.headerFinalezingUpload)\n ,\n HttpFileUploaderEvents.FINALIZE_UPLOAD\n )\n\n this.setState(UploadState.FINALIZING);\n\n\n const duration = (Date.now() - this.startTime) / 1000;\n\n const uploadResult: UploadResult = {\n success: true,\n finalizeUploadResponse: finalizeUploadEvent.hasResponse() ? finalizeUploadEvent.getResponse() : null ,\n totalChunks: this.totalChunks,\n totalBytes: this.file.size,\n duration,\n averageSpeed: this.file.size / duration,\n fileId: mediaId\n };\n\n this.setState(UploadState.COMPLETED);\n\n this._uploadEventDispatcher.dispatch(\n new UploadMediaCompleteEvent(uploadResult),HttpFileUploaderEvents.DOWNLOAD_MEDIA_COMPLETE\n )\n\n } catch (error) {\n throw error;\n }\n }\n}"],"mappings":"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","names":["pLimit"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BaseEvent } from '@wlindabla/event_dispatcher';
|
|
2
2
|
import { ResumeData, UploadResult } from '../../types/index.js';
|
|
3
|
-
import { ResponseEventInterface
|
|
3
|
+
import { ResponseEventInterface } from '@wlindabla/http_client/events';
|
|
4
|
+
import { FetchResponseInterface } from '@wlindabla/http_client';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Event data for MEDIA_CHUNK_UPLOAD_RESUME
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/events/complete/index.ts"],"sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\nimport { BaseEvent } from \"@wlindabla/event_dispatcher\";\nimport { ResumeData,UploadResult } from \"../../types\";\nimport {\n ResponseEventInterface
|
|
1
|
+
{"version":3,"sources":["../../../../src/events/complete/index.ts"],"sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\nimport { BaseEvent } from \"@wlindabla/event_dispatcher\";\nimport { ResumeData, UploadResult } from \"../../types\";\n\nimport type {\n ResponseEventInterface\n} from \"@wlindabla/http_client/events\";\n\nimport type {\n FetchResponseInterface\n} from \"@wlindabla/http_client\";\n\n/**\n * Event data for MEDIA_CHUNK_UPLOAD_RESUME\n */\nexport class ResumeUploadEvent {\n constructor(\n private readonly __resumeData: ResumeData,\n public readonly message: string) { }\n\n public get mediaId(): string | number { return this.__resumeData.fileId; }\n\n public get fileName(): string { return this.__resumeData.fileName; }\n\n public get uploadedChunks(): number { return this.__resumeData.uploadedChunks; }\n\n public get lastChunkIndex(): number { return this.__resumeData.lastChunkIndex; }\n\n public get lastBytePosition(): number { return this.__resumeData.lastBytePosition; }\n\n public get chunkSize(): number { return this.__resumeData.chunkSize; }\n\n public get fileSize(): number { return this.__resumeData.fileSize; }\n}\n\n/**\n * Event data for DOWNLOAD_MEDIA_COMPLETE\n */\nexport class UploadMediaCompleteEvent {\n constructor(private readonly _uploadResult: UploadResult) { }\n\n public get success(): boolean { return this._uploadResult.success; }\n\n public get mediaId(): string | number { return this._uploadResult.fileId! }\n\n public get totalBytes(): number { return this._uploadResult.totalBytes; }\n\n public get totalChunks(): number { return this._uploadResult.totalChunks; }\n\n public get finalizeUploadHttpResponse(): any { return this._uploadResult.finalizeUploadResponse; }\n\n public get operationDuration(): number { return this._uploadResult.duration; }\n\n public get averageSpeed(): number { return this._uploadResult.averageSpeed; }\n}\n\nexport class FinalizeUploadFailureEvent extends BaseEvent{\n constructor(\n public readonly error: Error,\n public readonly status?: number,\n public readonly errorData?: any,\n public readonly responseData?: any,\n public readonly isNetworkError?: boolean\n ) { super(); }\n}\n\nexport class FinalizeUploadEvent extends BaseEvent implements ResponseEventInterface{\n private fetchResponse: FetchResponseInterface|null;\n\n constructor(\n public readonly endPoint:string|URL,\n public readonly mediaId: string,\n public readonly mediaHash: string,\n public readonly headers?: HeadersInit\n ) {\n super();\n this.fetchResponse = null;\n }\n\n /**\n * Returns the response\n */\n public getResponse(): FetchResponseInterface | null {\n return this.fetchResponse;\n }\n\n /**\n * Sets the response\n */\n public setResponse(response: FetchResponseInterface): void {\n this.fetchResponse = response;\n }\n\n /**\n * Returns whether a response was set\n */\n public hasResponse(): boolean {\n return this.fetchResponse !== null;\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,8BAA0B;AAcnB,MAAM,kBAAkB;AAAA,EAC3B,YACqB,cACD,SAAiB;AADhB;AACD;AAAA,EAAmB;AAAA,EADlB;AAAA,EACD;AAAA,EA3BxB,OAwB+B;AAAA;AAAA;AAAA,EAK3B,IAAW,UAA2B;AAAE,WAAO,KAAK,aAAa;AAAA,EAAQ;AAAA,EAEzE,IAAW,WAAmB;AAAE,WAAO,KAAK,aAAa;AAAA,EAAU;AAAA,EAEnE,IAAW,iBAAyB;AAAE,WAAO,KAAK,aAAa;AAAA,EAAgB;AAAA,EAE/E,IAAW,iBAAyB;AAAE,WAAO,KAAK,aAAa;AAAA,EAAgB;AAAA,EAE/E,IAAW,mBAA2B;AAAE,WAAO,KAAK,aAAa;AAAA,EAAkB;AAAA,EAEnF,IAAW,YAAoB;AAAE,WAAO,KAAK,aAAa;AAAA,EAAW;AAAA,EAErE,IAAW,WAAmB;AAAE,WAAO,KAAK,aAAa;AAAA,EAAU;AACvE;AAKO,MAAM,yBAAyB;AAAA,EAClC,YAA6B,eAA6B;AAA7B;AAAA,EAA+B;AAAA,EAA/B;AAAA,EAhDjC,OA+CsC;AAAA;AAAA;AAAA,EAGlC,IAAW,UAAmB;AAAE,WAAO,KAAK,cAAc;AAAA,EAAS;AAAA,EAEnE,IAAW,UAA2B;AAAE,WAAO,KAAK,cAAc;AAAA,EAAQ;AAAA,EAE1E,IAAW,aAAqB;AAAE,WAAO,KAAK,cAAc;AAAA,EAAY;AAAA,EAExE,IAAW,cAAsB;AAAE,WAAO,KAAK,cAAc;AAAA,EAAa;AAAA,EAE1E,IAAW,6BAAkC;AAAE,WAAO,KAAK,cAAc;AAAA,EAAwB;AAAA,EAEjG,IAAW,oBAA4B;AAAE,WAAO,KAAK,cAAc;AAAA,EAAU;AAAA,EAE7E,IAAW,eAAuB;AAAE,WAAO,KAAK,cAAc;AAAA,EAAc;AAChF;AAEO,MAAM,mCAAmC,kCAAS;AAAA,EACrD,YACoB,OACA,QACA,WACA,cACA,gBAClB;AAAE,UAAM;AALU;AACA;AACA;AACA;AACA;AAAA,EACP;AAAA,EALO;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAvExB,OAiEyD;AAAA;AAAA;AAQzD;AAEO,MAAM,4BAA4B,kCAA2C;AAAA,EAGhF,YACoB,UACA,SACA,WACA,SAClB;AACE,UAAM;AALU;AACA;AACA;AACA;AAGhB,SAAK,gBAAgB;AAAA,EACzB;AAAA,EAPoB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAlFxB,OA2EoF;AAAA;AAAA;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAeD,cAA6C;AAChD,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKO,YAAY,UAAwC;AACvD,SAAK,gBAAgB;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKO,cAAuB;AAC1B,WAAO,KAAK,kBAAkB;AAAA,EAClC;AACJ;","names":[]}
|
|
@@ -5,6 +5,7 @@ export { FinalizeUploadEvent, FinalizeUploadFailureEvent, ResumeUploadEvent, Upl
|
|
|
5
5
|
import '../types/index.js';
|
|
6
6
|
import '@wlindabla/http_client';
|
|
7
7
|
import '@wlindabla/event_dispatcher';
|
|
8
|
+
import '@wlindabla/http_client/events';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* HttpFileUploaderEvents - Event Constants for File Upload Operations
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/events/initialize/index.ts"],"sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n InitializeUploadOptions,\n InitializeUploadResponse\n} from \"../../types\";\n\nimport { BaseEvent } from \"@wlindabla/event_dispatcher\";\n\n/**\n * Event data for Upload State INITIALIZE\n */\nexport class InitializingUploadEvent extends BaseEvent{\n private _mediaId: string | null;\n constructor(\n public readonly initUploadOptions: InitializeUploadOptions\n ) {\n super();\n this._mediaId = null;\n }\n\n public setMediaId(_mediaUploadId: string) {\n this._mediaId = _mediaUploadId;\n }\n\n public get mediaId(): string {\n if (this._mediaId === null) {\n throw new Error(\n 'MediaId has not been set. ' +\n 'This likely means the InitializeUploadSubscriber failed. ' +\n 'Check that INITIALIZE_UPLOAD event was properly handled.'\n );\n }\n return this._mediaId;\n }\n}\n\n/**\n * Event data for INITIALIZE_UPLOAD_STARTED\n */\nexport class InitializeUploadStartedEvent extends BaseEvent {\n constructor(\n public readonly fileName: string,\n public readonly fileSize: number,\n public readonly fileHash: string\n ) { super(); }\n}\n\n/**\n * Event data for INITIALIZE_UPLOAD_SUCCESS\n */\nexport class InitializeUploadSuccessEvent extends BaseEvent{\n constructor(\n public readonly status: number,\n public readonly sessionId: string,\n public readonly responseData: InitializeUploadResponse\n ) { super(); }\n}\n\n/**\n * Event data for INITIALIZE_UPLOAD_FAILURE\n */\nexport class InitializeUploadFailureEvent extends BaseEvent {\n constructor(\n public readonly error: Error,\n public readonly status?: number,\n public readonly errorData?: any,\n public readonly responseData?: any,\n public readonly isNetworkError?: boolean\n ) { super(); }\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA,8BAA0B;AAKnB,MAAM,gCAAgC,kCAAS;AAAA,EAElD,YACoB,mBAClB;AACE,UAAM;AAFU;AAGhB,SAAK,WAAW;AAAA,EACpB;AAAA,EAJoB;AAAA,EAxBxB,OAqBsD;AAAA;AAAA;AAAA,EAC1C;AAAA,EAQD,WAAW,gBAAwB;AACtC,SAAK,WAAW;AAAA,EACpB;AAAA,EAEA,IAAW,UAAkB;AACzB,QAAI,KAAK,aAAa,MAAM;AACxB,YAAM,IAAI;AAAA,QACN;AAAA,MAGJ;AAAA,IACJ;AACA,WAAO,KAAK;AAAA,EAChB;AACJ;AAKO,MAAM,qCAAqC,kCAAU;AAAA,EACxD,YACoB,UACA,UACA,UAClB;AAAE,UAAM;AAHU;AACA;AACA;AAAA,EACP;AAAA,EAHO;AAAA,EACA;AAAA,EACA;AAAA,EArDxB,OAiD4D;AAAA;AAAA;AAM5D;AAKO,MAAM,qCAAqC,kCAAS;AAAA,EACvD,YACoB,QACA,WACA,cAClB;AAAE,UAAM;AAHU;AACA;AACA;AAAA,EACP;AAAA,EAHO;AAAA,EACA;AAAA,EACA;AAAA,EAhExB,OA4D2D;AAAA;AAAA;AAM3D;AAKO,MAAM,qCAAqC,kCAAU;AAAA,EACxD,YACoB,OACA,QACA,WACA,cACA,gBAClB;AAAE,UAAM;AALU;AACA;AACA;AACA;AACA;AAAA,EACP;AAAA,EALO;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EA7ExB,OAuE4D;AAAA;AAAA;AAQ5D;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/events/initialize/index.ts"],"sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n InitializeUploadOptions,\n InitializeUploadResponse\n} from \"../../types\";\n\nimport { BaseEvent } from \"@wlindabla/event_dispatcher\";\n\n/**\n * Event data for Upload State INITIALIZE\n */\nexport class InitializingUploadEvent extends BaseEvent{\n private _mediaId: string | null;\n constructor(\n public readonly initUploadOptions: InitializeUploadOptions\n ) {\n super();\n this._mediaId = null;\n } \n\n public setMediaId(_mediaUploadId: string) {\n this._mediaId = _mediaUploadId;\n }\n\n public get mediaId(): string {\n if (this._mediaId === null) {\n throw new Error(\n 'MediaId has not been set. ' +\n 'This likely means the InitializeUploadSubscriber failed. ' +\n 'Check that INITIALIZE_UPLOAD event was properly handled.'\n );\n }\n return this._mediaId;\n }\n}\n\n/**\n * Event data for INITIALIZE_UPLOAD_STARTED\n */\nexport class InitializeUploadStartedEvent extends BaseEvent {\n constructor(\n public readonly fileName: string,\n public readonly fileSize: number,\n public readonly fileHash: string\n ) { super(); }\n}\n\n/**\n * Event data for INITIALIZE_UPLOAD_SUCCESS\n */\nexport class InitializeUploadSuccessEvent extends BaseEvent{\n constructor(\n public readonly status: number,\n public readonly sessionId: string,\n public readonly responseData: InitializeUploadResponse\n ) { super(); }\n}\n\n/**\n * Event data for INITIALIZE_UPLOAD_FAILURE\n */\nexport class InitializeUploadFailureEvent extends BaseEvent {\n constructor(\n public readonly error: Error,\n public readonly status?: number,\n public readonly errorData?: any,\n public readonly responseData?: any,\n public readonly isNetworkError?: boolean\n ) { super(); }\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA,8BAA0B;AAKnB,MAAM,gCAAgC,kCAAS;AAAA,EAElD,YACoB,mBAClB;AACE,UAAM;AAFU;AAGhB,SAAK,WAAW;AAAA,EACpB;AAAA,EAJoB;AAAA,EAxBxB,OAqBsD;AAAA;AAAA;AAAA,EAC1C;AAAA,EAQD,WAAW,gBAAwB;AACtC,SAAK,WAAW;AAAA,EACpB;AAAA,EAEA,IAAW,UAAkB;AACzB,QAAI,KAAK,aAAa,MAAM;AACxB,YAAM,IAAI;AAAA,QACN;AAAA,MAGJ;AAAA,IACJ;AACA,WAAO,KAAK;AAAA,EAChB;AACJ;AAKO,MAAM,qCAAqC,kCAAU;AAAA,EACxD,YACoB,UACA,UACA,UAClB;AAAE,UAAM;AAHU;AACA;AACA;AAAA,EACP;AAAA,EAHO;AAAA,EACA;AAAA,EACA;AAAA,EArDxB,OAiD4D;AAAA;AAAA;AAM5D;AAKO,MAAM,qCAAqC,kCAAS;AAAA,EACvD,YACoB,QACA,WACA,cAClB;AAAE,UAAM;AAHU;AACA;AACA;AAAA,EACP;AAAA,EAHO;AAAA,EACA;AAAA,EACA;AAAA,EAhExB,OA4D2D;AAAA;AAAA;AAM3D;AAKO,MAAM,qCAAqC,kCAAU;AAAA,EACxD,YACoB,OACA,QACA,WACA,cACA,gBAClB;AAAE,UAAM;AALU;AACA;AACA;AACA;AACA;AAAA,EACP;AAAA,EALO;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EA7ExB,OAuE4D;AAAA;AAAA;AAQ5D;","names":[]}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -11,3 +11,4 @@ export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeU
|
|
|
11
11
|
export { UploadCancelledEvent, UploadPausedEvent, UploadProgressEvent, UploadResumedEvent, UploadStateChangedEvent } from './events/state/index.js';
|
|
12
12
|
import '@wlindabla/http_client';
|
|
13
13
|
import '@wlindabla/event_dispatcher';
|
|
14
|
+
import '@wlindabla/http_client/events';
|
|
@@ -3,6 +3,7 @@ import { InitializingUploadEvent } from '../events/initialize/index.js';
|
|
|
3
3
|
import { FinalizeUploadEvent } from '../events/complete/index.js';
|
|
4
4
|
import '../types/index.js';
|
|
5
5
|
import '@wlindabla/http_client';
|
|
6
|
+
import '@wlindabla/http_client/events';
|
|
6
7
|
|
|
7
8
|
declare class InitializeUploadSubscriber implements EventSubscriberInterface {
|
|
8
9
|
private readonly eventDispatcher;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/subscribers/index.ts"],"sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n EventSubscriberInterface,\n EventDispatcherInterface\n} from \"@wlindabla/event_dispatcher\";\n\nimport {\n HttpFileUploaderEvents,\n InitializingUploadEvent,\n InitializeUploadStartedEvent,\n InitializeUploadSuccessEvent,\n InitializeUploadFailureEvent,\n FinalizeUploadEvent,\n FinalizeUploadFailureEvent\n} from \"../events\";\n\nimport {\n HttpFetchError,\n safeFetch\n} from \"@wlindabla/http_client/core\";\n\nimport { InitializeUploadResponse } from \"../types\";\n\nimport { InitializeUploadFailureException } from \"../exceptions\";\n\n\n//src/subsciber/index.ts\n\nexport class InitializeUploadSubscriber implements EventSubscriberInterface {\n constructor(private readonly eventDispatcher: EventDispatcherInterface) {\n \n }\n\n public getSubscribedEvents(): Record<string, string | { listener: string; priority?: number | undefined; }> {\n return {\n [HttpFileUploaderEvents.INITIALIZE_UPLOAD]: { listener: \"onInitializeUpload\", priority: 100}\n }\n }\n\n /**\n * Initializes upload session with the server.\n * \n * @param fileHash - SHA-256 hash of the file (first 1MB)\n * @returns Session ID from server, or null if initialization failed\n * @throws {FileUploadInitializationError} If server returns error or network fails\n */\n public async onInitializeUpload(event:InitializingUploadEvent):Promise<void>{\n event.stopPropagation();\n const initialzeUploadRequestOptions = event.initUploadOptions;\n\n this.eventDispatcher.dispatch(\n new InitializeUploadStartedEvent(\n initialzeUploadRequestOptions.fileName,\n initialzeUploadRequestOptions.fileSize,\n initialzeUploadRequestOptions.fileHash\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_STARTED\n );\n \n try {\n const response = await safeFetch({\n url:initialzeUploadRequestOptions.endpointInit,\n methodSend: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...initialzeUploadRequestOptions.headers\n },\n data: {\n fileName:initialzeUploadRequestOptions.fileName,\n fileSize:initialzeUploadRequestOptions.fileSize,\n fileHash:initialzeUploadRequestOptions.fileHash,\n fileType: initialzeUploadRequestOptions.fileType,\n metadata: initialzeUploadRequestOptions.metadata,\n },\n responseType: \"json\",\n retryCount: 3,\n retryOnStatusCode: true,\n timeout: 45000\n });\n\n const status = response.status;\n \n // Handle error responses (4xx, 5xx)\n if (response.failed) {\n console.error(`Initialize upload failed (HTTP ${status}):`, response);\n\n const errorUploadFailure =new InitializeUploadFailureException(\n response,\n `Server returned error: HTTP ${response.status}`\n );\n\n this.eventDispatcher.dispatch(\n new InitializeUploadFailureEvent(\n errorUploadFailure,\n status,\n response.data),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_FAILURE\n\n );\n \n throw errorUploadFailure;\n }\n\n const responseData = response.data as InitializeUploadResponse;\n\n // Validate server response struct\n if (!responseData || typeof responseData !== 'object') {\n const validationError = 'Invalid server response: expected object, got ' + typeof responseData\n console.error('Invalid response structure:', responseData);\n\n const err=new InitializeUploadFailureException(\n responseData,\n validationError\n );\n throw err;\n }\n // Extract session ID\n let sessionId =\n responseData.mediaId ||\n responseData.mediaIdFromServer ||\n responseData.sessionId ||\n responseData.uploadId;\n\n if (!sessionId) {\n const missingKeyError = 'Server response missing required field: \"mediaId\",\"mediaIdFromServer\", \"sessionId\", or \"uploadId\"';\n\n console.error('Missing session ID in response:', responseData);\n const err=new InitializeUploadFailureException(\n responseData,\n missingKeyError\n );\n throw err;\n }\n\n if (typeof sessionId === \"number\") { sessionId = sessionId.toString(); }\n\n event.setMediaId(sessionId);\n\n this.eventDispatcher.dispatch(\n new InitializeUploadSuccessEvent(\n status,\n sessionId,\n responseData\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_SUCCESS\n );\n\n } catch (error) {\n if (error instanceof HttpFetchError) {\n this.eventDispatcher.dispatch(\n new InitializeUploadFailureEvent(\n error instanceof Error ? error : new Error(String(error)),\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_FAILURE\n );\n return;\n }\n console.error('Initialize upload exception:', error);\n\n throw error;\n }\n }\n}\n\nexport class FinalizeUploadSubscriber implements EventSubscriberInterface{\n\n constructor(private readonly eventDispatcher: EventDispatcherInterface) {\n\n }\n\n public getSubscribedEvents(): Record<string, string | { listener: string; priority?: number | undefined; }> {\n return {\n [HttpFileUploaderEvents.FINALIZE_UPLOAD]: { listener: \"onFinalizeUpload\", priority: 100 }\n }\n }\n\n public async onFinalizeUpload(event: FinalizeUploadEvent): Promise<void>{\n event.stopPropagation();\n try {\n const responseFinalizeUpload = await safeFetch({\n url: event.endPoint,\n methodSend: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...event.headers\n },\n data: { mediaId: event.mediaId, mediaHash: event.mediaHash }\n });\n\n event.setResponse(responseFinalizeUpload)\n } catch (error) {\n if (error instanceof HttpFetchError) {\n this.eventDispatcher.dispatch(\n new FinalizeUploadFailureEvent(error),\n HttpFileUploaderEvents.FINALIZE_UPLOAD_FAILURE\n );\n return;\n }\n\n throw error;\n }\n }\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/subscribers/index.ts"],"sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n EventSubscriberInterface,\n EventDispatcherInterface\n} from \"@wlindabla/event_dispatcher\";\n\nimport {\n HttpFileUploaderEvents,\n InitializingUploadEvent,\n InitializeUploadStartedEvent,\n InitializeUploadSuccessEvent,\n InitializeUploadFailureEvent,\n FinalizeUploadEvent,\n FinalizeUploadFailureEvent\n} from \"../events\";\n\nimport {\n HttpFetchError,\n safeFetch\n} from \"@wlindabla/http_client/core\";\n\nimport { InitializeUploadResponse } from \"../types\";\n\nimport { InitializeUploadFailureException } from \"../exceptions\";\n\nexport class InitializeUploadSubscriber implements EventSubscriberInterface {\n constructor(private readonly eventDispatcher: EventDispatcherInterface) {}\n\n public getSubscribedEvents(): Record<string, string | { listener: string; priority?: number | undefined; }> {\n return {\n [HttpFileUploaderEvents.INITIALIZE_UPLOAD]: { listener: \"onInitializeUpload\", priority: 100}\n }\n }\n\n /**\n * Initializes upload session with the server.\n * \n * @param fileHash - SHA-256 hash of the file (first 1MB)\n * @returns Session ID from server, or null if initialization failed\n * @throws {FileUploadInitializationError} If server returns error or network fails\n */\n public async onInitializeUpload(event:InitializingUploadEvent):Promise<void>{\n event.stopPropagation();\n const initialzeUploadRequestOptions = event.initUploadOptions;\n\n this.eventDispatcher.dispatch(\n new InitializeUploadStartedEvent(\n initialzeUploadRequestOptions.fileName,\n initialzeUploadRequestOptions.fileSize,\n initialzeUploadRequestOptions.fileHash\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_STARTED\n );\n \n try {\n const response = await safeFetch({\n url:initialzeUploadRequestOptions.endpointInit,\n methodSend: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...initialzeUploadRequestOptions.headers\n },\n data: {\n fileName:initialzeUploadRequestOptions.fileName,\n fileSize:initialzeUploadRequestOptions.fileSize,\n fileHash:initialzeUploadRequestOptions.fileHash,\n fileType: initialzeUploadRequestOptions.fileType,\n metadata: initialzeUploadRequestOptions.metadata,\n },\n responseType: \"json\",\n retryCount: 3,\n retryOnStatusCode: true,\n timeout: 45000\n });\n\n const status = response.status;\n \n // Handle error responses (4xx, 5xx)\n if (response.failed) {\n console.error(`Initialize upload failed (HTTP ${status}):`, response);\n\n const errorUploadFailure =new InitializeUploadFailureException(\n response,\n `Server returned error: HTTP ${response.status}`\n );\n\n this.eventDispatcher.dispatch(\n new InitializeUploadFailureEvent(\n errorUploadFailure,\n status,\n response.data),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_FAILURE\n\n );\n \n throw errorUploadFailure;\n }\n\n const responseData = response.data as InitializeUploadResponse;\n\n // Validate server response struct\n if (!responseData || typeof responseData !== 'object') {\n const validationError = 'Invalid server response: expected object, got ' + typeof responseData\n console.error('Invalid response structure:', responseData);\n\n const err=new InitializeUploadFailureException(\n responseData,\n validationError\n );\n throw err;\n }\n // Extract session ID\n let sessionId =\n responseData.mediaId ||\n responseData.mediaIdFromServer ||\n responseData.sessionId ||\n responseData.uploadId;\n\n if (!sessionId) {\n const missingKeyError = 'Server response missing required field: \"mediaId\",\"mediaIdFromServer\", \"sessionId\", or \"uploadId\"';\n\n console.error('Missing session ID in response:', responseData);\n const err=new InitializeUploadFailureException(\n responseData,\n missingKeyError\n );\n throw err;\n }\n\n if (typeof sessionId === \"number\") { sessionId = sessionId.toString(); }\n\n event.setMediaId(sessionId);\n\n this.eventDispatcher.dispatch(\n new InitializeUploadSuccessEvent(\n status,\n sessionId,\n responseData\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_SUCCESS\n );\n\n } catch (error) {\n if (error instanceof HttpFetchError) {\n this.eventDispatcher.dispatch(\n new InitializeUploadFailureEvent(\n error instanceof Error ? error : new Error(String(error)),\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_FAILURE\n );\n return;\n }\n console.error('Initialize upload exception:', error);\n\n throw error;\n }\n }\n}\n\nexport class FinalizeUploadSubscriber implements EventSubscriberInterface{\n\n constructor(private readonly eventDispatcher: EventDispatcherInterface) {}\n\n public getSubscribedEvents(): Record<string, string | { listener: string; priority?: number | undefined; }> {\n return {\n [HttpFileUploaderEvents.FINALIZE_UPLOAD]: { listener: \"onFinalizeUpload\", priority: 100 }\n }\n }\n\n public async onFinalizeUpload(event: FinalizeUploadEvent): Promise<void>{\n event.stopPropagation();\n try {\n const responseFinalizeUpload = await safeFetch({\n url: event.endPoint,\n methodSend: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...event.headers\n },\n data: { mediaId: event.mediaId, mediaHash: event.mediaHash }\n });\n\n event.setResponse(responseFinalizeUpload)\n } catch (error) {\n if (error instanceof HttpFetchError) {\n this.eventDispatcher.dispatch(\n new FinalizeUploadFailureEvent(error),\n HttpFileUploaderEvents.FINALIZE_UPLOAD_FAILURE\n );\n return;\n }\n\n throw error;\n }\n }\n}"],"mappings":"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","names":[]}
|
|
@@ -72,5 +72,5 @@ var InitializeUploadFailureEvent = class extends BaseEvent {
|
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeUploadSuccessEvent, InitializingUploadEvent };
|
|
75
|
-
//# sourceMappingURL=chunk-
|
|
76
|
-
//# sourceMappingURL=chunk-
|
|
75
|
+
//# sourceMappingURL=chunk-3JTTZCSQ.js.map
|
|
76
|
+
//# sourceMappingURL=chunk-3JTTZCSQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/events/initialize/index.ts"],"names":[],"mappings":";;;AAqBO,IAAM,uBAAA,GAAN,cAAsC,SAAA,CAAS;AAAA,EAElD,YACoB,iBAAA,EAClB;AACE,IAAA,KAAA,EAAM;AAFU,IAAA,IAAA,CAAA,iBAAA,GAAA,iBAAA;AAGhB,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAAA,EACpB;AAAA,EAJoB,iBAAA;AAAA,EAxBxB;AAqBsD,IAAA,MAAA,CAAA,IAAA,EAAA,yBAAA,CAAA;AAAA;AAAA,EAC1C,QAAA;AAAA,EAQD,WAAW,cAAA,EAAwB;AACtC,IAAA,IAAA,CAAK,QAAA,GAAW,cAAA;AAAA,EACpB;AAAA,EAEA,IAAW,OAAA,GAAkB;AACzB,IAAA,IAAI,IAAA,CAAK,aAAa,IAAA,EAAM;AACxB,MAAA,MAAM,IAAI,KAAA;AAAA,QACN;AAAA,OAGJ;AAAA,IACJ;AACA,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EAChB;AACJ;AAKO,IAAM,4BAAA,GAAN,cAA2C,SAAA,CAAU;AAAA,EACxD,WAAA,CACoB,QAAA,EACA,QAAA,EACA,QAAA,EAClB;AAAE,IAAA,KAAA,EAAM;AAHU,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EACP;AAAA,EAHO,QAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EArDxB;AAiD4D,IAAA,MAAA,CAAA,IAAA,EAAA,8BAAA,CAAA;AAAA;AAM5D;AAKO,IAAM,4BAAA,GAAN,cAA2C,SAAA,CAAS;AAAA,EACvD,WAAA,CACoB,MAAA,EACA,SAAA,EACA,YAAA,EAClB;AAAE,IAAA,KAAA,EAAM;AAHU,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AAAA,EACP;AAAA,EAHO,MAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EAhExB;AA4D2D,IAAA,MAAA,CAAA,IAAA,EAAA,8BAAA,CAAA;AAAA;AAM3D;AAKO,IAAM,4BAAA,GAAN,cAA2C,SAAA,CAAU;AAAA,EACxD,WAAA,CACoB,KAAA,EACA,MAAA,EACA,SAAA,EACA,cACA,cAAA,EAClB;AAAE,IAAA,KAAA,EAAM;AALU,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AACA,IAAA,IAAA,CAAA,cAAA,GAAA,cAAA;AAAA,EACP;AAAA,EALO,KAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EA7ExB;AAuE4D,IAAA,MAAA,CAAA,IAAA,EAAA,8BAAA,CAAA;AAAA;AAQ5D","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../../src/events/initialize/index.ts"],"names":[],"mappings":";;;AAqBO,IAAM,uBAAA,GAAN,cAAsC,SAAA,CAAS;AAAA,EAElD,YACoB,iBAAA,EAClB;AACE,IAAA,KAAA,EAAM;AAFU,IAAA,IAAA,CAAA,iBAAA,GAAA,iBAAA;AAGhB,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAAA,EACpB;AAAA,EAJoB,iBAAA;AAAA,EAxBxB;AAqBsD,IAAA,MAAA,CAAA,IAAA,EAAA,yBAAA,CAAA;AAAA;AAAA,EAC1C,QAAA;AAAA,EAQD,WAAW,cAAA,EAAwB;AACtC,IAAA,IAAA,CAAK,QAAA,GAAW,cAAA;AAAA,EACpB;AAAA,EAEA,IAAW,OAAA,GAAkB;AACzB,IAAA,IAAI,IAAA,CAAK,aAAa,IAAA,EAAM;AACxB,MAAA,MAAM,IAAI,KAAA;AAAA,QACN;AAAA,OAGJ;AAAA,IACJ;AACA,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EAChB;AACJ;AAKO,IAAM,4BAAA,GAAN,cAA2C,SAAA,CAAU;AAAA,EACxD,WAAA,CACoB,QAAA,EACA,QAAA,EACA,QAAA,EAClB;AAAE,IAAA,KAAA,EAAM;AAHU,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EACP;AAAA,EAHO,QAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EArDxB;AAiD4D,IAAA,MAAA,CAAA,IAAA,EAAA,8BAAA,CAAA;AAAA;AAM5D;AAKO,IAAM,4BAAA,GAAN,cAA2C,SAAA,CAAS;AAAA,EACvD,WAAA,CACoB,MAAA,EACA,SAAA,EACA,YAAA,EAClB;AAAE,IAAA,KAAA,EAAM;AAHU,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AAAA,EACP;AAAA,EAHO,MAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EAhExB;AA4D2D,IAAA,MAAA,CAAA,IAAA,EAAA,8BAAA,CAAA;AAAA;AAM3D;AAKO,IAAM,4BAAA,GAAN,cAA2C,SAAA,CAAU;AAAA,EACxD,WAAA,CACoB,KAAA,EACA,MAAA,EACA,SAAA,EACA,cACA,cAAA,EAClB;AAAE,IAAA,KAAA,EAAM;AALU,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AACA,IAAA,IAAA,CAAA,cAAA,GAAA,cAAA;AAAA,EACP;AAAA,EALO,KAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EA7ExB;AAuE4D,IAAA,MAAA,CAAA,IAAA,EAAA,8BAAA,CAAA;AAAA;AAQ5D","file":"chunk-3JTTZCSQ.js","sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n InitializeUploadOptions,\n InitializeUploadResponse\n} from \"../../types\";\n\nimport { BaseEvent } from \"@wlindabla/event_dispatcher\";\n\n/**\n * Event data for Upload State INITIALIZE\n */\nexport class InitializingUploadEvent extends BaseEvent{\n private _mediaId: string | null;\n constructor(\n public readonly initUploadOptions: InitializeUploadOptions\n ) {\n super();\n this._mediaId = null;\n } \n\n public setMediaId(_mediaUploadId: string) {\n this._mediaId = _mediaUploadId;\n }\n\n public get mediaId(): string {\n if (this._mediaId === null) {\n throw new Error(\n 'MediaId has not been set. ' +\n 'This likely means the InitializeUploadSubscriber failed. ' +\n 'Check that INITIALIZE_UPLOAD event was properly handled.'\n );\n }\n return this._mediaId;\n }\n}\n\n/**\n * Event data for INITIALIZE_UPLOAD_STARTED\n */\nexport class InitializeUploadStartedEvent extends BaseEvent {\n constructor(\n public readonly fileName: string,\n public readonly fileSize: number,\n public readonly fileHash: string\n ) { super(); }\n}\n\n/**\n * Event data for INITIALIZE_UPLOAD_SUCCESS\n */\nexport class InitializeUploadSuccessEvent extends BaseEvent{\n constructor(\n public readonly status: number,\n public readonly sessionId: string,\n public readonly responseData: InitializeUploadResponse\n ) { super(); }\n}\n\n/**\n * Event data for INITIALIZE_UPLOAD_FAILURE\n */\nexport class InitializeUploadFailureEvent extends BaseEvent {\n constructor(\n public readonly error: Error,\n public readonly status?: number,\n public readonly errorData?: any,\n public readonly responseData?: any,\n public readonly isNetworkError?: boolean\n ) { super(); }\n}\n\n"]}
|
|
@@ -119,5 +119,5 @@ var FinalizeUploadEvent = class extends BaseEvent {
|
|
|
119
119
|
};
|
|
120
120
|
|
|
121
121
|
export { FinalizeUploadEvent, FinalizeUploadFailureEvent, ResumeUploadEvent, UploadMediaCompleteEvent };
|
|
122
|
-
//# sourceMappingURL=chunk-
|
|
123
|
-
//# sourceMappingURL=chunk-
|
|
122
|
+
//# sourceMappingURL=chunk-BNMI7DW3.js.map
|
|
123
|
+
//# sourceMappingURL=chunk-BNMI7DW3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/events/complete/index.ts"],"names":[],"mappings":"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","file":"chunk-BNMI7DW3.js","sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\nimport { BaseEvent } from \"@wlindabla/event_dispatcher\";\nimport { ResumeData, UploadResult } from \"../../types\";\n\nimport type {\n ResponseEventInterface\n} from \"@wlindabla/http_client/events\";\n\nimport type {\n FetchResponseInterface\n} from \"@wlindabla/http_client\";\n\n/**\n * Event data for MEDIA_CHUNK_UPLOAD_RESUME\n */\nexport class ResumeUploadEvent {\n constructor(\n private readonly __resumeData: ResumeData,\n public readonly message: string) { }\n\n public get mediaId(): string | number { return this.__resumeData.fileId; }\n\n public get fileName(): string { return this.__resumeData.fileName; }\n\n public get uploadedChunks(): number { return this.__resumeData.uploadedChunks; }\n\n public get lastChunkIndex(): number { return this.__resumeData.lastChunkIndex; }\n\n public get lastBytePosition(): number { return this.__resumeData.lastBytePosition; }\n\n public get chunkSize(): number { return this.__resumeData.chunkSize; }\n\n public get fileSize(): number { return this.__resumeData.fileSize; }\n}\n\n/**\n * Event data for DOWNLOAD_MEDIA_COMPLETE\n */\nexport class UploadMediaCompleteEvent {\n constructor(private readonly _uploadResult: UploadResult) { }\n\n public get success(): boolean { return this._uploadResult.success; }\n\n public get mediaId(): string | number { return this._uploadResult.fileId! }\n\n public get totalBytes(): number { return this._uploadResult.totalBytes; }\n\n public get totalChunks(): number { return this._uploadResult.totalChunks; }\n\n public get finalizeUploadHttpResponse(): any { return this._uploadResult.finalizeUploadResponse; }\n\n public get operationDuration(): number { return this._uploadResult.duration; }\n\n public get averageSpeed(): number { return this._uploadResult.averageSpeed; }\n}\n\nexport class FinalizeUploadFailureEvent extends BaseEvent{\n constructor(\n public readonly error: Error,\n public readonly status?: number,\n public readonly errorData?: any,\n public readonly responseData?: any,\n public readonly isNetworkError?: boolean\n ) { super(); }\n}\n\nexport class FinalizeUploadEvent extends BaseEvent implements ResponseEventInterface{\n private fetchResponse: FetchResponseInterface|null;\n\n constructor(\n public readonly endPoint:string|URL,\n public readonly mediaId: string,\n public readonly mediaHash: string,\n public readonly headers?: HeadersInit\n ) {\n super();\n this.fetchResponse = null;\n }\n\n /**\n * Returns the response\n */\n public getResponse(): FetchResponseInterface | null {\n return this.fetchResponse;\n }\n\n /**\n * Sets the response\n */\n public setResponse(response: FetchResponseInterface): void {\n this.fetchResponse = response;\n }\n\n /**\n * Returns whether a response was set\n */\n public hasResponse(): boolean {\n return this.fetchResponse !== null;\n }\n}"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { InitializeUploadFailureException } from './chunk-NXYS73I4.js';
|
|
2
2
|
import { HttpFileUploaderEvents } from './chunk-JDL3U4OX.js';
|
|
3
|
-
import { FinalizeUploadFailureEvent } from './chunk-
|
|
4
|
-
import { InitializeUploadStartedEvent, InitializeUploadFailureEvent, InitializeUploadSuccessEvent } from './chunk-
|
|
3
|
+
import { FinalizeUploadFailureEvent } from './chunk-BNMI7DW3.js';
|
|
4
|
+
import { InitializeUploadStartedEvent, InitializeUploadFailureEvent, InitializeUploadSuccessEvent } from './chunk-3JTTZCSQ.js';
|
|
5
5
|
import { __name } from './chunk-7QVYU63E.js';
|
|
6
6
|
import { safeFetch, HttpFetchError } from '@wlindabla/http_client/core';
|
|
7
7
|
|
|
@@ -160,5 +160,5 @@ var FinalizeUploadSubscriber = class {
|
|
|
160
160
|
};
|
|
161
161
|
|
|
162
162
|
export { FinalizeUploadSubscriber, InitializeUploadSubscriber };
|
|
163
|
-
//# sourceMappingURL=chunk-
|
|
164
|
-
//# sourceMappingURL=chunk-
|
|
163
|
+
//# sourceMappingURL=chunk-HYNJBWW5.js.map
|
|
164
|
+
//# sourceMappingURL=chunk-HYNJBWW5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/subscribers/index.ts"],"names":[],"mappings":"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","file":"chunk-HYNJBWW5.js","sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n EventSubscriberInterface,\n EventDispatcherInterface\n} from \"@wlindabla/event_dispatcher\";\n\nimport {\n HttpFileUploaderEvents,\n InitializingUploadEvent,\n InitializeUploadStartedEvent,\n InitializeUploadSuccessEvent,\n InitializeUploadFailureEvent,\n FinalizeUploadEvent,\n FinalizeUploadFailureEvent\n} from \"../events\";\n\nimport {\n HttpFetchError,\n safeFetch\n} from \"@wlindabla/http_client/core\";\n\nimport { InitializeUploadResponse } from \"../types\";\n\nimport { InitializeUploadFailureException } from \"../exceptions\";\n\nexport class InitializeUploadSubscriber implements EventSubscriberInterface {\n constructor(private readonly eventDispatcher: EventDispatcherInterface) {}\n\n public getSubscribedEvents(): Record<string, string | { listener: string; priority?: number | undefined; }> {\n return {\n [HttpFileUploaderEvents.INITIALIZE_UPLOAD]: { listener: \"onInitializeUpload\", priority: 100}\n }\n }\n\n /**\n * Initializes upload session with the server.\n * \n * @param fileHash - SHA-256 hash of the file (first 1MB)\n * @returns Session ID from server, or null if initialization failed\n * @throws {FileUploadInitializationError} If server returns error or network fails\n */\n public async onInitializeUpload(event:InitializingUploadEvent):Promise<void>{\n event.stopPropagation();\n const initialzeUploadRequestOptions = event.initUploadOptions;\n\n this.eventDispatcher.dispatch(\n new InitializeUploadStartedEvent(\n initialzeUploadRequestOptions.fileName,\n initialzeUploadRequestOptions.fileSize,\n initialzeUploadRequestOptions.fileHash\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_STARTED\n );\n \n try {\n const response = await safeFetch({\n url:initialzeUploadRequestOptions.endpointInit,\n methodSend: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...initialzeUploadRequestOptions.headers\n },\n data: {\n fileName:initialzeUploadRequestOptions.fileName,\n fileSize:initialzeUploadRequestOptions.fileSize,\n fileHash:initialzeUploadRequestOptions.fileHash,\n fileType: initialzeUploadRequestOptions.fileType,\n metadata: initialzeUploadRequestOptions.metadata,\n },\n responseType: \"json\",\n retryCount: 3,\n retryOnStatusCode: true,\n timeout: 45000\n });\n\n const status = response.status;\n \n // Handle error responses (4xx, 5xx)\n if (response.failed) {\n console.error(`Initialize upload failed (HTTP ${status}):`, response);\n\n const errorUploadFailure =new InitializeUploadFailureException(\n response,\n `Server returned error: HTTP ${response.status}`\n );\n\n this.eventDispatcher.dispatch(\n new InitializeUploadFailureEvent(\n errorUploadFailure,\n status,\n response.data),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_FAILURE\n\n );\n \n throw errorUploadFailure;\n }\n\n const responseData = response.data as InitializeUploadResponse;\n\n // Validate server response struct\n if (!responseData || typeof responseData !== 'object') {\n const validationError = 'Invalid server response: expected object, got ' + typeof responseData\n console.error('Invalid response structure:', responseData);\n\n const err=new InitializeUploadFailureException(\n responseData,\n validationError\n );\n throw err;\n }\n // Extract session ID\n let sessionId =\n responseData.mediaId ||\n responseData.mediaIdFromServer ||\n responseData.sessionId ||\n responseData.uploadId;\n\n if (!sessionId) {\n const missingKeyError = 'Server response missing required field: \"mediaId\",\"mediaIdFromServer\", \"sessionId\", or \"uploadId\"';\n\n console.error('Missing session ID in response:', responseData);\n const err=new InitializeUploadFailureException(\n responseData,\n missingKeyError\n );\n throw err;\n }\n\n if (typeof sessionId === \"number\") { sessionId = sessionId.toString(); }\n\n event.setMediaId(sessionId);\n\n this.eventDispatcher.dispatch(\n new InitializeUploadSuccessEvent(\n status,\n sessionId,\n responseData\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_SUCCESS\n );\n\n } catch (error) {\n if (error instanceof HttpFetchError) {\n this.eventDispatcher.dispatch(\n new InitializeUploadFailureEvent(\n error instanceof Error ? error : new Error(String(error)),\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_FAILURE\n );\n return;\n }\n console.error('Initialize upload exception:', error);\n\n throw error;\n }\n }\n}\n\nexport class FinalizeUploadSubscriber implements EventSubscriberInterface{\n\n constructor(private readonly eventDispatcher: EventDispatcherInterface) {}\n\n public getSubscribedEvents(): Record<string, string | { listener: string; priority?: number | undefined; }> {\n return {\n [HttpFileUploaderEvents.FINALIZE_UPLOAD]: { listener: \"onFinalizeUpload\", priority: 100 }\n }\n }\n\n public async onFinalizeUpload(event: FinalizeUploadEvent): Promise<void>{\n event.stopPropagation();\n try {\n const responseFinalizeUpload = await safeFetch({\n url: event.endPoint,\n methodSend: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...event.headers\n },\n data: { mediaId: event.mediaId, mediaHash: event.mediaHash }\n });\n\n event.setResponse(responseFinalizeUpload)\n } catch (error) {\n if (error instanceof HttpFetchError) {\n this.eventDispatcher.dispatch(\n new FinalizeUploadFailureEvent(error),\n HttpFileUploaderEvents.FINALIZE_UPLOAD_FAILURE\n );\n return;\n }\n\n throw error;\n }\n }\n}"]}
|
|
@@ -2,16 +2,20 @@ import { ChunkUploadHttpErrorException, FileUploadChunkError } from './chunk-NXY
|
|
|
2
2
|
import { FileUtils, createChunkFormData } from './chunk-MFYC4PBP.js';
|
|
3
3
|
import { HttpFileUploaderEvents } from './chunk-JDL3U4OX.js';
|
|
4
4
|
import { UploadChunkStartedEvent, ChunkUploadHttpErrorResponseEvent } from './chunk-LD2DWZRJ.js';
|
|
5
|
-
import { ResumeUploadEvent, FinalizeUploadEvent, UploadMediaCompleteEvent } from './chunk-
|
|
6
|
-
import { InitializingUploadEvent } from './chunk-
|
|
5
|
+
import { ResumeUploadEvent, FinalizeUploadEvent, UploadMediaCompleteEvent } from './chunk-BNMI7DW3.js';
|
|
6
|
+
import { InitializingUploadEvent } from './chunk-3JTTZCSQ.js';
|
|
7
7
|
import { UploadCancelledEvent, UploadProgressEvent, UploadStateChangedEvent, UploadPausedEvent, UploadResumedEvent } from './chunk-6225YMFE.js';
|
|
8
8
|
import { __name } from './chunk-7QVYU63E.js';
|
|
9
|
-
import {
|
|
10
|
-
import { HttpFetchError, safeFetch } from '@wlindabla/http_client';
|
|
9
|
+
import { HttpFetchError, safeFetch } from '@wlindabla/http_client/core';
|
|
11
10
|
import pLimit from 'p-limit';
|
|
12
11
|
|
|
13
12
|
var ChunkedFileUploader = class {
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* @param _uploadEventDispatcher: new BrowserEventDispatcher(), //or new NodeJSEventDispatcher() if you have an environment NodeJs
|
|
15
|
+
* @param uploadResumeData: UploadResumeCacheInterface
|
|
16
|
+
* @param options: UploadOptions
|
|
17
|
+
*/
|
|
18
|
+
constructor(_uploadEventDispatcher, uploadResumeData, options) {
|
|
15
19
|
this._uploadEventDispatcher = _uploadEventDispatcher;
|
|
16
20
|
this.uploadResumeData = uploadResumeData;
|
|
17
21
|
this.options = options;
|
|
@@ -72,17 +76,22 @@ var ChunkedFileUploader = class {
|
|
|
72
76
|
headerInitialzingUpload,
|
|
73
77
|
concurrency = 3
|
|
74
78
|
} = this.options;
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
let file;
|
|
80
|
+
try {
|
|
81
|
+
file = this.file;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
const fileHash = await FileUtils.generateFileHash(this.file);
|
|
77
86
|
let fileId;
|
|
78
87
|
try {
|
|
79
88
|
const initializationEvent = await this._uploadEventDispatcher.dispatchAsync(
|
|
80
89
|
new InitializingUploadEvent(
|
|
81
90
|
{
|
|
82
91
|
fileHash,
|
|
83
|
-
fileName:
|
|
84
|
-
fileSize:
|
|
85
|
-
fileType:
|
|
92
|
+
fileName: file.name,
|
|
93
|
+
fileSize: file.size,
|
|
94
|
+
fileType: file.type,
|
|
86
95
|
metadata,
|
|
87
96
|
endpointInit: this.endPointOptions.init,
|
|
88
97
|
headers: headerInitialzingUpload
|
|
@@ -706,7 +715,7 @@ var ChunkedFileUploader = class {
|
|
|
706
715
|
* @linkedin https://www.linkedin.com/in/internationales-web-apps-services-120520193/
|
|
707
716
|
* @github https://github.com/Agbokoudjo/file_uploader
|
|
708
717
|
*
|
|
709
|
-
* @version
|
|
718
|
+
* @version 2.0.1
|
|
710
719
|
* @since 1.0.0
|
|
711
720
|
* @license MIT
|
|
712
721
|
*
|
|
@@ -719,5 +728,5 @@ var ChunkedFileUploader = class {
|
|
|
719
728
|
*/
|
|
720
729
|
|
|
721
730
|
export { ChunkedFileUploader };
|
|
722
|
-
//# sourceMappingURL=chunk-
|
|
723
|
-
//# sourceMappingURL=chunk-
|
|
731
|
+
//# sourceMappingURL=chunk-TONVXBLH.js.map
|
|
732
|
+
//# sourceMappingURL=chunk-TONVXBLH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/index.ts"],"names":[],"mappings":"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","file":"chunk-TONVXBLH.js","sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n EventDispatcherInterface\n} from \"@wlindabla/event_dispatcher\";\n\nimport {\n FetchResponseInterface\n} from \"@wlindabla/http_client/contracts\";\n\nimport {\n safeFetch,\n HttpFetchError\n} from \"@wlindabla/http_client/core\";\n\nimport {\n ChunkError,\n ChunkInfo,\n ResumeData,\n UploadEndpoints,\n UploadOptions,\n UploadProgress,\n UploadResult,\n UploadState\n} from \"../types\";\n\nimport { UploadResumeCacheInterface } from \"../cache\";\nimport {\n FileUtils,\n createChunkFormData\n} from \"../utils\";\n\nimport {\n ChunkUploadHttpErrorResponseEvent,\n HttpFileUploaderEvents,\n InitializingUploadEvent,\n UploadCancelledEvent,\n UploadProgressEvent,\n UploadStateChangedEvent,\n UploadChunkStartedEvent,\n UploadPausedEvent,\n UploadResumedEvent,\n ResumeUploadEvent,\n FinalizeUploadEvent,\n UploadMediaCompleteEvent\n} from \"../events\";\n\nimport { ChunkUploadHttpErrorException, FileUploadChunkError } from \"../exceptions\";\n\nimport pLimit from 'p-limit';\n\n\n/**\n * ChunkedFileUploader\n *\n * A production-ready, event-driven chunked file upload engine for Browser and Node.js.\n *\n * Designed and developed by **AGBOKOUDJO Franck** at\n * **INTERNATIONALES WEB APPS & SERVICES**, this class provides a robust,\n * framework-agnostic solution for uploading large files to a remote server\n * by splitting them into smaller chunks and sending them in parallel with\n * configurable concurrency control.\n *\n * ---\n *\n * ### How It Works\n *\n * The upload process follows a strict three-phase lifecycle:\n *\n * 1. **Initialization** — A session is opened with the server via the `init` endpoint.\n * The file is identified by its name, size, type, and a SHA-256 hash of its\n * first megabyte. The server returns a unique `mediaId` that identifies the session.\n *\n * 2. **Chunk Upload** — The file is sliced into fixed-size chunks and uploaded\n * concurrently using `p-limit`. Each chunk carries its index, the total number\n * of chunks, and the session `mediaId`. Failed chunks are retried automatically\n * with exponential backoff up to `maxRetries` attempts.\n *\n * 3. **Finalization** — Once all chunks are successfully uploaded, the `finalize`\n * endpoint is called to instruct the server to assemble the chunks into the\n * final file.\n *\n * ---\n *\n * ### Event-Driven Architecture\n *\n * This class follows the **Symfony EventDispatcher pattern** via\n * `@wlindabla/event_dispatcher`. Every meaningful moment in the upload\n * lifecycle emits a typed event that your application can listen to:\n *\n * ```\n * IDLE → INITIALIZING → UPLOADING → FINALIZING → COMPLETED\n * ↓ ↓\n * FAILED PAUSED ↔ UPLOADING\n * ↓\n * CANCELLED\n * ```\n *\n * All event name constants are centralized in {@link HttpFileUploaderEvents}.\n *\n * ---\n *\n * ### Subscriber Registration (Required)\n *\n * Before calling `.upload()`, you **must** register the two built-in subscribers\n * on your dispatcher. They handle the HTTP communication for the init and finalize phases:\n *\n * ```typescript\n * // Browser\n * const dispatcher = new BrowserEventDispatcher(document);\n * dispatcher.addSubscriber(new InitializeUploadSubscriber(dispatcher));\n * dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));\n *\n * // Node.js\n * const dispatcher = new NodeEventDispatcher();\n * dispatcher.addSubscriber(new InitializeUploadSubscriber(dispatcher));\n * dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));\n * ```\n *\n * ---\n *\n * ### Fluent Builder API\n *\n * The class exposes a fluent API to configure the upload before starting:\n *\n * ```typescript\n * const uploader = new ChunkedFileUploader(dispatcher, cache, options);\n *\n * await uploader\n * .withFile(file)\n * .withEndpoints({\n * init: 'https://api.example.com/upload/init',\n * upload: 'https://api.example.com/upload/chunk',\n * finalize: 'https://api.example.com/upload/finalize'\n * })\n * .upload();\n * ```\n *\n * ---\n *\n * ### Resumable Uploads\n *\n * When `autoSave: true` is set in options, the upload progress is persisted\n * after each successful chunk via the {@link UploadResumeCacheInterface}.\n * A failed or interrupted upload can be resumed later:\n *\n * ```typescript\n * const resumeData = await uploader.loadResumeData(file.name);\n *\n * if (resumeData) {\n * await uploader\n * .withFile(file)\n * .withEndpoints(endpoints)\n * .resumeUpload(resumeData);\n * }\n * ```\n *\n * ---\n *\n * ### Concurrency\n *\n * Multiple chunks can be uploaded simultaneously. The `concurrency` option\n * controls how many parallel uploads are active at any given time.\n * The default value is `3`, which provides a good balance between speed\n * and server/network load:\n *\n * ```typescript\n * // Upload 5 chunks in parallel\n * new ChunkedFileUploader(dispatcher, cache, { concurrency: 5 });\n * ```\n *\n * ---\n *\n * ### Pause, Resume and Cancel\n *\n * The upload can be paused, resumed, or cancelled at any time:\n *\n * ```typescript\n * uploader.pause(); // Pauses after the current chunk finishes\n * uploader.resume(); // Resumes from where it was paused\n * uploader.cancel(); // Aborts immediately via AbortController\n * ```\n *\n * ---\n *\n * ### Cache\n *\n * The library does **not** provide a built-in cache implementation to stay\n * lightweight and environment-agnostic. You must implement\n * {@link UploadResumeCacheInterface} with your preferred storage backend\n * (localStorage, IndexedDB, Redis, filesystem, etc.).\n *\n * ---\n *\n * @author AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * @company INTERNATIONALES WEB APPS & SERVICES\n * @phone +229 0167 25 18 86\n * @linkedin https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * @github https://github.com/Agbokoudjo/file_uploader\n *\n * @version 2.0.1\n * @since 1.0.0\n * @license MIT\n *\n * @see {@link HttpFileUploaderEvents} All event name constants\n * @see {@link UploadResumeCacheInterface} Cache interface to implement\n * @see {@link InitializeUploadSubscriber} Handles the init HTTP phase\n * @see {@link FinalizeUploadSubscriber} Handles the finalize HTTP phase\n * @see {@link UploadOptions} Full configuration reference\n * @see {@link https://github.com/Agbokoudjo/file_uploader | GitHub Repository}\n */\nexport class ChunkedFileUploader {\n private _file: File |null;\n private _endpoints: UploadEndpoints|null;\n \n private isPaused: boolean;\n private startTime: number;\n private uploadedBytes: number;\n private abortController: AbortController;\n private state: UploadState;\n private totalChunks: number;\n private percentage: number;\n private uploadedChunks: number;\n private lastUploadedChunkIndex: number; \n\n /**\n * @param _uploadEventDispatcher: new BrowserEventDispatcher(), //or new NodeJSEventDispatcher() if you have an environment NodeJs\n * @param uploadResumeData: UploadResumeCacheInterface\n * @param options: UploadOptions\n */\n public constructor(\n private readonly _uploadEventDispatcher: EventDispatcherInterface,\n private readonly uploadResumeData: UploadResumeCacheInterface,\n private options: UploadOptions\n ) {\n \n this._file = null;\n this._endpoints = null;\n this.isPaused = false;\n this.startTime = 0;\n this.uploadedBytes = 0;\n this.abortController = new AbortController();\n this.state = UploadState.IDLE;\n this.totalChunks = 0;\n this.percentage = 0;\n this.uploadedChunks = 0;\n this.lastUploadedChunkIndex = -1; \n }\n\n /**\n * Starts the chunked file upload process.\n * \n * @throws {Error} If file or endpoints are not set\n * @throws {InitializeUploadFailureException} If server initialization fails\n * @throws {FileUploadChunkError} If a chunk fails after all retries\n * \n * @example\n * ```typescript\n * const uploader = new ChunkedFileUploader(dispatcher, cache, options);\n * \n * uploader\n * .withFile(file)\n * .withEndpoints({ init, upload, finalize });\n * \n * await uploader.upload();\n * ```\n */\n public async upload(): Promise<void>{\n this.setState(UploadState.INITIALIZING);\n\n const { maxRetries = 3, config, speedMbps, metadata,\n headerInitialzingUpload, concurrency = 3\n } = this.options;\n\n let file: File;\n try {\n file = this.file;\n } catch (error) {\n throw error;\n }\n \n // Generate file hash for integrity check\n const fileHash = await FileUtils.generateFileHash(this.file); \n let fileId: string;\n try {\n const initializationEvent = await this._uploadEventDispatcher.dispatchAsync(\n new InitializingUploadEvent(\n {\n fileHash: fileHash,\n fileName: file.name,\n fileSize: file.size,\n fileType: file.type,\n metadata: metadata,\n endpointInit: this.endPointOptions.init,\n headers: headerInitialzingUpload\n }),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD\n )\n\n fileId = initializationEvent.mediaId;\n } catch (error) {\n this.setState(UploadState.FAILED);\n throw error;\n }\n\n this.setState(UploadState.UPLOADING);\n this.startTime = Date.now();\n this.uploadedBytes = 0;\n this.uploadedChunks = 0;\n this.lastUploadedChunkIndex = -1;\n\n const chunkSize = this.options.chunkSize || FileUtils.calculateChunkSize(file.size, speedMbps, config);\n this.totalChunks = Math.ceil(file.size / chunkSize);\n try {\n await this.uploadChunksWithConcurrency(\n file,\n chunkSize,\n fileId,\n fileHash,\n maxRetries,\n concurrency,\n 0\n );\n\n await this.finalizeUpload(fileId, fileHash);\n \n } catch (error) {\n this.handleUploadFailure(error as Error);\n throw error;\n }\n }\n\n public withFile(file: File): this {\n if (!file) {\n throw new Error('File is required');\n }\n if (file.size === 0) {\n throw new Error('Cannot upload empty file');\n }\n if (!(file instanceof File) || !(file instanceof Blob)) {\n throw new TypeError('Expected File or Blob instance');\n }\n this._file = file;\n return this;\n }\n\n public withEndpoints(endpoints: UploadEndpoints): this {\n if (!endpoints.init || !endpoints.upload || !endpoints.finalize) {\n throw new Error('All endpoints (init, upload, finalize) are required');\n }\n this._endpoints = endpoints;\n return this;\n }\n\n private get endPointOptions():UploadEndpoints {\n if (!this._endpoints) {\n throw new Error('Endpoint URL is required');\n }\n\n return this._endpoints;\n }\n\n private get file(): File{ \n if (!this._file) {\n throw new Error(`\n This operation requires a mandatory file.Did you forget to upload the file? \n Use the withFile(file: File|Blob) function of the ChunkedFileUploader ${this} class that you instantiated.\n `)\n }\n\n return this._file;\n }\n\n /**\n * Upload all chunks with concurrency control using p-limit\n * \n * @param file - File to upload\n * @param chunkSize - Size of each chunk\n * @param fileId - Server file ID\n * @param fileHash - File hash\n * @param maxRetries - Max retry attempts per chunk\n * @param concurrency - Number of concurrent uploads (default: 3)\n */\n private async uploadChunksWithConcurrency(\n file: File,\n chunkSize: number,\n fileId: string,\n fileHash: string,\n maxRetries: number,\n concurrency: number,\n startIndex:number=0\n ): Promise<void> {\n try {\n const limit = pLimit(concurrency);\n\n // Créer toutes les promesses avec limite\n const uploadPromises: Promise<void>[] = [];\n\n for (let chunkIndex = startIndex; chunkIndex < this.totalChunks; chunkIndex++) {\n // Wrapper chaque upload dans le limiteur\n const limitedUpload = limit(() =>\n this.processChunk(\n file,\n chunkIndex,\n chunkSize,\n fileId,\n fileHash,\n maxRetries\n )\n );\n\n uploadPromises.push(limitedUpload);\n }\n\n // Attendre que tous les chunks soient uploadés\n await Promise.all(uploadPromises);\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Process a single chunk: slice, upload with retry, and save progress.\n * \n * @param file - The file being uploaded\n * @param currentChunkIndex - Index of the current chunk (0-based)\n * @param chunkSize - Size of each chunk in bytes\n * @param fileId - Server-provided file/session ID\n * @param fileHash - SHA-256 hash of the file\n * @param maxRetries - Maximum number of retry attempts\n * \n * @throws {UploadCancelledException} If upload is cancelled\n * @throws {FileUploadChunkError} If chunk upload fails after all retries\n */\n private async processChunk(\n file:File,\n currentChunkIndex: number,\n chunkSize:number,\n fileId: string,\n fileHash:string,\n maxRetries:number\n ): Promise<void>{\n try {\n if (this.abortController.signal.aborted) {\n this._uploadEventDispatcher.dispatch(\n new UploadCancelledEvent(\n file.name,\n this.totalChunks,\n this.uploadedBytes,\n this.percentage,\n currentChunkIndex,\n 'Upload cancelled by user',\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_CANCELLED\n )\n \n return;\n }\n\n while (this.isPaused) {\n await this.sleep(100);\n }\n // Calcule où commencer dans le fichier\n const start = currentChunkIndex * chunkSize;\n // chunkIndex=0 → start=0\n // chunkIndex=1 → start=300\n // chunkIndex=2 → start=600\n // chunkIndex=3 → start=900\n\n // Calcule où finir (sans depasser la fin du fichier)\n const end = Math.min(file.size, start + chunkSize);\n // chunkIndex=0 → end=min(1000, 300)=300\n // chunkIndex=1 → end=min(1000, 600)=600\n // chunkIndex=2 → end=min(1000, 900)=900\n // chunkIndex=3 → end=min(1000, 1200)=1000 ← Limité !\n\n // Découpe le morceau\n const chunk = file.slice(start, end);\n // chunkIndex=0 → slice(0, 300) → 300 bytes\n // chunkIndex=1 → slice(300, 600) → 300 bytes\n // chunkIndex=2 → slice(600, 900) → 300 bytes\n // chunkIndex=3 → slice(900, 1000)→ 100 bytes ← Plus petit !\n const chunkInfo: ChunkInfo = {\n index: currentChunkIndex,\n start,\n end,\n size: chunk.size,\n attempt: 0,\n status: 'pending'\n };\n\n this._uploadEventDispatcher.dispatch(\n new UploadChunkStartedEvent(chunkInfo),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_STARTED\n );\n // Upload with retry\n await this.uploadChunkWithRetry(\n chunk,\n chunkInfo,\n fileId,\n fileHash,\n this.totalChunks,\n maxRetries\n );\n\n // Auto-save progress\n if (this.options.autoSave) {\n await this.saveResumeData(fileId,chunkSize);\n }\n } catch (error) {\n throw error;\n \n }\n }\n\n private async uploadChunkWithRetry(\n chunk: Blob,\n chunkInfo: ChunkInfo,\n fileId: string,\n fileHash: string,\n totalChunks: number,\n maxRetries: number\n ): Promise<void> {\n let success = false;\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxRetries && !success; attempt++) {\n chunkInfo.attempt = attempt + 1;\n chunkInfo.status = 'uploading';\n\n try {\n const response = await this.uploadChunk(chunk, chunkInfo, fileId, fileHash, totalChunks);\n success = true;\n chunkInfo.status = 'success';\n\n this.updateProgress(chunk.size, chunkInfo.index)\n\n this.notifyProgress(\n this.uploadedChunks,\n totalChunks,\n this.file.size,\n response\n );\n return;\n } catch (error) {\n if (error instanceof ChunkUploadHttpErrorException) {\n this._uploadEventDispatcher.dispatch(\n new ChunkUploadHttpErrorResponseEvent(\n error.errorPayload,\n error.statusResponse,\n this.endPointOptions.upload,\n chunkInfo),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_HTTP_ERROR_RESPONSE\n )\n }\n\n lastError = error as Error;\n chunkInfo.status = 'error';\n\n const chunkError: ChunkError= {\n chunk: chunkInfo,\n error: lastError,\n attempt: attempt + 1,\n willRetry: attempt < maxRetries - 1\n };\n\n if(error instanceof HttpFetchError){\n this._uploadEventDispatcher.dispatch(chunkError,HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_FAILED)\n }\n\n if (attempt < maxRetries - 1) {\n const delay = Math.pow(2, attempt) * 1000;\n await this.sleep(delay);\n\n console.info(`Retry #${attempt + 2} in ${delay / 1000}s...`);\n }\n }\n }\n\n if (!success) {\n const fileUploadChunkError = new FileUploadChunkError(\n `Failed to upload chunk ${chunkInfo.index} after ${maxRetries} attempts`,\n {\n chunk: chunkInfo,\n error: lastError!,\n attempt: maxRetries,\n willRetry: false\n }\n );\n\n this._uploadEventDispatcher.dispatch(\n fileUploadChunkError,\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_MAXRETRY_EXPIRE\n )\n \n throw fileUploadChunkError;\n }\n\n }\n\n private async uploadChunk(\n chunk: Blob,\n chunkInfo: ChunkInfo,\n mediaIdFromServer: string,\n fileHash: string,\n totalChunks: number\n ): Promise<FetchResponseInterface> {\n const media = this.file;\n const chunkFormData = createChunkFormData(\n chunk,\n {\n chunkIndex: chunkInfo.index,\n mediaId: mediaIdFromServer,\n fileSize: media.size,\n fileName: media.name,\n fileHash: fileHash,\n totalChunks: totalChunks\n }\n );\n\n try {\n const response_of_server = await safeFetch({\n url: this.endPointOptions.upload,\n headers: this.options.headers,\n data: chunkFormData,\n methodSend: \"POST\",\n responseType: \"json\",\n timeout: this.options.timeout ?? 60000,\n retryCount: 2,\n retryOnStatusCode: false,\n signal: this.createChunkAbortSignal()\n })\n const statusResponse = response_of_server.status;\n //if the server send a response which not success with status code(>=4XX ou >=5XX)\n if (response_of_server.failed) {\n throw new ChunkUploadHttpErrorException(response_of_server.data, statusResponse)\n }\n\n return response_of_server;\n } catch (error) {\n throw error;\n }\n\n }\n\n private createChunkAbortSignal(): AbortSignal {\n const chunkController = new AbortController();\n\n this.abortController.signal.addEventListener('abort', () => {\n chunkController.abort();\n });\n\n return chunkController.signal;\n }\n\n private notifyProgress(\n uploadedChunks: number,\n totalChunks: number,\n totalBytes: number,\n httpResponse: FetchResponseInterface): void {\n // Temps écoulé (minimum 0.1s pour éviter division par zéro)\n const elapsed = Math.max((Date.now() - this.startTime) / 1000, 0.1);\n const speed = this.uploadedBytes / elapsed; // Vitesse instantanée\n const remainingBytes = totalBytes - this.uploadedBytes; // Bytes restants\n // Temps restant (null si pas assez de données)\n const estimatedTimeRemaining = uploadedChunks < 2 ? null : remainingBytes / speed;\n\n this.percentage = Math.round((this.uploadedBytes / totalBytes) * 100);\n\n const progress: UploadProgress = {\n uploadedChunks,\n totalChunks,\n uploadedBytes: this.uploadedBytes,\n totalBytes,\n percentage: this.percentage,\n currentChunk: uploadedChunks,\n speed, // bytes/seconde\n estimatedTimeRemaining, // secondes (ou null)\n elapsed // secondes écoulées\n };\n\n this._uploadEventDispatcher.dispatch(\n new UploadProgressEvent(\n progress,\n httpResponse.data,\n httpResponse.status\n )\n )\n \n console.info(\n `Progress: ${this.percentage}% | ` +\n `Speed: ${FileUtils.formatBytes(speed)}/s | ` +\n `ETA: ${estimatedTimeRemaining ? FileUtils.formatDuration(estimatedTimeRemaining) : 'Calculating...'}`\n );\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n /**\n * Save current upload progress to cache for resume capability\n * \n * @param fileId - Server-provided file/session ID\n * @param chunkSize - Size of each chunk in bytes\n * @returns Saved resume data\n */\n private async saveResumeData(fileId: string, chunkSize: number): Promise<ResumeData> {\n const data: ResumeData = {\n fileId: fileId,\n fileName: this.file.name,\n fileSize: this.file.size,\n uploadedChunks: this.uploadedChunks,\n lastChunkIndex: this.lastUploadedChunkIndex,\n lastBytePosition: this.uploadedBytes,\n chunkSize: chunkSize,\n concurrency:this.options.concurrency || 3\n };\n\n await this.uploadResumeData.setItem(`upload_${this.file.name}`, data);\n\n console.info(\n `Resume data saved: ${this.uploadedChunks}/${Math.ceil(this.file.size / chunkSize)} chunks, ` +\n `last chunk index: ${this.lastUploadedChunkIndex}`\n );\n\n return data;\n }\n\n private setState(newState: UploadState): void {\n const oldState = this.state;\n this.state = newState;\n\n this._uploadEventDispatcher.dispatch(\n new UploadStateChangedEvent(\n oldState,\n newState,\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_STATE_CHANGED\n )\n \n }\n\n public getState(): UploadState {\n return this.state;\n }\n\n private handleUploadFailure(error: Error): void {\n this.setState(UploadState.FAILED);\n\n this._uploadEventDispatcher.dispatch(error, HttpFileUploaderEvents.DOWNLOAD_MEDIA_FAILURE);\n console.error('Upload failed:', error);\n }\n\n public cancel(): void {\n this.abortController.abort();\n this.setState(UploadState.CANCELLED);\n }\n\n public pause(): void {\n this.isPaused = true;\n this.setState(UploadState.PAUSED);\n this._uploadEventDispatcher.dispatch(\n new UploadPausedEvent(\n this.file.name,\n this.totalChunks,\n this.uploadedBytes,\n this.percentage,\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_PAUSED\n );\n }\n\n\n public resume(): void {\n this.isPaused = false;\n this.setState(UploadState.UPLOADING);\n this._uploadEventDispatcher.dispatch(\n new UploadResumedEvent(\n this.file.name,\n this.totalChunks,\n this.uploadedBytes, \n this.percentage),\n HttpFileUploaderEvents.UPLOAD_RESUMED,\n );\n }\n\n /**\n * Load previously saved resume data\n * \n * @param fileName - Name of the file to resume\n * @returns Resume data or null if not found\n */\n async loadResumeData(fileName: string): Promise<ResumeData | null> {\n try {\n const data = await this.uploadResumeData.getItem(`upload_${fileName}`);\n\n if (data) {\n console.info(\n `Resume data loaded: ${data.uploadedChunks} chunks uploaded, ` +\n `last index: ${data.lastChunkIndex}`\n );\n }\n return data;\n } catch (error) {\n console.warn(`No resume data found for ${fileName}`);\n return null;\n }\n }\n\n /**\n * Resume upload from saved state\n * \n * @param resumeData - Previously saved resume data\n * @returns Upload result\n */\n public async resumeUpload(resumeData: ResumeData): Promise<void> {\n const __message = `Resuming upload from chunk ${resumeData.lastChunkIndex + 1} ` +\n `(${resumeData.uploadedChunks} chunks already uploaded)`;\n\n // Restore state\n this.uploadedBytes = resumeData.lastBytePosition;\n this.uploadedChunks = resumeData.uploadedChunks;\n this.lastUploadedChunkIndex = resumeData.lastChunkIndex;\n\n // Calculate adjusted start time for accurate speed calculation\n const assumedSpeed = 500000; // 500 KB/s assumed\n const timeAlreadySpent = resumeData.lastBytePosition / assumedSpeed;\n this.startTime = Date.now() - (timeAlreadySpent * 1000);\n\n const { maxRetries = 3 } = this.options;\n const fileHash = await FileUtils.generateFileHash(this.file);\n const chunkSize = resumeData.chunkSize;\n this.totalChunks = Math.ceil(this.file.size / chunkSize);\n\n try {\n this._uploadEventDispatcher.dispatch(\n new ResumeUploadEvent(resumeData,__message),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_RESUME\n )\n await this.uploadChunksWithConcurrency(\n this.file,\n chunkSize,\n resumeData.fileId,\n fileHash,\n maxRetries,\n resumeData.concurrency,\n resumeData.lastChunkIndex + 1\n )\n ;\n await this.finalizeUpload(resumeData.fileId, fileHash);\n\n } catch (error) {\n this.handleUploadFailure(error as Error);\n throw error;\n }\n }\n\n private updateProgress(chunkSize: number, chunkIndex: number): void {\n this.uploadedBytes += chunkSize;\n this.uploadedChunks++;\n this.lastUploadedChunkIndex = Math.max(this.lastUploadedChunkIndex,chunkIndex);\n }\n \n private async finalizeUpload(mediaId: string, fileHash: string): Promise<void> {\n try {\n \n const finalizeUploadEvent = await this._uploadEventDispatcher.dispatchAsync(\n new FinalizeUploadEvent(\n this.endPointOptions.finalize,\n mediaId,\n fileHash,\n this.options.headerFinalezingUpload)\n ,\n HttpFileUploaderEvents.FINALIZE_UPLOAD\n )\n\n this.setState(UploadState.FINALIZING);\n\n\n const duration = (Date.now() - this.startTime) / 1000;\n\n const uploadResult: UploadResult = {\n success: true,\n finalizeUploadResponse: finalizeUploadEvent.hasResponse() ? finalizeUploadEvent.getResponse() : null ,\n totalChunks: this.totalChunks,\n totalBytes: this.file.size,\n duration,\n averageSpeed: this.file.size / duration,\n fileId: mediaId\n };\n\n this.setState(UploadState.COMPLETED);\n\n this._uploadEventDispatcher.dispatch(\n new UploadMediaCompleteEvent(uploadResult),HttpFileUploaderEvents.DOWNLOAD_MEDIA_COMPLETE\n )\n\n } catch (error) {\n throw error;\n }\n }\n}"]}
|
|
@@ -151,7 +151,7 @@ import '@wlindabla/http_client';
|
|
|
151
151
|
* @linkedin https://www.linkedin.com/in/internationales-web-apps-services-120520193/
|
|
152
152
|
* @github https://github.com/Agbokoudjo/file_uploader
|
|
153
153
|
*
|
|
154
|
-
* @version
|
|
154
|
+
* @version 2.0.1
|
|
155
155
|
* @since 1.0.0
|
|
156
156
|
* @license MIT
|
|
157
157
|
*
|
|
@@ -177,8 +177,12 @@ declare class ChunkedFileUploader {
|
|
|
177
177
|
private percentage;
|
|
178
178
|
private uploadedChunks;
|
|
179
179
|
private lastUploadedChunkIndex;
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
/**
|
|
181
|
+
* @param _uploadEventDispatcher: new BrowserEventDispatcher(), //or new NodeJSEventDispatcher() if you have an environment NodeJs
|
|
182
|
+
* @param uploadResumeData: UploadResumeCacheInterface
|
|
183
|
+
* @param options: UploadOptions
|
|
184
|
+
*/
|
|
185
|
+
constructor(_uploadEventDispatcher: EventDispatcherInterface, uploadResumeData: UploadResumeCacheInterface, options: UploadOptions);
|
|
182
186
|
/**
|
|
183
187
|
* Starts the chunked file upload process.
|
|
184
188
|
*
|
package/dist/esm/core/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { ChunkedFileUploader } from '../chunk-
|
|
1
|
+
export { ChunkedFileUploader } from '../chunk-TONVXBLH.js';
|
|
2
2
|
import '../chunk-NXYS73I4.js';
|
|
3
3
|
import '../chunk-MFYC4PBP.js';
|
|
4
4
|
import '../chunk-X757PBC5.js';
|
|
5
5
|
import '../chunk-JDL3U4OX.js';
|
|
6
6
|
import '../chunk-LD2DWZRJ.js';
|
|
7
|
-
import '../chunk-
|
|
8
|
-
import '../chunk-
|
|
7
|
+
import '../chunk-BNMI7DW3.js';
|
|
8
|
+
import '../chunk-3JTTZCSQ.js';
|
|
9
9
|
import '../chunk-6225YMFE.js';
|
|
10
10
|
import '../chunk-7QVYU63E.js';
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BaseEvent } from '@wlindabla/event_dispatcher';
|
|
2
2
|
import { ResumeData, UploadResult } from '../../types/index.mjs';
|
|
3
|
-
import { ResponseEventInterface
|
|
3
|
+
import { ResponseEventInterface } from '@wlindabla/http_client/events';
|
|
4
|
+
import { FetchResponseInterface } from '@wlindabla/http_client';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Event data for MEDIA_CHUNK_UPLOAD_RESUME
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { FinalizeUploadEvent, FinalizeUploadFailureEvent, ResumeUploadEvent, UploadMediaCompleteEvent } from '../../chunk-
|
|
1
|
+
export { FinalizeUploadEvent, FinalizeUploadFailureEvent, ResumeUploadEvent, UploadMediaCompleteEvent } from '../../chunk-BNMI7DW3.js';
|
|
2
2
|
import '../../chunk-7QVYU63E.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -5,6 +5,7 @@ export { FinalizeUploadEvent, FinalizeUploadFailureEvent, ResumeUploadEvent, Upl
|
|
|
5
5
|
import '../types/index.mjs';
|
|
6
6
|
import '@wlindabla/http_client';
|
|
7
7
|
import '@wlindabla/event_dispatcher';
|
|
8
|
+
import '@wlindabla/http_client/events';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* HttpFileUploaderEvents - Event Constants for File Upload Operations
|
package/dist/esm/events/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { HttpFileUploaderEvents } from '../chunk-JDL3U4OX.js';
|
|
2
2
|
export { ChunkUploadHttpErrorResponseEvent, UploadChunkStartedEvent } from '../chunk-LD2DWZRJ.js';
|
|
3
|
-
export { FinalizeUploadEvent, FinalizeUploadFailureEvent, ResumeUploadEvent, UploadMediaCompleteEvent } from '../chunk-
|
|
4
|
-
export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeUploadSuccessEvent, InitializingUploadEvent } from '../chunk-
|
|
3
|
+
export { FinalizeUploadEvent, FinalizeUploadFailureEvent, ResumeUploadEvent, UploadMediaCompleteEvent } from '../chunk-BNMI7DW3.js';
|
|
4
|
+
export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeUploadSuccessEvent, InitializingUploadEvent } from '../chunk-3JTTZCSQ.js';
|
|
5
5
|
export { UploadCancelledEvent, UploadPausedEvent, UploadProgressEvent, UploadResumedEvent, UploadStateChangedEvent } from '../chunk-6225YMFE.js';
|
|
6
6
|
import '../chunk-7QVYU63E.js';
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeUploadSuccessEvent, InitializingUploadEvent } from '../../chunk-
|
|
1
|
+
export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeUploadSuccessEvent, InitializingUploadEvent } from '../../chunk-3JTTZCSQ.js';
|
|
2
2
|
import '../../chunk-7QVYU63E.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.d.mts
CHANGED
|
@@ -11,3 +11,4 @@ export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeU
|
|
|
11
11
|
export { UploadCancelledEvent, UploadPausedEvent, UploadProgressEvent, UploadResumedEvent, UploadStateChangedEvent } from './events/state/index.mjs';
|
|
12
12
|
import '@wlindabla/http_client';
|
|
13
13
|
import '@wlindabla/event_dispatcher';
|
|
14
|
+
import '@wlindabla/http_client/events';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export { FinalizeUploadSubscriber, InitializeUploadSubscriber } from './chunk-
|
|
1
|
+
export { FinalizeUploadSubscriber, InitializeUploadSubscriber } from './chunk-HYNJBWW5.js';
|
|
2
2
|
export { DefaultUploadResumeCacheAdapter, UploadCacheError } from './chunk-PFALORWQ.js';
|
|
3
|
-
export { ChunkedFileUploader } from './chunk-
|
|
3
|
+
export { ChunkedFileUploader } from './chunk-TONVXBLH.js';
|
|
4
4
|
export { ChunkUploadHttpErrorException, FileUploadChunkError, InitializeUploadFailureException, UploadCancelledException } from './chunk-NXYS73I4.js';
|
|
5
5
|
export { ChunkFormDataBuilder, ExponentialBackoffStrategy, FileUtils, LinearBackoffStrategy, createChunkFormData, updateProgressBarHTMLNotified } from './chunk-MFYC4PBP.js';
|
|
6
6
|
import './chunk-X757PBC5.js';
|
|
7
7
|
export { HttpFileUploaderEvents } from './chunk-JDL3U4OX.js';
|
|
8
8
|
export { ChunkUploadHttpErrorResponseEvent, UploadChunkStartedEvent } from './chunk-LD2DWZRJ.js';
|
|
9
|
-
export { FinalizeUploadEvent, FinalizeUploadFailureEvent, ResumeUploadEvent, UploadMediaCompleteEvent } from './chunk-
|
|
10
|
-
export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeUploadSuccessEvent, InitializingUploadEvent } from './chunk-
|
|
9
|
+
export { FinalizeUploadEvent, FinalizeUploadFailureEvent, ResumeUploadEvent, UploadMediaCompleteEvent } from './chunk-BNMI7DW3.js';
|
|
10
|
+
export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeUploadSuccessEvent, InitializingUploadEvent } from './chunk-3JTTZCSQ.js';
|
|
11
11
|
export { UploadCancelledEvent, UploadPausedEvent, UploadProgressEvent, UploadResumedEvent, UploadStateChangedEvent } from './chunk-6225YMFE.js';
|
|
12
12
|
import './chunk-7QVYU63E.js';
|
|
13
13
|
//# sourceMappingURL=index.js.map
|
|
@@ -3,6 +3,7 @@ import { InitializingUploadEvent } from '../events/initialize/index.mjs';
|
|
|
3
3
|
import { FinalizeUploadEvent } from '../events/complete/index.mjs';
|
|
4
4
|
import '../types/index.mjs';
|
|
5
5
|
import '@wlindabla/http_client';
|
|
6
|
+
import '@wlindabla/http_client/events';
|
|
6
7
|
|
|
7
8
|
declare class InitializeUploadSubscriber implements EventSubscriberInterface {
|
|
8
9
|
private readonly eventDispatcher;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { FinalizeUploadSubscriber, InitializeUploadSubscriber } from '../chunk-
|
|
1
|
+
export { FinalizeUploadSubscriber, InitializeUploadSubscriber } from '../chunk-HYNJBWW5.js';
|
|
2
2
|
import '../chunk-NXYS73I4.js';
|
|
3
3
|
import '../chunk-JDL3U4OX.js';
|
|
4
4
|
import '../chunk-LD2DWZRJ.js';
|
|
5
|
-
import '../chunk-
|
|
6
|
-
import '../chunk-
|
|
5
|
+
import '../chunk-BNMI7DW3.js';
|
|
6
|
+
import '../chunk-3JTTZCSQ.js';
|
|
7
7
|
import '../chunk-6225YMFE.js';
|
|
8
8
|
import '../chunk-7QVYU63E.js';
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wlindabla/file_uploader",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "A powerful, event-driven chunked file uploader for browser and Node.js.A robust, framework-agnostic TypeScript library for uploading large files in chunks with resume capability, automatic retry, and comprehensive event handling.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "AGBOKOUDJO Franck",
|
|
@@ -219,22 +219,22 @@
|
|
|
219
219
|
"release": "yarn build && changeset publish"
|
|
220
220
|
},
|
|
221
221
|
"dependencies": {
|
|
222
|
-
"@wlindabla/event_dispatcher": "^1.2.
|
|
223
|
-
"@wlindabla/http_client": "^1.
|
|
222
|
+
"@wlindabla/event_dispatcher": "^1.2.2",
|
|
223
|
+
"@wlindabla/http_client": "^1.2.3",
|
|
224
224
|
"p-limit": "^7.3.0"
|
|
225
225
|
},
|
|
226
226
|
"devDependencies": {
|
|
227
|
-
"@types/node": "^25.
|
|
227
|
+
"@types/node": "^25.9.3",
|
|
228
228
|
"@types/p-limit": "^2.2.0",
|
|
229
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
230
|
-
"@typescript-eslint/parser": "^8.
|
|
231
|
-
"eslint": "^10.
|
|
229
|
+
"@typescript-eslint/eslint-plugin": "^8.61.1",
|
|
230
|
+
"@typescript-eslint/parser": "^8.61.1",
|
|
231
|
+
"eslint": "^10.5.0",
|
|
232
232
|
"eslint-config-prettier": "^10.1.8",
|
|
233
|
-
"prettier": "^3.8.
|
|
233
|
+
"prettier": "^3.8.4",
|
|
234
234
|
"tsup": "^8.5.1",
|
|
235
235
|
"typescript": "^6.0.3",
|
|
236
|
-
"vite": "^8.0.
|
|
237
|
-
"vitest": "^4.1.
|
|
236
|
+
"vite": "^8.0.16",
|
|
237
|
+
"vitest": "^4.1.9"
|
|
238
238
|
},
|
|
239
239
|
"engines": {
|
|
240
240
|
"node": ">=18.0.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/subscribers/index.ts"],"names":[],"mappings":"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","file":"chunk-332NNKOW.js","sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n EventSubscriberInterface,\n EventDispatcherInterface\n} from \"@wlindabla/event_dispatcher\";\n\nimport {\n HttpFileUploaderEvents,\n InitializingUploadEvent,\n InitializeUploadStartedEvent,\n InitializeUploadSuccessEvent,\n InitializeUploadFailureEvent,\n FinalizeUploadEvent,\n FinalizeUploadFailureEvent\n} from \"../events\";\n\nimport {\n HttpFetchError,\n safeFetch\n} from \"@wlindabla/http_client/core\";\n\nimport { InitializeUploadResponse } from \"../types\";\n\nimport { InitializeUploadFailureException } from \"../exceptions\";\n\n\n//src/subsciber/index.ts\n\nexport class InitializeUploadSubscriber implements EventSubscriberInterface {\n constructor(private readonly eventDispatcher: EventDispatcherInterface) {\n \n }\n\n public getSubscribedEvents(): Record<string, string | { listener: string; priority?: number | undefined; }> {\n return {\n [HttpFileUploaderEvents.INITIALIZE_UPLOAD]: { listener: \"onInitializeUpload\", priority: 100}\n }\n }\n\n /**\n * Initializes upload session with the server.\n * \n * @param fileHash - SHA-256 hash of the file (first 1MB)\n * @returns Session ID from server, or null if initialization failed\n * @throws {FileUploadInitializationError} If server returns error or network fails\n */\n public async onInitializeUpload(event:InitializingUploadEvent):Promise<void>{\n event.stopPropagation();\n const initialzeUploadRequestOptions = event.initUploadOptions;\n\n this.eventDispatcher.dispatch(\n new InitializeUploadStartedEvent(\n initialzeUploadRequestOptions.fileName,\n initialzeUploadRequestOptions.fileSize,\n initialzeUploadRequestOptions.fileHash\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_STARTED\n );\n \n try {\n const response = await safeFetch({\n url:initialzeUploadRequestOptions.endpointInit,\n methodSend: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...initialzeUploadRequestOptions.headers\n },\n data: {\n fileName:initialzeUploadRequestOptions.fileName,\n fileSize:initialzeUploadRequestOptions.fileSize,\n fileHash:initialzeUploadRequestOptions.fileHash,\n fileType: initialzeUploadRequestOptions.fileType,\n metadata: initialzeUploadRequestOptions.metadata,\n },\n responseType: \"json\",\n retryCount: 3,\n retryOnStatusCode: true,\n timeout: 45000\n });\n\n const status = response.status;\n \n // Handle error responses (4xx, 5xx)\n if (response.failed) {\n console.error(`Initialize upload failed (HTTP ${status}):`, response);\n\n const errorUploadFailure =new InitializeUploadFailureException(\n response,\n `Server returned error: HTTP ${response.status}`\n );\n\n this.eventDispatcher.dispatch(\n new InitializeUploadFailureEvent(\n errorUploadFailure,\n status,\n response.data),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_FAILURE\n\n );\n \n throw errorUploadFailure;\n }\n\n const responseData = response.data as InitializeUploadResponse;\n\n // Validate server response struct\n if (!responseData || typeof responseData !== 'object') {\n const validationError = 'Invalid server response: expected object, got ' + typeof responseData\n console.error('Invalid response structure:', responseData);\n\n const err=new InitializeUploadFailureException(\n responseData,\n validationError\n );\n throw err;\n }\n // Extract session ID\n let sessionId =\n responseData.mediaId ||\n responseData.mediaIdFromServer ||\n responseData.sessionId ||\n responseData.uploadId;\n\n if (!sessionId) {\n const missingKeyError = 'Server response missing required field: \"mediaId\",\"mediaIdFromServer\", \"sessionId\", or \"uploadId\"';\n\n console.error('Missing session ID in response:', responseData);\n const err=new InitializeUploadFailureException(\n responseData,\n missingKeyError\n );\n throw err;\n }\n\n if (typeof sessionId === \"number\") { sessionId = sessionId.toString(); }\n\n event.setMediaId(sessionId);\n\n this.eventDispatcher.dispatch(\n new InitializeUploadSuccessEvent(\n status,\n sessionId,\n responseData\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_SUCCESS\n );\n\n } catch (error) {\n if (error instanceof HttpFetchError) {\n this.eventDispatcher.dispatch(\n new InitializeUploadFailureEvent(\n error instanceof Error ? error : new Error(String(error)),\n ),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD_FAILURE\n );\n return;\n }\n console.error('Initialize upload exception:', error);\n\n throw error;\n }\n }\n}\n\nexport class FinalizeUploadSubscriber implements EventSubscriberInterface{\n\n constructor(private readonly eventDispatcher: EventDispatcherInterface) {\n\n }\n\n public getSubscribedEvents(): Record<string, string | { listener: string; priority?: number | undefined; }> {\n return {\n [HttpFileUploaderEvents.FINALIZE_UPLOAD]: { listener: \"onFinalizeUpload\", priority: 100 }\n }\n }\n\n public async onFinalizeUpload(event: FinalizeUploadEvent): Promise<void>{\n event.stopPropagation();\n try {\n const responseFinalizeUpload = await safeFetch({\n url: event.endPoint,\n methodSend: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...event.headers\n },\n data: { mediaId: event.mediaId, mediaHash: event.mediaHash }\n });\n\n event.setResponse(responseFinalizeUpload)\n } catch (error) {\n if (error instanceof HttpFetchError) {\n this.eventDispatcher.dispatch(\n new FinalizeUploadFailureEvent(error),\n HttpFileUploaderEvents.FINALIZE_UPLOAD_FAILURE\n );\n return;\n }\n\n throw error;\n }\n }\n}"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/index.ts"],"names":[],"mappings":"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","file":"chunk-6DIKDA6J.js","sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\n\nimport {\n BrowserEventDispatcher,\n EventDispatcherInterface\n} from \"@wlindabla/event_dispatcher\";\n\nimport {\n FetchResponseInterface,\n safeFetch,\n HttpFetchError\n} from \"@wlindabla/http_client\";\n\nimport {\n ChunkError,\n ChunkInfo,\n ResumeData,\n UploadEndpoints,\n UploadOptions,\n UploadProgress,\n UploadResult,\n UploadState\n} from \"../types\";\n\nimport { UploadResumeCacheInterface } from \"../cache\";\nimport {\n FileUtils,\n createChunkFormData\n} from \"../utils\";\n\nimport {\n ChunkUploadHttpErrorResponseEvent,\n HttpFileUploaderEvents,\n InitializingUploadEvent,\n UploadCancelledEvent,\n UploadProgressEvent,\n UploadStateChangedEvent,\n UploadChunkStartedEvent,\n UploadPausedEvent,\n UploadResumedEvent,\n ResumeUploadEvent,\n FinalizeUploadEvent,\n UploadMediaCompleteEvent\n} from \"../events\";\n\nimport { ChunkUploadHttpErrorException, FileUploadChunkError } from \"../exceptions\";\n\nimport pLimit from 'p-limit';\n\n\n/**\n * ChunkedFileUploader\n *\n * A production-ready, event-driven chunked file upload engine for Browser and Node.js.\n *\n * Designed and developed by **AGBOKOUDJO Franck** at\n * **INTERNATIONALES WEB APPS & SERVICES**, this class provides a robust,\n * framework-agnostic solution for uploading large files to a remote server\n * by splitting them into smaller chunks and sending them in parallel with\n * configurable concurrency control.\n *\n * ---\n *\n * ### How It Works\n *\n * The upload process follows a strict three-phase lifecycle:\n *\n * 1. **Initialization** — A session is opened with the server via the `init` endpoint.\n * The file is identified by its name, size, type, and a SHA-256 hash of its\n * first megabyte. The server returns a unique `mediaId` that identifies the session.\n *\n * 2. **Chunk Upload** — The file is sliced into fixed-size chunks and uploaded\n * concurrently using `p-limit`. Each chunk carries its index, the total number\n * of chunks, and the session `mediaId`. Failed chunks are retried automatically\n * with exponential backoff up to `maxRetries` attempts.\n *\n * 3. **Finalization** — Once all chunks are successfully uploaded, the `finalize`\n * endpoint is called to instruct the server to assemble the chunks into the\n * final file.\n *\n * ---\n *\n * ### Event-Driven Architecture\n *\n * This class follows the **Symfony EventDispatcher pattern** via\n * `@wlindabla/event_dispatcher`. Every meaningful moment in the upload\n * lifecycle emits a typed event that your application can listen to:\n *\n * ```\n * IDLE → INITIALIZING → UPLOADING → FINALIZING → COMPLETED\n * ↓ ↓\n * FAILED PAUSED ↔ UPLOADING\n * ↓\n * CANCELLED\n * ```\n *\n * All event name constants are centralized in {@link HttpFileUploaderEvents}.\n *\n * ---\n *\n * ### Subscriber Registration (Required)\n *\n * Before calling `.upload()`, you **must** register the two built-in subscribers\n * on your dispatcher. They handle the HTTP communication for the init and finalize phases:\n *\n * ```typescript\n * // Browser\n * const dispatcher = new BrowserEventDispatcher(document);\n * dispatcher.addSubscriber(new InitializeUploadSubscriber(dispatcher));\n * dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));\n *\n * // Node.js\n * const dispatcher = new NodeEventDispatcher();\n * dispatcher.addSubscriber(new InitializeUploadSubscriber(dispatcher));\n * dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));\n * ```\n *\n * ---\n *\n * ### Fluent Builder API\n *\n * The class exposes a fluent API to configure the upload before starting:\n *\n * ```typescript\n * const uploader = new ChunkedFileUploader(dispatcher, cache, options);\n *\n * await uploader\n * .withFile(file)\n * .withEndpoints({\n * init: 'https://api.example.com/upload/init',\n * upload: 'https://api.example.com/upload/chunk',\n * finalize: 'https://api.example.com/upload/finalize'\n * })\n * .upload();\n * ```\n *\n * ---\n *\n * ### Resumable Uploads\n *\n * When `autoSave: true` is set in options, the upload progress is persisted\n * after each successful chunk via the {@link UploadResumeCacheInterface}.\n * A failed or interrupted upload can be resumed later:\n *\n * ```typescript\n * const resumeData = await uploader.loadResumeData(file.name);\n *\n * if (resumeData) {\n * await uploader\n * .withFile(file)\n * .withEndpoints(endpoints)\n * .resumeUpload(resumeData);\n * }\n * ```\n *\n * ---\n *\n * ### Concurrency\n *\n * Multiple chunks can be uploaded simultaneously. The `concurrency` option\n * controls how many parallel uploads are active at any given time.\n * The default value is `3`, which provides a good balance between speed\n * and server/network load:\n *\n * ```typescript\n * // Upload 5 chunks in parallel\n * new ChunkedFileUploader(dispatcher, cache, { concurrency: 5 });\n * ```\n *\n * ---\n *\n * ### Pause, Resume and Cancel\n *\n * The upload can be paused, resumed, or cancelled at any time:\n *\n * ```typescript\n * uploader.pause(); // Pauses after the current chunk finishes\n * uploader.resume(); // Resumes from where it was paused\n * uploader.cancel(); // Aborts immediately via AbortController\n * ```\n *\n * ---\n *\n * ### Cache\n *\n * The library does **not** provide a built-in cache implementation to stay\n * lightweight and environment-agnostic. You must implement\n * {@link UploadResumeCacheInterface} with your preferred storage backend\n * (localStorage, IndexedDB, Redis, filesystem, etc.).\n *\n * ---\n *\n * @author AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * @company INTERNATIONALES WEB APPS & SERVICES\n * @phone +229 0167 25 18 86\n * @linkedin https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * @github https://github.com/Agbokoudjo/file_uploader\n *\n * @version 1.0.0\n * @since 1.0.0\n * @license MIT\n *\n * @see {@link HttpFileUploaderEvents} All event name constants\n * @see {@link UploadResumeCacheInterface} Cache interface to implement\n * @see {@link InitializeUploadSubscriber} Handles the init HTTP phase\n * @see {@link FinalizeUploadSubscriber} Handles the finalize HTTP phase\n * @see {@link UploadOptions} Full configuration reference\n * @see {@link https://github.com/Agbokoudjo/file_uploader | GitHub Repository}\n */\nexport class ChunkedFileUploader {\n private _file: File |null;\n private _endpoints: UploadEndpoints|null;\n \n private isPaused: boolean;\n private startTime: number;\n private uploadedBytes: number;\n private abortController: AbortController;\n private state: UploadState;\n private totalChunks: number;\n private percentage: number;\n private uploadedChunks: number;\n private lastUploadedChunkIndex: number; \n\n public constructor(\n private readonly _uploadEventDispatcher: EventDispatcherInterface = new BrowserEventDispatcher(), //or new NodeJSEventDispatcher() if you have an environment NodeJs\n private readonly uploadResumeData: UploadResumeCacheInterface,\n private options: UploadOptions\n ) {\n \n this._file = null;\n this._endpoints = null;\n this.isPaused = false;\n this.startTime = 0;\n this.uploadedBytes = 0;\n this.abortController = new AbortController();\n this.state = UploadState.IDLE;\n this.totalChunks = 0;\n this.percentage = 0;\n this.uploadedChunks = 0;\n this.lastUploadedChunkIndex = -1; \n }\n\n /**\n * Starts the chunked file upload process.\n * \n * @throws {Error} If file or endpoints are not set\n * @throws {InitializeUploadFailureException} If server initialization fails\n * @throws {FileUploadChunkError} If a chunk fails after all retries\n * \n * @example\n * ```typescript\n * const uploader = new ChunkedFileUploader(dispatcher, cache, options);\n * \n * uploader\n * .withFile(file)\n * .withEndpoints({ init, upload, finalize });\n * \n * await uploader.upload();\n * ```\n */\n public async upload(): Promise<void>{\n this.setState(UploadState.INITIALIZING);\n\n const { maxRetries = 3, config, speedMbps, metadata,\n headerInitialzingUpload, concurrency = 3\n } = this.options;\n\n const file = this.file;\n // Generate file hash for integrity check\n const fileHash = await FileUtils.generateFileHash(file) ;\n let fileId: string;\n\n try {\n const initializationEvent = await this._uploadEventDispatcher.dispatchAsync(\n new InitializingUploadEvent(\n {\n fileHash: fileHash,\n fileName: this.file.name,\n fileSize: this.file.size,\n fileType: this.file.type,\n metadata: metadata,\n endpointInit: this.endPointOptions.init,\n headers: headerInitialzingUpload\n }),\n HttpFileUploaderEvents.INITIALIZE_UPLOAD\n )\n\n fileId = initializationEvent.mediaId;\n } catch (error) {\n this.setState(UploadState.FAILED);\n throw error;\n }\n\n this.setState(UploadState.UPLOADING);\n this.startTime = Date.now();\n this.uploadedBytes = 0;\n this.uploadedChunks = 0;\n this.lastUploadedChunkIndex = -1;\n\n const chunkSize = this.options.chunkSize || FileUtils.calculateChunkSize(file.size, speedMbps, config);\n this.totalChunks = Math.ceil(file.size / chunkSize);\n try {\n await this.uploadChunksWithConcurrency(\n file,\n chunkSize,\n fileId,\n fileHash,\n maxRetries,\n concurrency,\n 0\n );\n\n await this.finalizeUpload(fileId, fileHash);\n \n } catch (error) {\n this.handleUploadFailure(error as Error);\n throw error;\n }\n }\n\n public withFile(file: File): this {\n if (!file) {\n throw new Error('File is required');\n }\n if (file.size === 0) {\n throw new Error('Cannot upload empty file');\n }\n if (!(file instanceof File) || !(file instanceof Blob)) {\n throw new TypeError('Expected File or Blob instance');\n }\n this._file = file;\n return this;\n }\n\n public withEndpoints(endpoints: UploadEndpoints): this {\n if (!endpoints.init || !endpoints.upload || !endpoints.finalize) {\n throw new Error('All endpoints (init, upload, finalize) are required');\n }\n this._endpoints = endpoints;\n return this;\n }\n\n private get endPointOptions():UploadEndpoints {\n if (!this._endpoints) {\n throw new Error('Endpoint URL is required');\n }\n\n return this._endpoints;\n }\n\n private get file(): File{ \n if (!this._file) {\n throw new Error(`\n This operation requires a mandatory file.Did you forget to upload the file? \n Use the withFile(file: File|Blob) function of the ChunkedFileUploader ${this} class that you instantiated.\n `)\n }\n\n return this._file;\n }\n\n /**\n * Upload all chunks with concurrency control using p-limit\n * \n * @param file - File to upload\n * @param chunkSize - Size of each chunk\n * @param fileId - Server file ID\n * @param fileHash - File hash\n * @param maxRetries - Max retry attempts per chunk\n * @param concurrency - Number of concurrent uploads (default: 3)\n */\n private async uploadChunksWithConcurrency(\n file: File,\n chunkSize: number,\n fileId: string,\n fileHash: string,\n maxRetries: number,\n concurrency: number,\n startIndex:number=0\n ): Promise<void> {\n try {\n const limit = pLimit(concurrency);\n\n // Créer toutes les promesses avec limite\n const uploadPromises: Promise<void>[] = [];\n\n for (let chunkIndex = startIndex; chunkIndex < this.totalChunks; chunkIndex++) {\n // Wrapper chaque upload dans le limiteur\n const limitedUpload = limit(() =>\n this.processChunk(\n file,\n chunkIndex,\n chunkSize,\n fileId,\n fileHash,\n maxRetries\n )\n );\n\n uploadPromises.push(limitedUpload);\n }\n\n // Attendre que tous les chunks soient uploadés\n await Promise.all(uploadPromises);\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Process a single chunk: slice, upload with retry, and save progress.\n * \n * @param file - The file being uploaded\n * @param currentChunkIndex - Index of the current chunk (0-based)\n * @param chunkSize - Size of each chunk in bytes\n * @param fileId - Server-provided file/session ID\n * @param fileHash - SHA-256 hash of the file\n * @param maxRetries - Maximum number of retry attempts\n * \n * @throws {UploadCancelledException} If upload is cancelled\n * @throws {FileUploadChunkError} If chunk upload fails after all retries\n */\n private async processChunk(\n file:File,\n currentChunkIndex: number,\n chunkSize:number,\n fileId: string,\n fileHash:string,\n maxRetries:number\n ): Promise<void>{\n try {\n if (this.abortController.signal.aborted) {\n this._uploadEventDispatcher.dispatch(\n new UploadCancelledEvent(\n file.name,\n this.totalChunks,\n this.uploadedBytes,\n this.percentage,\n currentChunkIndex,\n 'Upload cancelled by user',\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_CANCELLED\n )\n \n return;\n }\n\n while (this.isPaused) {\n await this.sleep(100);\n }\n // Calcule où commencer dans le fichier\n const start = currentChunkIndex * chunkSize;\n // chunkIndex=0 → start=0\n // chunkIndex=1 → start=300\n // chunkIndex=2 → start=600\n // chunkIndex=3 → start=900\n\n // Calcule où finir (sans depasser la fin du fichier)\n const end = Math.min(file.size, start + chunkSize);\n // chunkIndex=0 → end=min(1000, 300)=300\n // chunkIndex=1 → end=min(1000, 600)=600\n // chunkIndex=2 → end=min(1000, 900)=900\n // chunkIndex=3 → end=min(1000, 1200)=1000 ← Limité !\n\n // Découpe le morceau\n const chunk = file.slice(start, end);\n // chunkIndex=0 → slice(0, 300) → 300 bytes\n // chunkIndex=1 → slice(300, 600) → 300 bytes\n // chunkIndex=2 → slice(600, 900) → 300 bytes\n // chunkIndex=3 → slice(900, 1000)→ 100 bytes ← Plus petit !\n const chunkInfo: ChunkInfo = {\n index: currentChunkIndex,\n start,\n end,\n size: chunk.size,\n attempt: 0,\n status: 'pending'\n };\n\n this._uploadEventDispatcher.dispatch(\n new UploadChunkStartedEvent(chunkInfo),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_STARTED\n );\n // Upload with retry\n await this.uploadChunkWithRetry(\n chunk,\n chunkInfo,\n fileId,\n fileHash,\n this.totalChunks,\n maxRetries\n );\n\n // Auto-save progress\n if (this.options.autoSave) {\n await this.saveResumeData(fileId,chunkSize);\n }\n } catch (error) {\n throw error;\n \n }\n }\n\n private async uploadChunkWithRetry(\n chunk: Blob,\n chunkInfo: ChunkInfo,\n fileId: string,\n fileHash: string,\n totalChunks: number,\n maxRetries: number\n ): Promise<void> {\n let success = false;\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxRetries && !success; attempt++) {\n chunkInfo.attempt = attempt + 1;\n chunkInfo.status = 'uploading';\n\n try {\n const response = await this.uploadChunk(chunk, chunkInfo, fileId, fileHash, totalChunks);\n success = true;\n chunkInfo.status = 'success';\n\n this.updateProgress(chunk.size, chunkInfo.index)\n\n this.notifyProgress(\n this.uploadedChunks,\n totalChunks,\n this.file.size,\n response\n );\n return;\n } catch (error) {\n if (error instanceof ChunkUploadHttpErrorException) {\n this._uploadEventDispatcher.dispatch(\n new ChunkUploadHttpErrorResponseEvent(\n error.errorPayload,\n error.statusResponse,\n this.endPointOptions.upload,\n chunkInfo),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_HTTP_ERROR_RESPONSE\n )\n }\n\n lastError = error as Error;\n chunkInfo.status = 'error';\n\n const chunkError: ChunkError= {\n chunk: chunkInfo,\n error: lastError,\n attempt: attempt + 1,\n willRetry: attempt < maxRetries - 1\n };\n\n if(error instanceof HttpFetchError){\n this._uploadEventDispatcher.dispatch(chunkError,HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_FAILED)\n }\n\n if (attempt < maxRetries - 1) {\n const delay = Math.pow(2, attempt) * 1000;\n await this.sleep(delay);\n\n console.info(`Retry #${attempt + 2} in ${delay / 1000}s...`);\n }\n }\n }\n\n if (!success) {\n const fileUploadChunkError = new FileUploadChunkError(\n `Failed to upload chunk ${chunkInfo.index} after ${maxRetries} attempts`,\n {\n chunk: chunkInfo,\n error: lastError!,\n attempt: maxRetries,\n willRetry: false\n }\n );\n\n this._uploadEventDispatcher.dispatch(\n fileUploadChunkError,\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_MAXRETRY_EXPIRE\n )\n throw fileUploadChunkError;\n }\n\n }\n\n private async uploadChunk(\n chunk: Blob,\n chunkInfo: ChunkInfo,\n mediaIdFromServer: string,\n fileHash: string,\n totalChunks: number\n ): Promise<FetchResponseInterface> {\n const media = this.file;\n const chunkFormData = createChunkFormData(\n chunk,\n {\n chunkIndex: chunkInfo.index,\n mediaId: mediaIdFromServer,\n fileSize: media.size,\n fileName: media.name,\n fileHash: fileHash,\n totalChunks: totalChunks\n }\n );\n\n try {\n const response_of_server = await safeFetch({\n url: this.endPointOptions.upload,\n headers: this.options.headers,\n data: chunkFormData,\n methodSend: \"POST\",\n responseType: \"json\",\n timeout: this.options.timeout ?? 60000,\n retryCount: 2,\n retryOnStatusCode: false,\n signal: this.createChunkAbortSignal()\n })\n const statusResponse = response_of_server.status;\n //if the server send a response which not success with status code(>=4XX ou >=5XX)\n if (response_of_server.failed) {\n throw new ChunkUploadHttpErrorException(response_of_server.data, statusResponse)\n }\n\n return response_of_server;\n } catch (error) {\n throw error;\n }\n\n }\n\n private createChunkAbortSignal(): AbortSignal {\n const chunkController = new AbortController();\n\n this.abortController.signal.addEventListener('abort', () => {\n chunkController.abort();\n });\n\n return chunkController.signal;\n }\n\n private notifyProgress(\n uploadedChunks: number,\n totalChunks: number,\n totalBytes: number,\n httpResponse: FetchResponseInterface): void {\n // Temps écoulé (minimum 0.1s pour éviter division par zéro)\n const elapsed = Math.max((Date.now() - this.startTime) / 1000, 0.1);\n const speed = this.uploadedBytes / elapsed; // Vitesse instantanée\n const remainingBytes = totalBytes - this.uploadedBytes; // Bytes restants\n // Temps restant (null si pas assez de données)\n const estimatedTimeRemaining = uploadedChunks < 2 ? null : remainingBytes / speed;\n\n this.percentage = Math.round((this.uploadedBytes / totalBytes) * 100);\n\n const progress: UploadProgress = {\n uploadedChunks,\n totalChunks,\n uploadedBytes: this.uploadedBytes,\n totalBytes,\n percentage: this.percentage,\n currentChunk: uploadedChunks,\n speed, // bytes/seconde\n estimatedTimeRemaining, // secondes (ou null)\n elapsed // secondes écoulées\n };\n\n this._uploadEventDispatcher.dispatch(\n new UploadProgressEvent(\n progress,\n httpResponse.data,\n httpResponse.status\n )\n )\n \n console.info(\n `Progress: ${this.percentage}% | ` +\n `Speed: ${FileUtils.formatBytes(speed)}/s | ` +\n `ETA: ${estimatedTimeRemaining ? FileUtils.formatDuration(estimatedTimeRemaining) : 'Calculating...'}`\n );\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n /**\n * Save current upload progress to cache for resume capability\n * \n * @param fileId - Server-provided file/session ID\n * @param chunkSize - Size of each chunk in bytes\n * @returns Saved resume data\n */\n private async saveResumeData(fileId: string, chunkSize: number): Promise<ResumeData> {\n const data: ResumeData = {\n fileId: fileId,\n fileName: this.file.name,\n fileSize: this.file.size,\n uploadedChunks: this.uploadedChunks,\n lastChunkIndex: this.lastUploadedChunkIndex,\n lastBytePosition: this.uploadedBytes,\n chunkSize: chunkSize,\n concurrency:this.options.concurrency || 3\n };\n\n await this.uploadResumeData.setItem(`upload_${this.file.name}`, data);\n\n console.info(\n `Resume data saved: ${this.uploadedChunks}/${Math.ceil(this.file.size / chunkSize)} chunks, ` +\n `last chunk index: ${this.lastUploadedChunkIndex}`\n );\n\n return data;\n }\n\n private setState(newState: UploadState): void {\n const oldState = this.state;\n this.state = newState;\n\n this._uploadEventDispatcher.dispatch(\n new UploadStateChangedEvent(\n oldState,\n newState,\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_STATE_CHANGED\n )\n \n }\n\n public getState(): UploadState {\n return this.state;\n }\n\n private handleUploadFailure(error: Error): void {\n this.setState(UploadState.FAILED);\n\n this._uploadEventDispatcher.dispatch(error, HttpFileUploaderEvents.DOWNLOAD_MEDIA_FAILURE);\n console.error('Upload failed:', error);\n }\n\n public cancel(): void {\n this.abortController.abort();\n this.setState(UploadState.CANCELLED);\n }\n\n public pause(): void {\n this.isPaused = true;\n this.setState(UploadState.PAUSED);\n this._uploadEventDispatcher.dispatch(\n new UploadPausedEvent(\n this.file.name,\n this.totalChunks,\n this.uploadedBytes,\n this.percentage,\n Date.now()\n ),\n HttpFileUploaderEvents.UPLOAD_PAUSED\n );\n }\n\n\n public resume(): void {\n this.isPaused = false;\n this.setState(UploadState.UPLOADING);\n this._uploadEventDispatcher.dispatch(\n new UploadResumedEvent(\n this.file.name,\n this.totalChunks,\n this.uploadedBytes, \n this.percentage),\n HttpFileUploaderEvents.UPLOAD_RESUMED,\n );\n }\n\n /**\n * Load previously saved resume data\n * \n * @param fileName - Name of the file to resume\n * @returns Resume data or null if not found\n */\n async loadResumeData(fileName: string): Promise<ResumeData | null> {\n try {\n const data = await this.uploadResumeData.getItem(`upload_${fileName}`);\n\n if (data) {\n console.info(\n `Resume data loaded: ${data.uploadedChunks} chunks uploaded, ` +\n `last index: ${data.lastChunkIndex}`\n );\n }\n return data;\n } catch (error) {\n console.warn(`No resume data found for ${fileName}`);\n return null;\n }\n }\n\n /**\n * Resume upload from saved state\n * \n * @param resumeData - Previously saved resume data\n * @returns Upload result\n */\n public async resumeUpload(resumeData: ResumeData): Promise<void> {\n const __message = `Resuming upload from chunk ${resumeData.lastChunkIndex + 1} ` +\n `(${resumeData.uploadedChunks} chunks already uploaded)`;\n\n // Restore state\n this.uploadedBytes = resumeData.lastBytePosition;\n this.uploadedChunks = resumeData.uploadedChunks;\n this.lastUploadedChunkIndex = resumeData.lastChunkIndex;\n\n // Calculate adjusted start time for accurate speed calculation\n const assumedSpeed = 500000; // 500 KB/s assumed\n const timeAlreadySpent = resumeData.lastBytePosition / assumedSpeed;\n this.startTime = Date.now() - (timeAlreadySpent * 1000);\n\n const { maxRetries = 3 } = this.options;\n const fileHash = await FileUtils.generateFileHash(this.file);\n const chunkSize = resumeData.chunkSize;\n this.totalChunks = Math.ceil(this.file.size / chunkSize);\n\n try {\n this._uploadEventDispatcher.dispatch(\n new ResumeUploadEvent(resumeData,__message),\n HttpFileUploaderEvents.MEDIA_CHUNK_UPLOAD_RESUME\n )\n await this.uploadChunksWithConcurrency(\n this.file,\n chunkSize,\n resumeData.fileId,\n fileHash,\n maxRetries,\n resumeData.concurrency,\n resumeData.lastChunkIndex + 1\n )\n ;\n await this.finalizeUpload(resumeData.fileId, fileHash);\n\n } catch (error) {\n this.handleUploadFailure(error as Error);\n throw error;\n }\n }\n\n private updateProgress(chunkSize: number, chunkIndex: number): void {\n this.uploadedBytes += chunkSize;\n this.uploadedChunks++;\n this.lastUploadedChunkIndex = Math.max(this.lastUploadedChunkIndex,chunkIndex);\n }\n \n private async finalizeUpload(mediaId: string, fileHash: string): Promise<void> {\n try {\n \n const finalizeUploadEvent = await this._uploadEventDispatcher.dispatchAsync(\n new FinalizeUploadEvent(\n this.endPointOptions.finalize,\n mediaId,\n fileHash,\n this.options.headerFinalezingUpload)\n ,\n HttpFileUploaderEvents.FINALIZE_UPLOAD\n )\n\n this.setState(UploadState.FINALIZING);\n\n\n const duration = (Date.now() - this.startTime) / 1000;\n\n const uploadResult: UploadResult = {\n success: true,\n finalizeUploadResponse: finalizeUploadEvent.hasResponse() ? finalizeUploadEvent.getResponse() : null ,\n totalChunks: this.totalChunks,\n totalBytes: this.file.size,\n duration,\n averageSpeed: this.file.size / duration,\n fileId: mediaId\n };\n\n this.setState(UploadState.COMPLETED);\n\n this._uploadEventDispatcher.dispatch(\n new UploadMediaCompleteEvent(uploadResult),HttpFileUploaderEvents.DOWNLOAD_MEDIA_COMPLETE\n )\n\n } catch (error) {\n throw error;\n }\n }\n}"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/events/complete/index.ts"],"names":[],"mappings":"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","file":"chunk-LTYMA4U4.js","sourcesContent":["/*\n * This file is part of the project by AGBOKOUDJO Franck.\n *\n * (c) AGBOKOUDJO Franck <internationaleswebservices@gmail.com>\n * Phone: +229 0167 25 18 86\n * LinkedIn: https://www.linkedin.com/in/internationales-web-apps-services-120520193/\n * Company: INTERNATIONALES WEB APPS & SERVICES\n *\n * For more information, please feel free to contact the author.\n */\nimport { BaseEvent } from \"@wlindabla/event_dispatcher\";\nimport { ResumeData,UploadResult } from \"../../types\";\nimport {\n ResponseEventInterface,\n FetchResponseInterface\n} from \"@wlindabla/http_client\";\n/**\n * Event data for MEDIA_CHUNK_UPLOAD_RESUME\n */\nexport class ResumeUploadEvent {\n constructor(\n private readonly __resumeData: ResumeData,\n public readonly message: string) { }\n\n public get mediaId(): string | number { return this.__resumeData.fileId; }\n\n public get fileName(): string { return this.__resumeData.fileName; }\n\n public get uploadedChunks(): number { return this.__resumeData.uploadedChunks; }\n\n public get lastChunkIndex(): number { return this.__resumeData.lastChunkIndex; }\n\n public get lastBytePosition(): number { return this.__resumeData.lastBytePosition; }\n\n public get chunkSize(): number { return this.__resumeData.chunkSize; }\n\n public get fileSize(): number { return this.__resumeData.fileSize; }\n}\n\n/**\n * Event data for DOWNLOAD_MEDIA_COMPLETE\n */\nexport class UploadMediaCompleteEvent {\n constructor(private readonly _uploadResult: UploadResult) { }\n\n public get success(): boolean { return this._uploadResult.success; }\n\n public get mediaId(): string | number { return this._uploadResult.fileId! }\n\n public get totalBytes(): number { return this._uploadResult.totalBytes; }\n\n public get totalChunks(): number { return this._uploadResult.totalChunks; }\n\n public get finalizeUploadHttpResponse(): any { return this._uploadResult.finalizeUploadResponse; }\n\n public get operationDuration(): number { return this._uploadResult.duration; }\n\n public get averageSpeed(): number { return this._uploadResult.averageSpeed; }\n}\n\nexport class FinalizeUploadFailureEvent extends BaseEvent{\n constructor(\n public readonly error: Error,\n public readonly status?: number,\n public readonly errorData?: any,\n public readonly responseData?: any,\n public readonly isNetworkError?: boolean\n ) { super(); }\n}\n\nexport class FinalizeUploadEvent extends BaseEvent implements ResponseEventInterface{\n private fetchResponse: FetchResponseInterface|null;\n\n constructor(\n public readonly endPoint:string|URL,\n public readonly mediaId: string,\n public readonly mediaHash: string,\n public readonly headers?: HeadersInit\n ) {\n super();\n this.fetchResponse = null;\n }\n\n /**\n * Returns the response\n */\n public getResponse(): FetchResponseInterface | null {\n return this.fetchResponse;\n }\n\n /**\n * Sets the response\n */\n public setResponse(response: FetchResponseInterface): void {\n this.fetchResponse = response;\n }\n\n /**\n * Returns whether a response was set\n */\n public hasResponse(): boolean {\n return this.fetchResponse !== null;\n }\n}"]}
|