@enegalan/request-manager 1.0.10 → 1.1.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.
@@ -1,604 +1,707 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define(factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.RequestManager = factory());
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
+ typeof define === 'function' && define.amd ? define(factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.RequestManager = factory());
5
5
  })(this, (function () { 'use strict';
6
6
 
7
- /**
8
- * RequestManager - A library for managing and regulating HTTP requests efficiently.
9
- * @license MIT
10
- * @author Eneko Galan <enekogalanelorza@gmail.com>
11
- * This library allows you to manage HTTP requests from any library (ajax, Ext.Ajax, axios, fetch, etc.)
12
- * by accepting Promises as parameters. When a request is repeated with the same identifier,
13
- * the previous request is automatically cancelled and the new one is executed, giving priority to the most recent requests.
14
- */
15
- class RequestManager {
16
- constructor(options = {}) {
17
- /**
18
- * Map to store active requests by their unique identifier.
19
- * @type {Map<string, import('./index.d.ts').ActiveRequest>}
20
- */
21
- this.activeRequests = new Map();
22
- /**
23
- * @type {import('./index.d.ts').Options}
24
- */
25
- this.options = options;
26
- /**
27
- * One-shot AbortController for getSignal()/getAbortController() handoff.
28
- * Consumed by the next request that does not pass options.abortController.
29
- * @type {AbortController|null}
30
- */
31
- this.abortController = null;
32
- }
33
-
34
- /**
35
- * Gets the manager options
36
- * @returns {import('./index.d.ts').Options} Manager options
37
- */
38
- getOptions() {
39
- return this.options;
40
- }
41
-
42
- /**
43
- * Sets the manager options
44
- * @param {import('./index.d.ts').Options} options - The options to set
45
- */
46
- setOptions(options) {
47
- this.options = options;
48
- }
49
-
50
- /**
51
- * Creates a new AbortController and returns its signal for the next request()
52
- * (one getSignal → one request). Do not use for parallel requests; use fetch(),
53
- * axios(), or request(url, ({ options }) => ...) instead — they create their own signal.
54
- * @returns {AbortSignal} The signal from a new AbortController
55
- * @example
56
- * const signal = requestManager.getSignal();
57
- * requestManager.request('/api/users', fetch('/api/users', { signal }));
58
- */
59
- getSignal() {
60
- return this.getAbortController().signal;
61
- }
62
-
63
- /**
64
- * Creates a new AbortController for the next request handoff.
65
- * Always returns a fresh controller (never reuses one from another in-flight request).
66
- * @returns {AbortController} A new AbortController instance
67
- */
68
- getAbortController() {
69
- this.abortController = new AbortController();
70
- return this.abortController;
71
- }
72
-
73
- /**
74
- * Checks if a request with the given identifier is currently active.
75
- * @param {string} requestId - The unique identifier to check
76
- * @returns {boolean} True if the request is active, false otherwise
77
- */
78
- isActive(requestId) {
79
- return this.activeRequests.has(requestId);
80
- }
81
-
82
- /**
83
- * Gets the number of active requests.
84
- * @returns {number} The number of currently active requests
85
- */
86
- getActiveCount() {
87
- return this.activeRequests.size;
7
+ function _arrayLikeToArray(r, a) {
8
+ (null == a || a > r.length) && (a = r.length);
9
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
10
+ return n;
11
+ }
12
+ function _arrayWithHoles(r) {
13
+ if (Array.isArray(r)) return r;
14
+ }
15
+ function _assertClassBrand(e, t, n) {
16
+ if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
17
+ throw new TypeError("Private element is not present on this object");
18
+ }
19
+ function _checkPrivateRedeclaration(e, t) {
20
+ if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
21
+ }
22
+ function _classPrivateMethodInitSpec(e, a) {
23
+ _checkPrivateRedeclaration(e, a), a.add(e);
24
+ }
25
+ function _defineProperty(e, r, t) {
26
+ return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
27
+ value: t,
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true
31
+ }) : e[r] = t, e;
32
+ }
33
+ function _iterableToArrayLimit(r, l) {
34
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
35
+ if (null != t) {
36
+ var e,
37
+ n,
38
+ i,
39
+ u,
40
+ a = [],
41
+ f = true,
42
+ o = false;
43
+ try {
44
+ if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
45
+ } catch (r) {
46
+ o = true, n = r;
47
+ } finally {
48
+ try {
49
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
50
+ } finally {
51
+ if (o) throw n;
88
52
  }
53
+ }
54
+ return a;
55
+ }
56
+ }
57
+ function _nonIterableRest() {
58
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
59
+ }
60
+ function ownKeys(e, r) {
61
+ var t = Object.keys(e);
62
+ if (Object.getOwnPropertySymbols) {
63
+ var o = Object.getOwnPropertySymbols(e);
64
+ r && (o = o.filter(function (r) {
65
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
66
+ })), t.push.apply(t, o);
67
+ }
68
+ return t;
69
+ }
70
+ function _objectSpread2(e) {
71
+ for (var r = 1; r < arguments.length; r++) {
72
+ var t = null != arguments[r] ? arguments[r] : {};
73
+ r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
74
+ _defineProperty(e, r, t[r]);
75
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
76
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
77
+ });
78
+ }
79
+ return e;
80
+ }
81
+ function _slicedToArray(r, e) {
82
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
83
+ }
84
+ function _toPrimitive(t, r) {
85
+ if ("object" != typeof t || !t) return t;
86
+ var e = t[Symbol.toPrimitive];
87
+ if (void 0 !== e) {
88
+ var i = e.call(t, r);
89
+ if ("object" != typeof i) return i;
90
+ throw new TypeError("@@toPrimitive must return a primitive value.");
91
+ }
92
+ return ("string" === r ? String : Number)(t);
93
+ }
94
+ function _toPropertyKey(t) {
95
+ var i = _toPrimitive(t, "string");
96
+ return "symbol" == typeof i ? i : i + "";
97
+ }
98
+ function _unsupportedIterableToArray(r, a) {
99
+ if (r) {
100
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
101
+ var t = {}.toString.call(r).slice(8, -1);
102
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
103
+ }
104
+ }
105
+
106
+ var _RequestManager_brand = /*#__PURE__*/new WeakSet();
107
+ /**
108
+ * RequestManager - A library for managing and regulating HTTP requests efficiently.
109
+ * @license MIT
110
+ * @author Eneko Galan <enekogalanelorza@gmail.com>
111
+ * This library allows you to manage HTTP requests from any library (ajax, Ext.Ajax, axios, fetch, etc.)
112
+ * by accepting Promises as parameters. When a request is repeated with the same identifier,
113
+ * the previous request is automatically cancelled and the new one is executed, giving priority to the most recent requests.
114
+ */
115
+ class RequestManager {
116
+ constructor() {
117
+ var _options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
118
+ /**
119
+ * Resolves the AbortController for a request: explicit option, pending handoff, or new.
120
+ * Clears the pending handoff so concurrent requests do not share it.
121
+ * @param {AbortController|undefined} provided - Optional AbortController from options
122
+ * @returns {AbortController}
123
+ * @private
124
+ */
125
+ _classPrivateMethodInitSpec(this, _RequestManager_brand);
126
+ /**
127
+ * @type {Map<string, import('./index.d.ts').ActiveRequest>}
128
+ */
129
+ this.activeRequests = new Map();
130
+ /**
131
+ * @type {import('./index.d.ts').Options}
132
+ */
133
+ this.options = _options;
134
+ /**
135
+ * One-shot AbortController for getSignal()/getAbortController() handoff.
136
+ * Consumed by the next request that does not pass options.abortController.
137
+ * @type {AbortController|null}
138
+ */
139
+ this.abortController = null;
140
+ }
89
141
 
90
- /**
91
- * Clears all active requests without cancelling them.
92
- * Use with caution - this will not cancel the underlying HTTP requests.
93
- */
94
- clear() {
95
- this.activeRequests.clear();
96
- }
142
+ /**
143
+ * Gets the manager options
144
+ * @returns {import('./index.d.ts').Options} Manager options
145
+ */
146
+ getOptions() {
147
+ return this.options;
148
+ }
97
149
 
98
- /**
99
- * Executes an HTTP request, cancelling any previous request with the same identifier.
100
- * @param {string} url - The URL to request
101
- * @param {Promise|import('./index.d.ts').RequestFunction|string} requestPromise - The request promise or function that returns a promise
102
- * @param {import('./index.d.ts').RequestOptions} options - Optional configuration
103
- * @returns {Promise} A Promise that resolves/rejects based on the most recent request
104
- * @example
105
- * // Request with Promise
106
- * requestManager.request('/api/users', axios.get('/api/users', { cancelToken: axios.CancelToken.source().token }));
107
- * @example
108
- * // Request with Function
109
- * requestManager.request('/api/users', ({ options }) => fetch('/api/users', { signal: options.signal, ...options }));
110
- * @example
111
- * // Request with Promise and custom cancellation grouping with requestKey
112
- * const options = {
113
- * requestKey: 'get-users',
114
- * cancelToken: axios.CancelToken.source().cancel
115
- * }
116
- * requestManager.request('/api/users', axios.get('/api/users', options), options);
117
- */
118
- request(url, requestPromise, options = {}) {
119
- return this.#_request(this.getRequestId(url, options), requestPromise, options);
120
- }
150
+ /**
151
+ * Sets the manager options
152
+ * @param {import('./index.d.ts').Options} options - The options to set
153
+ */
154
+ setOptions(options) {
155
+ this.options = options;
156
+ }
121
157
 
122
- /**
123
- * Executes an HTTP request using fetch, cancelling any previous request with the same identifier.
124
- * @param {string} url - The URL to fetch
125
- * @param {import('./index.d.ts').FetchOptions} options - Optional configuration
126
- * @returns {Promise} A Promise that resolves/rejects based on the most recent request
127
- * @example
128
- * // Simple GET request
129
- * requestManager.fetch('/api/users');
130
- * @example
131
- * // POST request with options
132
- * requestManager.fetch('/api/users', {
133
- * method: 'POST',
134
- * headers: { 'Content-Type': 'application/json' },
135
- * body: JSON.stringify({ name: 'John' })
136
- * });
137
- * @example
138
- * // Request with requestKey for custom cancellation grouping with requestKey
139
- * requestManager.fetch('/api/users', {
140
- * requestKey: 'get-users'
141
- * });
142
- */
143
- fetch(url, options = {}) {
144
- return this.#_request(this.getRequestId(url, options), url, options);
145
- }
158
+ /**
159
+ * Creates a new AbortController and returns its signal for the next request()
160
+ * (one getSignal one request). Do not use for parallel requests; use fetch(),
161
+ * axios(), or request(url, ({ options }) => ...) instead — they create their own signal.
162
+ * @returns {AbortSignal} The signal from a new AbortController
163
+ * @example
164
+ * const signal = requestManager.getSignal();
165
+ * requestManager.request('/api/users', fetch('/api/users', { signal }));
166
+ */
167
+ getSignal() {
168
+ return this.getAbortController().signal;
169
+ }
146
170
 
147
- /**
148
- * Executes an HTTP request using axios, cancelling any previous request with the same identifier.
149
- * @param {string} url - The URL to request
150
- * @param {import('./index.d.ts').AxiosRequestOptions} options - Optional configuration
151
- * @param {import('./index.d.ts').AxiosInstance|import('./index.d.ts').AxiosStatic|null} axiosInstance - Optional axios instance to use. If not provided, uses global axios.
152
- * @returns {Promise} A Promise that resolves/rejects based on the most recent request
153
- * @example
154
- * // Simple GET request (uses global axios)
155
- * requestManager.axios('/api/users');
156
- * @example
157
- * // With custom axios instance
158
- * const myAxios = axios.create({ baseURL: 'https://api.example.com' });
159
- * requestManager.axios('/users', {}, myAxios);
160
- * @example
161
- * // POST request with options
162
- * requestManager.axios('/api/users', {
163
- * method: 'POST',
164
- * headers: { 'Content-Type': 'application/json' },
165
- * body: JSON.stringify({ name: 'John' })
166
- * });
167
- * @example
168
- * // Request with requestKey for custom cancellation grouping with requestKey
169
- * requestManager.axios('/api/users', {
170
- * requestKey: 'get-users'
171
- * });
172
- */
173
- axios(url, options = {}, axiosInstance = null) {
174
- const axiosLib = axiosInstance || axios;
175
- const cancelToken = axiosLib.CancelToken.source();
176
- const requestId = this.getRequestId(url, options);
177
- return this.#_request(requestId, axiosLib({ url, cancelToken: cancelToken.token, ...options }), {
178
- cancelToken: cancelToken,
179
- ...options,
180
- });
181
- }
171
+ /**
172
+ * Creates a new AbortController for the next request handoff.
173
+ * Always returns a fresh controller (never reuses one from another in-flight request).
174
+ * @returns {AbortController} A new AbortController instance
175
+ */
176
+ getAbortController() {
177
+ this.abortController = new AbortController();
178
+ return this.abortController;
179
+ }
182
180
 
