@ngx-pwa/local-storage 16.3.0 → 18.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +14 -15
  2. package/esm2022/lib/databases/exceptions.mjs +3 -3
  3. package/esm2022/lib/databases/indexeddb-database.mjs +16 -15
  4. package/esm2022/lib/databases/local-database.mjs +9 -11
  5. package/esm2022/lib/databases/localstorage-database.mjs +13 -13
  6. package/esm2022/lib/databases/memory-database.mjs +7 -7
  7. package/esm2022/lib/providers.mjs +21 -36
  8. package/esm2022/lib/storage.module.mjs +10 -9
  9. package/esm2022/lib/storages/exceptions.mjs +2 -2
  10. package/esm2022/lib/storages/storage-map.service.mjs +124 -77
  11. package/esm2022/lib/tokens.mjs +1 -1
  12. package/esm2022/lib/validation/json-schema.mjs +1 -1
  13. package/esm2022/lib/validation/json-validator.mjs +14 -18
  14. package/esm2022/ngx-pwa-local-storage.mjs +1 -1
  15. package/esm2022/public-api.mjs +1 -4
  16. package/fesm2022/ngx-pwa-local-storage.mjs +586 -635
  17. package/fesm2022/ngx-pwa-local-storage.mjs.map +1 -1
  18. package/lib/databases/exceptions.d.ts +2 -2
  19. package/lib/databases/indexeddb-database.d.ts +13 -16
  20. package/lib/databases/local-database.d.ts +1 -2
  21. package/lib/databases/localstorage-database.d.ts +3 -3
  22. package/lib/databases/memory-database.d.ts +2 -2
  23. package/lib/providers.d.ts +21 -36
  24. package/lib/storage.module.d.ts +6 -4
  25. package/lib/storages/exceptions.d.ts +1 -1
  26. package/lib/storages/storage-map.service.d.ts +100 -46
  27. package/lib/tokens.d.ts +7 -0
  28. package/lib/validation/json-schema.d.ts +11 -18
  29. package/lib/validation/json-validator.d.ts +9 -10
  30. package/package.json +4 -4
  31. package/public-api.d.ts +2 -5
  32. package/schematics/collection.json +1 -1
  33. package/schematics/migration.json +1 -1
  34. package/schematics/ng-add/index.d.ts +1 -1
  35. package/schematics/ng-add/index.js +4 -10
  36. package/schematics/ng-add/index.js.map +1 -1
  37. package/schematics/ng-update/index.d.ts +1 -1
  38. package/schematics/ng-update/index.js +1 -2
  39. package/schematics/ng-update/index.js.map +1 -1
  40. package/schematics/utility/config.js +2 -1
  41. package/schematics/utility/config.js.map +1 -1
  42. package/schematics/utility/module.d.ts +1 -1
  43. package/schematics/utility/module.js +1 -1
  44. package/schematics/utility/module.js.map +1 -1
  45. package/esm2022/lib/storages/local-storage.service.mjs +0 -85
  46. package/lib/storages/local-storage.service.d.ts +0 -99
@@ -1,8 +1,8 @@
1
- import { isPlatformBrowser } from '@angular/common';
2
1
  import * as i0 from '@angular/core';
3
- import { InjectionToken, inject, Injectable, PLATFORM_ID, makeEnvironmentProviders, NgModule } from '@angular/core';
4
- import { ReplaySubject, fromEvent, race, throwError, of, Observable, asyncScheduler, from } from 'rxjs';
5
- import { mergeMap, map, first, takeWhile, tap, observeOn, catchError } from 'rxjs/operators';
2
+ import { InjectionToken, makeEnvironmentProviders, NgModule, inject, Injectable, PLATFORM_ID } from '@angular/core';
3
+ import { of, throwError, Observable, asyncScheduler, from, ReplaySubject, fromEvent, race } from 'rxjs';
4
+ import { observeOn, mergeMap, map, first, takeWhile, tap, catchError } from 'rxjs/operators';
5
+ import { isPlatformBrowser } from '@angular/common';
6
6
 
7
7
  /**
8
8
  * Exception message when `indexedDB` is not working
@@ -18,12 +18,12 @@ class IDBBrokenError extends Error {
18
18
  }
19
19
  }
20
20
  /**
21
- * Exception message when a value can't be serialized for `localStorage`
21
+ * Exception message when a value cannot be serialized for `localStorage`
22
22
  */
23
23
  const SERIALIZATION_ERROR = `The storage is currently localStorage,
24
24
  where data must be serialized, and the provided data can't be serialized.`;
25
25
  /**
26
- * Exception raised when a value can't be serialized for `localStorage`
26
+ * Exception throwned when a value cannot be serialized for `localStorage`
27
27
  */
