Skip to content

Commit 1dfe9aa

Browse files
authored
fix: throw when storing data that can't be serialized in localStorage (#104)
1 parent 849782e commit 1dfe9aa

File tree

7 files changed

+51
-4
lines changed

7 files changed

+51
-4
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ Could happen to anyone:
240240

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

245246
Should only happen if data was corrupted or modified from outside of the lib:

projects/ngx-pwa/local-storage/src/lib/databases/exceptions.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,16 @@ export const IDB_BROKEN_ERROR = 'indexedDB is not working';
99
export class IDBBrokenError extends Error {
1010
message = IDB_BROKEN_ERROR;
1111
}
12+
13+
/**
14+
* Exception message when a value can't be serialized for `localStorage`
15+
*/
16+
export const SERIALIZATION_ERROR = `The storage is currently localStorage,
17+
where data must be serialized, and the provided data can't be serialized.`;
18+
19+
/**
20+
* Exception raised when a value can't be serialized for `localStorage`
21+
*/
22+
export class SerializationError extends Error {
23+
message = SERIALIZATION_ERROR;
24+
}

projects/ngx-pwa/local-storage/src/lib/databases/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ export { LocalDatabase } from './local-database';
22
export { IndexedDBDatabase } from './indexeddb-database';
33
export { LocalStorageDatabase } from './localstorage-database';
44
export { MemoryDatabase } from './memory-database';
5-
export { IDB_BROKEN_ERROR, IDBBrokenError } from './exceptions';
5+
export { IDB_BROKEN_ERROR, IDBBrokenError, SERIALIZATION_ERROR, SerializationError } from './exceptions';

projects/ngx-pwa/local-storage/src/lib/databases/localstorage-database.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { observeOn } from 'rxjs/operators';
44

55
import { LocalDatabase } from './local-database';
66
import { LOCAL_STORAGE_PREFIX, LS_PREFIX } from '../tokens';
7+
import { SerializationError } from './exceptions';
78

89
@Injectable({
910
providedIn: 'root'
@@ -87,6 +88,13 @@ export class LocalStorageDatabase implements LocalDatabase {
8788
return throwError(error as TypeError);
8889
}
8990

91+
/* Check if data can be serialized */
92+
const dataPrototype = Object.getPrototypeOf(data);
93+
if ((typeof data === 'object') && (data !== null) && !Array.isArray(data) &&
94+
!((dataPrototype === Object.prototype) || (dataPrototype === null))) {
95+
return throwError(new SerializationError());
96+
}
97+
9098
/* Can fail if storage quota is exceeded */
9199
try {
92100
localStorage.setItem(this.prefixKey(key), serializedData);

projects/ngx-pwa/local-storage/src/lib/storages/storage-map.service.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,31 @@ function tests(description: string, localStorageServiceFactory: () => StorageMap
222222

223223
});
224224

225+
it('blob', (done) => {
226+
227+
const value = new Blob();
228+
229+
// tslint:disable-next-line: no-string-literal
230+
const observer = (localStorageService['database'] instanceof LocalStorageDatabase) ?
231+
{
232+
next: () => {},
233+
error: () => {
234+
expect().nothing();
235+
done();
236+
}
237+
} : {
238+
next: (result: unknown) => {
239+
expect(result).toEqual(value);
240+
done();
241+
}
242+
};
243+
244+
localStorageService.set(key, value).pipe(
245+
mergeMap(() => localStorageService.get(key))
246+
).subscribe(observer);
247+
248+
});
249+
225250
it('update', (done) => {
226251

227252
localStorageService.set(key, 'value').pipe(

projects/ngx-pwa/local-storage/src/lib/validation/exceptions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/**
2-
* Exception message when a value is not valid against thr JSON schema
2+
* Exception message when a value is not valid against the JSON schema
33
*/
44
export const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.
55
Check your JSON schema, otherwise it means data has been corrupted.`;
66

77
/**
8-
* Exception raised when a value is not valid against thr JSON schema
8+
* Exception raised when a value is not valid against the JSON schema
99
*/
1010
export class ValidationError extends Error {
1111
message = VALIDATION_ERROR;

projects/ngx-pwa/local-storage/src/public_api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export {
1010
JSONSchemaNumeric, JSONSchemaString, JSONSchemaArray, JSONSchemaArrayOf, JSONSchemaObject,
1111
VALIDATION_ERROR, ValidationError
1212
} from './lib/validation';
13-
export { LocalDatabase } from './lib/databases';
13+
export { LocalDatabase, SERIALIZATION_ERROR, SerializationError } from './lib/databases';
1414
export { LocalStorage, StorageMap, LSGetItemOptions } from './lib/storages';
1515
export {
1616
localStorageProviders, LocalStorageProvidersConfig,

0 commit comments

Comments
 (0)