@feardread/feature-factory 5.0.8 → 5.1.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.
- package/dist/bundle.min.js +2 -2
- package/dist/index.esm.js +3 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/rollup.config.mjs +3 -63
- package/src/factory/api.js +99 -23
- package/src/factory/cache.js +70 -71
- package/src/factory/index.js +119 -73
- package/src/factory/thunk.js +3 -3
- package/src/factory/utils.js +355 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feardread/feature-factory",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Library to interact with redux toolkit and reduce boilerplate / repeated code",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@rollup/plugin-json": "^6.1.0",
|
|
33
33
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
|
34
34
|
"@rollup/plugin-terser": "^0.4.4",
|
|
35
|
-
"rollup": "^4.
|
|
35
|
+
"rollup": "^4.51.0",
|
|
36
36
|
"rollup-plugin-dts": "^6.1.1",
|
|
37
37
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
38
38
|
"rollup-plugin-polyfill-node": "^0.13.0"
|
package/rollup.config.mjs
CHANGED
|
@@ -2,30 +2,7 @@ import terser from '@rollup/plugin-terser';
|
|
|
2
2
|
import resolve from "@rollup/plugin-node-resolve";
|
|
3
3
|
import commonjs from "@rollup/plugin-commonjs";
|
|
4
4
|
import json from "@rollup/plugin-json";
|
|
5
|
-
import polyfill from "rollup-plugin-polyfill-node";
|
|
6
5
|
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
|
|
7
|
-
import typescript from '@rollup/plugin-typescript'
|
|
8
|
-
import pkg from "./package.json" assert { type: 'json' };
|
|
9
|
-
import dts from 'rollup-plugin-dts'
|
|
10
|
-
const config = [
|
|
11
|
-
{
|
|
12
|
-
input: 'src/index.js',
|
|
13
|
-
output: {
|
|
14
|
-
file: 'refactory.js',
|
|
15
|
-
format: 'cjs',
|
|
16
|
-
sourcemap: true,
|
|
17
|
-
},
|
|
18
|
-
external: ['axios', 'os', 'url'],
|
|
19
|
-
plugins: [typescript()]
|
|
20
|
-
}, {
|
|
21
|
-
input: 'src/index.d.ts',
|
|
22
|
-
output: {
|
|
23
|
-
file: 'refactory.d.ts',
|
|
24
|
-
format: 'es'
|
|
25
|
-
},
|
|
26
|
-
plugins: [dts()]
|
|
27
|
-
}
|
|
28
|
-
];
|
|
29
6
|
|
|
30
7
|
const jsconfig = [{
|
|
31
8
|
input: 'src/index.js',
|
|
@@ -47,7 +24,7 @@ const jsconfig = [{
|
|
|
47
24
|
format: 'iife',
|
|
48
25
|
name: 'version',
|
|
49
26
|
plugins: [terser()]
|
|
50
|
-
}
|
|
27
|
+
},
|
|
51
28
|
],
|
|
52
29
|
plugins: [
|
|
53
30
|
peerDepsExternal(),
|
|
@@ -58,46 +35,9 @@ const jsconfig = [{
|
|
|
58
35
|
commonjs(),
|
|
59
36
|
json(),
|
|
60
37
|
terser()
|
|
61
|
-
]
|
|
38
|
+
],
|
|
39
|
+
context: "this",
|
|
62
40
|
},
|
|
63
41
|
];
|
|
64
42
|
|
|
65
43
|
export default jsconfig;
|
|
66
|
-
/*
|
|
67
|
-
export default [
|
|
68
|
-
{
|
|
69
|
-
input: 'src/index.ts',
|
|
70
|
-
output: [
|
|
71
|
-
{
|
|
72
|
-
file: 'dist/index.js',
|
|
73
|
-
format: 'cjs',
|
|
74
|
-
exports: 'named',
|
|
75
|
-
sourcemap: true,
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
file: 'dist/index.esm.js',
|
|
79
|
-
format: "esm",
|
|
80
|
-
exports: 'named',
|
|
81
|
-
sourcemap: true,
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
file: 'dist/bundle.min.js',
|
|
85
|
-
format: 'iife',
|
|
86
|
-
name: 'version',
|
|
87
|
-
plugins: [terser()]
|
|
88
|
-
}
|
|
89
|
-
],
|
|
90
|
-
plugins: [
|
|
91
|
-
peerDepsExternal(),
|
|
92
|
-
resolve({
|
|
93
|
-
browser: true,
|
|
94
|
-
preferBuiltins: false,
|
|
95
|
-
}),
|
|
96
|
-
commonjs(),
|
|
97
|
-
json(),
|
|
98
|
-
terser(),
|
|
99
|
-
typescript()
|
|
100
|
-
]
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
*/
|
package/src/factory/api.js
CHANGED
|
@@ -31,6 +31,7 @@ const setBaseUrl = (uri) => {
|
|
|
31
31
|
CONFIG.BASE_URL = uri || CONFIG.baseUrls['development'];
|
|
32
32
|
getBaseUrl();
|
|
33
33
|
};
|
|
34
|
+
|
|
34
35
|
/**
|
|
35
36
|
* Gets the appropriate base URL for the current environment
|
|
36
37
|
* @returns {string} Base URL
|
|
@@ -45,9 +46,9 @@ const getBaseUrl = () => {
|
|
|
45
46
|
* Gets authentication data from cache
|
|
46
47
|
* @returns {Object|null} Auth data or null
|
|
47
48
|
*/
|
|
48
|
-
const getAuthData =
|
|
49
|
+
const getAuthData = () => {
|
|
49
50
|
try {
|
|
50
|
-
const authData =
|
|
51
|
+
const authData = CacheFactory.local.get(CONFIG.cacheKeys.auth);
|
|
51
52
|
return authData && typeof authData === 'object' ? authData : null;
|
|
52
53
|
} catch (error) {
|
|
53
54
|
console.warn('Failed to retrieve auth data:', error);
|
|
@@ -78,8 +79,8 @@ const isTokenExpired = (token) => {
|
|
|
78
79
|
*/
|
|
79
80
|
const refreshAuthToken = async () => {
|
|
80
81
|
try {
|
|
81
|
-
const authData =
|
|
82
|
-
const refreshToken = authData?.refreshToken ||
|
|
82
|
+
const authData = getAuthData();
|
|
83
|
+
const refreshToken = authData?.refreshToken || CacheFactory.local.get(CONFIG.cacheKeys.refreshToken);
|
|
83
84
|
|
|
84
85
|
if (!refreshToken) {
|
|
85
86
|
throw new Error('No refresh token available');
|
|
@@ -96,11 +97,11 @@ const refreshAuthToken = async () => {
|
|
|
96
97
|
expiresAt: response.data.expiresAt,
|
|
97
98
|
};
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
CacheFactory.local.set(CONFIG.cacheKeys.auth, newAuthData);
|
|
100
101
|
return newAuthData.token;
|
|
101
102
|
} catch (error) {
|
|
102
103
|
console.error('Token refresh failed:', error);
|
|
103
|
-
|
|
104
|
+
clearAuthData();
|
|
104
105
|
return null;
|
|
105
106
|
}
|
|
106
107
|
};
|
|
@@ -108,12 +109,10 @@ const refreshAuthToken = async () => {
|
|
|
108
109
|
/**
|
|
109
110
|
* Clears authentication data from cache
|
|
110
111
|
*/
|
|
111
|
-
const clearAuthData =
|
|
112
|
+
const clearAuthData = () => {
|
|
112
113
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
CacheFactory.local.remove(CONFIG.cacheKeys.refreshToken),
|
|
116
|
-
]);
|
|
114
|
+
CacheFactory.local.remove(CONFIG.cacheKeys.auth);
|
|
115
|
+
CacheFactory.local.remove(CONFIG.cacheKeys.refreshToken);
|
|
117
116
|
} catch (error) {
|
|
118
117
|
console.warn('Failed to clear auth data:', error);
|
|
119
118
|
}
|
|
@@ -182,7 +181,7 @@ const requestInterceptor = async (config) => {
|
|
|
182
181
|
config._retry = config._retry || 0;
|
|
183
182
|
|
|
184
183
|
// Get authentication data
|
|
185
|
-
const authData =
|
|
184
|
+
const authData = getAuthData();
|
|
186
185
|
let token = authData?.token;
|
|
187
186
|
|
|
188
187
|
// Check if token needs refresh
|
|
@@ -304,7 +303,7 @@ const responseErrorInterceptor = async (error) => {
|
|
|
304
303
|
}
|
|
305
304
|
|
|
306
305
|
// Clear auth data and redirect to login
|
|
307
|
-
|
|
306
|
+
clearAuthData();
|
|
308
307
|
|
|
309
308
|
// Dispatch auth failure event
|
|
310
309
|
if (typeof window !== 'undefined') {
|
|
@@ -425,9 +424,9 @@ const API = {
|
|
|
425
424
|
* Sets authentication token
|
|
426
425
|
* @param {string} token - Auth token
|
|
427
426
|
* @param {Object} userData - User data
|
|
428
|
-
* @returns {
|
|
427
|
+
* @returns {boolean} Success status
|
|
429
428
|
*/
|
|
430
|
-
setAuth:
|
|
429
|
+
setAuth: (token, userData = {}) => {
|
|
431
430
|
try {
|
|
432
431
|
const authData = {
|
|
433
432
|
token,
|
|
@@ -436,8 +435,7 @@ const API = {
|
|
|
436
435
|
expiresAt: userData.expiresAt,
|
|
437
436
|
};
|
|
438
437
|
|
|
439
|
-
|
|
440
|
-
return true;
|
|
438
|
+
return CacheFactory.local.set(CONFIG.cacheKeys.auth, authData);
|
|
441
439
|
} catch (error) {
|
|
442
440
|
console.error('Failed to set auth:', error);
|
|
443
441
|
return false;
|
|
@@ -446,11 +444,11 @@ const API = {
|
|
|
446
444
|
|
|
447
445
|
/**
|
|
448
446
|
* Clears authentication
|
|
449
|
-
* @returns {
|
|
447
|
+
* @returns {boolean} Success status
|
|
450
448
|
*/
|
|
451
|
-
clearAuth:
|
|
449
|
+
clearAuth: () => {
|
|
452
450
|
try {
|
|
453
|
-
|
|
451
|
+
clearAuthData();
|
|
454
452
|
return true;
|
|
455
453
|
} catch (error) {
|
|
456
454
|
console.error('Failed to clear auth:', error);
|
|
@@ -460,10 +458,10 @@ const API = {
|
|
|
460
458
|
|
|
461
459
|
/**
|
|
462
460
|
* Gets current auth status
|
|
463
|
-
* @returns {
|
|
461
|
+
* @returns {Object} Auth status
|
|
464
462
|
*/
|
|
465
|
-
getAuthStatus:
|
|
466
|
-
const authData =
|
|
463
|
+
getAuthStatus: () => {
|
|
464
|
+
const authData = getAuthData();
|
|
467
465
|
const isAuthenticated = !!(authData?.token && !isTokenExpired(authData.token));
|
|
468
466
|
|
|
469
467
|
return {
|
|
@@ -524,6 +522,84 @@ const API = {
|
|
|
524
522
|
});
|
|
525
523
|
},
|
|
526
524
|
|
|
525
|
+
// Cache utility methods
|
|
526
|
+
/**
|
|
527
|
+
* Gets cached data
|
|
528
|
+
* @param {string} key - Cache key
|
|
529
|
+
* @param {any} defaultValue - Default value if not found
|
|
530
|
+
* @returns {any} Cached data or default value
|
|
531
|
+
*/
|
|
532
|
+
getCached: (key, defaultValue = null) => {
|
|
533
|
+
return CacheFactory.local.get(key, defaultValue);
|
|
534
|
+
},
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Sets cached data
|
|
538
|
+
* @param {string} key - Cache key
|
|
539
|
+
* @param {any} value - Value to cache
|
|
540
|
+
* @returns {boolean} Success status
|
|
541
|
+
*/
|
|
542
|
+
setCached: (key, value) => {
|
|
543
|
+
return CacheFactory.local.set(key, value);
|
|
544
|
+
},
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Removes cached data
|
|
548
|
+
* @param {string} key - Cache key
|
|
549
|
+
* @returns {boolean} Success status
|
|
550
|
+
*/
|
|
551
|
+
removeCached: (key) => {
|
|
552
|
+
return CacheFactory.local.remove(key);
|
|
553
|
+
},
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Clears all cached data
|
|
557
|
+
* @returns {boolean} Success status
|
|
558
|
+
*/
|
|
559
|
+
clearCache: () => {
|
|
560
|
+
return CacheFactory.local.clear();
|
|
561
|
+
},
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Gets cache statistics
|
|
565
|
+
* @returns {Object} Cache stats
|
|
566
|
+
*/
|
|
567
|
+
getCacheStats: () => {
|
|
568
|
+
return CacheFactory.local.getStats();
|
|
569
|
+
},
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Bulk cache operations
|
|
573
|
+
*/
|
|
574
|
+
cache: {
|
|
575
|
+
/**
|
|
576
|
+
* Gets multiple cached items
|
|
577
|
+
* @param {string[]} keys - Cache keys
|
|
578
|
+
* @returns {Object} Key-value pairs
|
|
579
|
+
*/
|
|
580
|
+
getMultiple: (keys) => {
|
|
581
|
+
return CacheFactory.local.bulk.get(keys);
|
|
582
|
+
},
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Sets multiple cached items
|
|
586
|
+
* @param {Object} items - Key-value pairs
|
|
587
|
+
* @returns {Object} Success status for each key
|
|
588
|
+
*/
|
|
589
|
+
setMultiple: (items) => {
|
|
590
|
+
return CacheFactory.local.bulk.set(items);
|
|
591
|
+
},
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Removes multiple cached items
|
|
595
|
+
* @param {string[]} keys - Cache keys
|
|
596
|
+
* @returns {Object} Success status for each key
|
|
597
|
+
*/
|
|
598
|
+
removeMultiple: (keys) => {
|
|
599
|
+
return CacheFactory.local.bulk.remove(keys);
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
|
|
527
603
|
// Configuration access
|
|
528
604
|
config: CONFIG,
|
|
529
605
|
getBaseUrl,
|
package/src/factory/cache.js
CHANGED
|
@@ -107,6 +107,30 @@ const safeParse = (value) => {
|
|
|
107
107
|
}
|
|
108
108
|
};
|
|
109
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Retries an operation with exponential backoff
|
|
112
|
+
* @param {Function} operation - Operation to retry
|
|
113
|
+
* @param {number} maxRetries - Maximum retry attempts
|
|
114
|
+
* @returns {any} Operation result
|
|
115
|
+
*/
|
|
116
|
+
const retryOperation = (operation, maxRetries) => {
|
|
117
|
+
let attempts = 0;
|
|
118
|
+
|
|
119
|
+
while (attempts <= maxRetries) {
|
|
120
|
+
try {
|
|
121
|
+
return operation();
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (attempts === maxRetries) {
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
attempts++;
|
|
127
|
+
// Simple synchronous delay simulation (not recommended for production)
|
|
128
|
+
// In a real scenario, you might want to remove retries for sync operations
|
|
129
|
+
// or handle them differently
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
110
134
|
/**
|
|
111
135
|
* Creates a cache instance with the specified configuration
|
|
112
136
|
* @param {Object} options - Configuration options
|
|
@@ -186,31 +210,12 @@ export const CacheFactory = (options = {}) => {
|
|
|
186
210
|
}
|
|
187
211
|
};
|
|
188
212
|
|
|
189
|
-
/**
|
|
190
|
-
* Retries an operation with exponential backoff
|
|
191
|
-
* @param {Function} operation - Operation to retry
|
|
192
|
-
* @param {number} attempts - Current attempt number
|
|
193
|
-
* @returns {Promise<any>} Operation result
|
|
194
|
-
*/
|
|
195
|
-
const retryOperation = async (operation, attempts = 0) => {
|
|
196
|
-
try {
|
|
197
|
-
return await operation();
|
|
198
|
-
} catch (error) {
|
|
199
|
-
if (attempts < config.maxRetries) {
|
|
200
|
-
const delay = Math.pow(2, attempts) * 100; // Exponential backoff
|
|
201
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
202
|
-
return retryOperation(operation, attempts + 1);
|
|
203
|
-
}
|
|
204
|
-
throw error;
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
213
|
return {
|
|
209
214
|
/**
|
|
210
215
|
* Checks if storage is available
|
|
211
216
|
* @returns {boolean} Storage availability status
|
|
212
217
|
*/
|
|
213
|
-
isAvailable
|
|
218
|
+
isAvailable() {
|
|
214
219
|
return storage !== null;
|
|
215
220
|
},
|
|
216
221
|
|
|
@@ -218,7 +223,7 @@ export const CacheFactory = (options = {}) => {
|
|
|
218
223
|
* Checks if using memory fallback
|
|
219
224
|
* @returns {boolean} Whether using memory storage
|
|
220
225
|
*/
|
|
221
|
-
isUsingMemoryFallback
|
|
226
|
+
isUsingMemoryFallback() {
|
|
222
227
|
return usingMemoryFallback;
|
|
223
228
|
},
|
|
224
229
|
|
|
@@ -226,7 +231,7 @@ export const CacheFactory = (options = {}) => {
|
|
|
226
231
|
* Gets storage type being used
|
|
227
232
|
* @returns {string} Storage type name
|
|
228
233
|
*/
|
|
229
|
-
getStorageType
|
|
234
|
+
getStorageType() {
|
|
230
235
|
return usingMemoryFallback ? 'memory' : storageType;
|
|
231
236
|
},
|
|
232
237
|
|
|
@@ -234,9 +239,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
234
239
|
* Sets an item in storage
|
|
235
240
|
* @param {string} key - Storage key
|
|
236
241
|
* @param {any} value - Value to store
|
|
237
|
-
* @returns {
|
|
242
|
+
* @returns {boolean} Success status
|
|
238
243
|
*/
|
|
239
|
-
set
|
|
244
|
+
set(key, value) {
|
|
240
245
|
if (!storage) {
|
|
241
246
|
console.error('CacheFactory: Storage not available');
|
|
242
247
|
return false;
|
|
@@ -254,9 +259,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
254
259
|
}
|
|
255
260
|
|
|
256
261
|
try {
|
|
257
|
-
|
|
262
|
+
retryOperation(() => {
|
|
258
263
|
storage.setItem(prefixedKey, serializedValue);
|
|
259
|
-
});
|
|
264
|
+
}, config.maxRetries);
|
|
260
265
|
|
|
261
266
|
log('SET', key, value);
|
|
262
267
|
return true;
|
|
@@ -270,9 +275,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
270
275
|
* Gets an item from storage
|
|
271
276
|
* @param {string} key - Storage key
|
|
272
277
|
* @param {any} defaultValue - Default value if key doesn't exist
|
|
273
|
-
* @returns {
|
|
278
|
+
* @returns {any} Retrieved value or default
|
|
274
279
|
*/
|
|
275
|
-
get
|
|
280
|
+
get(key, defaultValue = null) {
|
|
276
281
|
if (!storage) {
|
|
277
282
|
console.warn('CacheFactory: Storage not available');
|
|
278
283
|
return defaultValue;
|
|
@@ -286,9 +291,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
286
291
|
const prefixedKey = getPrefixedKey(key);
|
|
287
292
|
|
|
288
293
|
try {
|
|
289
|
-
const data =
|
|
294
|
+
const data = retryOperation(() => {
|
|
290
295
|
return storage.getItem(prefixedKey);
|
|
291
|
-
});
|
|
296
|
+
}, config.maxRetries);
|
|
292
297
|
|
|
293
298
|
if (data === null || data === 'undefined') {
|
|
294
299
|
log('GET_MISS', key);
|
|
@@ -307,9 +312,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
307
312
|
/**
|
|
308
313
|
* Removes an item from storage
|
|
309
314
|
* @param {string} key - Storage key
|
|
310
|
-
* @returns {
|
|
315
|
+
* @returns {boolean} Success status
|
|
311
316
|
*/
|
|
312
|
-
remove
|
|
317
|
+
remove(key) {
|
|
313
318
|
if (!storage) {
|
|
314
319
|
console.error('CacheFactory: Storage not available');
|
|
315
320
|
return false;
|
|
@@ -323,9 +328,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
323
328
|
const prefixedKey = getPrefixedKey(key);
|
|
324
329
|
|
|
325
330
|
try {
|
|
326
|
-
|
|
331
|
+
retryOperation(() => {
|
|
327
332
|
storage.removeItem(prefixedKey);
|
|
328
|
-
});
|
|
333
|
+
}, config.maxRetries);
|
|
329
334
|
|
|
330
335
|
log('REMOVE', key);
|
|
331
336
|
return true;
|
|
@@ -337,9 +342,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
337
342
|
|
|
338
343
|
/**
|
|
339
344
|
* Clears all items from storage (respects prefix)
|
|
340
|
-
* @returns {
|
|
345
|
+
* @returns {boolean} Success status
|
|
341
346
|
*/
|
|
342
|
-
clear
|
|
347
|
+
clear() {
|
|
343
348
|
if (!storage) {
|
|
344
349
|
console.error('CacheFactory: Storage not available');
|
|
345
350
|
return false;
|
|
@@ -348,12 +353,12 @@ export const CacheFactory = (options = {}) => {
|
|
|
348
353
|
try {
|
|
349
354
|
if (config.prefix) {
|
|
350
355
|
// Clear only prefixed items
|
|
351
|
-
const keys =
|
|
352
|
-
|
|
356
|
+
const keys = this.keys();
|
|
357
|
+
keys.forEach(key => this.remove(key));
|
|
353
358
|
} else {
|
|
354
|
-
|
|
359
|
+
retryOperation(() => {
|
|
355
360
|
storage.clear();
|
|
356
|
-
});
|
|
361
|
+
}, config.maxRetries);
|
|
357
362
|
}
|
|
358
363
|
|
|
359
364
|
log('CLEAR');
|
|
@@ -366,9 +371,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
366
371
|
|
|
367
372
|
/**
|
|
368
373
|
* Gets all keys from storage (without prefix)
|
|
369
|
-
* @returns {
|
|
374
|
+
* @returns {string[]} Array of keys
|
|
370
375
|
*/
|
|
371
|
-
keys
|
|
376
|
+
keys() {
|
|
372
377
|
if (!storage) {
|
|
373
378
|
console.warn('CacheFactory: Storage not available');
|
|
374
379
|
return [];
|
|
@@ -400,9 +405,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
400
405
|
/**
|
|
401
406
|
* Checks if a key exists in storage
|
|
402
407
|
* @param {string} key - Storage key
|
|
403
|
-
* @returns {
|
|
408
|
+
* @returns {boolean} Whether key exists
|
|
404
409
|
*/
|
|
405
|
-
has
|
|
410
|
+
has(key) {
|
|
406
411
|
if (!storage || !key || typeof key !== 'string') {
|
|
407
412
|
return false;
|
|
408
413
|
}
|
|
@@ -410,9 +415,9 @@ export const CacheFactory = (options = {}) => {
|
|
|
410
415
|
const prefixedKey = getPrefixedKey(key);
|
|
411
416
|
|
|
412
417
|
try {
|
|
413
|
-
const exists =
|
|
418
|
+
const exists = retryOperation(() => {
|
|
414
419
|
return storage.getItem(prefixedKey) !== null;
|
|
415
|
-
});
|
|
420
|
+
}, config.maxRetries);
|
|
416
421
|
|
|
417
422
|
log('HAS', key, exists);
|
|
418
423
|
return exists;
|
|
@@ -424,10 +429,10 @@ export const CacheFactory = (options = {}) => {
|
|
|
424
429
|
|
|
425
430
|
/**
|
|
426
431
|
* Gets storage usage information
|
|
427
|
-
* @returns {
|
|
432
|
+
* @returns {Object} Storage usage stats
|
|
428
433
|
*/
|
|
429
|
-
getStats
|
|
430
|
-
const keys =
|
|
434
|
+
getStats() {
|
|
435
|
+
const keys = this.keys();
|
|
431
436
|
|
|
432
437
|
return {
|
|
433
438
|
keyCount: keys.length,
|
|
@@ -445,16 +450,14 @@ export const CacheFactory = (options = {}) => {
|
|
|
445
450
|
/**
|
|
446
451
|
* Sets multiple items at once
|
|
447
452
|
* @param {Object} items - Key-value pairs to set
|
|
448
|
-
* @returns {
|
|
453
|
+
* @returns {Object} Results of each operation
|
|
449
454
|
*/
|
|
450
|
-
set:
|
|
455
|
+
set: (items) => {
|
|
451
456
|
const results = {};
|
|
452
457
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
})
|
|
457
|
-
);
|
|
458
|
+
Object.entries(items).forEach(([key, value]) => {
|
|
459
|
+
results[key] = this.set(key, value);
|
|
460
|
+
});
|
|
458
461
|
|
|
459
462
|
return results;
|
|
460
463
|
},
|
|
@@ -462,16 +465,14 @@ export const CacheFactory = (options = {}) => {
|
|
|
462
465
|
/**
|
|
463
466
|
* Gets multiple items at once
|
|
464
467
|
* @param {string[]} keys - Keys to retrieve
|
|
465
|
-
* @returns {
|
|
468
|
+
* @returns {Object} Retrieved key-value pairs
|
|
466
469
|
*/
|
|
467
|
-
get:
|
|
470
|
+
get: (keys) => {
|
|
468
471
|
const results = {};
|
|
469
472
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
})
|
|
474
|
-
);
|
|
473
|
+
keys.forEach(key => {
|
|
474
|
+
results[key] = this.get(key);
|
|
475
|
+
});
|
|
475
476
|
|
|
476
477
|
return results;
|
|
477
478
|
},
|
|
@@ -479,16 +480,14 @@ export const CacheFactory = (options = {}) => {
|
|
|
479
480
|
/**
|
|
480
481
|
* Removes multiple items at once
|
|
481
482
|
* @param {string[]} keys - Keys to remove
|
|
482
|
-
* @returns {
|
|
483
|
+
* @returns {Object} Results of each operation
|
|
483
484
|
*/
|
|
484
|
-
remove:
|
|
485
|
+
remove: (keys) => {
|
|
485
486
|
const results = {};
|
|
486
487
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
})
|
|
491
|
-
);
|
|
488
|
+
keys.forEach(key => {
|
|
489
|
+
results[key] = this.remove(key);
|
|
490
|
+
});
|
|
492
491
|
|
|
493
492
|
return results;
|
|
494
493
|
},
|
|
@@ -499,7 +498,7 @@ export const CacheFactory = (options = {}) => {
|
|
|
499
498
|
// Pre-configured instances for convenience
|
|
500
499
|
CacheFactory.local = CacheFactory({ type: 'local' });
|
|
501
500
|
CacheFactory.session = CacheFactory({ type: 'session' });
|
|
502
|
-
|
|
501
|
+
exports.Cache = CacheFactory({type: 'local'});
|
|
503
502
|
// Memory-only instance for testing or server-side use
|
|
504
503
|
CacheFactory.memory = CacheFactory({
|
|
505
504
|
type: 'session',
|