183
- /**
184
- * Executes an HTTP request using jQuery.ajax, cancelling any previous request with the same identifier.
185
- * @param {import('./index.d.ts').AjaxFunction} ajaxFunction - A function that receives { url, ...options } and returns a Promise
186
- * @param {string} url - The URL to request
187
- * @param {import('./index.d.ts').BaseRequestOptions & Record<string, any>} options - Optional configuration
188
- * @returns {Promise} A Promise that resolves/rejects based on the most recent request
189
- * @example
190
- * // Simple GET request
191
- * requestManager.ajax(ajaxFunction, '/api/users');
192
- * @example
193
- * // POST request with options
194
- * requestManager.ajax(ajaxFunction, '/api/users', {
195
- * method: 'POST',
196
- * headers: { 'Content-Type': 'application/json' },
197
- * body: JSON.stringify({ name: 'John' })
198
- * });
199
- * @example
200
- * // Request with requestKey for custom cancellation grouping with requestKey
201
- * requestManager.ajax(ajaxFunction, '/api/users', {
202
- * requestKey: 'get-users'
203
- * });
204
- */
205
- ajax(ajaxFunction, url, options = {}) {
206
- if (typeof ajaxFunction !== 'function') throw new Error('ajaxFunction parameter must be a function');
207
- return this.#_request(
208
- this.getRequestId(url, options),
209
- ({ options: requestOptions }) => ajaxFunction({ url, ...requestOptions }),
210
- options
211
- );
212
- }
181
+ /**
182
+ * Checks if a request with the given identifier is currently active.
183
+ * @param {string} requestId - The unique identifier to check
184
+ * @returns {boolean} True if the request is active, false otherwise
185
+ */
186
+ isActive(requestId) {
187
+ return this.activeRequests.has(requestId);
188
+ }
213
189
 
