@weapnl/js-junction 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v0.3.0
6
+ - Added `chunkUploadsBySize` option on the `Api` class to automatically chunk file uploads across multiple requests when the total size exceeds the configured size.
7
+
5
8
  ## v0.2.0
6
9
  - Added `data` propery to `delete` function of a Request to allow sending json data in the delete request.
7
10
  - Added `extraData` property to `destroy` function of a Model to allow sending extra json data in the delete request.
package/README.md CHANGED
@@ -13,6 +13,7 @@ This package has support for Typescript (TS).
13
13
  - [Performing Requests](#performing-requests)
14
14
  - [Applying Filters and Scopes](#applying-filters-and-scopes)
15
15
  - [Uploading Files with Spatie Medialibrary](#uploading-files-with-spatie-medialibrary)
16
+ - [Chunked Uploads](#chunked-uploads)
16
17
 
17
18
  ## Installation
18
19
  ```bash
@@ -439,3 +440,22 @@ employee.save();
439
440
  ```
440
441
 
441
442
  In this scenario, the uploaded files are linked to the `ProfilePicture` collection within the `Contact` relationship of the `Employee` model. When the `save()` method is called, the files are properly attached within the nested structure.
443
+
444
+ ### Chunked Uploads
445
+
446
+ When uploading multiple files via the `upload` method, the total combined size may exceed the server's limit, or you may want to split large batches into smaller requests. Use `chunkUploadsBySize` to split files across multiple requests automatically.
447
+
448
+ **Configuring chunk size:**
449
+ ```js
450
+ api.chunkUploadsBySize(10 * 1024 * 1024); // 10 MB per request
451
+ ```
452
+
453
+ **Resetting (single request for all files):**
454
+ ```js
455
+ api.chunkUploadsBySize(null); // default behavior
456
+ ```
457
+
458
+ **How it works:**
459
+ - When set, the `upload` method groups files into chunks where the total file size per chunk does not exceed the configured size.
460
+ - Each chunk is uploaded in a separate request; response data is combined automatically.
461
+ - A single file that exceeds the size on its own is sent as its own request.
package/index.d.ts CHANGED
@@ -9,6 +9,7 @@ declare class Api {
9
9
  constructor();
10
10
 
11
11
  host(host: string): this;
12
+ chunkUploadsBySize(bytes: number): this;
12
13
  suffix(suffix: string): this;
13
14
  readonly baseUrl: string;
14
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weapnl/js-junction",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "This project allows you to easily consume API's built with Junction.",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
package/src/api.js CHANGED
@@ -12,6 +12,7 @@ export default class Api {
12
12
  this.setHeader('X-Requested-With', 'XMLHttpRequest');
13
13
 
14
14
  this._requests = [];
15
+ this._chunkUploadSize = null;
15
16
 
16
17
  this.host('/').suffix('');
17
18
 
@@ -29,6 +30,20 @@ export default class Api {
29
30
  return this;
30
31
  }
31
32
 
33
+ /**
34
+ * Chunk file uploads into multiple requests when total size exceeds the given size.
35
+ * Useful when the API has a max upload limit, or to split large batches into smaller requests.
36
+ *
37
+ * @param {number} bytes Maximum total file size per request in bytes.
38
+ *
39
+ * @returns {this} The current instance.
40
+ */
41
+ chunkUploadsBySize (bytes) {
42
+ this._chunkUploadSize = bytes;
43
+
44
+ return this;
45
+ }
46
+
32
47
  /**
33
48
  * @param {string} suffix
34
49
  *
@@ -302,20 +302,69 @@ export default class Model extends Request {
302
302
  */
303
303
  async upload (files, collection) {
304
304
  this._media ??= {};
305
- const filesArray = (Array.isArray(files) ? files : [files]).filter((value) => value !== null);
305
+ files = _.flatMapDeep(Array.isArray(files) ? files : [files]).filter((value) => value instanceof File);
306
306
 
307
- if (filesArray.length === 0) {
307
+ if (files.length === 0) {
308
308
  this._media[collection] = {};
309
309
  return;
310
310
  }
311
311
 
312
- const request = await this.storeFiles({
313
- files: _.flatMapDeep(filesArray),
314
- }, {}, '/media/upload');
312
+ const chunkSize = this._connection.getChunkUploadSize();
315
313
 
316
- this._media[collection] = request._response.data;
314
+ const chunks = chunkSize ? this._chunkFilesBySize(files, chunkSize) : [files];
317
315
 
318
- return request._response.data;
316
+ let allResponseData = [];
317
+
318
+ for (const chunk of chunks) {
319
+ const request = await this.storeFiles({
320
+ files: chunk,
321
+ }, {}, '/media/upload');
322
+
323
+ if (request._response.data) {
324
+ allResponseData = allResponseData.concat(
325
+ _.castArray(request._response.data),
326
+ );
327
+ }
328
+ }
329
+
330
+ this._media[collection] = allResponseData;
331
+
332
+ return allResponseData;
333
+ }
334
+
335
+ /**
336
+ * Split files into chunks that don't exceed the given max size.
337
+ * A single file that exceeds the limit will still be sent as its own chunk.
338
+ *
339
+ * @param {File[]} files
340
+ * @param {number} maxSize Maximum total file size per chunk in bytes.
341
+ *
342
+ * @returns {File[][]} Array of file arrays (chunks).
343
+ * @private
344
+ */
345
+ _chunkFilesBySize (files, maxSize) {
346
+ const chunks = [];
347
+ let currentChunk = [];
348
+ let currentSize = 0;
349
+
350
+ for (const file of files) {
351
+ const fileSize = file.size || 0;
352
+
353
+ if (currentChunk.length > 0 && currentSize + fileSize > maxSize) {
354
+ chunks.push(currentChunk);
355
+ currentChunk = [];
356
+ currentSize = 0;
357
+ }
358
+
359
+ currentChunk.push(file);
360
+ currentSize += fileSize;
361
+ }
362
+
363
+ if (currentChunk.length > 0) {
364
+ chunks.push(currentChunk);
365
+ }
366
+
367
+ return chunks;
319
368
  }
320
369
 
321
370
  /**
package/src/connection.js CHANGED
@@ -33,6 +33,10 @@ export default class Connection {
33
33
  return this._config;
34
34
  }
35
35
 
36
+ getChunkUploadSize () {
37
+ return this._api?._chunkUploadSize ?? null;
38
+ }
39
+
36
40
  setConfig (config) {
37
41
  this._config = config;
38
42
  }