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