214
- /**
215
- * Executes an HTTP request using XMLHttpRequest, cancelling any previous request with the same identifier.
216
- * @param {string} url - The URL to request
217
- * @param {import('./index.d.ts').XhrOptions} options - Optional configuration
218
- * @returns {Promise<import('./index.d.ts').XhrResponse>} A Promise that resolves/rejects based on the most recent request
219
- * @example
220
- * // Simple GET request
221
- * requestManager.xhr('/api/users');
222
- * @example
223
- * // POST request with options
224
- * requestManager.xhr('/api/users', {
225
- * method: 'POST',
226
- * headers: { 'Content-Type': 'application/json' },
227
- * body: JSON.stringify({ name: 'John' })
228
- * });
229
- * @example
230
- * // Request with requestKey for custom cancellation grouping
231
- * requestManager.xhr('/api/users', {
232
- * requestKey: 'get-users'
233
- * });
234
- */
235
- xhr(url, options = {}) {
236
- const requestId = this.getRequestId(url, options);
237
- /** @type {import('./index.d.ts').RequestFunction<import('./index.d.ts').XhrResponse>} */
238
- const xhrFunction = ({ options: fetchOptions }) => {
239
- // Create XMLHttpRequest
240
- const xhr = new XMLHttpRequest();
241
- const method = (options.method || 'GET').toUpperCase();
242
- // Create a promise that wraps the XHR request
243
- const xhrPromise = new Promise((resolve, reject) => {
244
- xhr.onload = function () {
245
- if (xhr.status >= 200 && xhr.status < 300) {
246
- let response = xhr.response;
247
- if (
248
- options.responseType === 'json' ||
249
- (xhr.getResponseHeader('Content-Type') &&
250
- xhr.getResponseHeader('Content-Type').includes('application/json'))
251
- ) {
252
- try {
253
- response = JSON.parse(xhr.responseText);
254
- } catch {
255
- response = xhr.responseText;
256
- }
257
- }
258
- resolve({
259
- data: response,
260
- status: xhr.status,
261
- statusText: xhr.statusText,
262
- headers: xhr.getAllResponseHeaders(),
263
- xhr: xhr,
264
- });
265
- } else {
266
- reject({
267
- message: `Request failed with status ${xhr.status}`,
268
- status: xhr.status,
269
- statusText: xhr.statusText,
270
- xhr: xhr,
271
- });
272
- }
273
- };
274
- xhr.onerror = function () {
275
- reject({
276
- message: 'Network error',
277
- xhr: xhr,
278
- });
279
- };
280
- xhr.ontimeout = function () {
281
- reject({
282
- message: 'Request timeout',
283
- xhr: xhr,
284
- });
285
- };
286
-
287
- // Open the request
288
- xhr.open(method, url, true);
289
-
290
- // Set response type
291
- if (options.responseType) xhr.responseType = options.responseType;
292
- // Set withCredentials
293
- if (options.withCredentials !== undefined) xhr.withCredentials = options.withCredentials;
294
- // Set timeout
295
- if (options.timeout !== undefined) xhr.timeout = options.timeout;
296
- // Set headers
297
- if (options.headers)
298
- Object.keys(options.headers).forEach((key) => {
299
- xhr.setRequestHeader(key, options.headers[key]);
300
- });
301
-
302
- // Connect abort signal to xhr.abort()
303
- if (fetchOptions.signal) fetchOptions.signal.addEventListener('abort', () => xhr.abort());
304
-
305
- // Send the request
306
- xhr.send(options.body || null);
307
- });
308
- return xhrPromise;
309
- };
310
- return this.#_request(requestId, xhrFunction, options);
311
- }
190
+ /**
191
+ * Gets the number of active requests.
192
+ * @returns {number} The number of currently active requests
193
+ */
194
+ getActiveCount() {
195
+ return this.activeRequests.size;
196
+ }
312
197
 
