Skip to content

Commit

Permalink
fix: dom-exception on access to localStorage (#999)
Browse files Browse the repository at this point in the history
* fix(dom-exception): delays access to localStorage to async api

* fix(dom-exception): memoize storage compution
  • Loading branch information
nunomaduro committed Feb 7, 2020
1 parent d862a91 commit 4d0c5ec
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,37 @@ describe('browser local storage cache', () => {
expect(localStorage.length).toBe(0);
});

it('do throws localstorage related exceptions', async () => {
it('do throws localstorage exceptions on access', async () => {
const message =
"Failed to read the 'localStorage' property from 'Window': Access is denied for this document.";

const cache = createBrowserLocalStorageCache(
new Proxy(
{ key: 'foo' },
{
get(_, key) {
if (key === 'key') {
return 'foo';
}

// Simulates a window.localStorage access.
throw new DOMException(message);
},
}
)
);
const key = { foo: 'bar' };
const value = 'foo';
const fallback = 'bar';

await expect(cache.delete(key)).rejects.toEqual(new DOMException(message));
await expect(cache.set(key, value)).rejects.toEqual(new DOMException(message));
await expect(cache.get(key, () => Promise.resolve(fallback))).rejects.toEqual(
new DOMException(message)
);
});

it('do throws localstorage exceptions after access', async () => {
const cache = createBrowserLocalStorageCache({
key: version,
localStorage: notAvailableStorage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@ import { Cache, CacheEvents } from '@algolia/cache-common';
import { BrowserLocalStorageOptions } from '.';

export function createBrowserLocalStorageCache(options: BrowserLocalStorageOptions): Cache {
const storage = options.localStorage || window.localStorage;
const namespaceKey = `algoliasearch-client-js-${options.key}`;

// eslint-disable-next-line functional/no-let
let storage: Storage;
const getStorage = () => {
if (storage === undefined) {
storage = options.localStorage || window.localStorage;
}

return storage;
};

const getNamespace = <TValue>(): Record<string, TValue> => {
return JSON.parse(storage.getItem(namespaceKey) || '{}');
return JSON.parse(getStorage().getItem(namespaceKey) || '{}');
};

return {
Expand Down Expand Up @@ -38,7 +47,7 @@ export function createBrowserLocalStorageCache(options: BrowserLocalStorageOptio
// eslint-disable-next-line functional/immutable-data
namespace[JSON.stringify(key)] = value;

storage.setItem(namespaceKey, JSON.stringify(namespace));
getStorage().setItem(namespaceKey, JSON.stringify(namespace));

return value;
});
Expand All @@ -51,13 +60,13 @@ export function createBrowserLocalStorageCache(options: BrowserLocalStorageOptio
// eslint-disable-next-line functional/immutable-data
delete namespace[JSON.stringify(key)];

storage.setItem(namespaceKey, JSON.stringify(namespace));
getStorage().setItem(namespaceKey, JSON.stringify(namespace));
});
},

clear(): Readonly<Promise<void>> {
return Promise.resolve().then(() => {
storage.removeItem(namespaceKey);
getStorage().removeItem(namespaceKey);
});
},
};
Expand Down

0 comments on commit 4d0c5ec

Please sign in to comment.