@enegalan/request-manager 1.1.0 → 1.1.2

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/main.js CHANGED
@@ -163,7 +163,13 @@ class RequestManager {
163
163
  * });
164
164
  */
165
165
  axios(url, options = {}, axiosInstance = null) {
166
- const axiosLib = axiosInstance || axios;
166
+ const axiosLib = axiosInstance || (typeof axios !== 'undefined' ? axios : null);
167
+ if (!axiosLib) {
168
+ throw new Error(
169
+ 'axios was not found: pass an axios instance as the third argument of requestManager.axios() or make sure axios is available globally'
170
+ );
171
+ }
172
+ this.#_checkAxiosVersion(axiosLib);
167
173
  return this.#_request(
168
174
  this.getRequestId(url, options),
169
175
  ({ options: requestOptions }) => axiosLib({ url, ...requestOptions }),
@@ -224,7 +230,6 @@ class RequestManager {
224
230
  * });
225
231
  */
226
232
  xhr(url, options = {}) {
227
- const requestId = this.getRequestId(url, options);
228
233
  /** @type {import('./index.d.ts').RequestFunction<import('./index.d.ts').XhrResponse>} */
229
234
  const xhrFunction = ({ options: fetchOptions }) => {
230
235
  // Create XMLHttpRequest
@@ -233,6 +238,7 @@ class RequestManager {
233
238
  // Create a promise that wraps the XHR request
234
239
  const xhrPromise = new Promise((resolve, reject) => {
235
240
  xhr.onload = function () {
241
+ detachAbortListener();
236
242
  if (xhr.status >= 200 && xhr.status < 300) {
237
243
  let response = xhr.response;
238
244
  if (
@@ -262,12 +268,14 @@ class RequestManager {
262
268
  }
263
269
  };
264
270
  xhr.onerror = function () {
271
+ detachAbortListener();
265
272
  reject({
266
273
  message: 'Network error',
267
274
  xhr: xhr,
268
275
  });
269
276
  };
270
277
  xhr.ontimeout = function () {
278
+ detachAbortListener();
271
279
  reject({
272
280
  message: 'Request timeout',
273
281
  xhr: xhr,
@@ -290,14 +298,26 @@ class RequestManager {
290
298
  });
291
299
 
292
300
  // Connect abort signal to xhr.abort()
293
- if (fetchOptions.signal) fetchOptions.signal.addEventListener('abort', () => xhr.abort());
301
+ const abortListener = () => xhr.abort();
302
+ if (fetchOptions.signal) fetchOptions.signal.addEventListener('abort', abortListener);
303
+ // Detach the listener once the request settles so completed requests do not keep it alive
304
+ const detachAbortListener = () => {
305
+ if (fetchOptions.signal) fetchOptions.signal.removeEventListener('abort', abortListener);
306
+ };
307
+
308
+ xhr.onabort = function () {
309
+ reject({
310
+ message: 'Request was cancelled',
311
+ xhr: xhr,
312
+ });
313
+ };
294
314
 
295
315
  // Send the request
296
316
  xhr.send(options.body || null);
297
317
  });
298
318
  return xhrPromise;
299
319
  };
300
- return this.#_request(requestId, xhrFunction, options);
320
+ return this.#_request(this.getRequestId(url, options), xhrFunction, options);
301
321
  }
302
322
 
303
323
  /**
@@ -335,7 +355,11 @@ class RequestManager {
335
355
  if (cleanedUrl.includes('://')) cleanedUrl = cleanedUrl.split('://')[1];
336
356
  if (cleanedUrl.includes('#')) cleanedUrl = cleanedUrl.split('#')[0];
337
357
  if (!options.includeQuery && cleanedUrl.includes('?')) cleanedUrl = cleanedUrl.split('?')[0];
338
- return `${prefix}${cleanedUrl}`;
358
+
359
+ const methodPrefix =
360
+ options.includeMethod === false ? '' : `${(options.method || options.type || 'GET').toUpperCase()}_`;
361
+
362
+ return `${prefix}${methodPrefix}${cleanedUrl}`;
339
363
  }
340
364
 
341
365
  /**
@@ -444,7 +468,15 @@ class RequestManager {
444
468
  */
445
469
  #_prepareRequestOptions(options, signal) {
446
470
  const requestOptions = {};
447
- const customOptions = ['abortController', 'cancelToken', 'requestKey', 'noCancel', 'includeQuery'];
471
+ const customOptions = [
472
+ 'abortController',
473
+ 'cancelToken',
474
+ 'requestKey',
475
+ 'noCancel',
476
+ 'includeQuery',
477
+ 'includeMethod',
478
+ 'verbose',
479
+ ];
448
480
  Object.keys(options).forEach((key) => {
449
481
  if (customOptions.includes(key)) return;
450
482
  requestOptions[key] = options[key];
@@ -453,6 +485,24 @@ class RequestManager {
453
485
  return requestOptions;
454
486
  }
455
487
 
488
+ /**
489
+ * Warns when the provided axios instance predates 0.22.0, the first version
490
+ * supporting AbortSignal cancellation. Older instances silently ignore
491
+ * options.signal, so duplicate requests would not be cancelled.
492
+ * @param {object} axiosLib - The axios instance about to be used
493
+ * @private
494
+ */
495
+ #_checkAxiosVersion(axiosLib) {
496
+ const version = typeof axiosLib?.VERSION === 'string' ? axiosLib.VERSION : null;
497
+ if (!version) return;
498
+ const [major, minor] = version.split('.').map(Number);
499
+ if (major === 0 && minor < 22) {
500
+ console.warn(
501
+ `[request-manager] axios >= 0.22.0 is required: axios ${version} ignores the AbortSignal used for automatic cancellation. Please upgrade axios.`
502
+ );
503
+ }
504
+ }
505
+
456
506
  /**
457
507
  * Deletes a request from the active requests map and rejects the wrapper promise
458
508
  * @param {string} requestId - The unique identifier of the request
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@enegalan/request-manager",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "JavaScript library for managing and regulating HTTP requests efficiently",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
- "main": "dist/request-manager.cjs.js",
8
+ "main": "dist/request-manager.cjs",
9
9
  "module": "dist/request-manager.esm.js",
10
10
  "browser": "dist/request-manager.min.js",
11
11
  "unpkg": "dist/request-manager.min.js",
@@ -23,7 +23,7 @@
23
23
  ".": {
24
24
  "types": "./index.d.ts",
25
25
  "import": "./dist/request-manager.esm.js",
26
- "require": "./dist/request-manager.cjs.js",
26
+ "require": "./dist/request-manager.cjs",
27
27
  "browser": "./dist/request-manager.min.js",
28
28
  "default": "./dist/request-manager.esm.js"
29
29
  },
@@ -41,7 +41,9 @@
41
41
  "test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage"
42
42
  },
43
43
  "devDependencies": {
44
+ "@babel/preset-env": "^7.29.7",
44
45
  "@eslint/js": "^10.0.1",
46
+ "@rollup/plugin-babel": "^6.1.0",
45
47
  "@rollup/plugin-terser": "^0.4.4",
46
48
  "eslint": "^10.8.1",
47
49
  "eslint-config-prettier": "^10.1.8",