313
- /**
314
- * Returns the request identifier for a URL and options.
315
- * @param {string} url - The URL used when starting the request
316
- * @param {import('./index.d.ts').BaseRequestOptions} options - Same options used for the request
317
- * @returns {string} The request identifier
318
- * @example
319
- * requestManager.fetch('/api/users');
320
- * const id = requestManager.getRequestId('/api/users');
321
- * requestManager.cancel(id);
322
- */
323
- getRequestId(url, options = {}) {
324
- let requestKey = options.requestKey;
325
-
326
- const prefix = 'request_';
327
-
328
- // Generate a unique identifier to prevent cancellation for non cancelable requests
329
- if (options.noCancel) {
330
- return `${prefix}${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
331
- }
198
+ /**
199
+ * Clears all active requests without cancelling them.
200
+ * Use with caution - this will not cancel the underlying HTTP requests.
201
+ */
202
+ clear() {
203
+ this.activeRequests.clear();
204
+ }
332
205
 
333
- // Handle function requestKey
334
- if (typeof requestKey === 'function') {
335
- try {
336
- requestKey = requestKey();
337
- } catch {
338
- requestKey = null;
339
- }
340
- }
341
- if (requestKey !== null && requestKey !== undefined) return `${prefix}${String(requestKey)}`;
342
-
343
- // Use cleaned URL as key as fallback
344
- let cleanedUrl = url || '';
345
- if (cleanedUrl.includes('://')) cleanedUrl = cleanedUrl.split('://')[1];
346
- if (cleanedUrl.includes('#')) cleanedUrl = cleanedUrl.split('#')[0];
347
- if (!options.includeQuery && cleanedUrl.includes('?')) cleanedUrl = cleanedUrl.split('?')[0];
348
- return `${prefix}${cleanedUrl}`;
349
- }
206
+ /**
207
+ * Executes an HTTP request, cancelling any previous request with the same identifier.
208
+ * @param {string} url - The URL to request
209
+ * @param {Promise|import('./index.d.ts').RequestFunction|string} requestPromise - The request promise or function that returns a promise
210
+ * @param {import('./index.d.ts').RequestOptions} options - Optional configuration
211
+ * @returns {Promise} A Promise that resolves/rejects based on the most recent request
212
+ * @example
213
+ * // Request with Promise
214
+ * requestManager.request('/api/users', axios.get('/api/users'));
215
+ * @example
216
+ * // Request with Function
217
+ * requestManager.request('/api/users', ({ options }) => fetch('/api/users', { signal: options.signal, ...options }));
218
+ * @example
219
+ * // Request with Promise and custom cancellation grouping with requestKey
220
+ * const options = {
221
+ * requestKey: 'get-users'
222
+ * }
223
+ * requestManager.request('/api/users', axios.get('/api/users', options), options);
224
+ */
225
+ request(url, requestPromise) {
226
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
227
+ return _assertClassBrand(_RequestManager_brand, this, _request).call(this, this.getRequestId(url, options), requestPromise, options);
228
+ }
350
229
 
351
- /**
352
- * Cancels a specific request by its identifier.
353
- * @param {string} requestId - The unique identifier of the request to cancel
354
- * @returns {boolean} True if the request was found and cancelled, false otherwise
355
- */
356
- cancel(requestId) {
357
- /** @type {import('./index.d.ts').ActiveRequest|undefined} */
358
- const requestInfo = this.activeRequests.get(requestId);
359
- if (!requestInfo) return false;
230
+ /**
231
+ * Executes an HTTP request using fetch, cancelling any previous request with the same identifier.
232
+ * @param {string} url - The URL to fetch
233
+ * @param {import('./index.d.ts').FetchOptions} options - Optional configuration
234
+ * @returns {Promise} A Promise that resolves/rejects based on the most recent request
235
+ * @example
236
+ * // Simple GET request
237
+ * requestManager.fetch('/api/users');
238
+ * @example
239
+ * // POST request with options
240
+ * requestManager.fetch('/api/users', {
241
+ * method: 'POST',
242
+ * headers: { 'Content-Type': 'application/json' },
243
+ * body: JSON.stringify({ name: 'John' })
244
+ * });
245
+ * @example
246
+ * // Request with requestKey for custom cancellation grouping with requestKey
247
+ * requestManager.fetch('/api/users', {
248
+ * requestKey: 'get-users'
249
+ * });
250
+ */
251
+ fetch(url) {
252
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
253
+ return _assertClassBrand(_RequestManager_brand, this, _request).call(this, this.getRequestId(url, options), url, options);
254
+ }
360
255
 
361
- requestInfo.isCancelled = true; // Mark as cancelled
256
+ /**
257
+ * Executes an HTTP request using axios, cancelling any previous request with the same identifier.
258
+ * @param {string} url - The URL to request
259
+ * @param {import('./index.d.ts').AxiosRequestOptions} options - Optional configuration
260
+ * @param {import('./index.d.ts').AxiosInstance|import('./index.d.ts').AxiosStatic|null} axiosInstance - Optional axios instance to use. If not provided, uses global axios.
261
+ * @returns {Promise} A Promise that resolves/rejects based on the most recent request
262
+ * @example
263
+ * // Simple GET request (uses global axios)
264
+ * requestManager.axios('/api/users');
265
+ * @example
266
+ * // With custom axios instance
267
+ * const myAxios = axios.create({ baseURL: 'https://api.example.com' });
268
+ * requestManager.axios('/users', {}, myAxios);
269
+ * @example
270
+ * // POST request with options
271
+ * requestManager.axios('/api/users', {
272
+ * method: 'POST',
273
+ * headers: { 'Content-Type': 'application/json' },
274
+ * body: JSON.stringify({ name: 'John' })
275
+ * });
276
+ * @example
277
+ * // Request with requestKey for custom cancellation grouping with requestKey
278
+ * requestManager.axios('/api/users', {
279
+ * requestKey: 'get-users'
280
+ * });
281
+ */
282
+ axios(url) {
283
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
284
+ var axiosInstance = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
285
+ var axiosLib = axiosInstance || axios;
286
+ _assertClassBrand(_RequestManager_brand, this, _checkAxiosVersion).call(this, axiosLib);
287
+ return _assertClassBrand(_RequestManager_brand, this, _request).call(this, this.getRequestId(url, options), _ref => {
288
+ var requestOptions = _ref.options;
289
+ return axiosLib(_objectSpread2({
290
+ url
291
+ }, requestOptions));
292
+ }, options);
293
+ }
362
294
 
363
- // Try to abort using AbortController (for fetch)
364
- if (requestInfo.abortController && !requestInfo.abortController.signal.aborted) {
365
- try {
366
- requestInfo.abortController.abort('Request was cancelled');
367
- } catch (error) {}
368
- }
295
+ /**
296
+ * Executes an HTTP request using jQuery.ajax, cancelling any previous request with the same identifier.
297
+ * @param {import('./index.d.ts').AjaxFunction} ajaxFunction - A function that receives { url, ...options } and returns a Promise
298
+ * @param {string} url - The URL to request
299
+ * @param {import('./index.d.ts').BaseRequestOptions & Record<string, any>} options - Optional configuration
300
+ * @returns {Promise} A Promise that resolves/rejects based on the most recent request
301
+ * @example
302
+ * // Simple GET request
303
+ * requestManager.ajax(ajaxFunction, '/api/users');
304
+ * @example
305
+ * // POST request with options
306
+ * requestManager.ajax(ajaxFunction, '/api/users', {
307
+ * method: 'POST',
308
+ * headers: { 'Content-Type': 'application/json' },
309
+ * body: JSON.stringify({ name: 'John' })
310
+ * });
311
+ * @example
312
+ * // Request with requestKey for custom cancellation grouping with requestKey
313
+ * requestManager.ajax(ajaxFunction, '/api/users', {
314
+ * requestKey: 'get-users'
315
+ * });
316
+ */
317
+ ajax(ajaxFunction, url) {
318
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
319
+ if (typeof ajaxFunction !== 'function') throw new Error('ajaxFunction parameter must be a function');
320
+ return _assertClassBrand(_RequestManager_brand, this, _request).call(this, this.getRequestId(url, options), _ref2 => {
321
+ var requestOptions = _ref2.options;
322
+ return ajaxFunction(_objectSpread2({
323
+ url
324
+ }, requestOptions));
325
+ }, options);
326
+ }
369
327
 
370
- // Try to cancel using cancel token/function (for axios and others)
371
- if (requestInfo.cancelToken) {
328
+ /**
329
+ * Executes an HTTP request using XMLHttpRequest, cancelling any previous request with the same identifier.
330
+ * @param {string} url - The URL to request
331
+ * @param {import('./index.d.ts').XhrOptions} options - Optional configuration
332
+ * @returns {Promise<import('./index.d.ts').XhrResponse>} A Promise that resolves/rejects based on the most recent request
333
+ * @example
334
+ * // Simple GET request
335
+ * requestManager.xhr('/api/users');
336
+ * @example
337
+ * // POST request with options
338
+ * requestManager.xhr('/api/users', {
339
+ * method: 'POST',
340
+ * headers: { 'Content-Type': 'application/json' },
341
+ * body: JSON.stringify({ name: 'John' })
342
+ * });
343
+ * @example
344
+ * // Request with requestKey for custom cancellation grouping
345
+ * requestManager.xhr('/api/users', {
346
+ * requestKey: 'get-users'
347
+ * });
348
+ */
349
+ xhr(url) {
350
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
351
+ var requestId = this.getRequestId(url, options);
352
+ /** @type {import('./index.d.ts').RequestFunction<import('./index.d.ts').XhrResponse>} */
353
+ var xhrFunction = _ref3 => {
354
+ var fetchOptions = _ref3.options;
355
+ // Create XMLHttpRequest
356
+ var xhr = new XMLHttpRequest();
357
+ var method = (options.method || 'GET').toUpperCase();
358
+ // Create a promise that wraps the XHR request
359
+ var xhrPromise = new Promise((resolve, reject) => {
360
+ xhr.onload = function () {
361
+ if (xhr.status >= 200 && xhr.status < 300) {
362
+ var _xhr$getResponseHeade;
363
+ var response = xhr.response;
364
+ if (options.responseType === 'json' || (!options.responseType || options.responseType === 'text') && (_xhr$getResponseHeade = xhr.getResponseHeader('Content-Type')) !== null && _xhr$getResponseHeade !== void 0 && _xhr$getResponseHeade.includes('application/json') && typeof response === 'string') {
372
365
  try {
373
- if (typeof requestInfo.cancelToken === 'function') requestInfo.cancelToken();
374
- else if (requestInfo.cancelToken.cancel) requestInfo.cancelToken.cancel();
375
- } catch (error) {}
366
+ response = JSON.parse(response);
367
+ } catch (_unused) {}
368
+ }
369
+ resolve({
370
+ data: response,
371
+ status: xhr.status,
372
+ statusText: xhr.statusText,
373
+ headers: xhr.getAllResponseHeaders(),
374
+ xhr: xhr
375
+ });
376
+ } else {
377
+ reject({
378
+ message: "Request failed with status ".concat(xhr.status),
379
+ status: xhr.status,
380
+ statusText: xhr.statusText,
381
+ xhr: xhr
382
+ });
376
383
  }
377
-
378
- // Reject the wrapper promise
379
- this.#_deleteRequest(
380
- requestId,
381
- requestInfo.rejectWrapper,
382
- this.getOptions().verbose ? new Error(`Request ${requestId} was cancelled`) : null
383
- );
384
- return true;
385
- }
386
-
387
- /**
388
- * Link abort signal with HTTP client abort method.
389
- * Useful for custom HTTP clients that only support the abort method to cancel requests.
390
- * @param {Function} abortMethod - The abort method to call when the signal is aborted
391
- * @param {AbortSignal} signal - The signal to listen to
392
- */
393
- addAbortListener(abortMethod, signal) {
394
- if (!abortMethod || !signal) return;
395
- signal.addEventListener('abort', () => {
396
- if (typeof abortMethod === 'function') {
397
- try {
398
- abortMethod();
399
- } catch (error) {}
400
- }
384
+ };
385
+ xhr.onerror = function () {
386
+ reject({
387
+ message: 'Network error',
388
+ xhr: xhr
401
389
  });
402
- }
403
-
404
- /**
405
- * Cancels all active requests.
406
- * @returns {number} The number of requests that were cancelled
407
- */
408
- cancelAll() {
409
- const requestIds = Array.from(this.activeRequests.keys());
410
- let cancelledCount = 0;
411
- requestIds.forEach((requestId) => {
412
- if (this.cancel(requestId)) cancelledCount++;
390
+ };
391
+ xhr.ontimeout = function () {
392
+ reject({
393
+ message: 'Request timeout',
394
+ xhr: xhr
413
395
  });
414
- return cancelledCount;
415
- }
416
-
417
- /**
418
- * Resolves the AbortController for a request: explicit option, pending handoff, or new.
419
- * Clears the pending handoff so concurrent requests do not share it.
420
- * @param {AbortController|undefined} provided - Optional AbortController from options
421
- * @returns {AbortController}
422
- * @private
423
- */
424
- #_resolveAbortController(provided) {
425
- const abortController = provided || this.abortController || new AbortController();
426
- this.abortController = null;
427
- return abortController;
428
- }
429
-
430
- /**
431
- * Picks the best abort callback for a client request object.
432
- * @param {Object} req - The request object
433
- * @returns {Function|null}
434
- * @private
435
- */
436
- #_resolveAbortMethod(req) {
437
- if (!req) return null;
438
- if (typeof req.abort === 'function') return () => req.abort();
439
- const ExtAjax =
440
- typeof globalThis !== 'undefined' && globalThis.Ext && globalThis.Ext.Ajax ? globalThis.Ext.Ajax : null;
441
- if (req.xhr && ExtAjax && typeof ExtAjax.abort === 'function') {
442
- return () => ExtAjax.abort(req);
443
- }
444
- if (req.xhr && typeof req.xhr.abort === 'function') return () => req.xhr.abort();
445
- return null;
446
- }
396
+ };
397
+
398
+ // Open the request
399
+ xhr.open(method, url, true);
400
+
401
+ // Set response type
402
+ if (options.responseType) xhr.responseType = options.responseType;
403
+ // Set withCredentials
404
+ if (options.withCredentials !== undefined) xhr.withCredentials = options.withCredentials;
405
+ // Set timeout
406
+ if (options.timeout !== undefined) xhr.timeout = options.timeout;
407
+ // Set headers
408
+ if (options.headers) Object.keys(options.headers).forEach(key => {
409
+ xhr.setRequestHeader(key, options.headers[key]);
410
+ });
411
+
412
+ // Connect abort signal to xhr.abort()
413
+ if (fetchOptions.signal) fetchOptions.signal.addEventListener('abort', () => xhr.abort());
414
+
415
+ // Send the request
416
+ xhr.send(options.body || null);
417
+ });
418
+ return xhrPromise;
419
+ };
420
+ return _assertClassBrand(_RequestManager_brand, this, _request).call(this, requestId, xhrFunction, options);
421
+ }
447
422
 
448
- /**
449
- * Prepares request options by merging options and removing custom properties
450
- * @param {import('./index.d.ts').RequestOptions} options - Configuration options
451
- * @param {AbortSignal} signal - Abort signal to add to request options
452
- * @returns {Object} Prepared request options
453
- * @private
454
- */
455
- #_prepareRequestOptions(options, signal) {
456
- const requestOptions = {};
457
- const customOptions = ['abortController', 'cancelToken', 'requestKey', 'noCancel', 'includeQuery'];
458
- Object.keys(options).forEach((key) => {
459
- if (customOptions.includes(key)) return;
460
- requestOptions[key] = options[key];
461
- });
462
- requestOptions.signal = signal;
463
- return requestOptions;
423
+ /**
424
+ * Returns the request identifier for a URL and options.
425
+ * @param {string} url - The URL used when starting the request
426
+ * @param {import('./index.d.ts').BaseRequestOptions} options - Same options used for the request
427
+ * @returns {string} The request identifier
428
+ * @example
429
+ * requestManager.fetch('/api/users');
430
+ * const id = requestManager.getRequestId('/api/users');
431
+ * requestManager.cancel(id);
432
+ */
433
+ getRequestId(url) {
434
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
435
+ var requestKey = options.requestKey;
436
+ var prefix = 'request_';
437
+
438
+ // Generate a unique identifier to prevent cancellation for non cancelable requests
439
+ if (options.noCancel) {
440
+ return "".concat(prefix).concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 11));
441
+ }
442
+
443
+ // Handle function requestKey
444
+ if (typeof requestKey === 'function') {
445
+ try {
446
+ requestKey = requestKey();
447
+ } catch (_unused2) {
448
+ requestKey = null;
464
449
  }
450
+ }
451
+ if (requestKey !== null && requestKey !== undefined) return "".concat(prefix).concat(String(requestKey));
452
+
453
+ // Use cleaned URL as key as fallback
454
+ var cleanedUrl = url || '';
455
+ if (cleanedUrl.includes('://')) cleanedUrl = cleanedUrl.split('://')[1];
456
+ if (cleanedUrl.includes('#')) cleanedUrl = cleanedUrl.split('#')[0];
457
+ if (!options.includeQuery && cleanedUrl.includes('?')) cleanedUrl = cleanedUrl.split('?')[0];
458
+ var methodPrefix = options.includeMethod === false ? '' : "".concat((options.method || options.type || 'GET').toUpperCase(), "_");
459
+ return "".concat(prefix).concat(methodPrefix).concat(cleanedUrl);
460
+ }
465
461
 
466
- /**
467
- * Deletes a request from the active requests map and rejects the wrapper promise
468
- * @param {string} requestId - The unique identifier of the request
469
- * @param {Function} rejectWrapper - The function to reject the wrapper promise
470
- * @param {*} error - The error to reject the wrapper promise with; the wrapper is not rejected if null/undefined
471
- * @private
472
- */
473
- #_deleteRequest(requestId, rejectWrapper, error) {
474
- this.activeRequests.delete(requestId);
475
- if (error !== null && error !== undefined) {
476
- rejectWrapper(error);
477
- }
478
- }
462
+ /**
463
+ * Cancels a specific request by its identifier.
464
+ * @param {string} requestId - The unique identifier of the request to cancel
465
+ * @returns {boolean} True if the request was found and cancelled, false otherwise
466
+ */
467
+ cancel(requestId) {
468
+ /** @type {import('./index.d.ts').ActiveRequest|undefined} */
469
+ var requestInfo = this.activeRequests.get(requestId);
470
+ if (!requestInfo) return false;
471
+ requestInfo.isCancelled = true; // Mark as cancelled
472
+
473
+ // Try to abort using AbortController (for fetch)
474
+ if (requestInfo.abortController && !requestInfo.abortController.signal.aborted) {
475
+ try {
476
+ requestInfo.abortController.abort('Request was cancelled');
477
+ } catch (error) {}
478
+ }
479
+
480
+ // Try to cancel using cancel token/function (for axios and others)
481
+ if (requestInfo.cancelToken) {
482
+ try {
483
+ if (typeof requestInfo.cancelToken === 'function') requestInfo.cancelToken();else if (requestInfo.cancelToken.cancel) requestInfo.cancelToken.cancel();
484
+ } catch (error) {}
485
+ }
486
+
487
+ // Reject the wrapper promise
488
+ _assertClassBrand(_RequestManager_brand, this, _deleteRequest).call(this, requestId, requestInfo.rejectWrapper, this.getOptions().verbose ? new Error("Request ".concat(requestId, " was cancelled")) : null);
489
+ return true;
490
+ }
479
491
 
480
- /**
481
- * Completes a request by deleting it from the active requests map and resolving the wrapper promise
482
- * @param {string} requestId - The unique identifier of the request
483
- * @param {Function} resolveWrapper - The function to resolve the wrapper promise
484
- * @param {Promise} requestPromise - The request promise
485
- * @param {boolean} isCancelled - Whether the request was cancelled
486
- * @private
487
- */
488
- #_completeRequest(requestId, resolveWrapper, requestPromise, isCancelled) {
489
- this.activeRequests.delete(requestId);
490
- if (!isCancelled) {
491
- resolveWrapper(requestPromise);
492
- }
492
+ /**
493
+ * Link abort signal with HTTP client abort method.
494
+ * Useful for custom HTTP clients that only support the abort method to cancel requests.
495
+ * @param {Function} abortMethod - The abort method to call when the signal is aborted
496
+ * @param {AbortSignal} signal - The signal to listen to
497
+ */
498
+ addAbortListener(abortMethod, signal) {
499
+ if (!abortMethod || !signal) return;
500
+ signal.addEventListener('abort', () => {
501
+ if (typeof abortMethod === 'function') {
502
+ try {
503
+ abortMethod();
504
+ } catch (error) {}
493
505
  }
506
+ });
507
+ }
494
508
 
495
- /**
496
- * Internal method that handles the core request logic.
497
- * @param {string} requestId - Unique identifier for the request
498
- * @param {Promise|import('./index.d.ts').RequestFunction|string} requestPromise - The request promise, function, or URL string
499
- * @param {import('./index.d.ts').BaseRequestOptions} options - Configuration options
500
- * @returns {Promise} A Promise that resolves/rejects based on the most recent request
501
- * @private
502
- */
503
- #_request(requestId, requestPromise, options = {}) {
504
- const abortController = this.#_resolveAbortController(options.abortController);
505
-
506
- // Handle different types of requestPromise inputs
507
- // Priority: Function (Custom logic) > String (URL) > Promise (axios, fetch, etc.)
508
- if (typeof requestPromise === 'function') {
509
- // Function: custom logic for any library (axios, ajax, etc.)
510
- try {
511
- requestPromise = requestPromise({
512
- options: this.#_prepareRequestOptions(options, abortController.signal),
513
- });
514
- } catch (error) {
515
- return Promise.reject(error);
516
- }
517
- } else if (typeof requestPromise === 'string') {
518
- // String (URL): make fetch internally
519
- try {
520
- requestPromise = fetch(requestPromise, this.#_prepareRequestOptions(options, abortController.signal));
521
- } catch (error) {
522
- return Promise.reject(error);
523
- }
524
- }
509
+ /**
510
+ * Cancels all active requests.
511
+ * @returns {number} The number of requests that were cancelled
512
+ */
513
+ cancelAll() {
514
+ var requestIds = Array.from(this.activeRequests.keys());
515
+ var cancelledCount = 0;
516
+ requestIds.forEach(requestId => {
517
+ if (this.cancel(requestId)) cancelledCount++;
518
+ });
519
+ return cancelledCount;
520
+ }
521
+ }
522
+ function _resolveAbortController(provided) {
523
+ var abortController = provided || this.abortController || new AbortController();
524
+ this.abortController = null;
525
+ return abortController;
526
+ }
527
+ /**
528
+ * Picks the best abort callback for a client request object.
529
+ * @param {Object} req - The request object
530
+ * @returns {Function|null}
531
+ * @private
532
+ */
533
+ function _resolveAbortMethod(req) {
534
+ if (!req) return null;
535
+ if (typeof req.abort === 'function') return () => req.abort();
536
+ var ExtAjax = typeof globalThis !== 'undefined' && globalThis.Ext && globalThis.Ext.Ajax ? globalThis.Ext.Ajax : null;
537
+ if (req.xhr && ExtAjax && typeof ExtAjax.abort === 'function') {
538
+ return () => ExtAjax.abort(req);
539
+ }
540
+ if (req.xhr && typeof req.xhr.abort === 'function') return () => req.xhr.abort();
541
+ return null;
542
+ }
543
+ /**
544
+ * Prepares request options by merging options and removing custom properties
545
+ * @param {import('./index.d.ts').RequestOptions} options - Configuration options
546
+ * @param {AbortSignal} signal - Abort signal to add to request options
547
+ * @returns {Object} Prepared request options
548
+ * @private
549
+ */
550
+ function _prepareRequestOptions(options, signal) {
551
+ var requestOptions = {};
552
+ var customOptions = ['abortController', 'cancelToken', 'requestKey', 'noCancel', 'includeQuery'];
553
+ Object.keys(options).forEach(key => {
554
+ if (customOptions.includes(key)) return;
555
+ requestOptions[key] = options[key];
556
+ });
557
+ requestOptions.signal = signal;
558
+ return requestOptions;
559
+ }
560
+ /**
561
+ * Warns when the provided axios instance predates 0.22.0, the first version
562
+ * supporting AbortSignal cancellation. Older instances silently ignore
563
+ * options.signal, so duplicate requests would not be cancelled.
564
+ * @param {object} axiosLib - The axios instance about to be used
565
+ * @private
566
+ */
567
+ function _checkAxiosVersion(axiosLib) {
568
+ var version = typeof (axiosLib === null || axiosLib === void 0 ? void 0 : axiosLib.VERSION) === 'string' ? axiosLib.VERSION : null;
569
+ if (!version) return;
570
+ var _version$split$map = version.split('.').map(Number),
571
+ _version$split$map2 = _slicedToArray(_version$split$map, 2),
572
+ major = _version$split$map2[0],
573
+ minor = _version$split$map2[1];
574
+ if (major === 0 && minor < 22) {
575
+ console.warn("[request-manager] axios >= 0.22.0 is required: axios ".concat(version, " ignores the AbortSignal used for automatic cancellation. Please upgrade axios."));
576
+ }
577
+ }
578
+ /**
579
+ * Deletes a request from the active requests map and rejects the wrapper promise
580
+ * @param {string} requestId - The unique identifier of the request
581
+ * @param {Function} rejectWrapper - The function to reject the wrapper promise
582
+ * @param {*} error - The error to reject the wrapper promise with; the wrapper is not rejected if null/undefined
583
+ * @private
584
+ */
585
+ function _deleteRequest(requestId, rejectWrapper, error) {
586
+ this.activeRequests.delete(requestId);
587
+ if (error !== null && error !== undefined) {
588
+ rejectWrapper(error);
589
+ }
590
+ }
591
+ /**
592
+ * Completes a request by deleting it from the active requests map and resolving the wrapper promise
593
+ * @param {string} requestId - The unique identifier of the request
594
+ * @param {Function} resolveWrapper - The function to resolve the wrapper promise
595
+ * @param {Promise} requestPromise - The request promise
596
+ * @param {boolean} isCancelled - Whether the request was cancelled
597
+ * @private
598
+ */
599
+ function _completeRequest(requestId, resolveWrapper, requestPromise, isCancelled) {
600
+ this.activeRequests.delete(requestId);
601
+ if (!isCancelled) {
602
+ resolveWrapper(requestPromise);
603
+ }
604
+ }
605
+ /**
606
+ * Internal method that handles the core request logic.
607
+ * @param {string} requestId - Unique identifier for the request
608
+ * @param {Promise|import('./index.d.ts').RequestFunction|string} requestPromise - The request promise, function, or URL string
609
+ * @param {import('./index.d.ts').BaseRequestOptions} options - Configuration options
610
+ * @returns {Promise} A Promise that resolves/rejects based on the most recent request
611
+ * @private
612
+ */
613
+ function _request(requestId, requestPromise) {
614
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
615
+ var abortController = _assertClassBrand(_RequestManager_brand, this, _resolveAbortController).call(this, options.abortController);
616
+
617
+ // Handle different types of requestPromise inputs
618
+ // Priority: Function (Custom logic) > String (URL) > Promise (axios, fetch, etc.)
619
+ if (typeof requestPromise === 'function') {
620
+ // Function: custom logic for any library (axios, ajax, etc.)
621
+ try {
622
+ requestPromise = requestPromise({
623
+ options: _assertClassBrand(_RequestManager_brand, this, _prepareRequestOptions).call(this, options, abortController.signal)
624
+ });
625
+ } catch (error) {
626
+ return Promise.reject(error);
627
+ }
628
+ } else if (typeof requestPromise === 'string') {
629
+ // String (URL): make fetch internally
630
+ try {
631
+ requestPromise = fetch(requestPromise, _assertClassBrand(_RequestManager_brand, this, _prepareRequestOptions).call(this, options, abortController.signal));
632
+ } catch (error) {
633
+ return Promise.reject(error);
634
+ }
635
+ }
525
636
 
526
- // Link the request object's abort method (Ext.Ajax, XHR, etc.) to the cancellation signal
527
- this.addAbortListener(this.#_resolveAbortMethod(requestPromise), abortController.signal);
637
+ // Link the request object's abort method (Ext.Ajax, XHR, etc.) to the cancellation signal
638
+ this.addAbortListener(_assertClassBrand(_RequestManager_brand, this, _resolveAbortMethod).call(this, requestPromise), abortController.signal);
528
639
 
529
- // Cancel previous request with the same identifier if it exists
530
- if (!options.noCancel) this.cancel(requestId);
640
+ // Cancel previous request with the same identifier if it exists
641
+ if (!options.noCancel) this.cancel(requestId);
531
642
 
532
- // Create a wrapper promise that will be resolved/rejected based on the request
533
- let resolveWrapper, rejectWrapper;
534
- const wrapperPromise = new Promise((resolve, reject) => {
535
- resolveWrapper = resolve;
536
- rejectWrapper = reject;
537
- });
643
+ // Create a wrapper promise that will be resolved/rejected based on the request
644
+ var resolveWrapper, rejectWrapper;
645
+ var wrapperPromise = new Promise((resolve, reject) => {
646
+ resolveWrapper = resolve;
647
+ rejectWrapper = reject;
648
+ });
538
649
 
539
- /**
540
- * @type {import('./index.d.ts').ActiveRequest}
541
- */
542
- const requestInfo = {
543
- promise: requestPromise,
544
- abortController: abortController,
545
- cancelToken: options.cancelToken || null,
546
- resolveWrapper: resolveWrapper,
547
- rejectWrapper: rejectWrapper,
548
- isCancelled: false,
549
- };
550
-
551
- this.activeRequests.set(requestId, requestInfo);
552
-
553
- // Handle request promise completion
554
- if (requestPromise && typeof requestPromise.then === 'function') {
555
- try {
556
- let req = requestPromise.then((result) => {
557
- if (this.activeRequests.get(requestId) !== requestInfo) return;
558
- this.#_completeRequest(requestId, resolveWrapper, result, requestInfo.isCancelled);
559
- });
560
- if (req.catch)
561
- req.catch((error) => {
562
- onError(this, error);
563
- });
564
- } catch (error) {
565
- onError(this, error);
566
- }
567
- function onError(scope, error) {
568
- // Check if this requestInfo is still the active one, or if it was cancelled
569
- if (scope.activeRequests.get(requestId) !== requestInfo) return;
570
- if (requestInfo.isCancelled) {
571
- // Already cancelled: let cancel() handle cleanup and reject the wrapper promise
572
- scope.cancel(requestId);
573
- return;
574
- }
575
- // Only delete if this is still the active request
576
- scope.#_deleteRequest(requestId, rejectWrapper, error);
577
- }
578
- } else {
579
- // Non-promise (Ext.Ajax request object, raw XHR, etc.). Keep tracked until the
580
- // underlying XHR finishes so a later duplicate can still cancel it.
581
- const xhr =
582
- requestPromise &&
583
- (requestPromise.xhr ||
584
- (typeof XMLHttpRequest !== 'undefined' && requestPromise instanceof XMLHttpRequest
585
- ? requestPromise
586
- : null));
587
- const finish = () => {
588
- if (this.activeRequests.get(requestId) !== requestInfo) return;
589
- this.#_completeRequest(requestId, resolveWrapper, requestPromise, requestInfo.isCancelled);
590
- };
591
- if (xhr && typeof xhr.addEventListener === 'function') {
592
- xhr.addEventListener('loadend', finish);
593
- } else {
594
- setTimeout(finish, 0);
595
- }
596
- }
597
- return wrapperPromise;
650
+ /**
651
+ * @type {import('./index.d.ts').ActiveRequest}
652
+ */
653
+ var requestInfo = {
654
+ promise: requestPromise,
655
+ abortController: abortController,
656
+ cancelToken: options.cancelToken || null,
657
+ resolveWrapper: resolveWrapper,
658
+ rejectWrapper: rejectWrapper,
659
+ isCancelled: false
660
+ };
661
+ this.activeRequests.set(requestId, requestInfo);
662
+
663
+ // Handle request promise completion
664
+ if (requestPromise && typeof requestPromise.then === 'function') {
665
+ try {
666
+ var req = requestPromise.then(result => {
667
+ if (this.activeRequests.get(requestId) !== requestInfo) return;
668
+ _assertClassBrand(_RequestManager_brand, this, _completeRequest).call(this, requestId, resolveWrapper, result, requestInfo.isCancelled);
669
+ });
670
+ if (req.catch) req.catch(error => {
671
+ onError(this, error);
672
+ });
673
+ } catch (error) {
674
+ onError(this, error);
675
+ }
676
+ function onError(scope, error) {
677
+ // Check if this requestInfo is still the active one, or if it was cancelled
678
+ if (scope.activeRequests.get(requestId) !== requestInfo) return;
679
+ if (requestInfo.isCancelled) {
680
+ // Already cancelled: let cancel() handle cleanup and reject the wrapper promise
681
+ scope.cancel(requestId);
682
+ return;
598
683
  }
684
+ // Only delete if this is still the active request
685
+ _assertClassBrand(_RequestManager_brand, scope, _deleteRequest).call(scope, requestId, rejectWrapper, error);
686
+ }
687
+ } else {
688
+ // Non-promise (Ext.Ajax request object, raw XHR, etc.). Keep tracked until the
689
+ // underlying XHR finishes so a later duplicate can still cancel it.
690
+ var xhr = requestPromise && (requestPromise.xhr || (typeof XMLHttpRequest !== 'undefined' && requestPromise instanceof XMLHttpRequest ? requestPromise : null));
691
+ var finish = () => {
692
+ if (this.activeRequests.get(requestId) !== requestInfo) return;
693
+ _assertClassBrand(_RequestManager_brand, this, _completeRequest).call(this, requestId, resolveWrapper, requestPromise, requestInfo.isCancelled);
694
+ };
695
+ if (xhr && typeof xhr.addEventListener === 'function') {
696
+ xhr.addEventListener('loadend', finish);
697
+ } else {
698
+ setTimeout(finish, 0);
699
+ }
599
700
  }
701
+ return wrapperPromise;
702
+ }
600
703
 
601
- return RequestManager;
704
+ return RequestManager;
602
705
 
603
706
  }));
604
707
  //# sourceMappingURL=request-manager.umd.js.map