Skip to content

Commit

Permalink
fix(core): Check for storage initialization errors (#13938)
Browse files Browse the repository at this point in the history
* fix(core): Check for storage initialization errors

* address nits and add logger

* fixed unit test errors

* bundle size fixes

* implementing feedback

Co-authored-by: AllanZhengYP <[email protected]>

---------

Co-authored-by: AllanZhengYP <[email protected]>
  • Loading branch information
cwomack and AllanZhengYP authored Nov 8, 2024
1 parent 4458d30 commit 0f50917
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 13 deletions.
6 changes: 3 additions & 3 deletions packages/aws-amplify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@
"name": "[Analytics] record (Pinpoint)",
"path": "./dist/esm/analytics/index.mjs",
"import": "{ record }",
"limit": "17.41 kB"
"limit": "17.5 kB"
},
{
"name": "[Analytics] record (Kinesis)",
Expand All @@ -317,7 +317,7 @@
"name": "[Analytics] identifyUser (Pinpoint)",
"path": "./dist/esm/analytics/index.mjs",
"import": "{ identifyUser }",
"limit": "15.91 kB"
"limit": "15.95 kB"
},
{
"name": "[Analytics] enable",
Expand Down Expand Up @@ -497,7 +497,7 @@
"name": "[Storage] uploadData (S3)",
"path": "./dist/esm/storage/index.mjs",
"import": "{ uploadData }",
"limit": "20.08 kB"
"limit": "20.15 kB"
}
]
}
22 changes: 22 additions & 0 deletions packages/core/__tests__/storage/DefaultStorage.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DefaultStorage } from '../../src/storage/DefaultStorage';
import { InMemoryStorage } from '../../src/storage/InMemoryStorage';

const key = 'k';
const value = 'value';
Expand Down Expand Up @@ -35,4 +36,25 @@ describe('DefaultStorage', () => {
await defaultStorage.clear();
expect(defaultStorage.getItem(key)).resolves.toBeNull();
});

it('should fall back to alternative storage when localStorage is not accessible', async () => {
// Mock window.localStorage to throw an error
const originalLocalStorage = window.localStorage;

Object.defineProperty(window, 'localStorage', {
value: undefined,
writable: true,
});

// Create a new DefaultStorage instance to trigger the fallback
const fallbackStorage = new DefaultStorage();

// Verify that the storage still works as expected
expect(fallbackStorage.storage instanceof InMemoryStorage).toEqual(true);

// Restore the original localStorage
Object.defineProperty(window, 'localStorage', {
value: originalLocalStorage,
});
});
});
24 changes: 23 additions & 1 deletion packages/core/__tests__/storage/SessionStorage.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { InMemoryStorage } from '../../src/storage/InMemoryStorage';
import { SessionStorage } from '../../src/storage/SessionStorage';

const key = 'k';
const value = 'value';

describe('sessionStorage', () => {
describe('SessionStorage', () => {
let sessionStorage: SessionStorage;

beforeEach(() => {
Expand Down Expand Up @@ -37,4 +38,25 @@ describe('sessionStorage', () => {
await sessionStorage.clear();
expect(await sessionStorage.getItem(key)).toBeNull();
});

it('should fall back to alternative storage when sessionStorage is not accessible', async () => {
// Mock window.sessionStorage to throw an error
const originalSessionStorage = window.sessionStorage;

Object.defineProperty(window, 'sessionStorage', {
value: undefined,
writable: true,
});

// Create a new SessionStorage instance to trigger the fallback
const fallbackStorage = new SessionStorage();

// Verify that the storage still works as expected
expect(fallbackStorage.storage instanceof InMemoryStorage).toEqual(true);

// Restore the original sessionStorage
Object.defineProperty(window, 'sessionStorage', {
value: originalSessionStorage,
});
});
});
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"name": "Cache (default browser storage)",
"path": "./dist/esm/index.mjs",
"import": "{ Cache }",
"limit": "3.3 kB"
"limit": "3.4 kB"
}
],
"exports": {
Expand Down
45 changes: 37 additions & 8 deletions packages/core/src/storage/utils.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,51 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { ConsoleLogger } from '../Logger';

import { InMemoryStorage } from './InMemoryStorage';

/**
* @internal
* @returns Either a reference to window.localStorage or an in-memory storage as fallback
*/
export const getLocalStorageWithFallback = (): Storage =>
typeof window !== 'undefined' && window.localStorage
? window.localStorage
: new InMemoryStorage();

const logger = new ConsoleLogger('CoreStorageUtils');

export const getLocalStorageWithFallback = (): Storage => {
try {
// Attempt to use localStorage directly
if (typeof window !== 'undefined' && window.localStorage) {
return window.localStorage;
}
} catch (e) {
// Handle any errors related to localStorage access
logger.error('LocalStorage access failed:', e);
}

// Return in-memory storage as a fallback if localStorage is not accessible
return new InMemoryStorage();
};

/**
* @internal
* @returns Either a reference to window.sessionStorage or an in-memory storage as fallback
*/
export const getSessionStorageWithFallback = (): Storage =>
typeof window !== 'undefined' && window.sessionStorage
? window.sessionStorage
: new InMemoryStorage();
export const getSessionStorageWithFallback = (): Storage => {
try {
// Attempt to use sessionStorage directly
if (typeof window !== 'undefined' && window.sessionStorage) {
// Verify we can actually use it by testing access
window.sessionStorage.getItem('test');

return window.sessionStorage;
}

throw new Error('sessionStorage is not defined');
} catch (e) {
// Handle any errors related to sessionStorage access
logger.error('SessionStorage access failed:', e);

return new InMemoryStorage();
}
};

0 comments on commit 0f50917

Please sign in to comment.