Skip to content

fix: throw when storing data that can't be serialized in localStorage #104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ Could happen to anyone:

Could only happen when in `localStorage` fallback:
- `.setItem()`: error in JSON serialization because of circular references (`TypeError`)
- `.setItem()`: trying to store data that can't be serialized like `Blob`, `Map` or `Set` (`SerializationError` from this lib)
- `.getItem()`: error in JSON unserialization (`SyntaxError`)

Should only happen if data was corrupted or modified from outside of the lib:
Expand Down
13 changes: 13 additions & 0 deletions projects/ngx-pwa/local-storage/src/lib/databases/exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,16 @@ export const IDB_BROKEN_ERROR = 'indexedDB is not working';
export class IDBBrokenError extends Error {
message = IDB_BROKEN_ERROR;
}

/**
* Exception message when a value can't be serialized for `localStorage`
*/
export const SERIALIZATION_ERROR = `The storage is currently localStorage,
where data must be serialized, and the provided data can't be serialized.`;

/**
* Exception raised when a value can't be serialized for `localStorage`
*/
export class SerializationError extends Error {
message = SERIALIZATION_ERROR;
}
2 changes: 1 addition & 1 deletion projects/ngx-pwa/local-storage/src/lib/databases/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ export { LocalDatabase } from './local-database';
export { IndexedDBDatabase } from './indexeddb-database';
export { LocalStorageDatabase } from './localstorage-database';
export { MemoryDatabase } from './memory-database';
export { IDB_BROKEN_ERROR, IDBBrokenError } from './exceptions';
export { IDB_BROKEN_ERROR, IDBBrokenError, SERIALIZATION_ERROR, SerializationError } from './exceptions';
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { observeOn } from 'rxjs/operators';

import { LocalDatabase } from './local-database';
import { LOCAL_STORAGE_PREFIX, LS_PREFIX } from '../tokens';
import { SerializationError } from './exceptions';

@Injectable({
providedIn: 'root'
Expand Down Expand Up @@ -87,6 +88,13 @@ export class LocalStorageDatabase implements LocalDatabase {
return throwError(error as TypeError);
}

/* Check if data can be serialized */
const dataPrototype = Object.getPrototypeOf(data);
if ((typeof data === 'object') && (data !== null) && !Array.isArray(data) &&
!((dataPrototype === Object.prototype) || (dataPrototype === null))) {
return throwError(new SerializationError());
}

/* Can fail if storage quota is exceeded */
try {
localStorage.setItem(this.prefixKey(key), serializedData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,31 @@ function tests(description: string, localStorageServiceFactory: () => StorageMap

});

it('blob', (done) => {

const value = new Blob();

// tslint:disable-next-line: no-string-literal
const observer = (localStorageService['database'] instanceof LocalStorageDatabase) ?
{
next: () => {},
error: () => {
expect().nothing();
done();
}
} : {
next: (result: unknown) => {
expect(result).toEqual(value);
done();
}
};

localStorageService.set(key, value).pipe(
mergeMap(() => localStorageService.get(key))
).subscribe(observer);

});

it('update', (done) => {

localStorageService.set(key, 'value').pipe(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/**
* Exception message when a value is not valid against thr JSON schema
* Exception message when a value is not valid against the JSON schema
*/
export const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.
Check your JSON schema, otherwise it means data has been corrupted.`;

/**
* Exception raised when a value is not valid against thr JSON schema
* Exception raised when a value is not valid against the JSON schema
*/
export class ValidationError extends Error {
message = VALIDATION_ERROR;
Expand Down
2 changes: 1 addition & 1 deletion projects/ngx-pwa/local-storage/src/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export {
JSONSchemaNumeric, JSONSchemaString, JSONSchemaArray, JSONSchemaArrayOf, JSONSchemaObject,
VALIDATION_ERROR, ValidationError
} from './lib/validation';
export { LocalDatabase } from './lib/databases';
export { LocalDatabase, SERIALIZATION_ERROR, SerializationError } from './lib/databases';
export { LocalStorage, StorageMap, LSGetItemOptions } from './lib/storages';
export {
localStorageProviders, LocalStorageProvidersConfig,
Expand Down