create-request 0.0.1-beta.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1522 +0,0 @@
1
- (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.createRequest = {}));
5
- })(this, (function (exports) { 'use strict';
6
-
7
- /**
8
- * Enum for HTTP methods
9
- */
10
- exports.HttpMethod = void 0;
11
- (function (HttpMethod) {
12
- HttpMethod["GET"] = "GET";
13
- HttpMethod["PUT"] = "PUT";
14
- HttpMethod["POST"] = "POST";
15
- HttpMethod["HEAD"] = "HEAD";
16
- HttpMethod["PATCH"] = "PATCH";
17
- HttpMethod["DELETE"] = "DELETE";
18
- HttpMethod["OPTIONS"] = "OPTIONS";
19
- })(exports.HttpMethod || (exports.HttpMethod = {}));
20
- /**
21
- * Enum for request priorities
22
- */
23
- exports.RequestPriority = void 0;
24
- (function (RequestPriority) {
25
- RequestPriority["LOW"] = "low";
26
- RequestPriority["HIGH"] = "high";
27
- RequestPriority["AUTO"] = "auto";
28
- })(exports.RequestPriority || (exports.RequestPriority = {}));
29
- /**
30
- * Enum for credentials policies
31
- */
32
- exports.CredentialsPolicy = void 0;
33
- (function (CredentialsPolicy) {
34
- CredentialsPolicy["OMIT"] = "omit";
35
- CredentialsPolicy["INCLUDE"] = "include";
36
- CredentialsPolicy["SAME_ORIGIN"] = "same-origin";
37
- })(exports.CredentialsPolicy || (exports.CredentialsPolicy = {}));
38
- /**
39
- * Enum for request modes
40
- */
41
- exports.RequestMode = void 0;
42
- (function (RequestMode) {
43
- RequestMode["CORS"] = "cors";
44
- RequestMode["NO_CORS"] = "no-cors";
45
- RequestMode["SAME_ORIGIN"] = "same-origin";
46
- RequestMode["NAVIGATE"] = "navigate";
47
- })(exports.RequestMode || (exports.RequestMode = {}));
48
- /**
49
- * Enum for redirect modes
50
- */
51
- exports.RedirectMode = void 0;
52
- (function (RedirectMode) {
53
- RedirectMode["ERROR"] = "error";
54
- RedirectMode["FOLLOW"] = "follow";
55
- RedirectMode["MANUAL"] = "manual";
56
- })(exports.RedirectMode || (exports.RedirectMode = {}));
57
- /**
58
- * Enum for cache modes
59
- */
60
- exports.CacheMode = void 0;
61
- (function (CacheMode) {
62
- CacheMode["DEFAULT"] = "default";
63
- CacheMode["RELOAD"] = "reload";
64
- CacheMode["NO_STORE"] = "no-store";
65
- CacheMode["NO_CACHE"] = "no-cache";
66
- CacheMode["FORCE_CACHE"] = "force-cache";
67
- CacheMode["ONLY_IF_CACHED"] = "only-if-cached";
68
- })(exports.CacheMode || (exports.CacheMode = {}));
69
- /**
70
- * Enum for cookie SameSite policies
71
- */
72
- exports.SameSitePolicy = void 0;
73
- (function (SameSitePolicy) {
74
- SameSitePolicy["LAX"] = "Lax";
75
- SameSitePolicy["NONE"] = "None";
76
- SameSitePolicy["STRICT"] = "Strict";
77
- })(exports.SameSitePolicy || (exports.SameSitePolicy = {}));
78
- /**
79
- * Enum for body types
80
- */
81
- var BodyType;
82
- (function (BodyType) {
83
- BodyType["JSON"] = "json";
84
- BodyType["STRING"] = "string";
85
- BodyType["BINARY"] = "binary";
86
- })(BodyType || (BodyType = {}));
87
- /**
88
- * Referrer policies for fetch requests
89
- */
90
- var ReferrerPolicy;
91
- (function (ReferrerPolicy) {
92
- ReferrerPolicy["ORIGIN"] = "origin";
93
- ReferrerPolicy["UNSAFE_URL"] = "unsafe-url";
94
- ReferrerPolicy["SAME_ORIGIN"] = "same-origin";
95
- ReferrerPolicy["NO_REFERRER"] = "no-referrer";
96
- ReferrerPolicy["STRICT_ORIGIN"] = "strict-origin";
97
- ReferrerPolicy["ORIGIN_WHEN_CROSS_ORIGIN"] = "origin-when-cross-origin";
98
- ReferrerPolicy["NO_REFERRER_WHEN_DOWNGRADE"] = "no-referrer-when-downgrade";
99
- ReferrerPolicy["STRICT_ORIGIN_WHEN_CROSS_ORIGIN"] = "strict-origin-when-cross-origin";
100
- })(ReferrerPolicy || (ReferrerPolicy = {}));
101
-
102
- class RequestError extends Error {
103
- constructor(message, url, method, options = {}) {
104
- super(message);
105
- this.name = "RequestError";
106
- this.url = url;
107
- this.method = method;
108
- this.status = options.status;
109
- this.response = options.response;
110
- this.timeoutError = options.timeoutError;
111
- // For better stack traces in modern environments
112
- if (Error.captureStackTrace) {
113
- Error.captureStackTrace(this, RequestError);
114
- }
115
- // Maintains proper prototype chain for instanceof checks
116
- Object.setPrototypeOf(this, RequestError.prototype);
117
- }
118
- /**
119
- * Static methods for creating specific types of RequestError
120
- */
121
- static timeout(url, method, timeoutMs) {
122
- return new RequestError(`Request timed out after ${timeoutMs}ms`, url, method, {
123
- timeoutError: true,
124
- });
125
- }
126
- static fromResponse(response, url, method) {
127
- return new RequestError(`Request failed with status ${response.status}`, url, method, {
128
- status: response.status,
129
- response,
130
- });
131
- }
132
- static networkError(url, method, originalError) {
133
- const error = new RequestError(`Network error: ${originalError.message}`, url, method);
134
- error.stack = originalError.stack;
135
- return error;
136
- }
137
- }
138
-
139
- /**
140
- * Wrapper for HTTP responses with methods to transform the response data
141
- */
142
- class ResponseWrapper {
143
- constructor(response) {
144
- this.bodyUsed = false;
145
- this.response = response;
146
- }
147
- // Wrapper properties
148
- get status() {
149
- return this.response.status;
150
- }
151
- get statusText() {
152
- return this.response.statusText;
153
- }
154
- get headers() {
155
- return this.response.headers;
156
- }
157
- get ok() {
158
- return this.response.ok;
159
- }
160
- get raw() {
161
- return this.response;
162
- }
163
- // Response body methods with caching
164
- async getJson() {
165
- if (this.jsonCache !== undefined) {
166
- return this.jsonCache;
167
- }
168
- if (this.bodyUsed) {
169
- // If we already have text, try to parse it as JSON
170
- if (this.textCache !== undefined) {
171
- try {
172
- // Fix unsafe assignment by explicitly casting to unknown first
173
- this.jsonCache = JSON.parse(this.textCache);
174
- return this.jsonCache;
175
- }
176
- catch (e) {
177
- throw new Error("Cannot parse cached text as JSON");
178
- }
179
- }
180
- throw new Error("Response body has already been consumed in a different format");
181
- }
182
- this.bodyUsed = true;
183
- this.jsonCache = (await this.response.json());
184
- return this.jsonCache;
185
- }
186
- async getText() {
187
- if (this.textCache !== undefined) {
188
- return this.textCache;
189
- }
190
- if (this.bodyUsed) {
191
- // If we already have JSON, convert it to text
192
- if (this.jsonCache !== undefined) {
193
- this.textCache = JSON.stringify(this.jsonCache);
194
- return this.textCache;
195
- }
196
- // If we have blob, convert to text
197
- if (this.blobCache !== undefined) {
198
- this.textCache = await this.blobCache.text();
199
- return this.textCache;
200
- }
201
- throw new Error("Response body has already been consumed in a format that cannot be converted to text");
202
- }
203
- this.bodyUsed = true;
204
- this.textCache = await this.response.text();
205
- return this.textCache;
206
- }
207
- async getBlob() {
208
- if (this.blobCache !== undefined) {
209
- return this.blobCache;
210
- }
211
- if (this.bodyUsed) {
212
- // If we have text, convert to Blob
213
- if (this.textCache !== undefined) {
214
- this.blobCache = new Blob([this.textCache], { type: "text/plain" });
215
- return this.blobCache;
216
- }
217
- throw new Error("Response body has already been consumed in a format that cannot be converted to Blob");
218
- }
219
- this.bodyUsed = true;
220
- this.blobCache = await this.response.blob();
221
- return this.blobCache;
222
- }
223
- async getArrayBuffer() {
224
- if (this.arrayBufferCache !== undefined) {
225
- return this.arrayBufferCache;
226
- }
227
- if (this.bodyUsed) {
228
- // If we have text, convert to ArrayBuffer
229
- if (this.textCache !== undefined) {
230
- const encoder = new TextEncoder();
231
- // Fix ArrayBufferLike by explicitly casting to ArrayBuffer
232
- const uint8Array = encoder.encode(this.textCache);
233
- this.arrayBufferCache = uint8Array.buffer;
234
- return this.arrayBufferCache;
235
- }
236
- // If we have blob, convert to ArrayBuffer
237
- if (this.blobCache !== undefined) {
238
- this.arrayBufferCache = await this.blobCache.arrayBuffer();
239
- return this.arrayBufferCache;
240
- }
241
- throw new Error("Response body has already been consumed in a format that cannot be converted to ArrayBuffer");
242
- }
243
- this.bodyUsed = true;
244
- this.arrayBufferCache = await this.response.arrayBuffer();
245
- return this.arrayBufferCache;
246
- }
247
- getBody() {
248
- if (this.bodyUsed) {
249
- throw new Error("Response body has already been consumed");
250
- }
251
- this.bodyUsed = true;
252
- return this.response.body;
253
- }
254
- }
255
-
256
- /**
257
- * Parse size strings like "10MB" into bytes
258
- * @param size Size as number or string with units
259
- */
260
- function parseSize(size) {
261
- var _a;
262
- if (typeof size === "number")
263
- return size;
264
- const match = size.match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB)?$/i);
265
- if (!match)
266
- return 0;
267
- const num = parseFloat(match[1]);
268
- const unit = (_a = match[2]) === null || _a === void 0 ? void 0 : _a.toUpperCase();
269
- switch (unit) {
270
- case "KB":
271
- return num * 1024;
272
- case "MB":
273
- return num * 1024 * 1024;
274
- case "GB":
275
- return num * 1024 * 1024 * 1024;
276
- default:
277
- return num;
278
- }
279
- }
280
- /**
281
- * Create a memory storage provider using Map
282
- */
283
- function createMemoryStorage() {
284
- const store = new Map();
285
- return {
286
- get(key) {
287
- return store.get(key) || null;
288
- },
289
- set(key, value) {
290
- store.set(key, value);
291
- },
292
- has(key) {
293
- return store.has(key);
294
- },
295
- delete(key) {
296
- store.delete(key);
297
- },
298
- clear() {
299
- store.clear();
300
- },
301
- };
302
- }
303
- /**
304
- * Create a localStorage-based storage provider
305
- */
306
- function createLocalStorageStorage() {
307
- return {
308
- get(key) {
309
- if (typeof localStorage === "undefined")
310
- return null;
311
- return localStorage.getItem(key);
312
- },
313
- set(key, value) {
314
- if (typeof localStorage === "undefined")
315
- return;
316
- try {
317
- localStorage.setItem(key, value);
318
- }
319
- catch (e) {
320
- // Handle quota exceeded errors
321
- console.warn("Cache storage quota exceeded, clearing cache");
322
- void this.clear();
323
- try {
324
- localStorage.setItem(key, value);
325
- }
326
- catch (e) {
327
- console.error("Failed to set cache item even after clearing cache");
328
- }
329
- }
330
- },
331
- has(key) {
332
- if (typeof localStorage === "undefined")
333
- return false;
334
- return localStorage.getItem(key) !== null;
335
- },
336
- delete(key) {
337
- if (typeof localStorage === "undefined")
338
- return;
339
- localStorage.removeItem(key);
340
- },
341
- clear() {
342
- if (typeof localStorage === "undefined")
343
- return;
344
- localStorage.clear();
345
- },
346
- };
347
- }
348
- /**
349
- * Create a sessionStorage-based storage provider
350
- */
351
- function createSessionStorageStorage() {
352
- return {
353
- get(key) {
354
- if (typeof sessionStorage === "undefined")
355
- return null;
356
- return sessionStorage.getItem(key);
357
- },
358
- set(key, value) {
359
- if (typeof sessionStorage === "undefined")
360
- return;
361
- try {
362
- sessionStorage.setItem(key, value);
363
- }
364
- catch (e) {
365
- // Handle quota exceeded errors
366
- console.warn("Cache storage quota exceeded, clearing cache");
367
- void this.clear();
368
- try {
369
- sessionStorage.setItem(key, value);
370
- }
371
- catch (e) {
372
- console.error("Failed to set cache item even after clearing cache");
373
- }
374
- }
375
- },
376
- has(key) {
377
- if (typeof sessionStorage === "undefined")
378
- return false;
379
- return sessionStorage.getItem(key) !== null;
380
- },
381
- delete(key) {
382
- if (typeof sessionStorage === "undefined")
383
- return;
384
- sessionStorage.removeItem(key);
385
- },
386
- clear() {
387
- if (typeof sessionStorage === "undefined")
388
- return;
389
- sessionStorage.clear();
390
- },
391
- };
392
- }
393
- /**
394
- * Create a storage provider from a cache options object
395
- */
396
- function createStorageProvider(options) {
397
- const { storage } = options || {};
398
- if (!storage) {
399
- // Default to memory storage
400
- return createMemoryStorage();
401
- }
402
- // Check if storage is already a StorageProvider
403
- if (typeof storage.get === "function" && typeof storage.set === "function") {
404
- return storage;
405
- }
406
- // Check if it's localStorage or sessionStorage
407
- if (storage === localStorage) {
408
- return createLocalStorageStorage();
409
- }
410
- if (storage === sessionStorage) {
411
- return createSessionStorageStorage();
412
- }
413
- // Check if it's a Map
414
- if (storage instanceof Map) {
415
- return {
416
- get(key) {
417
- return storage.get(key) || null;
418
- },
419
- set(key, value, _ttl) {
420
- storage.set(key, value);
421
- },
422
- has(key) {
423
- return storage.has(key);
424
- },
425
- delete(key) {
426
- storage.delete(key);
427
- },
428
- clear() {
429
- storage.clear();
430
- },
431
- };
432
- }
433
- // Default to memory storage
434
- console.warn("Unsupported storage type, falling back to memory storage");
435
- return createMemoryStorage();
436
- }
437
-
438
- /**
439
- * Cache manager that handles storage operations
440
- */
441
- class CacheManager {
442
- constructor(options = {}) {
443
- this.entryCount = 0;
444
- this.totalSize = 0;
445
- this.options = options;
446
- this.storage = createStorageProvider(options);
447
- }
448
- /**
449
- * Generate a cache key based on request details
450
- */
451
- generateKey(url, method, headers, body) {
452
- // Use custom key generator if provided
453
- if (this.options.keyGenerator) {
454
- const customKey = this.options.keyGenerator(url, method, headers, body);
455
- return this.options.keyPrefix ? `${this.options.keyPrefix}:${customKey}` : customKey;
456
- }
457
- // Default key generation
458
- let key = `${method}:${url}`;
459
- // Add vary headers to key if specified
460
- if (this.options.varyByHeaders && headers) {
461
- const varyHeaders = {};
462
- this.options.varyByHeaders.forEach(header => {
463
- const normalizedHeader = header.toLowerCase();
464
- // Find the header in case-insensitive way
465
- Object.keys(headers).forEach(h => {
466
- if (h.toLowerCase() === normalizedHeader) {
467
- varyHeaders[normalizedHeader] = headers[h];
468
- }
469
- });
470
- });
471
- if (Object.keys(varyHeaders).length > 0) {
472
- key += `:${JSON.stringify(varyHeaders)}`;
473
- }
474
- }
475
- // Include body in cache key for non-GET requests if it's a simple value
476
- if (method !== "GET" && body !== undefined && body !== null) {
477
- try {
478
- if (typeof body === "string" || typeof body === "number" || typeof body === "boolean") {
479
- key += `:${String(body)}`;
480
- }
481
- else if (typeof body === "object") {
482
- key += `:${JSON.stringify(body)}`;
483
- }
484
- }
485
- catch (e) {
486
- console.warn("Failed to stringify request body for cache key");
487
- }
488
- }
489
- // Add prefix if specified
490
- return this.options.keyPrefix ? `${this.options.keyPrefix}:${key}` : key;
491
- }
492
- /**
493
- * Get a value from cache
494
- */
495
- async get(key) {
496
- const value = await Promise.resolve(this.storage.get(key));
497
- if (!value)
498
- return null;
499
- try {
500
- const entry = JSON.parse(value);
501
- // Check if the entry has expired
502
- if (entry.expiry && entry.expiry < Date.now()) {
503
- await Promise.resolve(this.storage.delete(key));
504
- return null;
505
- }
506
- return entry;
507
- }
508
- catch (e) {
509
- // If we can't parse the cached value, remove it
510
- await Promise.resolve(this.storage.delete(key));
511
- return null;
512
- }
513
- }
514
- /**
515
- * Set a value in cache
516
- */
517
- async set(key, value, headers) {
518
- const now = Date.now();
519
- const ttl = this.options.ttl;
520
- const entry = {
521
- value,
522
- timestamp: now,
523
- expiry: ttl ? now + ttl : null,
524
- headers,
525
- };
526
- const serialized = JSON.stringify(entry);
527
- // Check size constraints if applicable
528
- if (this.options.maxSize) {
529
- const maxBytes = parseSize(this.options.maxSize);
530
- const entrySize = new TextEncoder().encode(serialized).length;
531
- // If a single entry exceeds the max size, reject it without clearing the cache
532
- if (entrySize > maxBytes) {
533
- console.warn(`Cache entry size (${entrySize} bytes) exceeds maximum cache size (${maxBytes} bytes)`);
534
- return;
535
- }
536
- // Only clear if adding this entry would exceed the total limit
537
- if (this.totalSize + entrySize > maxBytes) {
538
- // Simple strategy: clear everything
539
- // A more sophisticated strategy would remove oldest entries first
540
- await Promise.resolve(this.storage.clear());
541
- this.totalSize = 0;
542
- this.entryCount = 0;
543
- }
544
- this.totalSize += entrySize;
545
- }
546
- // Check max entries constraint
547
- if (this.options.maxEntries) {
548
- this.entryCount++;
549
- if (this.entryCount > this.options.maxEntries) {
550
- // Simple strategy: clear everything
551
- // A more sophisticated strategy would use LRU cache
552
- await Promise.resolve(this.storage.clear());
553
- this.entryCount = 1;
554
- }
555
- }
556
- // Pass ttl to storage provider if available
557
- await Promise.resolve(this.storage.set(key, serialized, ttl));
558
- }
559
- /**
560
- * Check if a key exists in the cache
561
- */
562
- async has(key) {
563
- return Promise.resolve(this.storage.has(key));
564
- }
565
- /**
566
- * Delete a key from the cache
567
- */
568
- async delete(key) {
569
- return Promise.resolve(this.storage.delete(key));
570
- }
571
- /**
572
- * Clear the entire cache
573
- */
574
- async clear() {
575
- this.entryCount = 0;
576
- this.totalSize = 0;
577
- return Promise.resolve(this.storage.clear());
578
- }
579
- }
580
-
581
- /**
582
- * Global configuration for create-request
583
- */
584
- class Config {
585
- constructor() {
586
- // CSRF configuration
587
- this.csrfHeaderName = "X-CSRF-Token";
588
- this.xsrfCookieName = "XSRF-TOKEN";
589
- this.xsrfHeaderName = "X-XSRF-TOKEN";
590
- this.csrfToken = null;
591
- this.enableAutoXsrf = true;
592
- this.enableAntiCsrf = true; // X-Requested-With header
593
- }
594
- /**
595
- * Get the singleton instance
596
- */
597
- static getInstance() {
598
- if (!Config.instance) {
599
- Config.instance = new Config();
600
- }
601
- return Config.instance;
602
- }
603
- /**
604
- * Set a global CSRF token to be used for all requests
605
- */
606
- setCsrfToken(token) {
607
- this.csrfToken = token;
608
- return this;
609
- }
610
- /**
611
- * Get the global CSRF token
612
- */
613
- getCsrfToken() {
614
- return this.csrfToken;
615
- }
616
- /**
617
- * Set the CSRF header name (default is X-CSRF-Token)
618
- */
619
- setCsrfHeaderName(name) {
620
- this.csrfHeaderName = name;
621
- return this;
622
- }
623
- /**
624
- * Get the CSRF header name
625
- */
626
- getCsrfHeaderName() {
627
- return this.csrfHeaderName;
628
- }
629
- /**
630
- * Set the XSRF cookie name to look for (default is XSRF-TOKEN)
631
- */
632
- setXsrfCookieName(name) {
633
- this.xsrfCookieName = name;
634
- return this;
635
- }
636
- /**
637
- * Get the XSRF cookie name
638
- */
639
- getXsrfCookieName() {
640
- return this.xsrfCookieName;
641
- }
642
- /**
643
- * Set the XSRF header name to send the token in (default is X-XSRF-TOKEN)
644
- */
645
- setXsrfHeaderName(name) {
646
- this.xsrfHeaderName = name;
647
- return this;
648
- }
649
- /**
650
- * Get the XSRF header name
651
- */
652
- getXsrfHeaderName() {
653
- return this.xsrfHeaderName;
654
- }
655
- /**
656
- * Enable or disable automatic XSRF token extraction from cookies
657
- */
658
- setEnableAutoXsrf(enable) {
659
- this.enableAutoXsrf = enable;
660
- return this;
661
- }
662
- /**
663
- * Check if automatic XSRF is enabled
664
- */
665
- isAutoXsrfEnabled() {
666
- return this.enableAutoXsrf;
667
- }
668
- /**
669
- * Enable or disable automatic addition of anti-CSRF headers
670
- */
671
- setEnableAntiCsrf(enable) {
672
- this.enableAntiCsrf = enable;
673
- return this;
674
- }
675
- /**
676
- * Check if anti-CSRF is enabled
677
- */
678
- isAntiCsrfEnabled() {
679
- return this.enableAntiCsrf;
680
- }
681
- /**
682
- * Reset all configuration options to their defaults
683
- */
684
- reset() {
685
- this.csrfToken = null;
686
- this.csrfHeaderName = "X-CSRF-Token";
687
- this.enableAntiCsrf = true;
688
- this.xsrfCookieName = "XSRF-TOKEN";
689
- this.xsrfHeaderName = "X-XSRF-TOKEN";
690
- this.enableAutoXsrf = true;
691
- return this;
692
- }
693
- }
694
-
695
- class CookieUtils {
696
- /**
697
- * Formats cookies for a request
698
- * @param cookies Object containing cookie name-value pairs or cookie options
699
- * @returns Formatted cookie string for the Cookie header
700
- */
701
- static formatRequestCookies(cookies) {
702
- const cookiePairs = [];
703
- Object.entries(cookies).forEach(([name, valueOrOptions]) => {
704
- let value;
705
- if (typeof valueOrOptions === "string") {
706
- value = valueOrOptions;
707
- }
708
- else {
709
- // Extract value from options object without validation
710
- value = valueOrOptions.value;
711
- }
712
- // Add the cookie to the request
713
- cookiePairs.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`);
714
- });
715
- return cookiePairs.join("; ");
716
- }
717
- }
718
-
719
- /**
720
- * Utility class for CSRF token management
721
- */
722
- class CsrfUtils {
723
- /**
724
- * Extracts CSRF token from a meta tag in the document head
725
- * @param metaName The name attribute of the meta tag (default: "csrf-token")
726
- * @returns The CSRF token or null if not found
727
- */
728
- static getTokenFromMeta(metaName = "csrf-token") {
729
- if (typeof document === "undefined") {
730
- return null;
731
- }
732
- const meta = document.querySelector(`meta[name="${metaName}"]`);
733
- return (meta === null || meta === void 0 ? void 0 : meta.getAttribute("content")) || null;
734
- }
735
- /**
736
- * Extracts CSRF token from a cookie
737
- * @param cookieName The name of the cookie containing the CSRF token
738
- * @returns The CSRF token or null if not found
739
- */
740
- static getTokenFromCookie(cookieName = "csrf-token") {
741
- if (typeof document === "undefined") {
742
- return null;
743
- }
744
- const cookies = document.cookie.split(";");
745
- for (const cookie of cookies) {
746
- const [name, value] = cookie.trim().split("=");
747
- if (name === cookieName) {
748
- return decodeURIComponent(value);
749
- }
750
- }
751
- return null;
752
- }
753
- /**
754
- * Validates if the provided string is a potential CSRF token
755
- * Checks if the token meets security requirements
756
- * @param token The token to validate
757
- * @returns Whether the token is valid
758
- */
759
- static isValidToken(token) {
760
- // Basic checks for null/undefined and type
761
- if (typeof token !== "string") {
762
- return false;
763
- }
764
- if (token.length < 8)
765
- return false;
766
- // If token is longer than 10 chars, perform additional security checks
767
- if (token.length > 10) {
768
- // Check for valid character set (alphanumeric & common token symbols)
769
- const validTokenRegex = /^[A-Za-z0-9\-_=+/.]+$/;
770
- if (!validTokenRegex.test(token)) {
771
- return false;
772
- }
773
- // For longer tokens, check for sufficient entropy (at least 2 character types)
774
- const hasUpperCase = /[A-Z]/.test(token);
775
- const hasLowerCase = /[a-z]/.test(token);
776
- const hasNumbers = /[0-9]/.test(token);
777
- const hasSpecials = /[-_=+/.]/.test(token);
778
- const characterTypesCount = [hasUpperCase, hasLowerCase, hasNumbers, hasSpecials].filter(Boolean).length;
779
- return characterTypesCount >= 2;
780
- }
781
- // For shorter tokens (8-10 chars), just return true if we reached here
782
- return true;
783
- }
784
- }
785
-
786
- // Base class with common functionality for all request types
787
- class BaseRequest {
788
- constructor() {
789
- this.requestOptions = {
790
- headers: {},
791
- };
792
- this.queryParams = new URLSearchParams();
793
- this.autoApplyCsrfProtection = true;
794
- this.cacheEnabled = false;
795
- }
796
- withHeaders(headers) {
797
- this.requestOptions.headers = {
798
- ...this.requestOptions.headers,
799
- ...headers,
800
- };
801
- return this;
802
- }
803
- withTimeout(timeout) {
804
- if (!Number.isFinite(timeout) || timeout <= 0)
805
- throw new Error("Timeout must be a positive number");
806
- this.requestOptions.timeout = timeout;
807
- return this;
808
- }
809
- withRetries(retries) {
810
- if (!Number.isInteger(retries) || retries < 0)
811
- throw new Error("Retry count must be a non-negative integer");
812
- this.requestOptions.retries = retries;
813
- return this;
814
- }
815
- onRetry(callback) {
816
- this.requestOptions.onRetry = callback;
817
- return this;
818
- }
819
- /**
820
- * Sets the credentials policy for the request
821
- * @param credentialsPolicy - Can be 'omit', 'same-origin', or 'include'
822
- * @returns The instance for chaining
823
- */
824
- withCredentials(credentialsPolicy = exports.CredentialsPolicy.SAME_ORIGIN) {
825
- this.requestOptions.credentials = credentialsPolicy;
826
- return this;
827
- }
828
- /**
829
- * Allows providing an external AbortController to cancel the request
830
- * @param controller - The AbortController to use for this request
831
- * @returns The instance for chaining
832
- */
833
- withAbortController(controller) {
834
- this.abortController = controller;
835
- return this;
836
- }
837
- /**
838
- * Sets the referrer for the request
839
- * @param referrer - The referrer URL or policy
840
- * @returns The instance for chaining
841
- */
842
- withReferrer(referrer) {
843
- this.requestOptions.referrer = referrer;
844
- return this;
845
- }
846
- /**
847
- * Sets the referrer policy for the request
848
- * @param policy - The referrer policy to use
849
- * @returns The instance for chaining
850
- */
851
- withReferrerPolicy(policy) {
852
- this.requestOptions.referrerPolicy = policy;
853
- return this;
854
- }
855
- /**
856
- * Sets the redirect policy for the request
857
- * @param redirect - Can be 'follow', 'error', or 'manual'
858
- * @returns The instance for chaining
859
- */
860
- withRedirect(redirect) {
861
- this.requestOptions.redirect = redirect;
862
- return this;
863
- }
864
- /**
865
- * Sets the keepalive flag for the request
866
- * @param keepalive - Whether to allow the request to outlive the page
867
- * @returns The instance for chaining
868
- */
869
- withKeepAlive(keepalive) {
870
- this.requestOptions.keepalive = keepalive;
871
- return this;
872
- }
873
- /**
874
- * Sets the priority of the request
875
- * @param priority - Can be 'high', 'low', or 'auto'
876
- * @returns The instance for chaining
877
- */
878
- withPriority(priority) {
879
- this.requestOptions.priority = priority;
880
- return this;
881
- }
882
- /**
883
- * Adds query parameters to the request URL
884
- * @param params - An object containing the query parameters
885
- * @returns The instance for chaining
886
- */
887
- withQueryParams(params) {
888
- Object.entries(params).forEach(([key, value]) => {
889
- if (value === null || value === undefined) {
890
- return;
891
- }
892
- if (Array.isArray(value)) {
893
- // Handle array values - add multiple entries with the same key
894
- value.forEach(v => this.queryParams.append(key, String(v)));
895
- }
896
- else {
897
- this.queryParams.append(key, String(value));
898
- }
899
- });
900
- return this;
901
- }
902
- /**
903
- * Adds a single query parameter
904
- * @param key - The parameter name
905
- * @param value - The parameter value, can be a single value or array of values
906
- * @returns The instance for chaining
907
- */
908
- withQueryParam(key, value) {
909
- if (value === null || value === undefined)
910
- return this;
911
- if (Array.isArray(value))
912
- value.forEach(v => this.queryParams.append(key, String(v)));
913
- else
914
- this.queryParams.append(key, String(value));
915
- return this;
916
- }
917
- /**
918
- * Sets the mode of the request
919
- * @param mode - The mode for the request (cors, no-cors, same-origin, navigate)
920
- * @returns The instance for chaining
921
- */
922
- withMode(mode) {
923
- this.requestOptions.mode = mode;
924
- return this;
925
- }
926
- /**
927
- * Shorthand for setting the Content-Type header
928
- * @param contentType - The content type
929
- * @returns The instance for chaining
930
- */
931
- withContentType(contentType) {
932
- return this.withHeaders({
933
- "Content-Type": contentType,
934
- });
935
- }
936
- /**
937
- * Shorthand for setting the Authorization header
938
- * @param authValue - The authorization value
939
- * @returns The instance for chaining
940
- */
941
- withAuthorization(authValue) {
942
- return this.withHeaders({
943
- Authorization: authValue,
944
- });
945
- }
946
- /**
947
- * Shorthand for setting up Basic authentication
948
- * @param username - The username
949
- * @param password - The password
950
- * @returns The instance for chaining
951
- */
952
- withBasicAuth(username, password) {
953
- const credentials = this.encodeBase64(`${username}:${password}`);
954
- return this.withAuthorization(`Basic ${credentials}`);
955
- }
956
- /**
957
- * Cross-environment base64 encoding
958
- * Works in both browser and Node.js environments
959
- */
960
- encodeBase64(str) {
961
- // Modern approach using TextEncoder (available in both modern browsers and Node.js)
962
- if (typeof TextEncoder !== "undefined" && typeof btoa === "function") {
963
- const encoder = new TextEncoder();
964
- const bytes = encoder.encode(str);
965
- return btoa(String.fromCharCode.apply(null, [...new Uint8Array(bytes)]));
966
- }
967
- // Browser environment
968
- if (typeof btoa === "function")
969
- return btoa(str);
970
- // Node.js environment
971
- if (typeof Buffer !== "undefined")
972
- return Buffer.from(str).toString("base64");
973
- // Fallback (should never happen in modern environments)
974
- throw new Error("Base64 encoding is not supported in this environment");
975
- }
976
- /**
977
- * Sets the bearer token for authentication
978
- * @param token - The bearer token
979
- * @returns The instance for chaining
980
- */
981
- withBearerToken(token) {
982
- return this.withAuthorization(`Bearer ${token}`);
983
- }
984
- /**
985
- * Helper function to check for header presence in a case-insensitive way
986
- * @param headers Headers object
987
- * @param headerName Header name to check
988
- * @returns Boolean indicating if the header exists (case-insensitive)
989
- */
990
- hasHeader(headers, headerName) {
991
- return Object.keys(headers).some(key => key.toLowerCase() === headerName.toLowerCase());
992
- }
993
- /**
994
- * Sets cookies for the request
995
- * @param cookies Object containing cookie name-value pairs or cookie options
996
- * @returns The instance for chaining
997
- */
998
- withCookies(cookies) {
999
- const cookieEntries = Object.entries(cookies);
1000
- if (cookieEntries.length === 0) {
1001
- return this;
1002
- }
1003
- // Get current headers or initialize empty object
1004
- const currentHeaders = this.requestOptions.headers || {};
1005
- // Get all existing cookie headers with different cases
1006
- const cookieValues = [];
1007
- const cookieHeaderKeys = [];
1008
- Object.keys(currentHeaders).forEach(key => {
1009
- if (key.toLowerCase() === "cookie") {
1010
- // Don't add empty cookie values
1011
- if (currentHeaders[key])
1012
- cookieValues.push(currentHeaders[key]);
1013
- cookieHeaderKeys.push(key);
1014
- }
1015
- });
1016
- // Format the new cookies
1017
- const cookieString = CookieUtils.formatRequestCookies(cookies);
1018
- // Choose which header name to use - preserve existing case if possible
1019
- const headerName = cookieHeaderKeys.length > 0 ? cookieHeaderKeys[0] : "Cookie";
1020
- // Combine all existing cookie values with the new ones
1021
- const combinedCookieValue = [...cookieValues, cookieString].filter(Boolean).join("; ");
1022
- // Create a new headers object without any cookie headers
1023
- const newHeaders = { ...currentHeaders };
1024
- cookieHeaderKeys.forEach(key => {
1025
- delete newHeaders[key];
1026
- });
1027
- // Set the new combined cookie header
1028
- this.requestOptions.headers = {
1029
- ...newHeaders,
1030
- [headerName]: combinedCookieValue,
1031
- };
1032
- return this;
1033
- }
1034
- /**
1035
- * Set a single cookie
1036
- * @param name Cookie name
1037
- * @param value Cookie value or options object
1038
- * @returns The instance for chaining
1039
- */
1040
- withCookie(name, value) {
1041
- return this.withCookies({ [name]: value });
1042
- }
1043
- /**
1044
- * Sets a CSRF token in the request headers
1045
- * @param token The CSRF token
1046
- * @param headerName The name of the header to use (default: X-CSRF-Token)
1047
- * @returns The instance for chaining
1048
- */
1049
- withCsrfToken(token, headerName = "X-CSRF-Token") {
1050
- return this.withHeaders({
1051
- [headerName]: token,
1052
- });
1053
- }
1054
- /**
1055
- * Disables automatic anti-CSRF protection.
1056
- * By default, X-Requested-With: XMLHttpRequest header is sent with all requests.
1057
- * @returns The instance for chaining
1058
- */
1059
- withoutCsrfProtection() {
1060
- this.autoApplyCsrfProtection = false;
1061
- return this;
1062
- }
1063
- /**
1064
- * Sets common security headers to help prevent CSRF attacks
1065
- * @returns The instance for chaining
1066
- */
1067
- withAntiCsrfHeaders() {
1068
- return this.withHeaders({
1069
- "X-Requested-With": "XMLHttpRequest",
1070
- });
1071
- }
1072
- /**
1073
- * Enables caching for the request with the specified options
1074
- * @param options The cache configuration options
1075
- * @returns The instance for chaining
1076
- */
1077
- withCache(options = {}) {
1078
- this.cacheEnabled = true;
1079
- this.cacheManager = new CacheManager(options);
1080
- return this;
1081
- }
1082
- /**
1083
- * Send the request to the specified URL
1084
- * @param url The URL to send the request to
1085
- */
1086
- sendTo(url) {
1087
- // Format the URL with query parameters
1088
- url = this.formatUrlWithQueryParams(url);
1089
- // Apply automatic CSRF protection if enabled
1090
- if (this.autoApplyCsrfProtection) {
1091
- const config = Config.getInstance();
1092
- // Apply anti-CSRF headers if enabled
1093
- if (config.isAntiCsrfEnabled()) {
1094
- this.withHeaders({
1095
- "X-Requested-With": "XMLHttpRequest",
1096
- });
1097
- }
1098
- // Apply global CSRF token if set
1099
- const globalToken = config.getCsrfToken();
1100
- if (globalToken) {
1101
- // Check if local token exists using case-insensitive comparison
1102
- const headers = this.requestOptions.headers;
1103
- const csrfHeaderName = config.getCsrfHeaderName();
1104
- const hasLocalToken = this.hasHeader(headers, "X-CSRF-Token") || this.hasHeader(headers, csrfHeaderName);
1105
- if (!hasLocalToken) {
1106
- this.withHeaders({
1107
- [csrfHeaderName]: globalToken,
1108
- });
1109
- }
1110
- }
1111
- // check for XSRF token in cookies and send it as a header
1112
- if (config.isAutoXsrfEnabled() && typeof document !== "undefined") {
1113
- const xsrfToken = CsrfUtils.getTokenFromCookie(config.getXsrfCookieName());
1114
- if (xsrfToken && CsrfUtils.isValidToken(xsrfToken)) {
1115
- const headers = this.requestOptions.headers;
1116
- const xsrfHeaderName = config.getXsrfHeaderName();
1117
- const hasLocalToken = this.hasHeader(headers, "X-XSRF-TOKEN") || this.hasHeader(headers, xsrfHeaderName);
1118
- if (!hasLocalToken) {
1119
- this.withHeaders({
1120
- [xsrfHeaderName]: xsrfToken,
1121
- });
1122
- }
1123
- }
1124
- }
1125
- }
1126
- // Cast the request options to RequestInit to ensure compatibility
1127
- const fetchOptions = {
1128
- ...this.requestOptions,
1129
- method: this.method,
1130
- };
1131
- // Create the base promise - handle caching if enabled
1132
- let basePromise;
1133
- if (this.cacheEnabled && this.cacheManager) {
1134
- const cacheKey = this.cacheManager.generateKey(url, this.method, this.requestOptions.headers, this.requestOptions.body);
1135
- basePromise = this.executeWithCache(url, fetchOptions, cacheKey);
1136
- }
1137
- else {
1138
- basePromise = !this.requestOptions.retries ? this.executeRequest(url, fetchOptions) : this.executeWithRetries(url, fetchOptions);
1139
- }
1140
- const responsePromise = basePromise;
1141
- // Attach convenience methods that begin processing immediately
1142
- responsePromise.getJson = async () => {
1143
- return basePromise.then(response => response.getJson());
1144
- };
1145
- responsePromise.getText = async () => {
1146
- return basePromise.then(response => response.getText());
1147
- };
1148
- responsePromise.getBlob = async () => {
1149
- return basePromise.then(response => response.getBlob());
1150
- };
1151
- responsePromise.getArrayBuffer = async () => {
1152
- return basePromise.then(response => response.getArrayBuffer());
1153
- };
1154
- responsePromise.getBody = async () => {
1155
- return basePromise.then(response => response.getBody());
1156
- };
1157
- responsePromise.getData = async (selector) => {
1158
- try {
1159
- const data = await basePromise.then(response => response.getJson());
1160
- // If no selector is provided, return the raw JSON data
1161
- if (!selector)
1162
- return data;
1163
- // Apply the selector if provided
1164
- return selector(data);
1165
- }
1166
- catch (error) {
1167
- if (error instanceof Error) {
1168
- // If selector fails, enhance the error with the original data
1169
- const enhancedError = new Error(`Data selector failed: ${error.message}. Original data: ${JSON.stringify(await basePromise.then(response => response.getJson()), null, 2)}`);
1170
- enhancedError.stack = error.stack;
1171
- throw enhancedError;
1172
- }
1173
- throw error;
1174
- }
1175
- };
1176
- return responsePromise;
1177
- }
1178
- /**
1179
- * Formats the URL with any query parameters
1180
- * @param url The base URL
1181
- * @returns The URL with query parameters appended
1182
- */
1183
- formatUrlWithQueryParams(url) {
1184
- if (!this.queryParams.toString()) {
1185
- return url;
1186
- }
1187
- try {
1188
- // Try to use the URL constructor (works for absolute URLs)
1189
- const urlObj = new URL(url);
1190
- // Merge our query params with any that might be in the URL already
1191
- this.queryParams.forEach((value, key) => {
1192
- urlObj.searchParams.append(key, value);
1193
- });
1194
- return urlObj.toString();
1195
- }
1196
- catch (error) {
1197
- // Handle relative URLs
1198
- const hasExistingParams = url.includes("?");
1199
- const separator = hasExistingParams ? "&" : "?";
1200
- return `${url}${separator}${this.queryParams.toString()}`;
1201
- }
1202
- }
1203
- /**
1204
- * Executes a request with configured retry logic
1205
- * @param url The formatted URL to send the request to
1206
- * @param fetchOptions The fetch options to use
1207
- * @returns A wrapped response object
1208
- */
1209
- async executeWithRetries(url, fetchOptions) {
1210
- let attempt = 0;
1211
- const maxRetries = this.requestOptions.retries || 0;
1212
- do {
1213
- try {
1214
- return await this.executeRequest(url, fetchOptions);
1215
- }
1216
- catch (error) {
1217
- const requestError = error instanceof RequestError ? error : RequestError.networkError(url, fetchOptions.method, error);
1218
- // Don't retry on timeout errors or if we've reached the max retries
1219
- if (attempt >= maxRetries || requestError.timeoutError)
1220
- throw requestError;
1221
- attempt++;
1222
- if (this.requestOptions.onRetry) {
1223
- await this.requestOptions.onRetry({ attempt, error: requestError });
1224
- }
1225
- }
1226
- } while (attempt <= maxRetries);
1227
- // If we somehow get here, we throw an error to avoid undefined behavior
1228
- throw new RequestError(`Max retries reached (${maxRetries}) but request still failed`, url, fetchOptions.method);
1229
- }
1230
- async executeRequest(url, fetchOptions) {
1231
- // Create a request controller for timeout if needed, or use the provided one
1232
- const controller = this.abortController || new AbortController();
1233
- const { signal } = controller;
1234
- // Use the controller signal for the fetch request, but don't overwrite an existing signal
1235
- fetchOptions.signal = fetchOptions.signal || signal;
1236
- let timeoutId;
1237
- // Flag to track if abort was caused by our timeout
1238
- let abortedByTimeout = false;
1239
- // Handle timeout regardless of whether an external controller is provided
1240
- if (this.requestOptions.timeout) {
1241
- if (this.abortController) {
1242
- // If we have an external controller, create a separate timeout controller
1243
- // that won't interfere with the external one
1244
- // Use AbortSignal.timeout if available (modern browsers)
1245
- if (typeof AbortSignal.timeout === "function") {
1246
- const timeoutSignal = AbortSignal.timeout(this.requestOptions.timeout);
1247
- // Add event listener to propagate the abort to the main controller
1248
- timeoutSignal.addEventListener("abort", () => {
1249
- if (!controller.signal.aborted) {
1250
- abortedByTimeout = true;
1251
- controller.abort();
1252
- }
1253
- });
1254
- }
1255
- else {
1256
- // Fallback for browsers without AbortSignal.timeout
1257
- timeoutId = setTimeout(() => {
1258
- if (!controller.signal.aborted) {
1259
- abortedByTimeout = true;
1260
- controller.abort();
1261
- }
1262
- }, this.requestOptions.timeout);
1263
- }
1264
- }
1265
- else {
1266
- timeoutId = setTimeout(() => {
1267
- abortedByTimeout = true;
1268
- controller.abort();
1269
- }, this.requestOptions.timeout);
1270
- }
1271
- }
1272
- try {
1273
- let response;
1274
- try {
1275
- response = await fetch(url, fetchOptions);
1276
- }
1277
- catch (error) {
1278
- // Check if this is an abort error that was specifically caused by our timeout
1279
- if (error instanceof DOMException && error.name === "AbortError" && abortedByTimeout) {
1280
- throw RequestError.timeout(url, fetchOptions.method, this.requestOptions.timeout);
1281
- }
1282
- // Otherwise it's either a user-triggered abort or another network error
1283
- throw RequestError.networkError(url, fetchOptions.method, error);
1284
- }
1285
- if (!response.ok) {
1286
- throw RequestError.fromResponse(response, url, fetchOptions.method);
1287
- }
1288
- // Return a wrapped response instead of parsing it
1289
- return new ResponseWrapper(response);
1290
- }
1291
- finally {
1292
- if (timeoutId) {
1293
- clearTimeout(timeoutId);
1294
- }
1295
- }
1296
- }
1297
- /**
1298
- * Executes a request using cache when possible
1299
- * @param url The formatted URL to send the request to
1300
- * @param fetchOptions The fetch options to use
1301
- * @param cacheKey The cache key for this request
1302
- */
1303
- async executeWithCache(url, fetchOptions, cacheKey) {
1304
- // Try to get from cache first
1305
- if (this.cacheManager) {
1306
- const cachedEntry = await this.cacheManager.get(cacheKey);
1307
- if (cachedEntry) {
1308
- // Create a synthetic Response object from cached data
1309
- const cachedResponse = new Response(JSON.stringify(cachedEntry.value), {
1310
- status: 200,
1311
- headers: new Headers(cachedEntry.headers || {}),
1312
- });
1313
- return new ResponseWrapper(cachedResponse);
1314
- }
1315
- }
1316
- // Not in cache, make the actual request
1317
- const response = await (!this.requestOptions.retries ? this.executeRequest(url, fetchOptions) : this.executeWithRetries(url, fetchOptions));
1318
- // Cache the successful response if caching is enabled
1319
- // Only cache successful responses
1320
- if (response.ok && this.cacheManager) {
1321
- // Clone the response so we don't consume it
1322
- try {
1323
- const responseData = await response.getJson();
1324
- // Extract headers to store in cache
1325
- const headers = {};
1326
- response.headers.forEach((value, key) => {
1327
- headers[key] = value;
1328
- });
1329
- // Store in cache
1330
- await this.cacheManager.set(cacheKey, responseData, headers);
1331
- }
1332
- catch (error) {
1333
- // Failed to cache, but we can still return the response
1334
- console.warn("Failed to cache response:", error);
1335
- }
1336
- }
1337
- return response;
1338
- }
1339
- }
1340
-
1341
- /**
1342
- * Base class for requests that can have a body (POST, PUT, PATCH)
1343
- */
1344
- class BodyRequest extends BaseRequest {
1345
- /**
1346
- * Sets the body of the request
1347
- * @param body - The request body
1348
- */
1349
- withBody(body) {
1350
- this.body = body;
1351
- // Set body type and validate
1352
- if (typeof body === "string") {
1353
- this.bodyType = BodyType.STRING;
1354
- this.setContentTypeIfNeeded("text/plain");
1355
- }
1356
- else if (body !== null &&
1357
- typeof body === "object" &&
1358
- !(body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer || body instanceof URLSearchParams || body instanceof ReadableStream)) {
1359
- this.bodyType = BodyType.JSON;
1360
- this.setContentTypeIfNeeded("application/json");
1361
- // Validate JSON is stringifiable early
1362
- try {
1363
- JSON.stringify(body);
1364
- }
1365
- catch (error) {
1366
- throw new Error(`Failed to stringify request body: ${String(error)}`);
1367
- }
1368
- }
1369
- else {
1370
- this.bodyType = BodyType.BINARY;
1371
- }
1372
- return this;
1373
- }
1374
- setContentTypeIfNeeded(contentType) {
1375
- // Only set if not already set
1376
- const headers = this.requestOptions.headers;
1377
- if (!Object.keys(headers).some(header => header.toLowerCase() === "content-type")) {
1378
- this.withContentType(contentType);
1379
- }
1380
- }
1381
- /**
1382
- * Send the request to the specified URL
1383
- * Overrides the base implementation to add body handling
1384
- */
1385
- sendTo(url) {
1386
- if (this.body !== undefined) {
1387
- // Remove previous body if it exists
1388
- if (this.requestOptions.body)
1389
- delete this.requestOptions.body;
1390
- // Process the body based on its type
1391
- if (this.bodyType === BodyType.JSON) {
1392
- this.requestOptions.body = JSON.stringify(this.body);
1393
- }
1394
- else {
1395
- this.requestOptions.body = this.body;
1396
- }
1397
- }
1398
- return super.sendTo(url);
1399
- }
1400
- }
1401
-
1402
- // Methods without body
1403
- class GetRequest extends BaseRequest {
1404
- constructor() {
1405
- super(...arguments);
1406
- this.method = exports.HttpMethod.GET;
1407
- }
1408
- }
1409
- class HeadRequest extends BaseRequest {
1410
- constructor() {
1411
- super(...arguments);
1412
- this.method = exports.HttpMethod.HEAD;
1413
- }
1414
- }
1415
- class OptionsRequest extends BaseRequest {
1416
- constructor() {
1417
- super(...arguments);
1418
- this.method = exports.HttpMethod.OPTIONS;
1419
- }
1420
- }
1421
- class DeleteRequest extends BaseRequest {
1422
- constructor() {
1423
- super(...arguments);
1424
- this.method = exports.HttpMethod.DELETE;
1425
- }
1426
- }
1427
- // Methods with body
1428
- class PostRequest extends BodyRequest {
1429
- constructor() {
1430
- super(...arguments);
1431
- this.method = exports.HttpMethod.POST;
1432
- }
1433
- }
1434
- class PutRequest extends BodyRequest {
1435
- constructor() {
1436
- super(...arguments);
1437
- this.method = exports.HttpMethod.PUT;
1438
- }
1439
- }
1440
- class PatchRequest extends BodyRequest {
1441
- constructor() {
1442
- super(...arguments);
1443
- this.method = exports.HttpMethod.PATCH;
1444
- }
1445
- }
1446
-
1447
- /**
1448
- * Create a GET request
1449
- */
1450
- function get() {
1451
- return new GetRequest();
1452
- }
1453
- /**
1454
- * Create a POST request
1455
- */
1456
- function post() {
1457
- return new PostRequest();
1458
- }
1459
- /**
1460
- * Create a PUT request
1461
- */
1462
- function put() {
1463
- return new PutRequest();
1464
- }
1465
- /**
1466
- * Create a DELETE request
1467
- * Note: We use 'del' to avoid JS keyword conflict
1468
- */
1469
- function del() {
1470
- return new DeleteRequest();
1471
- }
1472
- /**
1473
- * Create a PATCH request
1474
- */
1475
- function patch() {
1476
- return new PatchRequest();
1477
- }
1478
- /**
1479
- * Create a HEAD request
1480
- */
1481
- function head() {
1482
- return new HeadRequest();
1483
- }
1484
- /**
1485
- * Create an OPTIONS request
1486
- */
1487
- function options() {
1488
- return new OptionsRequest();
1489
- }
1490
-
1491
- // Create the main API object with configuration
1492
- const create = {
1493
- get,
1494
- post,
1495
- put,
1496
- del,
1497
- patch,
1498
- head,
1499
- options,
1500
- // Add configuration access
1501
- config: Config.getInstance(),
1502
- };
1503
-
1504
- exports.CacheManager = CacheManager;
1505
- exports.CookieUtils = CookieUtils;
1506
- exports.DeleteRequest = DeleteRequest;
1507
- exports.GetRequest = GetRequest;
1508
- exports.HeadRequest = HeadRequest;
1509
- exports.OptionsRequest = OptionsRequest;
1510
- exports.PatchRequest = PatchRequest;
1511
- exports.PostRequest = PostRequest;
1512
- exports.PutRequest = PutRequest;
1513
- exports.RequestError = RequestError;
1514
- exports.ResponseWrapper = ResponseWrapper;
1515
- exports.createLocalStorageStorage = createLocalStorageStorage;
1516
- exports.createMemoryStorage = createMemoryStorage;
1517
- exports.createSessionStorageStorage = createSessionStorageStorage;
1518
- exports["default"] = create;
1519
-
1520
- Object.defineProperty(exports, '__esModule', { value: true });
1521
-
1522
- }));