@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feardread/feature-factory",
3
- "version": "5.0.8",
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.22.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
- */
@@ -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 = async () => {
49
+ const getAuthData = () => {
49
50
  try {
50
- const authData = await CacheFactory.local.get(CONFIG.cacheKeys.auth);
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 = await getAuthData();
82
- const refreshToken = authData?.refreshToken || await CacheFactory.local.get(CONFIG.cacheKeys.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
- await CacheFactory.local.set(CONFIG.cacheKeys.auth, newAuthData);
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
- await clearAuthData();
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 = async () => {
112
+ const clearAuthData = () => {
112
113
  try {
113
- await Promise.all([
114
- CacheFactory.local.remove(CONFIG.cacheKeys.auth),
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 = await getAuthData();
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
- await clearAuthData();
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 {Promise<boolean>} Success status
427
+ * @returns {boolean} Success status
429
428
  */
430
- setAuth: async (token, userData = {}) => {
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
- await CacheFactory.local.set(CONFIG.cacheKeys.auth, authData);
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 {Promise<boolean>} Success status
447
+ * @returns {boolean} Success status
450
448
  */
451
- clearAuth: async () => {
449
+ clearAuth: () => {
452
450
  try {
453
- await clearAuthData();
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 {Promise<Object>} Auth status
461
+ * @returns {Object} Auth status
464
462
  */
465
- getAuthStatus: async () => {
466
- const authData = await getAuthData();
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,
@@ -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 {Promise<boolean>} Success status
242
+ * @returns {boolean} Success status
238
243
  */
239
- set: async (key, value) => {
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
- await retryOperation(() => {
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 {Promise<any>} Retrieved value or default
278
+ * @returns {any} Retrieved value or default
274
279
  */
275
- get: async (key, defaultValue = null) => {
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 = await retryOperation(() => {
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 {Promise<boolean>} Success status
315
+ * @returns {boolean} Success status
311
316
  */
312
- remove: async (key) => {
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
- await retryOperation(() => {
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 {Promise<boolean>} Success status
345
+ * @returns {boolean} Success status
341
346
  */
342
- clear: async () => {
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 = await this.keys();
352
- await Promise.all(keys.map(key => this.remove(key)));
356
+ const keys = this.keys();
357
+ keys.forEach(key => this.remove(key));
353
358
  } else {
354
- await retryOperation(() => {
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 {Promise<string[]>} Array of keys
374
+ * @returns {string[]} Array of keys
370
375
  */
371
- keys: async () => {
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 {Promise<boolean>} Whether key exists
408
+ * @returns {boolean} Whether key exists
404
409
  */
405
- has: async (key) => {
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 = await retryOperation(() => {
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 {Promise<Object>} Storage usage stats
432
+ * @returns {Object} Storage usage stats
428
433
  */
429
- getStats: async () => {
430
- const keys = await this.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 {Promise<Object>} Results of each operation
453
+ * @returns {Object} Results of each operation
449
454
  */
450
- set: async (items) => {
455
+ set: (items) => {
451
456
  const results = {};
452
457
 
453
- await Promise.all(
454
- Object.entries(items).map(async ([key, value]) => {
455
- results[key] = await this.set(key, value);
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 {Promise<Object>} Retrieved key-value pairs
468
+ * @returns {Object} Retrieved key-value pairs
466
469
  */
467
- get: async (keys) => {
470
+ get: (keys) => {
468
471
  const results = {};
469
472
 
470
- await Promise.all(
471
- keys.map(async (key) => {
472
- results[key] = await this.get(key);
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 {Promise<Object>} Results of each operation
483
+ * @returns {Object} Results of each operation
483
484
  */
484
- remove: async (keys) => {
485
+ remove: (keys) => {
485
486
  const results = {};
486
487
 
487
- await Promise.all(
488
- keys.map(async (key) => {
489
- results[key] = await this.remove(key);
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',