@feardread/feature-factory 3.0.2 → 4.0.2
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 +1 -1
- package/src/factory/api.js +521 -56
- package/src/factory/cache.js +479 -27
- package/src/factory/index.js +171 -100
- package/src/factory/service.js +412 -18
- package/src/factory/state.js +430 -5
- package/src/factory/thunk.js +264 -38
- package/src/factories/api.js +0 -72
- package/src/factories/api.ts +0 -72
- package/src/factories/cache.js +0 -71
- package/src/factories/cache.ts +0 -71
- package/src/factories/factory.js +0 -149
- package/src/factories/factory.ts +0 -158
- package/src/factories/service.js +0 -28
- package/src/factories/service.ts +0 -28
- package/src/factories/state.js +0 -10
- package/src/factories/state.ts +0 -10
- package/src/factories/thunk.js +0 -53
- package/src/factories/thunk.ts +0 -53
- package/src/index.ts +0 -7
- package/tsconfig.json +0 -11
package/src/factory/cache.js
CHANGED
|
@@ -1,57 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage types supported by the CacheFactory
|
|
3
|
+
*/
|
|
4
|
+
const STORAGE_TYPES = {
|
|
5
|
+
LOCAL: 'localStorage',
|
|
6
|
+
SESSION: 'sessionStorage',
|
|
7
|
+
};
|
|
1
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Default configuration options
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_OPTIONS = {
|
|
13
|
+
type: 'session',
|
|
14
|
+
prefix: '',
|
|
15
|
+
enableLogging: false,
|
|
16
|
+
fallbackToMemory: true,
|
|
17
|
+
maxRetries: 3,
|
|
18
|
+
};
|
|
2
19
|
|
|
3
|
-
|
|
20
|
+
/**
|
|
21
|
+
* In-memory fallback storage for when browser storage is unavailable
|
|
22
|
+
*/
|
|
23
|
+
class MemoryStorage {
|
|
24
|
+
constructor() {
|
|
25
|
+
this.data = new Map();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setItem(key, value) {
|
|
29
|
+
this.data.set(key, value);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getItem(key) {
|
|
33
|
+
return this.data.get(key) || null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
removeItem(key) {
|
|
37
|
+
this.data.delete(key);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
clear() {
|
|
41
|
+
this.data.clear();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get length() {
|
|
45
|
+
return this.data.size;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
key(index) {
|
|
49
|
+
const keys = Array.from(this.data.keys());
|
|
50
|
+
return keys[index] || null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
keys() {
|
|
54
|
+
return Array.from(this.data.keys());
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Validates storage availability and functionality
|
|
60
|
+
* @param {Storage} storage - The storage object to test
|
|
61
|
+
* @returns {boolean} Whether storage is available and functional
|
|
62
|
+
*/
|
|
63
|
+
const isStorageAvailable = (storage) => {
|
|
64
|
+
if (!storage) return false;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const testKey = '__cache_factory_test__';
|
|
68
|
+
const testValue = 'test';
|
|
69
|
+
|
|
70
|
+
storage.setItem(testKey, testValue);
|
|
71
|
+
const retrieved = storage.getItem(testKey);
|
|
72
|
+
storage.removeItem(testKey);
|
|
73
|
+
|
|
74
|
+
return retrieved === testValue;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Safely serializes data to JSON string
|
|
82
|
+
* @param {any} value - Value to serialize
|
|
83
|
+
* @returns {string|null} Serialized value or null if serialization fails
|
|
84
|
+
*/
|
|
85
|
+
const safeStringify = (value) => {
|
|
86
|
+
try {
|
|
87
|
+
return JSON.stringify(value);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error('CacheFactory: Failed to serialize value', error);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Safely parses JSON string
|
|
96
|
+
* @param {string} value - JSON string to parse
|
|
97
|
+
* @returns {any|null} Parsed value or null if parsing fails
|
|
98
|
+
*/
|
|
99
|
+
const safeParse = (value) => {
|
|
100
|
+
if (value === null || value === undefined) return null;
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
return JSON.parse(value);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
// Return the original value if it's not valid JSON
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Creates a cache instance with the specified configuration
|
|
112
|
+
* @param {Object} options - Configuration options
|
|
113
|
+
* @param {string} options.type - Storage type ('local' or 'session')
|
|
114
|
+
* @param {string} options.prefix - Key prefix for namespacing
|
|
115
|
+
* @param {boolean} options.enableLogging - Enable debug logging
|
|
116
|
+
* @param {boolean} options.fallbackToMemory - Use memory storage as fallback
|
|
117
|
+
* @param {number} options.maxRetries - Maximum retry attempts for operations
|
|
118
|
+
* @returns {Object} Cache instance with storage methods
|
|
119
|
+
*/
|
|
4
120
|
export const CacheFactory = (options = {}) => {
|
|
5
|
-
|
|
121
|
+
const config = { ...DEFAULT_OPTIONS, ...options };
|
|
122
|
+
const storageType = config.type === 'local' ? STORAGE_TYPES.LOCAL : STORAGE_TYPES.SESSION;
|
|
123
|
+
|
|
124
|
+
let storage = null;
|
|
125
|
+
let usingMemoryFallback = false;
|
|
126
|
+
|
|
127
|
+
// Initialize storage
|
|
128
|
+
const initializeStorage = () => {
|
|
129
|
+
if (typeof window === 'undefined') {
|
|
130
|
+
// Server-side rendering or Node.js environment
|
|
131
|
+
if (config.fallbackToMemory) {
|
|
132
|
+
storage = new MemoryStorage();
|
|
133
|
+
usingMemoryFallback = true;
|
|
134
|
+
if (config.enableLogging) {
|
|
135
|
+
console.warn('CacheFactory: Browser storage unavailable, using memory fallback');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const browserStorage = window[storageType];
|
|
142
|
+
|
|
143
|
+
if (isStorageAvailable(browserStorage)) {
|
|
144
|
+
storage = browserStorage;
|
|
145
|
+
} else if (config.fallbackToMemory) {
|
|
146
|
+
storage = new MemoryStorage();
|
|
147
|
+
usingMemoryFallback = true;
|
|
148
|
+
if (config.enableLogging) {
|
|
149
|
+
console.warn(`CacheFactory: ${storageType} unavailable, using memory fallback`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
initializeStorage();
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Generates a prefixed key
|
|
158
|
+
* @param {string} key - Original key
|
|
159
|
+
* @returns {string} Prefixed key
|
|
160
|
+
*/
|
|
161
|
+
const getPrefixedKey = (key) => {
|
|
162
|
+
return config.prefix ? `${config.prefix}${key}` : key;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Removes prefix from key
|
|
167
|
+
* @param {string} prefixedKey - Prefixed key
|
|
168
|
+
* @returns {string} Original key
|
|
169
|
+
*/
|
|
170
|
+
const removePrefixFromKey = (prefixedKey) => {
|
|
171
|
+
if (!config.prefix) return prefixedKey;
|
|
172
|
+
return prefixedKey.startsWith(config.prefix)
|
|
173
|
+
? prefixedKey.slice(config.prefix.length)
|
|
174
|
+
: prefixedKey;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Logs debug information if logging is enabled
|
|
179
|
+
* @param {string} operation - Operation name
|
|
180
|
+
* @param {string} key - Storage key
|
|
181
|
+
* @param {any} data - Additional data to log
|
|
182
|
+
*/
|
|
183
|
+
const log = (operation, key, data = null) => {
|
|
184
|
+
if (config.enableLogging) {
|
|
185
|
+
console.debug(`CacheFactory[${storageType}]: ${operation}`, { key, data, usingMemoryFallback });
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
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
|
+
};
|
|
6
207
|
|
|
7
208
|
return {
|
|
8
|
-
|
|
9
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Checks if storage is available
|
|
211
|
+
* @returns {boolean} Storage availability status
|
|
212
|
+
*/
|
|
213
|
+
isAvailable: () => {
|
|
214
|
+
return storage !== null;
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Checks if using memory fallback
|
|
219
|
+
* @returns {boolean} Whether using memory storage
|
|
220
|
+
*/
|
|
221
|
+
isUsingMemoryFallback: () => {
|
|
222
|
+
return usingMemoryFallback;
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Gets storage type being used
|
|
227
|
+
* @returns {string} Storage type name
|
|
228
|
+
*/
|
|
229
|
+
getStorageType: () => {
|
|
230
|
+
return usingMemoryFallback ? 'memory' : storageType;
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Sets an item in storage
|
|
235
|
+
* @param {string} key - Storage key
|
|
236
|
+
* @param {any} value - Value to store
|
|
237
|
+
* @returns {Promise<boolean>} Success status
|
|
238
|
+
*/
|
|
239
|
+
set: async (key, value) => {
|
|
240
|
+
if (!storage) {
|
|
241
|
+
console.error('CacheFactory: Storage not available');
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!key || typeof key !== 'string') {
|
|
246
|
+
throw new Error('CacheFactory: Invalid key provided');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const prefixedKey = getPrefixedKey(key);
|
|
250
|
+
const serializedValue = safeStringify(value);
|
|
251
|
+
|
|
252
|
+
if (serializedValue === null) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
await retryOperation(() => {
|
|
258
|
+
storage.setItem(prefixedKey, serializedValue);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
log('SET', key, value);
|
|
262
|
+
return true;
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.error(`CacheFactory: Error setting item ${key}:`, error);
|
|
10
265
|
return false;
|
|
11
266
|
}
|
|
12
|
-
return true;
|
|
13
267
|
},
|
|
14
|
-
|
|
15
|
-
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Gets an item from storage
|
|
271
|
+
* @param {string} key - Storage key
|
|
272
|
+
* @param {any} defaultValue - Default value if key doesn't exist
|
|
273
|
+
* @returns {Promise<any>} Retrieved value or default
|
|
274
|
+
*/
|
|
275
|
+
get: async (key, defaultValue = null) => {
|
|
276
|
+
if (!storage) {
|
|
277
|
+
console.warn('CacheFactory: Storage not available');
|
|
278
|
+
return defaultValue;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (!key || typeof key !== 'string' || key === 'undefined') {
|
|
282
|
+
console.warn('CacheFactory: Invalid key provided for get operation');
|
|
283
|
+
return defaultValue;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const prefixedKey = getPrefixedKey(key);
|
|
16
287
|
|
|
17
288
|
try {
|
|
18
|
-
|
|
289
|
+
const data = await retryOperation(() => {
|
|
290
|
+
return storage.getItem(prefixedKey);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
if (data === null || data === 'undefined') {
|
|
294
|
+
log('GET_MISS', key);
|
|
295
|
+
return defaultValue;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const parsedData = safeParse(data);
|
|
299
|
+
log('GET_HIT', key, parsedData);
|
|
300
|
+
return parsedData;
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error(`CacheFactory: Error getting item ${key}:`, error);
|
|
303
|
+
return defaultValue;
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Removes an item from storage
|
|
309
|
+
* @param {string} key - Storage key
|
|
310
|
+
* @returns {Promise<boolean>} Success status
|
|
311
|
+
*/
|
|
312
|
+
remove: async (key) => {
|
|
313
|
+
if (!storage) {
|
|
314
|
+
console.error('CacheFactory: Storage not available');
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
19
317
|
|
|
318
|
+
if (!key || typeof key !== 'string') {
|
|
319
|
+
console.warn('CacheFactory: Invalid key provided for remove operation');
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const prefixedKey = getPrefixedKey(key);
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
await retryOperation(() => {
|
|
327
|
+
storage.removeItem(prefixedKey);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
log('REMOVE', key);
|
|
331
|
+
return true;
|
|
20
332
|
} catch (error) {
|
|
21
|
-
console.error(`Error
|
|
333
|
+
console.error(`CacheFactory: Error removing item ${key}:`, error);
|
|
22
334
|
return false;
|
|
23
335
|
}
|
|
24
|
-
return true;
|
|
25
336
|
},
|
|
26
|
-
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Clears all items from storage (respects prefix)
|
|
340
|
+
* @returns {Promise<boolean>} Success status
|
|
341
|
+
*/
|
|
342
|
+
clear: async () => {
|
|
343
|
+
if (!storage) {
|
|
344
|
+
console.error('CacheFactory: Storage not available');
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
|
|
27
348
|
try {
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
349
|
+
if (config.prefix) {
|
|
350
|
+
// Clear only prefixed items
|
|
351
|
+
const keys = await this.keys();
|
|
352
|
+
await Promise.all(keys.map(key => this.remove(key)));
|
|
353
|
+
} else {
|
|
354
|
+
await retryOperation(() => {
|
|
355
|
+
storage.clear();
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
log('CLEAR');
|
|
360
|
+
return true;
|
|
361
|
+
} catch (error) {
|
|
362
|
+
console.error('CacheFactory: Error clearing storage:', error);
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Gets all keys from storage (without prefix)
|
|
369
|
+
* @returns {Promise<string[]>} Array of keys
|
|
370
|
+
*/
|
|
371
|
+
keys: async () => {
|
|
372
|
+
if (!storage) {
|
|
373
|
+
console.warn('CacheFactory: Storage not available');
|
|
374
|
+
return [];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
try {
|
|
378
|
+
let keys = [];
|
|
379
|
+
|
|
380
|
+
if (usingMemoryFallback) {
|
|
381
|
+
keys = storage.keys();
|
|
382
|
+
} else {
|
|
383
|
+
keys = Object.keys(storage);
|
|
31
384
|
}
|
|
32
385
|
|
|
386
|
+
// Filter by prefix and remove prefix from keys
|
|
387
|
+
const filteredKeys = config.prefix
|
|
388
|
+
? keys.filter(key => key.startsWith(config.prefix))
|
|
389
|
+
.map(key => removePrefixFromKey(key))
|
|
390
|
+
: keys;
|
|
33
391
|
|
|
392
|
+
log('KEYS', null, filteredKeys);
|
|
393
|
+
return filteredKeys;
|
|
34
394
|
} catch (error) {
|
|
35
|
-
console.error(
|
|
36
|
-
return
|
|
395
|
+
console.error('CacheFactory: Error getting keys:', error);
|
|
396
|
+
return [];
|
|
37
397
|
}
|
|
38
398
|
},
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Checks if a key exists in storage
|
|
402
|
+
* @param {string} key - Storage key
|
|
403
|
+
* @returns {Promise<boolean>} Whether key exists
|
|
404
|
+
*/
|
|
405
|
+
has: async (key) => {
|
|
406
|
+
if (!storage || !key || typeof key !== 'string') {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const prefixedKey = getPrefixedKey(key);
|
|
411
|
+
|
|
412
|
+
try {
|
|
413
|
+
const exists = await retryOperation(() => {
|
|
414
|
+
return storage.getItem(prefixedKey) !== null;
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
log('HAS', key, exists);
|
|
418
|
+
return exists;
|
|
419
|
+
} catch (error) {
|
|
420
|
+
console.error(`CacheFactory: Error checking if key ${key} exists:`, error);
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
44
423
|
},
|
|
45
|
-
|
|
46
|
-
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Gets storage usage information
|
|
427
|
+
* @returns {Promise<Object>} Storage usage stats
|
|
428
|
+
*/
|
|
429
|
+
getStats: async () => {
|
|
430
|
+
const keys = await this.keys();
|
|
431
|
+
|
|
432
|
+
return {
|
|
433
|
+
keyCount: keys.length,
|
|
434
|
+
storageType: this.getStorageType(),
|
|
435
|
+
usingMemoryFallback: usingMemoryFallback,
|
|
436
|
+
prefix: config.prefix || 'none',
|
|
437
|
+
keys: keys,
|
|
438
|
+
};
|
|
47
439
|
},
|
|
48
|
-
|
|
49
|
-
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Bulk operations
|
|
443
|
+
*/
|
|
444
|
+
bulk: {
|
|
445
|
+
/**
|
|
446
|
+
* Sets multiple items at once
|
|
447
|
+
* @param {Object} items - Key-value pairs to set
|
|
448
|
+
* @returns {Promise<Object>} Results of each operation
|
|
449
|
+
*/
|
|
450
|
+
set: async (items) => {
|
|
451
|
+
const results = {};
|
|
452
|
+
|
|
453
|
+
await Promise.all(
|
|
454
|
+
Object.entries(items).map(async ([key, value]) => {
|
|
455
|
+
results[key] = await this.set(key, value);
|
|
456
|
+
})
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
return results;
|
|
460
|
+
},
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Gets multiple items at once
|
|
464
|
+
* @param {string[]} keys - Keys to retrieve
|
|
465
|
+
* @returns {Promise<Object>} Retrieved key-value pairs
|
|
466
|
+
*/
|
|
467
|
+
get: async (keys) => {
|
|
468
|
+
const results = {};
|
|
469
|
+
|
|
470
|
+
await Promise.all(
|
|
471
|
+
keys.map(async (key) => {
|
|
472
|
+
results[key] = await this.get(key);
|
|
473
|
+
})
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
return results;
|
|
477
|
+
},
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Removes multiple items at once
|
|
481
|
+
* @param {string[]} keys - Keys to remove
|
|
482
|
+
* @returns {Promise<Object>} Results of each operation
|
|
483
|
+
*/
|
|
484
|
+
remove: async (keys) => {
|
|
485
|
+
const results = {};
|
|
486
|
+
|
|
487
|
+
await Promise.all(
|
|
488
|
+
keys.map(async (key) => {
|
|
489
|
+
results[key] = await this.remove(key);
|
|
490
|
+
})
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
return results;
|
|
494
|
+
},
|
|
50
495
|
},
|
|
51
496
|
};
|
|
52
|
-
}
|
|
497
|
+
};
|
|
53
498
|
|
|
499
|
+
// Pre-configured instances for convenience
|
|
54
500
|
CacheFactory.local = CacheFactory({ type: 'local' });
|
|
55
501
|
CacheFactory.session = CacheFactory({ type: 'session' });
|
|
56
502
|
|
|
57
|
-
|
|
503
|
+
// Memory-only instance for testing or server-side use
|
|
504
|
+
CacheFactory.memory = CacheFactory({
|
|
505
|
+
type: 'session',
|
|
506
|
+
fallbackToMemory: true
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
export default CacheFactory;
|