28
28
  class SerializationError extends Error {
29
29
  constructor() {
@@ -90,6 +90,406 @@ const IDB_NO_WRAP = new InjectionToken("localStorageIDBWrap", {
90
90
  factory: () => DEFAULT_IDB_NO_WRAP
91
91
  });
92
92
 
93
+ /**
94
+ * Allows to add a prefix before `localStorage` keys.
95
+ *
96
+ * *Use only* for interoperability with other APIs or to avoid collision for multiple applications on the same subdomain.
97
+ *
98
+ * **WARNING: do not change this option in an application already deployed in production, as previously stored data would be lost.**
99
+ *
100
+ * @example
101
+ * export const appConfig: ApplicationConfig = {
102
+ * providers: [provideLocalStoragePrefix('custom_')]
103
+ * };
104
+ */
105
+ function provideLocalStoragePrefix(prefix) {
106
+ return makeEnvironmentProviders([{ provide: LS_PREFIX, useValue: prefix }]);
107
+ }
108
+ /**
109
+ * Allows to change the name used for `indexedDB` database.
110
+ *
111
+ * *Use only* for interoperability with other APIs or to avoid collision for multiple applications on the same subdomain.
112
+ *
113
+ * **WARNING: do not change this option in an application already deployed in production, as previously stored data would be lost.**
114
+ *
115
+ * @example
116
+ * export const appConfig: ApplicationConfig = {
117
+ * providers: [provideIndexedDBDataBaseName('custom')]
118
+ * };
119
+ */
120
+ function provideIndexedDBDataBaseName(name) {
121
+ return makeEnvironmentProviders([{ provide: IDB_DB_NAME, useValue: name }]);
122
+ }
123
+ /**
124
+ * Allows to change the database version used for `indexedDB` database.
125
+ * Must be an unsigned **integer**.
126
+ *
127
+ * **Use with caution as the creation of the store depends on the version.**
128
+ *
129
+ * *Use only* for interoperability with other APIs or to avoid collision for multiple applications on the same subdomain.
130
+ *
131
+ * **WARNING: do not change this option in an applicattion already deployed in production, as previously stored data would be lost.**
132
+ *
133
+ * @example
134
+ * export const appConfig: ApplicationConfig = {
135
+ * providers: [provideIndexedDBDataBaseVersion(2)]
136
+ * };
137
+ */
138
+ function provideIndexedDBDataBaseVersion(version) {
139
+ return makeEnvironmentProviders([{ provide: IDB_DB_VERSION, useValue: version }]);
140
+ }
141
+ /**
142
+ * Allows to change the name used for `indexedDB` object store.
143
+ *
144
+ * *Use only* for interoperability with other APIs.
145
+ *
146
+ * **WARNING: do not change this option in an application already deployed in production, as previously stored data would be lost.**
147
+ *
148
+ * @example
149
+ * export const appConfig: ApplicationConfig = {
150
+ * providers: [provideIndexedDBStoreName('custom')]
151
+ * };
152
+ */
153
+ function provideIndexedDBStoreName(name) {
154
+ return makeEnvironmentProviders([{ provide: IDB_STORE_NAME, useValue: name }]);
155
+ }
156
+
157
+ /**
158
+ * This module is only here for backward compatibility, **do not add it by yourself**
159
+ *
160
+ * @ignore
161
+ */
162
+ class StorageModule {
163
+ /**
164
+ * Only useful to provide options, otherwise it does nothing.
165
+ *
166
+ * **Must be used at initialization, ie. in `AppModule`, and must not be loaded again in another module.**
167
+ */
168
+ static forRoot(config) {
169
+ return {
170
+ ngModule: StorageModule,
171
+ providers: [
172
+ config.LSPrefix ? { provide: LS_PREFIX, useValue: config.LSPrefix } : [],
173
+ config.IDBDBName ? { provide: IDB_DB_NAME, useValue: config.IDBDBName } : [],
174
+ config.IDBStoreName ? { provide: IDB_STORE_NAME, useValue: config.IDBStoreName } : [],
175
+ config.IDBDBVersion ? { provide: IDB_DB_VERSION, useValue: config.IDBDBVersion } : [],
176
+ (config.IDBNoWrap === false) ? { provide: IDB_NO_WRAP, useValue: config.IDBNoWrap } : [],
177
+ ],
178
+ };
179
+ }
180
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: StorageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
181
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.0.0", ngImport: i0, type: StorageModule }); }
182
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: StorageModule }); }
183
+ }
184
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: StorageModule, decorators: [{
185
+ type: NgModule
186
+ }] });
187
+
188
+ /**
189
+ * Exception message when a value is not valid against the JSON schema
190
+ */
191
+ const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.
192
+ Check your JSON schema, otherwise it means data has been corrupted.`;
193
+ /**
194
+ * Exception throwned when a value is not valid against the JSON schema
195
+ */
196
+ class ValidationError extends Error {
197
+ constructor() {
198
+ super(...arguments);
199
+ this.message = VALIDATION_ERROR;
200
+ }
201
+ }
202
+
203
+ class LocalStorageDatabase {
204
+ constructor() {
205
+ /* Prefix if asked, or no prefix otherwise */
206
+ this.prefix = inject(LS_PREFIX) || "";
207
+ }
208
+ /**
209
+ * Number of items in `localStorage`
210
+ */
211
+ get size() {
212
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
213
+ return of(localStorage.length);
214
+ }
215
+ /**
216
+ * Gets an item value in `localStorage`
217
+ * @param key The item's key
218
+ * @returns The item's value if the key exists, `undefined` otherwise, wrapped in a RxJS `Observable`
219
+ */
220
+ get(key) {
221
+ /* Get raw data */
222
+ const unparsedData = localStorage.getItem(this.prefixKey(key));
223
+ /* No need to parse if data is `null` or `undefined` */
224
+ if (unparsedData !== null) {
225
+ /* Try to parse */
226
+ try {
227
+ const parsedData = JSON.parse(unparsedData);
228
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
229
+ return of(parsedData);
230
+ }
231
+ catch (error) {
232
+ return throwError(() => error);
233
+ }
234
+ }
235
+ return of(undefined);
236
+ }
237
+ /**
238
+ * Store an item in `localStorage`
239
+ * @param key The item's key
240
+ * @param data The item's value
241
+ * @returns A RxJS `Observable` to wait the end of the operation
242
+ */
243
+ set(key, data) {
244
+ let serializedData = null;
245
+ /* Check if data can be serialized */
246
+ const dataPrototype = Object.getPrototypeOf(data);
247
+ if ((typeof data === "object") && (data !== null) && !Array.isArray(data) &&
248
+ !((dataPrototype === Object.prototype) || (dataPrototype === null))) {
249
+ return throwError(() => new SerializationError());
250
+ }
251
+ /* Try to stringify (can fail on circular references) */
252
+ try {
253
+ serializedData = JSON.stringify(data);
254
+ }
255
+ catch (error) {
256
+ return throwError(() => error);
257
+ }
258
+ /* Can fail if storage quota is exceeded */
259
+ try {
260
+ localStorage.setItem(this.prefixKey(key), serializedData);
261
+ }
262
+ catch (error) {
263
+ return throwError(() => error);
264
+ }
265
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
266
+ return of(undefined);
267
+ }
268
+ /**
269
+ * Deletes an item in `localStorage`
270
+ * @param key The item's key
271
+ * @returns A RxJS `Observable` to wait the end of the operation
272
+ */
273
+ delete(key) {
274
+ localStorage.removeItem(this.prefixKey(key));
275
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
276
+ return of(undefined);
277
+ }
278
+ /**
279
+ * Deletes all items in `localStorage`
280
+ * @returns A RxJS `Observable` to wait the end of the operation
281
+ */
282
+ clear() {
283
+ localStorage.clear();
284
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
285
+ return of(undefined);
286
+ }
287
+ /**
288
+ * Get all keys in `localStorage`
289
+ * Note the order of the keys may be inconsistent in Firefox
290
+ * @returns A RxJS `Observable` iterating on keys
291
+ */
292
+ keys() {
293
+ /* Create an `Observable` from keys */
294
+ return new Observable((subscriber) => {
295
+ /* Iteretate over all the indexes */
296
+ for (let index = 0; index < localStorage.length; index += 1) {
297
+ /* Cast as we are sure in this case the key is not `null` */
298
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Ensured by the logic
299
+ subscriber.next(this.getUnprefixedKey(index));
300
+ }
301
+ subscriber.complete();
302
+ }).pipe(
303
+ /* Required to work like other databases which are asynchronous */
304
+ observeOn(asyncScheduler));
305
+ }
306
+ /**
307
+ * Check if a key exists in `localStorage`
308
+ * @param key The item's key
309
+ * @returns A RxJS `Observable` telling if the key exists or not
310
+ */
311
+ has(key) {
312
+ /* Itérate over all indexes in storage */
313
+ for (let index = 0; index < localStorage.length; index += 1) {
314
+ if (key === this.getUnprefixedKey(index)) {
315
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
316
+ return of(true);
317
+ }
318
+ }
319
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
320
+ return of(false);
321
+ }
322
+ /**
323
+ * Get an unprefixed key
324
+ * @param index Index of the key
325
+ * @returns The unprefixed key name if exists, `null` otherwise
326
+ */
327
+ getUnprefixedKey(index) {
328
+ /* Get the key in storage: may have a prefix */
329
+ const prefixedKey = localStorage.key(index);
330
+ if (prefixedKey !== null) {
331
+ /* If no prefix, the key is already good, otherwrite strip the prefix */
332
+ return !this.prefix ? prefixedKey : prefixedKey.substring(this.prefix.length);
333
+ }
334
+ return null;
335
+ }
336
+ /**
337
+ * Add the prefix to a key
338
+ * @param key The key name
339
+ * @returns The prefixed key name
340
+ */
341
+ prefixKey(key) {
342
+ return `${this.prefix}${key}`;
343
+ }
344
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: LocalStorageDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
345
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: LocalStorageDatabase, providedIn: "root" }); }
346
+ }
347
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: LocalStorageDatabase, decorators: [{
348
+ type: Injectable,
349
+ args: [{
350
+ providedIn: "root"
351
+ }]
352
+ }], ctorParameters: () => [] });
353
+
354
+ class MemoryDatabase {
355
+ constructor() {
356
+ /**
357
+ * Memory storage
358
+ */
359
+ this.memoryStorage = new Map();
360
+ }
361
+ /**
362
+ * Number of items in memory
363
+ */
364
+ get size() {
365
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
366
+ return of(this.memoryStorage.size);
367
+ }
368
+ /**
369
+ * Gets an item value in memory
370
+ * @param key The item's key
371
+ * @returns The item's value if the key exists, `undefined` otherwise, wrapped in a RxJS `Observable`
372
+ */
373
+ get(key) {
374
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
375
+ return of(this.memoryStorage.get(key));
376
+ }
377
+ /**
378
+ * Sets an item in memory
379
+ * @param key The item's key
380
+ * @param data The item's value
381
+ * @returns A RxJS `Observable` to wait the end of the operation
382
+ */
383
+ set(key, data) {
384
+ this.memoryStorage.set(key, data);
385
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
386
+ return of(undefined);
387
+ }
388
+ /**
389
+ * Deletes an item in memory
390
+ * @param key The item's key
391
+ * @returns A RxJS `Observable` to wait the end of the operation
392
+ */
393
+ delete(key) {
394
+ this.memoryStorage.delete(key);
395
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
396
+ return of(undefined);
397
+ }
398
+ /**
399
+ * Deletes all items in memory
400
+ * @returns A RxJS `Observable` to wait the end of the operation
401
+ */
402
+ clear() {
403
+ this.memoryStorage.clear();
404
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
405
+ return of(undefined);
406
+ }
407
+ /**
408
+ * Get all keys in memory
409
+ * @returns A RxJS `Observable` iterating on keys
410
+ */
411
+ keys() {
412
+ /* Create an `Observable` from keys */
413
+ return from(this.memoryStorage.keys());
414
+ }
415
+ /**
416
+ * Check if a key exists in memory
417
+ * @param key Key name
418
+ * @returns a RxJS `Observable` telling if the key exists or not
419
+ */
420
+ has(key) {
421
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
422
+ return of(this.memoryStorage.has(key));
423
+ }
424
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: MemoryDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
425
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: MemoryDatabase, providedIn: "root" }); }
426
+ }
427
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: MemoryDatabase, decorators: [{
428
+ type: Injectable,
429
+ args: [{
430
+ providedIn: "root"
431
+ }]
432
+ }] });
433
+
434
+ /**
435
+ * Factory to create a storage according to browser support
436
+ * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/BROWSERS_SUPPORT.md}
437
+ */
438
+ function localDatabaseFactory() {
439
+ const platformId = inject(PLATFORM_ID);
440
+ /* When storage is fully disabled in browser (via the "Block all cookies" option),
441
+ * just trying to check `indexedDB` or `localStorage` variables causes a security exception.
442
+ * Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118
443
+ */
444
+ try {
445
+ // Do not explicit `window` here, as the global object is not the same in web workers
446
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- They can be undefined in some browsers scenarios
447
+ if (isPlatformBrowser(platformId) && (indexedDB !== undefined) && (indexedDB !== null) && ("open" in indexedDB)) {
448
+ /* Check:
449
+ * - if we are in a browser context (issue: server-side rendering)
450
+ * - it could exist but be `undefined` or `null`
451
+ * - it could exists but not having a working API
452
+ * Will be the case for:
453
+ * - All other browsers in normal mode
454
+ * - Chromium / Safari / Firefox private mode, but in this case, data will be swiped when the user leaves the app */
455
+ return new IndexedDBDatabase();
456
+ }
457
+ else if (isPlatformBrowser(platformId)
458
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- They can be undefined in some browsers scenarios
459
+ && (localStorage !== undefined) && (localStorage !== null) && ("getItem" in localStorage)) {
460
+ /* Check:
461
+ * - if we are in a browser context (issue: server-side rendering)
462
+ * - if `localStorage` exists (to be sure)
463
+ * - it could exists but not having a working API
464
+ * Will be the case for:
465
+ * - Safari cross-origin iframes, detected later in `IndexedDBDatabase.connect()`
466
+ * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/42}
467
+ */
468
+ return new LocalStorageDatabase();
469
+ }
470
+ }
471
+ catch {
472
+ // Nothing to do
473
+ }
474
+ /* Will be the case for:
475
+ * - In browsers if storage has been fully disabled (via the "Block all cookies" option)
476
+ * - Server-side rendering
477
+ * - All other non-browser context
478
+ */
479
+ return new MemoryDatabase();
480
+ }
481
+ class LocalDatabase {
482
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: LocalDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
483
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: LocalDatabase, providedIn: "root", useFactory: localDatabaseFactory }); }
484
+ }
485
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: LocalDatabase, decorators: [{
486
+ type: Injectable,
487
+ args: [{
488
+ providedIn: "root",
489
+ useFactory: localDatabaseFactory,
490
+ }]
491
+ }] });
492
+
93
493
  class IndexedDBDatabase {
94
494
  constructor() {
95
495
  /**
@@ -150,9 +550,9 @@ class IndexedDBDatabase {
150
550
  if ((request.result !== undefined) && (request.result !== null)) {
151
551
  /* Prior to v8, the value was wrapped in an `{ value: ...}` object */
152
552
  if (!this.noWrap && (typeof request.result === "object") && (this.wrapIndex in request.result) &&
153
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
553
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- Required by indexedDb behavior
154
554
  (request.result[this.wrapIndex] !== undefined) && (request.result[this.wrapIndex] !== null)) {
155
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
555
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- Required by indexedDb behavior
156
556
  return request.result[this.wrapIndex];
157
557
  }
158
558
  else {
@@ -242,13 +642,14 @@ class IndexedDBDatabase {
242
642
  /* Listen to success event */
243
643
  const success$ = fromEvent(request, "success").pipe(
244
644
  /* Stop the `Observable` when the cursor is `null` */
645
+ // eslint-disable-next-line rxjs/no-ignored-takewhile-value -- Required by indexedDb behavior, getting the result from the event does not always work
245
646
  takeWhile(() => (request.result !== null)),
246
647
  /* This lib only allows string keys, but user could have added other types of keys from outside
247
648
  * It's OK to cast as the cursor as been tested in the previous operator */
248
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
649
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-base-to-string -- Required by indexedDb behavior, and strings are enforced by the lib
249
650
  map(() => request.result.key.toString()),
250
651
  /* Iterate on the cursor */
251
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
652
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Required by indexedDb behavior
252
653
  tap(() => { request.result.continue(); }));
253
654
  /* Listen to error event and if so, throw an error */
254
655
  const error$ = this.listenError(request);
@@ -305,9 +706,9 @@ class IndexedDBDatabase {
305
706
  this.database.next(request.result);
306
707
  },
307
708
  error: () => {
308
- /* Firefox private mode issue: fallback storage if IndexedDb connection is failing
309
- * @see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=781982}
310
- * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/26} */
709
+ /* Keeping this error management for safety, but it should not happen anymore.
710
+ * It was for Firefox private mode issue in Firefox versions < 115
711
+ * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/26} */
311
712
  this.database.error(new IDBBrokenError());
312
713
  },
313
714
  });
@@ -335,477 +736,61 @@ class IndexedDBDatabase {
335
736
  * Open an `indexedDB` transaction and get our store
336
737
  * @param mode `readonly` or `readwrite`
337
738
  * @returns An `indexedDB` transaction store and events, wrapped in an RxJS `Observable`
338
- */
339
- transaction(mode) {
340
- /* From the `indexedDB` connection, open a transaction and get the store */
341
- return this.database
342
- .pipe(mergeMap((database) => {
343
- let transaction;
344
- try {
345
- transaction = database.transaction([this.storeName], mode);
346
- }
347
- catch (error) {
348
- /* The store could have been deleted from outside */
349
- return throwError(() => error);
350
- }
351
- /* Get the store from the transaction */
352
- const store = transaction.objectStore(this.storeName);
353
- /* Listen transaction `complete` and `error` events */
354
- const events = this.listenTransactionEvents(transaction);
355
- return of({ store, events });
356
- }));
357
- }
358
- /**
359
- * Listen errors on a transaction or request, and throw if trigerred
360
- * @param transactionOrRequest `indexedDb` transaction or request to listen
361
- * @returns An `Observable` listening to errors
362
- */
363
- listenError(transactionOrRequest) {
364
- return fromEvent(transactionOrRequest, "error").pipe(
365
- /* Throw on error to be able to catch errors in RxJS way.
366
- * Here `event.target` must be used, as `transactionOrRequest.error` will be `null`
367
- * if we are on the request and the error is only triggered later by the transaction */
368
- mergeMap((event) => throwError(() => event.target?.error)));
369
- }
370
- /**
371
- * Listen transaction `complete` and `error` events
372
- * @param transaction Transaction to listen
373
- * @returns An `Observable` listening to transaction `complete` and `error` events
374
- */
375
- listenTransactionEvents(transaction) {
376
- /* Listen to the `complete` event */
377
- const complete$ = fromEvent(transaction, "complete");
378
- /* Listen to the `error` event */
379
- const error$ = this.listenError(transaction);
380
- /* Choose the first event to occur */
381
- return race([complete$, error$]);
382
- }
383
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: IndexedDBDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
384
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: IndexedDBDatabase, providedIn: "root" }); }
385
- }
386
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: IndexedDBDatabase, decorators: [{
387
- type: Injectable,
388
- args: [{
389
- providedIn: "root"
390
- }]
391
- }], ctorParameters: function () { return []; } });
392
-
393
- class LocalStorageDatabase {
394
- constructor() {
395
- /* Prefix if asked, or no prefix otherwise */
396
- this.prefix = inject(LS_PREFIX) || "";
397
- }
398
- /**
399
- * Number of items in `localStorage`
400
- */
401
- get size() {
402
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
403
- return of(localStorage.length);
404
- }
405
- /**
406
- * Gets an item value in `localStorage`
407
- * @param key The item's key
408
- * @returns The item's value if the key exists, `undefined` otherwise, wrapped in a RxJS `Observable`
409
- */
410
- get(key) {
411
- /* Get raw data */
412
- const unparsedData = localStorage.getItem(this.prefixKey(key));
413
- let parsedData;
414
- /* No need to parse if data is `null` or `undefined` */
415
- if ((unparsedData !== undefined) && (unparsedData !== null)) {
416
- /* Try to parse */
417
- try {
418
- parsedData = JSON.parse(unparsedData);
419
- }
420
- catch (error) {
421
- return throwError(() => error);
422
- }
423
- }
424
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
425
- return of(parsedData);
426
- }
427
- /**
428
- * Store an item in `localStorage`
429
- * @param key The item's key
430
- * @param data The item's value
431
- * @returns A RxJS `Observable` to wait the end of the operation
432
- */
433
- set(key, data) {
434
- let serializedData = null;
435
- /* Check if data can be serialized */
436
- const dataPrototype = Object.getPrototypeOf(data);
437
- if ((typeof data === "object") && (data !== null) && !Array.isArray(data) &&
438
- !((dataPrototype === Object.prototype) || (dataPrototype === null))) {
439
- return throwError(() => new SerializationError());
440
- }
441
- /* Try to stringify (can fail on circular references) */
442
- try {
443
- serializedData = JSON.stringify(data);
444
- }
445
- catch (error) {
446
- return throwError(() => error);
447
- }
448
- /* Can fail if storage quota is exceeded */
449
- try {
450
- localStorage.setItem(this.prefixKey(key), serializedData);
451
- }
452
- catch (error) {
453
- return throwError(() => error);
454
- }
455
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
456
- return of(undefined);
457
- }
458
- /**
459
- * Deletes an item in `localStorage`
460
- * @param key The item's key
461
- * @returns A RxJS `Observable` to wait the end of the operation
462
- */
463
- delete(key) {
464
- localStorage.removeItem(this.prefixKey(key));
465
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
466
- return of(undefined);
467
- }
468
- /**
469
- * Deletes all items in `localStorage`
470
- * @returns A RxJS `Observable` to wait the end of the operation
471
- */
472
- clear() {
473
- localStorage.clear();
474
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
475
- return of(undefined);
476
- }
477
- /**
478
- * Get all keys in `localStorage`
479
- * Note the order of the keys may be inconsistent in Firefox
480
- * @returns A RxJS `Observable` iterating on keys
481
- */
482
- keys() {
483
- /* Create an `Observable` from keys */
484
- return new Observable((subscriber) => {
485
- /* Iteretate over all the indexes */
486
- for (let index = 0; index < localStorage.length; index += 1) {
487
- /* Cast as we are sure in this case the key is not `null` */
488
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
489
- subscriber.next(this.getUnprefixedKey(index));
490
- }
491
- subscriber.complete();
492
- }).pipe(
493
- /* Required to work like other databases which are asynchronous */
494
- observeOn(asyncScheduler));
495
- }
496
- /**
497
- * Check if a key exists in `localStorage`
498
- * @param key The item's key
499
- * @returns A RxJS `Observable` telling if the key exists or not
500
- */
501
- has(key) {
502
- /* Itérate over all indexes in storage */
503
- for (let index = 0; index < localStorage.length; index += 1) {
504
- if (key === this.getUnprefixedKey(index)) {
505
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
506
- return of(true);
507
- }
508
- }
509
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
510
- return of(false);
511
- }
512
- /**
513
- * Get an unprefixed key
514
- * @param index Index of the key
515
- * @returns The unprefixed key name if exists, `null` otherwise
516
- */
517
- getUnprefixedKey(index) {
518
- /* Get the key in storage: may have a prefix */
519
- const prefixedKey = localStorage.key(index);
520
- if (prefixedKey !== null) {
521
- /* If no prefix, the key is already good, otherwrite strip the prefix */
522
- return !this.prefix ? prefixedKey : prefixedKey.substring(this.prefix.length);
523
- }
524
- return null;
525
- }
526
- /**
527
- * Add the prefix to a key
528
- * @param key The key name
529
- * @returns The prefixed key name
530
- */
531
- prefixKey(key) {
532
- return `${this.prefix}${key}`;
533
- }
534
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorageDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
535
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorageDatabase, providedIn: "root" }); }
536
- }
537
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorageDatabase, decorators: [{
538
- type: Injectable,
539
- args: [{
540
- providedIn: "root"
541
- }]
542
- }], ctorParameters: function () { return []; } });
543
-
544
- class MemoryDatabase {
545
- constructor() {
546
- /**
547
- * Memory storage
548
- */
549
- this.memoryStorage = new Map();
550
- }
551
- /**
552
- * Number of items in memory
553
- */
554
- get size() {
555
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
556
- return of(this.memoryStorage.size);
557
- }
558
- /**
559
- * Gets an item value in memory
560
- * @param key The item's key
561
- * @returns The item's value if the key exists, `undefined` otherwise, wrapped in a RxJS `Observable`
562
- */
563
- get(key) {
564
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
565
- return of(this.memoryStorage.get(key));
566
- }
567
- /**
568
- * Sets an item in memory
569
- * @param key The item's key
570
- * @param data The item's value
571
- * @returns A RxJS `Observable` to wait the end of the operation
572
- */
573
- set(key, data) {
574
- this.memoryStorage.set(key, data);
575
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
576
- return of(undefined);
577
- }
578
- /**
579
- * Deletes an item in memory
580
- * @param key The item's key
581
- * @returns A RxJS `Observable` to wait the end of the operation
582
- */
583
- delete(key) {
584
- this.memoryStorage.delete(key);
585
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
586
- return of(undefined);
587
- }
588
- /**
589
- * Deletes all items in memory
590
- * @returns A RxJS `Observable` to wait the end of the operation
591
- */
592
- clear() {
593
- this.memoryStorage.clear();
594
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
595
- return of(undefined);
739
+ */
740
+ transaction(mode) {
741
+ /* From the `indexedDB` connection, open a transaction and get the store */
742
+ return this.database
743
+ .pipe(mergeMap((database) => {
744
+ let transaction;
745
+ try {
746
+ transaction = database.transaction([this.storeName], mode);
747
+ }
748
+ catch (error) {
749
+ /* The store could have been deleted from outside */
750
+ return throwError(() => error);
751
+ }
752
+ /* Get the store from the transaction */
753
+ const store = transaction.objectStore(this.storeName);
754
+ /* Listen transaction `complete` and `error` events */
755
+ const events = this.listenTransactionEvents(transaction);
756
+ return of({ store, events });
757
+ }));
596
758
  }
597
759
  /**
598
- * Get all keys in memory
599
- * @returns A RxJS `Observable` iterating on keys
760
+ * Listen errors on a transaction or request, and throw if trigerred
761
+ * @param transactionOrRequest `indexedDb` transaction or request to listen
762
+ * @returns An `Observable` listening to errors
600
763
  */
601
- keys() {
602
- /* Create an `Observable` from keys */
603
- return from(this.memoryStorage.keys());
764
+ listenError(transactionOrRequest) {
765
+ return fromEvent(transactionOrRequest, "error").pipe(
766
+ /* Throw on error to be able to catch errors in RxJS way.
767
+ * Here `event.target` must be used, as `transactionOrRequest.error` will be `null`
768
+ * if we are on the request and the error is only triggered later by the transaction */
769
+ mergeMap((event) => throwError(() => event.target?.error)));
604
770
  }
605
771
  /**
606
- * Check if a key exists in memory
607
- * @param key Key name
608
- * @returns a RxJS `Observable` telling if the key exists or not
772
+ * Listen transaction `complete` and `error` events
773
+ * @param transaction Transaction to listen
774
+ * @returns An `Observable` listening to transaction `complete` and `error` events
609
775
  */
610
- has(key) {
611
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
612
- return of(this.memoryStorage.has(key));
776
+ listenTransactionEvents(transaction) {
777
+ /* Listen to the `complete` event */
778
+ const complete$ = fromEvent(transaction, "complete");
779
+ /* Listen to the `error` event */
780
+ const error$ = this.listenError(transaction);
781
+ /* Choose the first event to occur */
782
+ return race([complete$, error$]);
613
783
  }
614
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MemoryDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
615
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MemoryDatabase, providedIn: "root" }); }
784
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: IndexedDBDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
785
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: IndexedDBDatabase, providedIn: "root" }); }
616
786
  }
617
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MemoryDatabase, decorators: [{
787
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: IndexedDBDatabase, decorators: [{
618
788
  type: Injectable,
619
789
  args: [{
620
790
  providedIn: "root"
621
791
  }]
622
- }] });
623
-
624
- /**
625
- * Factory to create a storage according to browser support
626
- * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/BROWSERS_SUPPORT.md}
627
- */
628
- function localDatabaseFactory() {
629
- const platformId = inject(PLATFORM_ID);
630
- /* When storage is fully disabled in browser (via the "Block all cookies" option),
631
- * just trying to check `indexedDB` or `localStorage` variables causes a security exception.
632
- * Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118
633
- */
634
- try {
635
- // Do not explicit `window` here, as the global object is not the same in web workers
636
- if (isPlatformBrowser(platformId) && (indexedDB !== undefined) && (indexedDB !== null) && ("open" in indexedDB)) {
637
- /* Check:
638
- * - if we are in a browser context (issue: server-side rendering)
639
- * - it could exist but be `undefined` or `null`
640
- * - it could exists but not having a working API
641
- * Will be the case for:
642
- * - All other browsers in normal mode
643
- * - Chromium / Safari private mode, but in this case, data will be swiped when the user leaves the app */
644
- return new IndexedDBDatabase();
645
- }
646
- else if (isPlatformBrowser(platformId)
647
- && (localStorage !== undefined) && (localStorage !== null) && ("getItem" in localStorage)) {
648
- /* Check:
649
- * - if we are in a browser context (issue: server-side rendering)
650
- * - if `localStorage` exists (to be sure)
651
- * - it could exists but not having a working API
652
- * Will be the case for:
653
- * - Safari cross-origin iframes, detected later in `IndexedDBDatabase.connect()`
654
- * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/42}
655
- * - Firefox private mode, but in this case, data will be swiped when the user leaves the app
656
- * For Firefox, can only be detected later in `IndexedDBDatabase.connect()`
657
- * @see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=781982}
658
- */
659
- return new LocalStorageDatabase();
660
- }
661
- }
662
- catch {
663
- // Nothing to do
664
- }
665
- /* Will be the case for:
666
- * - In browsers if storage has been fully disabled (via the "Block all cookies" option)
667
- * - Server-side rendering
668
- * - All other non-browser context
669
- */
670
- return new MemoryDatabase();
671
- }
672
- /** @deprecated Will be removed in v17 */
673
- class LocalDatabase {
674
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
675
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalDatabase, providedIn: "root", useFactory: localDatabaseFactory }); }
676
- }
677
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalDatabase, decorators: [{
678
- type: Injectable,
679
- args: [{
680
- providedIn: "root",
681
- useFactory: localDatabaseFactory,
682
- }]
683
- }] });
684
-
685
- /**
686
- * Allows to add a prefix before `localStorage` keys.
687
- * *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
688
- * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
689
- *
690
- * @example
691
- * bootstrapApplication(AppComponent, {
692
- * providers: [provideLocalStoragePrefix('custom_')]
693
- * });
694
- *
695
- * @example
696
- * NgModule({
697
- * providers: [provideLocalStoragePrefix('custom_')]
698
- * })
699
- * export class AppModule
700
- */
701
- function provideLocalStoragePrefix(prefix) {
702
- return makeEnvironmentProviders([{ provide: LS_PREFIX, useValue: prefix }]);
703
- }
704
- /**
705
- * Allows to change the name used for `indexedDB` database.
706
- * *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
707
- * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
708
- *
709
- * @example
710
- * bootstrapApplication(AppComponent, {
711
- * providers: [provideIndexedDBDataBaseName('custom')]
712
- * });
713
- *
714
- * @example
715
- * NgModule({
716
- * providers: [provideIndexedDBDataBaseName('custom')]
717
- * })
718
- * export class AppModule
719
- */
720
- function provideIndexedDBDataBaseName(name) {
721
- return makeEnvironmentProviders([{ provide: IDB_DB_NAME, useValue: name }]);
722
- }
723
- /**
724
- * Allows to change the database version used for `indexedDB` database.
725
- * Must be an unsigned **integer**.
726
- * **Use with caution as the creation of the store depends on the version.**
727
- * *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
728
- * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
729
- *
730
- * @example
731
- * bootstrapApplication(AppComponent, {
732
- * providers: [provideIndexedDBDataBaseVersion(2)]
733
- * });
734
- *
735
- * @example
736
- * NgModule({
737
- * providers: [provideIndexedDBDataBaseVersion(2)]
738
- * })
739
- * export class AppModule
740
- */
741
- function provideIndexedDBDataBaseVersion(version) {
742
- return makeEnvironmentProviders([{ provide: IDB_DB_VERSION, useValue: version }]);
743
- }
744
- /**
745
- * Allows to change the name used for `indexedDB` object store.
746
- * *Use only* for interoperability with other APIs.
747
- * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
748
- *
749
- * @example
750
- * bootstrapApplication(AppComponent, {
751
- * providers: [provideIndexedDBStoreName('custom')]
752
- * });
753
- *
754
- * @example
755
- * NgModule({
756
- * providers: [provideIndexedDBStoreName('custom')]
757
- * })
758
- * export class AppModule
759
- */
760
- function provideIndexedDBStoreName(name) {
761
- return makeEnvironmentProviders([{ provide: IDB_STORE_NAME, useValue: name }]);
762
- }
763
-
764
- /**
765
- * This module is only here for backward compatibility, do not add it by yourself
766
- */
767
- class StorageModule {
768
- /**
769
- * Only useful to provide options, otherwise it does nothing.
770
- * **Must be used at initialization, ie. in `AppModule`, and must not be loaded again in another module.**
771
- *
772
- */
773
- static forRoot(config) {
774
- return {
775
- ngModule: StorageModule,
776
- providers: [
777
- config.LSPrefix ? { provide: LS_PREFIX, useValue: config.LSPrefix } : [],
778
- config.IDBDBName ? { provide: IDB_DB_NAME, useValue: config.IDBDBName } : [],
779
- config.IDBStoreName ? { provide: IDB_STORE_NAME, useValue: config.IDBStoreName } : [],
780
- config.IDBDBVersion ? { provide: IDB_DB_VERSION, useValue: config.IDBDBVersion } : [],
781
- (config.IDBNoWrap === false) ? { provide: IDB_NO_WRAP, useValue: config.IDBNoWrap } : [],
782
- ],
783
- };
784
- }
785
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
786
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.0", ngImport: i0, type: StorageModule }); }
787
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule }); }
788
- }
789
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule, decorators: [{
790
- type: NgModule
791
- }] });
792
-
793
- /**
794
- * Exception message when a value is not valid against the JSON schema
795
- */
796
- const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.
797
- Check your JSON schema, otherwise it means data has been corrupted.`;
798
- /**
799
- * Exception raised when a value is not valid against the JSON schema
800
- */
801
- class ValidationError extends Error {
802
- constructor() {
803
- super(...arguments);
804
- this.message = VALIDATION_ERROR;
805
- }
806
- }
792
+ }], ctorParameters: () => [] });
807
793
 
