@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.
Files changed (34) hide show
  1. package/README.md +3 -8
  2. package/dist/cjs/core/index.d.ts +7 -3
  3. package/dist/cjs/core/index.js +20 -11
  4. package/dist/cjs/core/index.js.map +1 -1
  5. package/dist/cjs/events/complete/index.d.ts +2 -1
  6. package/dist/cjs/events/complete/index.js.map +1 -1
  7. package/dist/cjs/events/index.d.ts +1 -0
  8. package/dist/cjs/events/initialize/index.js.map +1 -1
  9. package/dist/cjs/index.d.ts +1 -0
  10. package/dist/cjs/subscribers/index.d.ts +1 -0
  11. package/dist/cjs/subscribers/index.js.map +1 -1
  12. package/dist/esm/{chunk-DN5B6PRW.js → chunk-3JTTZCSQ.js} +2 -2
  13. package/dist/esm/{chunk-DN5B6PRW.js.map → chunk-3JTTZCSQ.js.map} +1 -1
  14. package/dist/esm/{chunk-LTYMA4U4.js → chunk-BNMI7DW3.js} +2 -2
  15. package/dist/esm/chunk-BNMI7DW3.js.map +1 -0
  16. package/dist/esm/{chunk-332NNKOW.js → chunk-HYNJBWW5.js} +4 -4
  17. package/dist/esm/chunk-HYNJBWW5.js.map +1 -0
  18. package/dist/esm/{chunk-6DIKDA6J.js → chunk-TONVXBLH.js} +22 -13
  19. package/dist/esm/chunk-TONVXBLH.js.map +1 -0
  20. package/dist/esm/core/index.d.mts +7 -3
  21. package/dist/esm/core/index.js +3 -3
  22. package/dist/esm/events/complete/index.d.mts +2 -1
  23. package/dist/esm/events/complete/index.js +1 -1
  24. package/dist/esm/events/index.d.mts +1 -0
  25. package/dist/esm/events/index.js +2 -2
  26. package/dist/esm/events/initialize/index.js +1 -1
  27. package/dist/esm/index.d.mts +1 -0
  28. package/dist/esm/index.js +4 -4
  29. package/dist/esm/subscribers/index.d.mts +1 -0
  30. package/dist/esm/subscribers/index.js +3 -3
  31. package/package.json +10 -10
  32. package/dist/esm/chunk-332NNKOW.js.map +0 -1
  33. package/dist/esm/chunk-6DIKDA6J.js.map +0 -1
  34. 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 {
@@ -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 1.0.0
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
- constructor(_uploadEventDispatcher: EventDispatcherInterface | undefined, //or new NodeJSEventDispatcher() if you have an environment NodeJs
181
- uploadResumeData: UploadResumeCacheInterface, options: UploadOptions);
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
  *
@@ -32,8 +32,7 @@ __export(core_exports, {
32
32
  ChunkedFileUploader: () => ChunkedFileUploader
33
33
  });
34
34
  module.exports = __toCommonJS(core_exports);
35
- var import_event_dispatcher = require("@wlindabla/event_dispatcher");
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 1.0.0
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
- constructor(_uploadEventDispatcher = new import_event_dispatcher.BrowserEventDispatcher(), uploadResumeData, options) {
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
- const file = this.file;
264
- const fileHash = await import_utils.FileUtils.generateFileHash(file);
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: this.file.name,
272
- fileSize: this.file.size,
273
- fileType: this.file.type,
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 import_http_client.HttpFetchError) {
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, import_http_client.safeFetch)({
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, FetchResponseInterface } from '@wlindabla/http_client';
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,\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}"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,8BAA0B;AASnB,MAAM,kBAAkB;AAAA,EAC3B,YACqB,cACD,SAAiB;AADhB;AACD;AAAA,EAAmB;AAAA,EADlB;AAAA,EACD;AAAA,EAtBxB,OAmB+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,EA3CjC,OA0CsC;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,EAlExB,OA4DyD;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,EA7ExB,OAsEoF;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":[]}
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":[]}
@@ -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-DN5B6PRW.js.map
76
- //# sourceMappingURL=chunk-DN5B6PRW.js.map
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-DN5B6PRW.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"]}
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-LTYMA4U4.js.map
123
- //# sourceMappingURL=chunk-LTYMA4U4.js.map
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-LTYMA4U4.js';
4
- import { InitializeUploadStartedEvent, InitializeUploadFailureEvent, InitializeUploadSuccessEvent } from './chunk-DN5B6PRW.js';
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-332NNKOW.js.map
164
- //# sourceMappingURL=chunk-332NNKOW.js.map
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-LTYMA4U4.js';
6
- import { InitializingUploadEvent } from './chunk-DN5B6PRW.js';
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 { BrowserEventDispatcher } from '@wlindabla/event_dispatcher';
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
- constructor(_uploadEventDispatcher = new BrowserEventDispatcher(), uploadResumeData, options) {
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
- const file = this.file;
76
- const fileHash = await FileUtils.generateFileHash(file);
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: this.file.name,
84
- fileSize: this.file.size,
85
- fileType: this.file.type,
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 1.0.0
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-6DIKDA6J.js.map
723
- //# sourceMappingURL=chunk-6DIKDA6J.js.map
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 1.0.0
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
- constructor(_uploadEventDispatcher: EventDispatcherInterface | undefined, //or new NodeJSEventDispatcher() if you have an environment NodeJs
181
- uploadResumeData: UploadResumeCacheInterface, options: UploadOptions);
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
  *
@@ -1,11 +1,11 @@
1
- export { ChunkedFileUploader } from '../chunk-6DIKDA6J.js';
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-LTYMA4U4.js';
8
- import '../chunk-DN5B6PRW.js';
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, FetchResponseInterface } from '@wlindabla/http_client';
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-LTYMA4U4.js';
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
@@ -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-LTYMA4U4.js';
4
- export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeUploadSuccessEvent, InitializingUploadEvent } from '../chunk-DN5B6PRW.js';
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-DN5B6PRW.js';
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
@@ -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-332NNKOW.js';
1
+ export { FinalizeUploadSubscriber, InitializeUploadSubscriber } from './chunk-HYNJBWW5.js';
2
2
  export { DefaultUploadResumeCacheAdapter, UploadCacheError } from './chunk-PFALORWQ.js';
3
- export { ChunkedFileUploader } from './chunk-6DIKDA6J.js';
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-LTYMA4U4.js';
10
- export { InitializeUploadFailureEvent, InitializeUploadStartedEvent, InitializeUploadSuccessEvent, InitializingUploadEvent } from './chunk-DN5B6PRW.js';
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-332NNKOW.js';
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-LTYMA4U4.js';
6
- import '../chunk-DN5B6PRW.js';
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.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.1",
223
- "@wlindabla/http_client": "^1.1.5",
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.6.0",
227
+ "@types/node": "^25.9.3",
228
228
  "@types/p-limit": "^2.2.0",
229
- "@typescript-eslint/eslint-plugin": "^8.59.1",
230
- "@typescript-eslint/parser": "^8.59.1",
231
- "eslint": "^10.2.1",
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.3",
233
+ "prettier": "^3.8.4",
234
234
  "tsup": "^8.5.1",
235
235
  "typescript": "^6.0.3",
236
- "vite": "^8.0.10",
237
- "vitest": "^4.1.5"
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}"]}