create-request 0.0.1-beta.6 → 0.0.1-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +354 -98
- package/dist/library/BaseRequest.d.ts +23 -0
- package/dist/library/ResponseWrapper.d.ts +1 -0
- package/dist/library/enums.d.ts +13 -0
- package/dist/library/index.d.ts +4 -0
- package/dist/library/index.esm.js +436 -3
- package/dist/library/index.js +439 -2
- package/dist/library/types/cache.d.ts +62 -0
- package/dist/library/utils/CacheManager.d.ts +35 -0
- package/dist/library/utils/CacheStorage.d.ts +57 -0
- package/dist/library/utils/StorageProvider.d.ts +33 -0
- package/package.json +1 -1
package/dist/library/index.js
CHANGED
|
@@ -84,6 +84,20 @@
|
|
|
84
84
|
BodyType["STRING"] = "string";
|
|
85
85
|
BodyType["BINARY"] = "binary";
|
|
86
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 = {}));
|
|
87
101
|
|
|
88
102
|
class RequestError extends Error {
|
|
89
103
|
constructor(message, url, method, options = {}) {
|
|
@@ -239,6 +253,331 @@
|
|
|
239
253
|
}
|
|
240
254
|
}
|
|
241
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
|
+
|
|
242
581
|
/**
|
|
243
582
|
* Global configuration for create-request
|
|
244
583
|
*/
|
|
@@ -452,6 +791,7 @@
|
|
|
452
791
|
};
|
|
453
792
|
this.queryParams = new URLSearchParams();
|
|
454
793
|
this.autoApplyCsrfProtection = true;
|
|
794
|
+
this.cacheEnabled = false;
|
|
455
795
|
}
|
|
456
796
|
withHeaders(headers) {
|
|
457
797
|
this.requestOptions.headers = {
|
|
@@ -503,6 +843,15 @@
|
|
|
503
843
|
this.requestOptions.referrer = referrer;
|
|
504
844
|
return this;
|
|
505
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
|
+
}
|
|
506
855
|
/**
|
|
507
856
|
* Sets the redirect policy for the request
|
|
508
857
|
* @param redirect - Can be 'follow', 'error', or 'manual'
|
|
@@ -609,6 +958,12 @@
|
|
|
609
958
|
* Works in both browser and Node.js environments
|
|
610
959
|
*/
|
|
611
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
|
+
}
|
|
612
967
|
// Browser environment
|
|
613
968
|
if (typeof btoa === "function")
|
|
614
969
|
return btoa(str);
|
|
@@ -714,6 +1069,16 @@
|
|
|
714
1069
|
"X-Requested-With": "XMLHttpRequest",
|
|
715
1070
|
});
|
|
716
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
|
+
}
|
|
717
1082
|
/**
|
|
718
1083
|
* Send the request to the specified URL
|
|
719
1084
|
* @param url The URL to send the request to
|
|
@@ -763,8 +1128,15 @@
|
|
|
763
1128
|
...this.requestOptions,
|
|
764
1129
|
method: this.method,
|
|
765
1130
|
};
|
|
766
|
-
// Create the base promise
|
|
767
|
-
|
|
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
|
+
}
|
|
768
1140
|
const responsePromise = basePromise;
|
|
769
1141
|
// Attach convenience methods that begin processing immediately
|
|
770
1142
|
responsePromise.getJson = async () => {
|
|
@@ -782,6 +1154,25 @@
|
|
|
782
1154
|
responsePromise.getBody = async () => {
|
|
783
1155
|
return basePromise.then(response => response.getBody());
|
|
784
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
|
+
};
|
|
785
1176
|
return responsePromise;
|
|
786
1177
|
}
|
|
787
1178
|
/**
|
|
@@ -903,6 +1294,48 @@
|
|
|
903
1294
|
}
|
|
904
1295
|
}
|
|
905
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
|
+
}
|
|
906
1339
|
}
|
|
907
1340
|
|
|
908
1341
|
/**
|
|
@@ -1068,6 +1501,7 @@
|
|
|
1068
1501
|
config: Config.getInstance(),
|
|
1069
1502
|
};
|
|
1070
1503
|
|
|
1504
|
+
exports.CacheManager = CacheManager;
|
|
1071
1505
|
exports.CookieUtils = CookieUtils;
|
|
1072
1506
|
exports.DeleteRequest = DeleteRequest;
|
|
1073
1507
|
exports.GetRequest = GetRequest;
|
|
@@ -1078,6 +1512,9 @@
|
|
|
1078
1512
|
exports.PutRequest = PutRequest;
|
|
1079
1513
|
exports.RequestError = RequestError;
|
|
1080
1514
|
exports.ResponseWrapper = ResponseWrapper;
|
|
1515
|
+
exports.createLocalStorageStorage = createLocalStorageStorage;
|
|
1516
|
+
exports.createMemoryStorage = createMemoryStorage;
|
|
1517
|
+
exports.createSessionStorageStorage = createSessionStorageStorage;
|
|
1081
1518
|
exports["default"] = create;
|
|
1082
1519
|
|
|
1083
1520
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { StorageProvider } from "../utils/StorageProvider";
|
|
2
|
+
/**
|
|
3
|
+
* Cache entry with metadata
|
|
4
|
+
*/
|
|
5
|
+
export interface CacheEntry {
|
|
6
|
+
value: any;
|
|
7
|
+
expiry: number | null;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Options for cache configuration
|
|
13
|
+
*/
|
|
14
|
+
export interface CacheOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Storage provider to use for caching
|
|
17
|
+
* Default is memory cache (new Map())
|
|
18
|
+
*/
|
|
19
|
+
storage?: StorageProvider | Storage | Map<string, any>;
|
|
20
|
+
/**
|
|
21
|
+
* Time to live in milliseconds
|
|
22
|
+
* Default is no expiration
|
|
23
|
+
*/
|
|
24
|
+
ttl?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Custom key generator function
|
|
27
|
+
* @param url Request URL
|
|
28
|
+
* @param method Request method
|
|
29
|
+
* @param headers Request headers
|
|
30
|
+
* @param body Request body
|
|
31
|
+
*/
|
|
32
|
+
keyGenerator?: (url: string, method: string, headers?: Record<string, string>, body?: any) => string;
|
|
33
|
+
/**
|
|
34
|
+
* Headers to vary the cache by
|
|
35
|
+
* If these headers change, a new cache entry will be created
|
|
36
|
+
*/
|
|
37
|
+
varyByHeaders?: string[];
|
|
38
|
+
/**
|
|
39
|
+
* Maximum number of entries in the cache
|
|
40
|
+
* Only applicable for memory cache (Map)
|
|
41
|
+
*/
|
|
42
|
+
maxEntries?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Maximum size of the cache in bytes or with units (e.g. "10MB")
|
|
45
|
+
* String format supports KB, MB, GB (case-insensitive)
|
|
46
|
+
*/
|
|
47
|
+
maxSize?: number | string;
|
|
48
|
+
/**
|
|
49
|
+
* Prefix for cache keys
|
|
50
|
+
* Useful for namespacing cache entries
|
|
51
|
+
*/
|
|
52
|
+
keyPrefix?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Type for cacheable response data
|
|
56
|
+
*/
|
|
57
|
+
export type CacheableResponse = {
|
|
58
|
+
data: any;
|
|
59
|
+
headers: Record<string, string>;
|
|
60
|
+
status: number;
|
|
61
|
+
statusText: string;
|
|
62
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CacheEntry, CacheOptions } from "../types/cache";
|
|
2
|
+
/**
|
|
3
|
+
* Cache manager that handles storage operations
|
|
4
|
+
*/
|
|
5
|
+
export declare class CacheManager {
|
|
6
|
+
private storage;
|
|
7
|
+
private options;
|
|
8
|
+
private entryCount;
|
|
9
|
+
private totalSize;
|
|
10
|
+
constructor(options?: CacheOptions);
|
|
11
|
+
/**
|
|
12
|
+
* Generate a cache key based on request details
|
|
13
|
+
*/
|
|
14
|
+
generateKey(url: string, method: string, headers?: Record<string, string>, body?: unknown): string;
|
|
15
|
+
/**
|
|
16
|
+
* Get a value from cache
|
|
17
|
+
*/
|
|
18
|
+
get(key: string): Promise<CacheEntry | null>;
|
|
19
|
+
/**
|
|
20
|
+
* Set a value in cache
|
|
21
|
+
*/
|
|
22
|
+
set(key: string, value: unknown, headers?: Record<string, string>): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a key exists in the cache
|
|
25
|
+
*/
|
|
26
|
+
has(key: string): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Delete a key from the cache
|
|
29
|
+
*/
|
|
30
|
+
delete(key: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Clear the entire cache
|
|
33
|
+
*/
|
|
34
|
+
clear(): Promise<void>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { CacheEntry, CacheOptions } from "../types/cache";
|
|
2
|
+
import type { StorageProvider } from "./StorageProvider";
|
|
3
|
+
/**
|
|
4
|
+
* Parse size strings like "10MB" into bytes
|
|
5
|
+
* @param size Size as number or string with units
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseSize(size: string | number): number;
|
|
8
|
+
/**
|
|
9
|
+
* Create a memory storage provider using Map
|
|
10
|
+
*/
|
|
11
|
+
export declare function createMemoryStorage(): StorageProvider;
|
|
12
|
+
/**
|
|
13
|
+
* Create a localStorage-based storage provider
|
|
14
|
+
*/
|
|
15
|
+
export declare function createLocalStorageStorage(): StorageProvider;
|
|
16
|
+
/**
|
|
17
|
+
* Create a sessionStorage-based storage provider
|
|
18
|
+
*/
|
|
19
|
+
export declare function createSessionStorageStorage(): StorageProvider;
|
|
20
|
+
/**
|
|
21
|
+
* Create a storage provider from a cache options object
|
|
22
|
+
*/
|
|
23
|
+
export declare function createStorageProvider(options?: CacheOptions): StorageProvider;
|
|
24
|
+
/**
|
|
25
|
+
* Cache manager that handles storage operations
|
|
26
|
+
*/
|
|
27
|
+
export declare class CacheManager {
|
|
28
|
+
private storage;
|
|
29
|
+
private options;
|
|
30
|
+
private entryCount;
|
|
31
|
+
private totalSize;
|
|
32
|
+
constructor(options?: CacheOptions);
|
|
33
|
+
/**
|
|
34
|
+
* Generate a cache key based on request details
|
|
35
|
+
*/
|
|
36
|
+
generateKey(url: string, method: string, headers?: Record<string, string>, body?: any): string;
|
|
37
|
+
/**
|
|
38
|
+
* Get a value from cache
|
|
39
|
+
*/
|
|
40
|
+
get(key: string): Promise<CacheEntry | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Set a value in cache
|
|
43
|
+
*/
|
|
44
|
+
set(key: string, value: unknown, headers?: Record<string, string>): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Check if a key exists in the cache
|
|
47
|
+
*/
|
|
48
|
+
has(key: string): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Delete a key from the cache
|
|
51
|
+
*/
|
|
52
|
+
delete(key: string): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Clear the entire cache
|
|
55
|
+
*/
|
|
56
|
+
clear(): Promise<void>;
|
|
57
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for storage providers used by the cache system
|
|
3
|
+
*/
|
|
4
|
+
export interface StorageProvider {
|
|
5
|
+
/**
|
|
6
|
+
* Get a value from storage
|
|
7
|
+
* @param key The key to retrieve
|
|
8
|
+
* @returns The stored value or null if not found
|
|
9
|
+
*/
|
|
10
|
+
get(key: string): Promise<string | null> | string | null;
|
|
11
|
+
/**
|
|
12
|
+
* Set a value in storage
|
|
13
|
+
* @param key The key to store
|
|
14
|
+
* @param value The value to store
|
|
15
|
+
* @param ttl Optional TTL in milliseconds
|
|
16
|
+
* @returns Promise or void
|
|
17
|
+
*/
|
|
18
|
+
set(key: string, value: string, ttl?: number): Promise<void> | void;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a key exists in storage
|
|
21
|
+
* @param key The key to check
|
|
22
|
+
*/
|
|
23
|
+
has(key: string): Promise<boolean> | boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Delete a value from storage
|
|
26
|
+
* @param key The key to delete
|
|
27
|
+
*/
|
|
28
|
+
delete(key: string): Promise<void> | void;
|
|
29
|
+
/**
|
|
30
|
+
* Clear all values from storage
|
|
31
|
+
*/
|
|
32
|
+
clear(): Promise<void> | void;
|
|
33
|
+
}
|