808
- /** @deprecated Will be removed in v17 */
809
794
  class JSONValidator {
810
795
  /**
811
796
  * Validate a JSON data against a Jsubset of the JSON Schema standard.
@@ -853,16 +838,15 @@ class JSONValidator {
853
838
  return false;
854
839
  }
855
840
  if (schema.pattern) {
856
- let regularExpression = null;
857
841
  try {
858
- regularExpression = new RegExp(schema.pattern);
842
+ const regularExpression = new RegExp(schema.pattern);
843
+ if (!regularExpression.test(data)) {
844
+ return false;
845
+ }
859
846
  }
860
847
  catch {
861
848
  // Nothing to do
862
849
  }
863
- if (regularExpression && !regularExpression.test(data)) {
864
- return false;
865
- }
866
850
  }
867
851
  return true;
868
852
  }
@@ -969,9 +953,8 @@ class JSONValidator {
969
953
  return false;
970
954
  }
971
955
  if (schemas) {
972
- for (let i = 0; i < schemas.length; i += 1) {
973
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
974
- if (!this.validate(data[i], schemas[i])) {
956
+ for (const [index, schema] of schemas.entries()) {
957
+ if (!this.validate(data[index], schema)) {
975
958
  return false;
976
959
  }
977
960
  }
@@ -998,7 +981,7 @@ class JSONValidator {
998
981
  /* Validate required properties */
999
982
  if (schema.required) {
1000
983
  for (const requiredProp of schema.required) {
1001
- if (!Object.prototype.hasOwnProperty.call(data, requiredProp)) {
984
+ if (!Object.hasOwn(data, requiredProp)) {
1002
985
  return false;
1003
986
  }
1004
987
  }
@@ -1006,8 +989,8 @@ class JSONValidator {
1006
989
  /* Recursively validate all properties */
1007
990
  for (const property in schema.properties) {
1008
991
  /* Filter to keep only real properties (no internal JS stuff) and check if the data has the property too */
1009
- if (Object.prototype.hasOwnProperty.call(schema.properties, property) && Object.prototype.hasOwnProperty.call(data, property)) {
1010
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
992
+ if (Object.hasOwn(schema.properties, property) && Object.hasOwn(data, property)) {
993
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Ensured by the logic
1011
994
  if (!this.validate(data[property], schema.properties[property])) {
1012
995
  return false;
1013
996
  }
@@ -1040,10 +1023,10 @@ class JSONValidator {
1040
1023
  /* Cast as the data can be of multiple types, and so TypeScript is lost */
1041
1024
  return (schema.enum.includes(data));
1042
1025
  }
1043
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1044
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, providedIn: "root" }); }
1026
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: JSONValidator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1027
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: JSONValidator, providedIn: "root" }); }
1045
1028
  }
