UNPKG

30.6 kBJavaScriptView Raw
1"use strict";
2// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3// SPDX-License-Identifier: Apache-2.0
4Object.defineProperty(exports, "__esModule", { value: true });
5var tslib_1 = require("tslib");
6var core_1 = require("@aws-amplify/core");
7var async_storage_1 = tslib_1.__importDefault(require("@react-native-async-storage/async-storage"));
8exports.AsyncStorage = async_storage_1.default;
9var StorageCache_1 = require("./StorageCache");
10var Utils_1 = require("./Utils");
11var logger = new core_1.ConsoleLogger('AsyncStorageCache');
12/*
13 * Customized cache which based on the AsyncStorage with LRU implemented
14 */
15var AsyncStorageCache = /** @class */ (function (_super) {
16 tslib_1.__extends(AsyncStorageCache, _super);
17 /**
18 * initialize the cache
19 *
20 * @param {Object} config - the configuration of the cache
21 */
22 function AsyncStorageCache(config) {
23 var _this = this;
24 var cache_config = config
25 ? Object.assign({}, Utils_1.defaultConfig, config)
26 : Utils_1.defaultConfig;
27 _this = _super.call(this, cache_config) || this;
28 _this.getItem = _this.getItem.bind(_this);
29 _this.setItem = _this.setItem.bind(_this);
30 _this.removeItem = _this.removeItem.bind(_this);
31 logger.debug('Using AsyncStorageCache');
32 return _this;
33 }
34 /**
35 * decrease current size of the cache
36 * @private
37 * @param amount - the amount of the cache size which needs to be decreased
38 */
39 AsyncStorageCache.prototype._decreaseCurSizeInBytes = function (amount) {
40 return tslib_1.__awaiter(this, void 0, void 0, function () {
41 var curSize;
42 return tslib_1.__generator(this, function (_a) {
43 switch (_a.label) {
44 case 0: return [4 /*yield*/, this.getCacheCurSize()];
45 case 1:
46 curSize = _a.sent();
47 return [4 /*yield*/, async_storage_1.default.setItem(this.cacheCurSizeKey, (curSize - amount).toString())];
48 case 2:
49 _a.sent();
50 return [2 /*return*/];
51 }
52 });
53 });
54 };
55 /**
56 * increase current size of the cache
57 * @private
58 * @param amount - the amount of the cache szie which need to be increased
59 */
60 AsyncStorageCache.prototype._increaseCurSizeInBytes = function (amount) {
61 return tslib_1.__awaiter(this, void 0, void 0, function () {
62 var curSize;
63 return tslib_1.__generator(this, function (_a) {
64 switch (_a.label) {
65 case 0: return [4 /*yield*/, this.getCacheCurSize()];
66 case 1:
67 curSize = _a.sent();
68 return [4 /*yield*/, async_storage_1.default.setItem(this.cacheCurSizeKey, (curSize + amount).toString())];
69 case 2:
70 _a.sent();
71 return [2 /*return*/];
72 }
73 });
74 });
75 };
76 /**
77 * update the visited time if item has been visited
78 * @private
79 * @param item - the item which need to be refreshed
80 * @param prefixedKey - the key of the item
81 *
82 * @return the refreshed item
83 */
84 AsyncStorageCache.prototype._refreshItem = function (item, prefixedKey) {
85 return tslib_1.__awaiter(this, void 0, void 0, function () {
86 return tslib_1.__generator(this, function (_a) {
87 switch (_a.label) {
88 case 0:
89 item.visitedTime = Utils_1.getCurrTime();
90 return [4 /*yield*/, async_storage_1.default.setItem(prefixedKey, JSON.stringify(item))];
91 case 1:
92 _a.sent();
93 return [2 /*return*/, item];
94 }
95 });
96 });
97 };
98 /**
99 * check wether item is expired
100 * @private
101 * @param key - the key of the item
102 *
103 * @return true if the item is expired.
104 */
105 AsyncStorageCache.prototype._isExpired = function (key) {
106 return tslib_1.__awaiter(this, void 0, void 0, function () {
107 var text, item;
108 return tslib_1.__generator(this, function (_a) {
109 switch (_a.label) {
110 case 0: return [4 /*yield*/, async_storage_1.default.getItem(key)];
111 case 1:
112 text = _a.sent();
113 item = JSON.parse(text);
114 if (Utils_1.getCurrTime() >= item.expires) {
115 return [2 /*return*/, true];
116 }
117 return [2 /*return*/, false];
118 }
119 });
120 });
121 };
122 /**
123 * delete item from cache
124 * @private
125 * @param prefixedKey - the key of the item
126 * @param size - optional, the byte size of the item
127 */
128 AsyncStorageCache.prototype._removeItem = function (prefixedKey, size) {
129 return tslib_1.__awaiter(this, void 0, void 0, function () {
130 var itemSize, _a, _b, _c, removeItemError_1;
131 return tslib_1.__generator(this, function (_d) {
132 switch (_d.label) {
133 case 0:
134 if (!size) return [3 /*break*/, 1];
135 _a = size;
136 return [3 /*break*/, 3];
137 case 1:
138 _c = (_b = JSON).parse;
139 return [4 /*yield*/, async_storage_1.default.getItem(prefixedKey)];
140 case 2:
141 _a = _c.apply(_b, [_d.sent()]).byteSize;
142 _d.label = 3;
143 case 3:
144 itemSize = _a;
145 // first try to update the current size of the cache
146 return [4 /*yield*/, this._decreaseCurSizeInBytes(itemSize)];
147 case 4:
148 // first try to update the current size of the cache
149 _d.sent();
150 _d.label = 5;
151 case 5:
152 _d.trys.push([5, 7, , 9]);
153 return [4 /*yield*/, async_storage_1.default.removeItem(prefixedKey)];
154 case 6:
155 _d.sent();
156 return [3 /*break*/, 9];
157 case 7:
158 removeItemError_1 = _d.sent();
159 // if some error happened, we need to rollback the current size
160 return [4 /*yield*/, this._increaseCurSizeInBytes(itemSize)];
161 case 8:
162 // if some error happened, we need to rollback the current size
163 _d.sent();
164 logger.error("Failed to remove item: " + removeItemError_1);
165 return [3 /*break*/, 9];
166 case 9: return [2 /*return*/];
167 }
168 });
169 });
170 };
171 /**
172 * put item into cache
173 * @private
174 * @param prefixedKey - the key of the item
175 * @param itemData - the value of the item
176 * @param itemSizeInBytes - the byte size of the item
177 */
178 AsyncStorageCache.prototype._setItem = function (prefixedKey, item) {
179 return tslib_1.__awaiter(this, void 0, void 0, function () {
180 var setItemErr_1;
181 return tslib_1.__generator(this, function (_a) {
182 switch (_a.label) {
183 case 0:
184 // first try to update the current size of the cache.
185 return [4 /*yield*/, this._increaseCurSizeInBytes(item.byteSize)];
186 case 1:
187 // first try to update the current size of the cache.
188 _a.sent();
189 _a.label = 2;
190 case 2:
191 _a.trys.push([2, 4, , 6]);
192 return [4 /*yield*/, async_storage_1.default.setItem(prefixedKey, JSON.stringify(item))];
193 case 3:
194 _a.sent();
195 return [3 /*break*/, 6];
196 case 4:
197 setItemErr_1 = _a.sent();
198 // if some error happened, we need to rollback the current size
199 return [4 /*yield*/, this._decreaseCurSizeInBytes(item.byteSize)];
200 case 5:
201 // if some error happened, we need to rollback the current size
202 _a.sent();
203 logger.error("Failed to set item " + setItemErr_1);
204 return [3 /*break*/, 6];
205 case 6: return [2 /*return*/];
206 }
207 });
208 });
209 };
210 /**
211 * total space needed when poping out items
212 * @private
213 * @param itemSize
214 *
215 * @return total space needed
216 */
217 AsyncStorageCache.prototype._sizeToPop = function (itemSize) {
218 return tslib_1.__awaiter(this, void 0, void 0, function () {
219 var spaceItemNeed, cacheThresholdSpace;
220 return tslib_1.__generator(this, function (_a) {
221 switch (_a.label) {
222 case 0: return [4 /*yield*/, this.getCacheCurSize()];
223 case 1:
224 spaceItemNeed = (_a.sent()) + itemSize - this.config.capacityInBytes;
225 cacheThresholdSpace = (1 - this.config.warningThreshold) * this.config.capacityInBytes;
226 return [2 /*return*/, spaceItemNeed > cacheThresholdSpace
227 ? spaceItemNeed
228 : cacheThresholdSpace];
229 }
230 });
231 });
232 };
233 /**
234 * see whether cache is full
235 * @private
236 * @param itemSize
237 *
238 * @return true if cache is full
239 */
240 AsyncStorageCache.prototype._isCacheFull = function (itemSize) {
241 return tslib_1.__awaiter(this, void 0, void 0, function () {
242 var _a;
243 return tslib_1.__generator(this, function (_b) {
244 switch (_b.label) {
245 case 0:
246 _a = itemSize;
247 return [4 /*yield*/, this.getCacheCurSize()];
248 case 1: return [2 /*return*/, (_a + (_b.sent()) > this.config.capacityInBytes)];
249 }
250 });
251 });
252 };
253 /**
254 * scan the storage and find out all the keys owned by this cache
255 * also clean the expired keys while scanning
256 * @private
257 * @return array of keys
258 */
259 AsyncStorageCache.prototype._findValidKeys = function () {
260 return tslib_1.__awaiter(this, void 0, void 0, function () {
261 var keys, keyInCache, i, key;
262 return tslib_1.__generator(this, function (_a) {
263 switch (_a.label) {
264 case 0:
265 keys = [];
266 return [4 /*yield*/, async_storage_1.default.getAllKeys()];
267 case 1:
268 keyInCache = _a.sent();
269 i = 0;
270 _a.label = 2;
271 case 2:
272 if (!(i < keyInCache.length)) return [3 /*break*/, 7];
273 key = keyInCache[i];
274 if (!(key.indexOf(this.config.keyPrefix) === 0 &&
275 key !== this.cacheCurSizeKey)) return [3 /*break*/, 6];
276 return [4 /*yield*/, this._isExpired(key)];
277 case 3:
278 if (!_a.sent()) return [3 /*break*/, 5];
279 return [4 /*yield*/, this._removeItem(key)];
280 case 4:
281 _a.sent();
282 return [3 /*break*/, 6];
283 case 5:
284 keys.push(key);
285 _a.label = 6;
286 case 6:
287 i += 1;
288 return [3 /*break*/, 2];
289 case 7: return [2 /*return*/, keys];
290 }
291 });
292 });
293 };
294 /**
295 * get all the items we have, sort them by their priority,
296 * if priority is same, sort them by their last visited time
297 * pop out items from the low priority (5 is the lowest)
298 * @private
299 * @param keys - all the keys in this cache
300 * @param sizeToPop - the total size of the items which needed to be poped out
301 */
302 AsyncStorageCache.prototype._popOutItems = function (keys, sizeToPop) {
303 return tslib_1.__awaiter(this, void 0, void 0, function () {
304 var items, remainedSize, i, val, item, i;
305 return tslib_1.__generator(this, function (_a) {
306 switch (_a.label) {
307 case 0:
308 items = [];
309 remainedSize = sizeToPop;
310 i = 0;
311 _a.label = 1;
312 case 1:
313 if (!(i < keys.length)) return [3 /*break*/, 4];
314 return [4 /*yield*/, async_storage_1.default.getItem(keys[i])];
315 case 2:
316 val = _a.sent();
317 if (val != null) {
318 item = JSON.parse(val);
319 items.push(item);
320 }
321 _a.label = 3;
322 case 3:
323 i += 1;
324 return [3 /*break*/, 1];
325 case 4:
326 // first compare priority
327 // then compare visited time
328 items.sort(function (a, b) {
329 if (a.priority > b.priority) {
330 return -1;
331 }
332 else if (a.priority < b.priority) {
333 return 1;
334 }
335 else {
336 if (a.visitedTime < b.visitedTime) {
337 return -1;
338 }
339 else
340 return 1;
341 }
342 });
343 i = 0;
344 _a.label = 5;
345 case 5:
346 if (!(i < items.length)) return [3 /*break*/, 8];
347 // pop out items until we have enough room for new item
348 return [4 /*yield*/, this._removeItem(items[i].key, items[i].byteSize)];
349 case 6:
350 // pop out items until we have enough room for new item
351 _a.sent();
352 remainedSize -= items[i].byteSize;
353 if (remainedSize <= 0) {
354 return [2 /*return*/];
355 }
356 _a.label = 7;
357 case 7:
358 i += 1;
359 return [3 /*break*/, 5];
360 case 8: return [2 /*return*/];
361 }
362 });
363 });
364 };
365 /**
366 * Set item into cache. You can put number, string, boolean or object.
367 * The cache will first check whether has the same key.
368 * If it has, it will delete the old item and then put the new item in
369 * The cache will pop out items if it is full
370 * You can specify the cache item options. The cache will abort and output a warning:
371 * If the key is invalid
372 * If the size of the item exceeds itemMaxSize.
373 * If the value is undefined
374 * If incorrect cache item configuration
375 * If error happened with browser storage
376 *
377 * @param {String} key - the key of the item
378 * @param {Object} value - the value of the item
379 * @param {Object} [options] - optional, the specified meta-data
380 * @return {Prmoise}
381 */
382 AsyncStorageCache.prototype.setItem = function (key, value, options) {
383 return tslib_1.__awaiter(this, void 0, void 0, function () {
384 var prefixedKey, cacheItemOptions, item, val, validKeys, sizeToPop, e_1;
385 return tslib_1.__generator(this, function (_a) {
386 switch (_a.label) {
387 case 0:
388 logger.debug("Set item: key is " + key + ", value is " + value + " with options: " + options);
389 prefixedKey = this.config.keyPrefix + key;
390 // invalid keys
391 if (prefixedKey === this.config.keyPrefix ||
392 prefixedKey === this.cacheCurSizeKey) {
393 logger.warn("Invalid key: should not be empty or 'CurSize'");
394 return [2 /*return*/];
395 }
396 if (typeof value === 'undefined') {
397 logger.warn("The value of item should not be undefined!");
398 return [2 /*return*/];
399 }
400 cacheItemOptions = {
401 priority: options && options.priority !== undefined
402 ? options.priority
403 : this.config.defaultPriority,
404 expires: options && options.expires !== undefined
405 ? options.expires
406 : this.config.defaultTTL + Utils_1.getCurrTime(),
407 };
408 if (cacheItemOptions.priority < 1 || cacheItemOptions.priority > 5) {
409 logger.warn("Invalid parameter: priority due to out or range. It should be within 1 and 5.");
410 return [2 /*return*/];
411 }
412 item = this.fillCacheItem(prefixedKey, value, cacheItemOptions);
413 // check wether this item is too big;
414 if (item.byteSize > this.config.itemMaxSize) {
415 logger.warn("Item with key: " + key + " you are trying to put into is too big!");
416 return [2 /*return*/];
417 }
418 _a.label = 1;
419 case 1:
420 _a.trys.push([1, 12, , 13]);
421 return [4 /*yield*/, async_storage_1.default.getItem(prefixedKey)];
422 case 2:
423 val = _a.sent();
424 if (!val) return [3 /*break*/, 4];
425 return [4 /*yield*/, this._removeItem(prefixedKey, JSON.parse(val).byteSize)];
426 case 3:
427 _a.sent();
428 _a.label = 4;
429 case 4: return [4 /*yield*/, this._isCacheFull(item.byteSize)];
430 case 5:
431 if (!_a.sent()) return [3 /*break*/, 10];
432 return [4 /*yield*/, this._findValidKeys()];
433 case 6:
434 validKeys = _a.sent();
435 return [4 /*yield*/, this._isCacheFull(item.byteSize)];
436 case 7:
437 if (!_a.sent()) return [3 /*break*/, 10];
438 return [4 /*yield*/, this._sizeToPop(item.byteSize)];
439 case 8:
440 sizeToPop = _a.sent();
441 return [4 /*yield*/, this._popOutItems(validKeys, sizeToPop)];
442 case 9:
443 _a.sent();
444 _a.label = 10;
445 case 10:
446 // put item in the cache
447 return [4 /*yield*/, this._setItem(prefixedKey, item)];
448 case 11:
449 // put item in the cache
450 _a.sent();
451 return [3 /*break*/, 13];
452 case 12:
453 e_1 = _a.sent();
454 logger.warn("setItem failed! " + e_1);
455 return [3 /*break*/, 13];
456 case 13: return [2 /*return*/];
457 }
458 });
459 });
460 };
461 /**
462 * Get item from cache. It will return null if item doesn’t exist or it has been expired.
463 * If you specified callback function in the options,
464 * then the function will be executed if no such item in the cache
465 * and finally put the return value into cache.
466 * Please make sure the callback function will return the value you want to put into the cache.
467 * The cache will abort output a warning:
468 * If the key is invalid
469 * If error happened with AsyncStorage
470 *
471 * @param {String} key - the key of the item
472 * @param {Object} [options] - the options of callback function
473 * @return {Promise} - return a promise resolves to be the value of the item
474 */
475 AsyncStorageCache.prototype.getItem = function (key, options) {
476 return tslib_1.__awaiter(this, void 0, void 0, function () {
477 var ret, prefixedKey, item, val, e_2;
478 return tslib_1.__generator(this, function (_a) {
479 switch (_a.label) {
480 case 0:
481 logger.debug("Get item: key is " + key + " with options " + options);
482 ret = null;
483 prefixedKey = this.config.keyPrefix + key;
484 if (prefixedKey === this.config.keyPrefix ||
485 prefixedKey === this.cacheCurSizeKey) {
486 logger.warn("Invalid key: should not be empty or 'CurSize'");
487 return [2 /*return*/, null];
488 }
489 _a.label = 1;
490 case 1:
491 _a.trys.push([1, 8, , 9]);
492 return [4 /*yield*/, async_storage_1.default.getItem(prefixedKey)];
493 case 2:
494 ret = _a.sent();
495 if (!(ret != null)) return [3 /*break*/, 7];
496 return [4 /*yield*/, this._isExpired(prefixedKey)];
497 case 3:
498 if (!_a.sent()) return [3 /*break*/, 5];
499 // if expired, remove that item and return null
500 return [4 /*yield*/, this._removeItem(prefixedKey, JSON.parse(ret).byteSize)];
501 case 4:
502 // if expired, remove that item and return null
503 _a.sent();
504 return [3 /*break*/, 7];
505 case 5:
506 item = JSON.parse(ret);
507 return [4 /*yield*/, this._refreshItem(item, prefixedKey)];
508 case 6:
509 item = _a.sent();
510 return [2 /*return*/, item.data];
511 case 7:
512 if (options && options.callback !== undefined) {
513 val = options.callback();
514 if (val !== null) {
515 this.setItem(key, val, options);
516 }
517 return [2 /*return*/, val];
518 }
519 return [2 /*return*/, null];
520 case 8:
521 e_2 = _a.sent();
522 logger.warn("getItem failed! " + e_2);
523 return [2 /*return*/, null];
524 case 9: return [2 /*return*/];
525 }
526 });
527 });
528 };
529 /**
530 * remove item from the cache
531 * The cache will abort output a warning:
532 * If error happened with AsyncStorage
533 * @param {String} key - the key of the item
534 * @return {Promise}
535 */
536 AsyncStorageCache.prototype.removeItem = function (key) {
537 return tslib_1.__awaiter(this, void 0, void 0, function () {
538 var prefixedKey, val, e_3;
539 return tslib_1.__generator(this, function (_a) {
540 switch (_a.label) {
541 case 0:
542 logger.debug("Remove item: key is " + key);
543 prefixedKey = this.config.keyPrefix + key;
544 if (prefixedKey === this.config.keyPrefix ||
545 prefixedKey === this.cacheCurSizeKey) {
546 return [2 /*return*/];
547 }
548 _a.label = 1;
549 case 1:
550 _a.trys.push([1, 5, , 6]);
551 return [4 /*yield*/, async_storage_1.default.getItem(prefixedKey)];
552 case 2:
553 val = _a.sent();
554 if (!val) return [3 /*break*/, 4];
555 return [4 /*yield*/, this._removeItem(prefixedKey, JSON.parse(val).byteSize)];
556 case 3:
557 _a.sent();
558 _a.label = 4;
559 case 4: return [3 /*break*/, 6];
560 case 5:
561 e_3 = _a.sent();
562 logger.warn("removeItem failed! " + e_3);
563 return [3 /*break*/, 6];
564 case 6: return [2 /*return*/];
565 }
566 });
567 });
568 };
569 /**
570 * clear the entire cache
571 * The cache will abort output a warning:
572 * If error happened with AsyncStorage
573 * @return {Promise}
574 */
575 AsyncStorageCache.prototype.clear = function () {
576 return tslib_1.__awaiter(this, void 0, void 0, function () {
577 var keys, keysToRemove, i, i, e_4;
578 return tslib_1.__generator(this, function (_a) {
579 switch (_a.label) {
580 case 0:
581 logger.debug("Clear Cache");
582 _a.label = 1;
583 case 1:
584 _a.trys.push([1, 7, , 8]);
585 return [4 /*yield*/, async_storage_1.default.getAllKeys()];
586 case 2:
587 keys = _a.sent();
588 keysToRemove = [];
589 for (i = 0; i < keys.length; i += 1) {
590 if (keys[i].indexOf(this.config.keyPrefix) === 0) {
591 keysToRemove.push(keys[i]);
592 }
593 }
594 i = 0;
595 _a.label = 3;
596 case 3:
597 if (!(i < keysToRemove.length)) return [3 /*break*/, 6];
598 return [4 /*yield*/, async_storage_1.default.removeItem(keysToRemove[i])];
599 case 4:
600 _a.sent();
601 _a.label = 5;
602 case 5:
603 i += 1;
604 return [3 /*break*/, 3];
605 case 6: return [3 /*break*/, 8];
606 case 7:
607 e_4 = _a.sent();
608 logger.warn("clear failed! " + e_4);
609 return [3 /*break*/, 8];
610 case 8: return [2 /*return*/];
611 }
612 });
613 });
614 };
615 /**
616 * return the current size of the cache
617 * @return {Promise}
618 */
619 AsyncStorageCache.prototype.getCacheCurSize = function () {
620 return tslib_1.__awaiter(this, void 0, void 0, function () {
621 var ret;
622 return tslib_1.__generator(this, function (_a) {
623 switch (_a.label) {
624 case 0: return [4 /*yield*/, async_storage_1.default.getItem(this.cacheCurSizeKey)];
625 case 1:
626 ret = _a.sent();
627 if (!!ret) return [3 /*break*/, 3];
628 return [4 /*yield*/, async_storage_1.default.setItem(this.cacheCurSizeKey, '0')];
629 case 2:
630 _a.sent();
631 ret = '0';
632 _a.label = 3;
633 case 3: return [2 /*return*/, Number(ret)];
634 }
635 });
636 });
637 };
638 /**
639 * Return all the keys in the cache.
640 * Will return an empty array if error happend.
641 * @return {Promise}
642 */
643 AsyncStorageCache.prototype.getAllKeys = function () {
644 return tslib_1.__awaiter(this, void 0, void 0, function () {
645 var keys, retKeys, i, e_5;
646 return tslib_1.__generator(this, function (_a) {
647 switch (_a.label) {
648 case 0:
649 _a.trys.push([0, 2, , 3]);
650 return [4 /*yield*/, async_storage_1.default.getAllKeys()];
651 case 1:
652 keys = _a.sent();
653 retKeys = [];
654 for (i = 0; i < keys.length; i += 1) {
655 if (keys[i].indexOf(this.config.keyPrefix) === 0 &&
656 keys[i] !== this.cacheCurSizeKey) {
657 retKeys.push(keys[i].substring(this.config.keyPrefix.length));
658 }
659 }
660 return [2 /*return*/, retKeys];
661 case 2:
662 e_5 = _a.sent();
663 logger.warn("getALlkeys failed! " + e_5);
664 return [2 /*return*/, []];
665 case 3: return [2 /*return*/];
666 }
667 });
668 });
669 };
670 /**
671 * Return a new instance of cache with customized configuration.
672 * @param {Object} config - the customized configuration
673 * @return {Object} - the new instance of Cache
674 */
675 AsyncStorageCache.prototype.createInstance = function (config) {
676 if (config.keyPrefix === Utils_1.defaultConfig.keyPrefix) {
677 logger.error('invalid keyPrefix, setting keyPrefix with timeStamp');
678 config.keyPrefix = Utils_1.getCurrTime.toString();
679 }
680 return new AsyncStorageCache(config);
681 };
682 return AsyncStorageCache;
683}(StorageCache_1.StorageCache));
684exports.AsyncStorageCache = AsyncStorageCache;
685var instance = new AsyncStorageCache();
686exports.Cache = instance;
687core_1.Amplify.register(instance);
688//# sourceMappingURL=AsyncStorageCache.js.map
\No newline at end of file