1046
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, decorators: [{
1029
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: JSONValidator, decorators: [{
1047
1030
  type: Injectable,
1048
1031
  args: [{
1049
1032
  providedIn: "root"
@@ -1051,19 +1034,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
1051
1034
  }] });
1052
1035
 
1053
1036
  class StorageMap {
1037
+ #database;
1038
+ #jsonValidator;
1039
+ #notifiers = new Map();
1054
1040
  /**
1055
1041
  * Constructor params are provided by Angular (but can also be passed manually in tests)
1056
1042
  * @param database Storage to use
1057
- * @param jsonValidator Validator service
1058
- * @param LSPrefix Prefix for `localStorage` keys to avoid collision for multiple apps on the same subdomain or for interoperability
1059
1043
  */
1060
- constructor(database, jsonValidator = new JSONValidator()) {
1061
- this.database = database;
1062
- this.jsonValidator = jsonValidator;
1063
- this.notifiers = new Map();
1044
+ constructor(database) {
1045
+ this.#database = database;
1046
+ this.#jsonValidator = new JSONValidator();
1064
1047
  }
1065
1048
  /**
1066
- * **Number of items** in storage, wrapped in an `Observable`.
1049
+ * **Number of items** in storage, wrapped in an Observable.
1050
+ *
1051
+ * Note you do *not* need to unsubscribe (it is a self-completing Observable).
1067
1052
  *
1068
1053
  * @example
1069
1054
  * this.storageMap.size.subscribe((size) => {
@@ -1071,14 +1056,17 @@ class StorageMap {
1071
1056
  * });
1072
1057
  */
1073
1058
  get size() {
1074
- return this.database.size
1059
+ return this.#database.size
1075
1060
  /* Catch if `indexedDb` is broken */
1076
- .pipe(this.catchIDBBroken(() => this.database.size));
1061
+ .pipe(this.#catchIDBBroken(() => this.#database.size));
1077
1062
  }
1078
1063
  /**
1079
- * Tells you which storage engine is used. *Only useful for interoperability.*
1064
+ * Tells you which storage engine is used.
1065
+ *
1066
+ * *Only useful for interoperability.*
1067
+ *
1080
1068
  * Note that due to some browsers issues in some special contexts
1081
- * (Firefox private mode and Safari cross-origin iframes),
1069
+ * (like Safari cross-origin iframes),
1082
1070
  * **this information may be wrong at initialization,**
1083
1071
  * as the storage could fallback from `indexedDB` to `localStorage`
1084
1072
  * only after a first read or write operation.
@@ -1090,13 +1078,13 @@ class StorageMap {
1090
1078
  * if (this.storageMap.backingEngine === 'indexedDB') {}
1091
1079
  */
1092
1080
  get backingEngine() {
1093
- if (this.database instanceof IndexedDBDatabase) {
1081
+ if (this.#database instanceof IndexedDBDatabase) {
1094
1082
  return "indexedDB";
1095
1083
  }
1096
- else if (this.database instanceof LocalStorageDatabase) {
1084
+ else if (this.#database instanceof LocalStorageDatabase) {
1097
1085
  return "localStorage";
1098
1086
  }
1099
- else if (this.database instanceof MemoryDatabase) {
1087
+ else if (this.#database instanceof MemoryDatabase) {
1100
1088
  return "memory";
1101
1089
  }
1102
1090
  else {
@@ -1104,10 +1092,12 @@ class StorageMap {
1104
1092
  }
1105
1093
  }
1106
1094
  /**
1107
- * Info about `indexedDB` database. *Only useful for interoperability.*
1095
+ * Information about `indexedDB` database.
1096
+ *
1097
+ * *Only useful for interoperability.*
1098
+ *
1108
1099
  * @returns `indexedDB` database name, store name and database version.
1109
- * **Values will be empty if the storage is not `indexedDB`,**
1110
- * **so it should be used after an engine check**.
1100
+ * **Values will be empty if the storage is not `indexedDB`, so it should be used after an engine check**.
1111
1101
  *
1112
1102
  * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/INTEROPERABILITY.md}
1113
1103
  *
@@ -1117,15 +1107,17 @@ class StorageMap {
1117
1107
  * }
1118
1108
  */
1119
1109
  get backingStore() {
1120
- return (this.database instanceof IndexedDBDatabase) ?
1121
- this.database.backingStore :
1110
+ return (this.#database instanceof IndexedDBDatabase) ?
1111
+ this.#database.backingStore :
1122
1112
  { database: "", store: "", version: 0 };
1123
1113
  }
1124
1114
  /**
1125
- * Info about `localStorage` fallback storage. *Only useful for interoperability.*
1115
+ * Information about `localStorage` fallback storage.
1116
+ *
1117
+ * *Only useful for interoperability.*
1118
+ *
1126
1119
  * @returns `localStorage` prefix.
1127
- * **Values will be empty if the storage is not `localStorage`,**
1128
- * **so it should be used after an engine check**.
1120
+ * **Values will be empty if the storage is not `localStorage`, so it should be used after an engine check**.
1129
1121
  *
1130
1122
  * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/INTEROPERABILITY.md}
1131
1123
  *
@@ -1135,22 +1127,22 @@ class StorageMap {
1135
1127
  * }
1136
1128
  */
1137
1129
  get fallbackBackingStore() {
1138
- return (this.database instanceof LocalStorageDatabase) ?
1139
- { prefix: this.database.prefix } :
1130
+ return (this.#database instanceof LocalStorageDatabase) ?
1131
+ { prefix: this.#database.prefix } :
1140
1132
  { prefix: "" };
1141
1133
  }
1142
1134
  get(key, schema) {
1143
1135
  /* Get the data in storage */
1144
- return this.database.get(key).pipe(
1136
+ return this.#database.get(key).pipe(
1145
1137
  /* Check if `indexedDb` is broken */
1146
- this.catchIDBBroken(() => this.database.get(key)), mergeMap((data) => {
1138
+ this.#catchIDBBroken(() => this.#database.get(key)), mergeMap((data) => {
1147
1139
  /* No need to validate if the data is empty */
1148
1140
  if ((data === undefined) || (data === null)) {
1149
1141
  return of(undefined);
1150
1142
  }
1151
1143
  else if (schema) {
1152
1144
  /* Validate data against a JSON schema if provided */
1153
- if (!this.jsonValidator.validate(data, schema)) {
1145
+ if (!this.#jsonValidator.validate(data, schema)) {
1154
1146
  return throwError(() => new ValidationError());
1155
1147
  }
1156
1148
  /* Data have been checked, so it's OK to cast */
@@ -1161,12 +1153,19 @@ class StorageMap {
1161
1153
  }));
1162
1154
  }
1163
1155
  /**
1164
- * Set an item in storage.
1165
- * Note that setting `null` or `undefined` will remove the item to avoid some browsers issues.
1156
+ * Store an item in storage.
1157
+ *
1158
+ * Note that:
1159
+ * * you *do* need to subscribe, even if you do not have something specific to do after writing in storage, otherwise nothing happens (because it is how RxJS Observables work),
1160
+ * * but you do *not* need to unsubscribe (it is a self-completing Observable),
1161
+ * * setting `null` or `undefined` will remove the item to avoid some browsers issues,
1162
+ * * you should stick to serializable JSON data, meaning primitive types, arrays and literal objects. Date, Map, Set, Blob and other special structures can cause issues in some scenarios.
1163
+ * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/SERIALIZATION.md}
1164
+ *
1166
1165
  * @param key The item's key
1167
1166
  * @param data The item's value
1168
1167
  * @param schema Optional JSON schema to validate the data
1169
- * @returns A RxJS `Observable` to wait the end of the operation
1168
+ * @returns A RxJS Observable to wait the end of the operation
1170
1169
  *
1171
1170
  * @example
1172
1171
  * this.storageMap.set('key', 'value').subscribe(() => {});
@@ -1178,54 +1177,68 @@ class StorageMap {
1178
1177
  return this.delete(key);
1179
1178
  }
1180
1179
  /* Validate data against a JSON schema if provided */
1181
- if (schema && !this.jsonValidator.validate(data, schema)) {
1180
+ if (schema && !this.#jsonValidator.validate(data, schema)) {
1182
1181
  return throwError(() => new ValidationError());
1183
1182
  }
1184
- return this.database.set(key, data).pipe(
1183
+ return this.#database.set(key, data).pipe(
1185
1184
  /* Catch if `indexedDb` is broken */
1186
- this.catchIDBBroken(() => this.database.set(key, data)),
1185
+ this.#catchIDBBroken(() => this.#database.set(key, data)),
1187
1186
  /* Notify watchers (must be last because it should only happen if the operation succeeds) */
1188
- tap(() => { this.notify(key, data); }));
1187
+ tap(() => { this.#notify(key, data); }));
1189
1188
  }
1190
1189
  /**
1191
- * Delete an item in storage
1190
+ * Delete an item in storage.
1191
+ *
1192
+ * Note that:
1193
+ * * you *do* need to subscribe, even if you do not have something specific to do after deleting, otherwise nothing happens (because it is how RxJS Observables work),
1194
+ * * but you do *not* need to unsubscribe (it is a self-completing Observable).
1195
+ *
1192
1196
  * @param key The item's key
1193
- * @returns A RxJS `Observable` to wait the end of the operation
1197
+ * @returns A RxJS Observable to wait the end of the operation
1194
1198
  *
1195
1199
  * @example
1196
1200
  * this.storageMap.delete('key').subscribe(() => {});
1197
1201
  */
1198
1202
  delete(key) {
1199
- return this.database.delete(key).pipe(
1203
+ return this.#database.delete(key).pipe(
1200
1204
  /* Catch if `indexedDb` is broken */
1201
- this.catchIDBBroken(() => this.database.delete(key)),
1205
+ this.#catchIDBBroken(() => this.#database.delete(key)),
1202
1206
  /* Notify watchers (must be last because it should only happen if the operation succeeds) */
1203
- tap(() => { this.notify(key, undefined); }));
1207
+ tap(() => { this.#notify(key, undefined); }));
1204
1208
  }
1205
1209
  /**
1206
- * Delete all items in storage
1207
- * @returns A RxJS `Observable` to wait the end of the operation
1210
+ * Delete all items in storage.
1211
+ *
1212
+ * Note that:
1213
+ * * you *do* need to subscribe, even if you do not have something specific to do after clearing, otherwise nothing happens (because it is how RxJS Observables work),
1214
+ * * but you do *not* need to unsubscribe (it is a self-completing Observable).
1215
+ *
1216
+ * @returns A RxJS Observable to wait the end of the operation
1208
1217
  *
1209
1218
  * @example
1210
1219
  * this.storageMap.clear().subscribe(() => {});
1211
1220
  */
1212
1221
  clear() {
1213
- return this.database.clear().pipe(
1222
+ return this.#database.clear().pipe(
1214
1223
  /* Catch if `indexedDb` is broken */
1215
- this.catchIDBBroken(() => this.database.clear()),
1224
+ this.#catchIDBBroken(() => this.#database.clear()),
1216
1225
  /* Notify watchers (must be last because it should only happen if the operation succeeds) */
1217
1226
  tap(() => {
1218
- for (const key of this.notifiers.keys()) {
1219
- this.notify(key, undefined);
1227
+ for (const key of this.#notifiers.keys()) {
1228
+ this.#notify(key, undefined);
1220
1229
  }
1221
1230
  }));
1222
1231
  }
1223
1232
  /**
1224
- * Get all keys stored in storage. Note **this is an *iterating* `Observable`**:
1233
+ * Get all keys stored in storage.
1234
+ *
1235
+ * Note **this is an *iterating* Observable**:
1225
1236
  * * if there is no key, the `next` callback will not be invoked,
1226
1237
  * * if you need to wait the whole operation to end, be sure to act in the `complete` callback,
1227
- * as this `Observable` can emit several values and so will invoke the `next` callback several times.
1228
- * @returns A list of the keys wrapped in a RxJS `Observable`
1238
+ * as this Observable can emit several values and so will invoke the `next` callback several times,
1239
+ * * you do *not* need to unsubscribe (it is a self-completing Observable).
1240
+ *
1241
+ * @returns A list of the keys wrapped in a RxJS Observable
1229
1242
  *
1230
1243
  * @example
1231
1244
  * this.storageMap.keys().subscribe({
@@ -1234,13 +1247,16 @@ class StorageMap {
1234
1247
  * });
1235
1248
  */
1236
1249
  keys() {
1237
- return this.database.keys()
1250
+ return this.#database.keys()
1238
1251
  /* Catch if `indexedDb` is broken */
1239
- .pipe(this.catchIDBBroken(() => this.database.keys()));
1252
+ .pipe(this.#catchIDBBroken(() => this.#database.keys()));
1240
1253
  }
1241
1254
  /**
1242
- * Tells if a key exists in storage
1243
- * @returns A RxJS `Observable` telling if the key exists
1255
+ * Tells if a key exists in storage.
1256
+ *
1257
+ * Note you do *not* need to unsubscribe (it is a self-completing Observable).
1258
+ *
1259
+ * @returns A RxJS Observable telling if the key exists
1244
1260
  *
1245
1261
  * @example
1246
1262
  * this.storageMap.has('key').subscribe((hasKey) => {
@@ -1248,24 +1264,28 @@ class StorageMap {
1248
1264
  * });
1249
1265
  */
1250
1266
  has(key) {
1251
- return this.database.has(key)
1267
+ return this.#database.has(key)
1252
1268
  /* Catch if `indexedDb` is broken */
1253
- .pipe(this.catchIDBBroken(() => this.database.has(key)));
1269
+ .pipe(this.#catchIDBBroken(() => this.#database.has(key)));
1254
1270
  }
1255
1271
  watch(key, schema) {
1256
1272
  /* Check if there is already a notifier */
1257
- if (!this.notifiers.has(key)) {
1258
- this.notifiers.set(key, new ReplaySubject(1));
1273
+ if (!this.#notifiers.has(key)) {
1274
+ this.#notifiers.set(key, new ReplaySubject(1));
1259
1275
  }
1260
1276
  /* Non-null assertion is required because TypeScript doesn't narrow `.has()` yet */
1261
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1262
- const notifier = this.notifiers.get(key);
1277
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Ensured by the logic
1278
+ const notifier = this.#notifiers.get(key);
1263
1279
  /* Get the current item value */
1264
1280
  (schema ? this.get(key, schema) : this.get(key)).subscribe({
1265
- next: (result) => notifier.next(result),
1266
- error: (error) => notifier.error(error),
1281
+ next: (result) => {
1282
+ notifier.next(result);
1283
+ },
1284
+ error: (error) => {
1285
+ notifier.error(error);
1286
+ },
1267
1287
  });
1268
- /* Only the public API of the `Observable` should be returned */
1288
+ /* Only the public API of the Observable should be returned */
1269
1289
  return (schema ?
1270
1290
  notifier.asObservable() :
1271
1291
  notifier.asObservable());
@@ -1275,8 +1295,8 @@ class StorageMap {
1275
1295
  * @param key The item's key
1276
1296
  * @param data The new value
1277
1297
  */
1278
- notify(key, value) {
1279
- const notifier = this.notifiers.get(key);
1298
+ #notify(key, value) {
1299
+ const notifier = this.#notifiers.get(key);
1280
1300
  if (notifier) {
1281
1301
  notifier.next(value);
1282
1302
  }
@@ -1285,12 +1305,12 @@ class StorageMap {
1285
1305
  * RxJS operator to catch if `indexedDB` is broken
1286
1306
  * @param operationCallback Callback with the operation to redo
1287
1307
  */
1288
- catchIDBBroken(operationCallback) {
1308
+ #catchIDBBroken(operationCallback) {
1289
1309
  return catchError((error) => {
1290
1310
  /* Check if `indexedDB` is broken based on error message (the specific error class seems to be lost in the process) */
1291
1311
  if ((error !== undefined) && (error !== null)
1292
1312
  && (typeof error === "object") && ("message" in error)
1293
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1313
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- Required because TypeScript narrowing is not working here
1294
1314
  && (error.message === IDB_BROKEN_ERROR)) {
1295
1315
  /* When storage is fully disabled in browser (via the "Block all cookies" option),
1296
1316
  * just trying to check `localStorage` variable causes a security exception.
@@ -1299,16 +1319,16 @@ class StorageMap {
1299
1319
  try {
1300
1320
  if ("getItem" in localStorage) {
1301
1321
  /* Fallback to `localStorage` if available */
1302
- this.database = new LocalStorageDatabase();
1322
+ this.#database = new LocalStorageDatabase();
1303
1323
  }
1304
1324
  else {
1305
1325
  /* Fallback to memory storage otherwise */
1306
- this.database = new MemoryDatabase();
1326
+ this.#database = new MemoryDatabase();
1307
1327
  }
1308
1328
  }
1309
1329
  catch {
1310
1330
  /* Fallback to memory storage otherwise */
1311
- this.database = new MemoryDatabase();
1331
+ this.#database = new MemoryDatabase();
1312
1332
  }
1313
1333
  /* Redo the operation */
1314
1334
  return operationCallback();
@@ -1320,95 +1340,26 @@ class StorageMap {
1320
1340
  }
1321
1341
  });
1322
1342
  }
1323
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageMap, deps: [{ token: LocalDatabase }, { token: JSONValidator }], target: i0.ɵɵFactoryTarget.Injectable }); }
1324
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageMap, providedIn: "root" }); }
1325
- }
1326
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageMap, decorators: [{
1327
- type: Injectable,
1328
- args: [{
1329
- providedIn: "root"
1330
- }]
1331
- }], ctorParameters: function () { return [{ type: LocalDatabase }, { type: JSONValidator }]; } });
1332
-
1333
- /**
1334
- * @deprecated Will be removed in v17, use `StorageMap`
1335
- * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/MIGRATION_TO_V16.md}
1336
- */
1337
- class LocalStorage {
1338
- /**
1339
- * Number of items in storage wrapped in an `Observable`
1340
- *
1341
- * @example
1342
- * this.localStorage.length.subscribe((length) => {
1343
- * console.log(length);
1344
- * });
1345
- */
1346
- get length() {
1347
- return this.storageMap.size;
1348
- }
1349
- /* Use the `StorageMap` service to avoid code duplication */
1350
- constructor(storageMap) {
1351
- this.storageMap = storageMap;
1352
- }
1353
- getItem(key, schema) {
1354
- if (schema) {
1355
- /* Backward compatibility with version <= 7 */
1356
- schema = ("schema" in schema) ? schema.schema : schema;
1357
- }
1358
- return (schema ? this.storageMap.get(key, schema) : this.storageMap.get(key)).pipe(
1359
- /* Transform `undefined` into `null` to align with `localStorage` API */
1360
- map((value) => (value !== undefined) ? value : null));
1361
- }
1362
- /**
1363
- * Set an item in storage.
1364
- * Note that setting `null` or `undefined` will remove the item to avoid some browsers issues.
1365
- * @param key The item's key
1366
- * @param data The item's value
1367
- * @param schema Optional JSON schema to validate the data
1368
- * @returns A RxJS `Observable` to wait the end of the operation
1369
- *
1370
- * @example
1371
- * this.localStorage.set('key', 'value').subscribe(() => {});
1372
- */
1373
- setItem(key, data, schema) {
1374
- return this.storageMap.set(key, data, schema).pipe(
1375
- /* Transform `undefined` into `true` for backward compatibility with v7 */
1376
- map(() => true));
1377
- }
1378
- /**
1379
- * Delete an item in storage
1380
- * @param key The item's key
1381
- * @returns A RxJS `Observable` to wait the end of the operation
1382
- *
1383
- * @example
1384
- * this.localStorage.delete('key').subscribe(() => {});
1385
- */
1386
- removeItem(key) {
1387
- return this.storageMap.delete(key).pipe(
1388
- /* Transform `undefined` into `true` for backward compatibility with v7 */
1389
- map(() => true));
1390
- }
1391
1343
  /**
1392
- * Delete all items in storage
1393
- * @returns A RxJS `Observable` to wait the end of the operation
1394
- *
1395
- * @example
1396
- * this.localStorage.clear().subscribe(() => {});
1344
+ * THIS METHOD IS FOR INTERNAL PURPOSE ONLY AND MUST NOT BE USED,
1345
+ * IT CAN BE REMOVED AT ANY TIME AND MESSING WITH IT CAN CAUSE ISSUES
1346
+ * @private
1347
+ * @ignore
1397
1348
  */
1398
- clear() {
1399
- return this.storageMap.clear().pipe(
1400
- /* Transform `undefined` into `true` for backward compatibility with v7 */
1401
- map(() => true));
1349
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment, @typescript-eslint/prefer-ts-expect-error -- Silence the not used error, it is used in tests
1350
+ // @ts-ignore
1351
+ ɵinternalGetDatabase() {
1352
+ return this.#database;
1402
1353
  }
1403
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, deps: [{ token: StorageMap }], target: i0.ɵɵFactoryTarget.Injectable }); }
1404
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, providedIn: "root" }); }
1354
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: StorageMap, deps: [{ token: LocalDatabase }], target: i0.ɵɵFactoryTarget.Injectable }); }
1355
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: StorageMap, providedIn: "root" }); }
1405
1356
  }
1406
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, decorators: [{
1357
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: StorageMap, decorators: [{
1407
1358
  type: Injectable,
1408
1359
  args: [{
1409
1360
  providedIn: "root"
1410
1361
  }]
1411
- }], ctorParameters: function () { return [{ type: StorageMap }]; } });
1362
+ }], ctorParameters: () => [{ type: LocalDatabase }] });
1412
1363
 
1413
1364
  /*
1414
1365
  * Public API Surface of local-storage
@@ -1418,5 +1369,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
1418
1369
  * Generated bundle index. Do not edit.
1419
1370
  */
1420
1371
 
1421
- export { JSONValidator, LocalDatabase, LocalStorage, SERIALIZATION_ERROR, SerializationError, StorageMap, StorageModule, VALIDATION_ERROR, ValidationError, provideIndexedDBDataBaseName, provideIndexedDBDataBaseVersion, provideIndexedDBStoreName, provideLocalStoragePrefix };
1372
+ export { SERIALIZATION_ERROR, SerializationError, StorageMap, StorageModule, VALIDATION_ERROR, ValidationError, provideIndexedDBDataBaseName, provideIndexedDBDataBaseVersion, provideIndexedDBStoreName, provideLocalStoragePrefix };
1422
1373
  //# sourceMappingURL=ngx-pwa-local-storage.mjs.map