@ngx-pwa/local-storage 15.0.0 → 16.1.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 (58) hide show
  1. package/{esm2020 → esm2022}/lib/databases/exceptions.mjs +2 -2
  2. package/esm2022/lib/databases/indexeddb-database.mjs +305 -0
  3. package/esm2022/lib/databases/local-database.mjs +67 -0
  4. package/esm2022/lib/databases/localstorage-database.mjs +158 -0
  5. package/esm2022/lib/databases/memory-database.mjs +84 -0
  6. package/{esm2020 → esm2022}/lib/providers.mjs +3 -3
  7. package/esm2022/lib/storage.module.mjs +33 -0
  8. package/esm2022/lib/storages/local-storage.service.mjs +85 -0
  9. package/esm2022/lib/storages/storage-map.service.mjs +293 -0
  10. package/esm2022/lib/tokens.mjs +59 -0
  11. package/esm2022/lib/validation/json-schema.mjs +5 -0
  12. package/esm2022/lib/validation/json-validator.mjs +244 -0
  13. package/esm2022/public-api.mjs +12 -0
  14. package/{fesm2020 → fesm2022}/ngx-pwa-local-storage.mjs +540 -553
  15. package/fesm2022/ngx-pwa-local-storage.mjs.map +1 -0
  16. package/lib/databases/indexeddb-database.d.ts +2 -2
  17. package/lib/databases/local-database.d.ts +1 -1
  18. package/lib/databases/localstorage-database.d.ts +3 -3
  19. package/lib/databases/memory-database.d.ts +2 -2
  20. package/lib/providers.d.ts +1 -1
  21. package/lib/storage.module.d.ts +3 -10
  22. package/lib/storages/local-storage.service.d.ts +7 -3
  23. package/lib/storages/storage-map.service.d.ts +6 -7
  24. package/lib/tokens.d.ts +1 -1
  25. package/lib/validation/json-schema.d.ts +8 -8
  26. package/lib/validation/json-validator.d.ts +1 -1
  27. package/package.json +10 -16
  28. package/public-api.d.ts +10 -10
  29. package/schematics/collection.json +1 -1
  30. package/schematics/migration.json +1 -1
  31. package/schematics/ng-add/index.d.ts +1 -1
  32. package/schematics/ng-add/index.js +7 -7
  33. package/schematics/ng-add/index.js.map +1 -1
  34. package/schematics/ng-add/schema.json +2 -2
  35. package/schematics/ng-update/index.d.ts +1 -1
  36. package/schematics/ng-update/index.js +3 -3
  37. package/schematics/ng-update/index.js.map +1 -1
  38. package/schematics/utility/config.d.ts +1 -1
  39. package/schematics/utility/config.js +7 -7
  40. package/schematics/utility/module.d.ts +1 -1
  41. package/schematics/utility/module.js +6 -6
  42. package/schematics/utility/module.js.map +1 -1
  43. package/esm2020/lib/databases/indexeddb-database.mjs +0 -304
  44. package/esm2020/lib/databases/local-database.mjs +0 -66
  45. package/esm2020/lib/databases/localstorage-database.mjs +0 -160
  46. package/esm2020/lib/databases/memory-database.mjs +0 -83
  47. package/esm2020/lib/storage.module.mjs +0 -39
  48. package/esm2020/lib/storages/local-storage.service.mjs +0 -80
  49. package/esm2020/lib/storages/storage-map.service.mjs +0 -299
  50. package/esm2020/lib/tokens.mjs +0 -59
  51. package/esm2020/lib/validation/json-schema.mjs +0 -5
  52. package/esm2020/lib/validation/json-validator.mjs +0 -243
  53. package/esm2020/public-api.mjs +0 -12
  54. package/fesm2015/ngx-pwa-local-storage.mjs +0 -1432
  55. package/fesm2015/ngx-pwa-local-storage.mjs.map +0 -1
  56. package/fesm2020/ngx-pwa-local-storage.mjs.map +0 -1
  57. /package/{esm2020 → esm2022}/lib/storages/exceptions.mjs +0 -0
  58. /package/{esm2020 → esm2022}/ngx-pwa-local-storage.mjs +0 -0
@@ -1,266 +1,53 @@
1
- import * as i0 from '@angular/core';
2
- import { Injectable, InjectionToken, inject, Inject, PLATFORM_ID, NgModule, makeEnvironmentProviders } from '@angular/core';
3
1
  import { isPlatformBrowser } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { InjectionToken, inject, Injectable, PLATFORM_ID, makeEnvironmentProviders, NgModule } from '@angular/core';
4
4
  import { ReplaySubject, fromEvent, race, throwError, of, Observable, asyncScheduler, from } from 'rxjs';
5
5
  import { mergeMap, map, first, takeWhile, tap, observeOn, catchError } from 'rxjs/operators';
6
6
 
7
- class JSONValidator {
8
- /**
9
- * Validate a JSON data against a Jsubset of the JSON Schema standard.
10
- * Types are enforced to validate everything: each schema must
11
- * @param data JSON data to validate
12
- * @param schema Subset of JSON Schema. Must have a `type`.
13
- * @returns If data is valid: `true`, if it is invalid: `false`
14
- * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/VALIDATION.md}
15
- */
16
- validate(data, schema) {
17
- switch (schema.type) {
18
- case 'string':
19
- return this.validateString(data, schema);
20
- case 'number':
21
- case 'integer':
22
- return this.validateNumber(data, schema);
23
- case 'boolean':
24
- return this.validateBoolean(data, schema);
25
- case 'array':
26
- return this.validateArray(data, schema);
27
- case 'object':
28
- return this.validateObject(data, schema);
29
- }
30
- }
31
- /**
32
- * Validate a string
33
- * @param data Data to validate
34
- * @param schema Schema describing the string
35
- * @returns If data is valid: `true`, if it is invalid: `false`
36
- */
37
- validateString(data, schema) {
38
- if (typeof data !== 'string') {
39
- return false;
40
- }
41
- if (!this.validateConst(data, schema)) {
42
- return false;
43
- }
44
- if (!this.validateEnum(data, schema)) {
45
- return false;
46
- }
47
- if ((schema.maxLength !== undefined) && (data.length > schema.maxLength)) {
48
- return false;
49
- }
50
- if ((schema.minLength !== undefined) && (data.length < schema.minLength)) {
51
- return false;
52
- }
53
- if (schema.pattern) {
54
- let regularExpression = null;
55
- try {
56
- regularExpression = new RegExp(schema.pattern);
57
- }
58
- catch {
59
- // Nothing to do
60
- }
61
- if (regularExpression && !regularExpression.test(data)) {
62
- return false;
63
- }
64
- }
65
- return true;
66
- }
67
- /**
68
- * Validate a number or an integer
69
- * @param data Data to validate
70
- * @param schema Schema describing the number or integer
71
- * @returns If data is valid: `true`, if it is invalid: `false`
72
- */
73
- validateNumber(data, schema) {
74
- if (typeof data !== 'number') {
75
- return false;
76
- }
77
- if ((schema.type === 'integer') && !Number.isInteger(data)) {
78
- return false;
79
- }
80
- if (!this.validateConst(data, schema)) {
81
- return false;
82
- }
83
- if (!this.validateEnum(data, schema)) {
84
- return false;
85
- }
86
- /* Test is done this way to not divide by 0 */
87
- if (schema.multipleOf && !Number.isInteger(data / schema.multipleOf)) {
88
- return false;
89
- }
90
- if ((schema.maximum !== undefined) && (data > schema.maximum)) {
91
- return false;
92
- }
93
- if ((schema.exclusiveMaximum !== undefined) && (data >= schema.exclusiveMaximum)) {
94
- return false;
95
- }
96
- if ((schema.minimum !== undefined) && (data < schema.minimum)) {
97
- return false;
98
- }
99
- if ((schema.exclusiveMinimum !== undefined) && (data <= schema.exclusiveMinimum)) {
100
- return false;
101
- }
102
- return true;
103
- }
104
- /**
105
- * Validate a boolean
106
- * @param data Data to validate
107
- * @param schema Schema describing the boolean
108
- * @returns If data is valid: `true`, if it is invalid: `false`
109
- */
110
- validateBoolean(data, schema) {
111
- if (typeof data !== 'boolean') {
112
- return false;
113
- }
114
- if (!this.validateConst(data, schema)) {
115
- return false;
116
- }
117
- return true;
118
- }
119
- /**
120
- * Validate an array
121
- * @param data Data to validate
122
- * @param schema Schema describing the array
123
- * @returns If data is valid: `true`, if it is invalid: `false`
124
- */
125
- validateArray(data, schema) {
126
- if (!Array.isArray(data)) {
127
- return false;
128
- }
129
- if ((schema.maxItems !== undefined) && (data.length > schema.maxItems)) {
130
- return false;
131
- }
132
- if ((schema.minItems !== undefined) && (data.length < schema.minItems)) {
133
- return false;
134
- }
135
- if (schema.uniqueItems) {
136
- /* Create a set to eliminate values with multiple occurences */
137
- const dataSet = new Set(data);
138
- if (data.length !== dataSet.size) {
139
- return false;
140
- }
141
- }
142
- /* Specific test for tuples */
143
- if (Array.isArray(schema.items)) {
144
- // TODO: cast should not be needed here
145
- return this.validateTuple(data, schema.items);
146
- }
147
- /* Validate all the values in array */
148
- for (const value of data) {
149
- // TODO: remove when TypeScript 4.1 is available
150
- // (currently the narrowed type from `Array.isArray()` is lost on readonly arrays)
151
- if (!this.validate(value, schema.items)) {
152
- return false;
153
- }
154
- }
155
- return true;
156
- }
157
- /**
158
- * Validate a tuple (array with fixed length and multiple types)
159
- * @param data Data to validate
160
- * @param schemas Schemas describing the tuple
161
- * @returns If data is valid: `true`, if it is invalid: `false`
162
- */
163
- validateTuple(data, schemas) {
164
- /* Tuples have a fixed length */
165
- if (data.length !== schemas.length) {
166
- return false;
167
- }
168
- for (let i = 0; i < schemas.length; i += 1) {
169
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
170
- if (!this.validate(data[i], schemas[i])) {
171
- return false;
172
- }
173
- }
174
- return true;
175
- }
176
- /**
177
- * Validate an object
178
- * @param data Data to validate
179
- * @param schema JSON schema describing the object
180
- * @returns If data is valid: `true`, if it is invalid: `false`
181
- */
182
- validateObject(data, schema) {
183
- /* Check the type and if not `null` as `null` also have the type `object` in old browsers */
184
- if ((typeof data !== 'object') || (data === null)) {
185
- return false;
186
- }
187
- /* Check if the object doesn't have more properties than expected
188
- * Equivalent of `additionalProperties: false`
189
- */
190
- if (Object.keys(schema.properties).length < Object.keys(data).length) {
191
- return false;
192
- }
193
- /* Validate required properties */
194
- if (schema.required) {
195
- for (const requiredProp of schema.required) {
196
- if (!Object.prototype.hasOwnProperty.call(data, requiredProp)) {
197
- return false;
198
- }
199
- }
200
- }
201
- /* Recursively validate all properties */
202
- for (const property in schema.properties) {
203
- /* Filter to keep only real properties (no internal JS stuff) and check if the data has the property too */
204
- if (Object.prototype.hasOwnProperty.call(schema.properties, property) && Object.prototype.hasOwnProperty.call(data, property)) {
205
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
206
- if (!this.validate(data[property], schema.properties[property])) {
207
- return false;
208
- }
209
- }
210
- }
211
- return true;
212
- }
213
- /**
214
- * Validate a constant
215
- * @param data Data ta validate
216
- * @param schema JSON schema describing the constant
217
- * @returns If data is valid: `true`, if it is invalid: `false`
218
- */
219
- validateConst(data, schema) {
220
- if (!schema.const) {
221
- return true;
222
- }
223
- return (data === schema.const);
7
+ /**
8
+ * Exception message when `indexedDB` is not working
9
+ */
10
+ const IDB_BROKEN_ERROR = "indexedDB is not working";
11
+ /**
12
+ * Exception raised when `indexedDB` is not working
13
+ */
14
+ class IDBBrokenError extends Error {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.message = IDB_BROKEN_ERROR;
224
18
  }
225
- /**
226
- * Validate an enum
227
- * @param data Data ta validate
228
- * @param schema JSON schema describing the enum
229
- * @returns If data is valid: `true`, if it is invalid: `false`
230
- */
231
- validateEnum(data, schema) {
232
- if (!schema.enum) {
233
- return true;
234
- }
235
- /* Cast as the data can be of multiple types, and so TypeScript is lost */
236
- return (schema.enum.includes(data));
19
+ }
20
+ /**
21
+ * Exception message when a value can't be serialized for `localStorage`
22
+ */
23
+ const SERIALIZATION_ERROR = `The storage is currently localStorage,
24
+ where data must be serialized, and the provided data can't be serialized.`;
25
+ /**
26
+ * Exception raised when a value can't be serialized for `localStorage`
27
+ */
28
+ class SerializationError extends Error {
29
+ constructor() {
30
+ super(...arguments);
31
+ this.message = SERIALIZATION_ERROR;
237
32
  }
238
33
  }
239
- JSONValidator.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: JSONValidator, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
240
- JSONValidator.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: JSONValidator, providedIn: 'root' });
241
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: JSONValidator, decorators: [{
242
- type: Injectable,
243
- args: [{
244
- providedIn: 'root'
245
- }]
246
- }] });
247
34
 
248
35
  /**
249
36
  * Token to provide a prefix to `localStorage` keys.
250
37
  */
251
- const LS_PREFIX = new InjectionToken('localStoragePrefix', {
252
- providedIn: 'root',
253
- factory: () => ''
38
+ const LS_PREFIX = new InjectionToken("localStoragePrefix", {
39
+ providedIn: "root",
40
+ factory: () => ""
254
41
  });
255
42
  /**
256
43
  * Default name used for `indexedDB` database.
257
44
  */
258
- const DEFAULT_IDB_DB_NAME = 'ngStorage';
45
+ const DEFAULT_IDB_DB_NAME = "ngStorage";
259
46
  /**
260
47
  * Token to provide `indexedDB` database name.
261
48
  */
262
- const IDB_DB_NAME = new InjectionToken('localStorageIDBDBName', {
263
- providedIn: 'root',
49
+ const IDB_DB_NAME = new InjectionToken("localStorageIDBDBName", {
50
+ providedIn: "root",
264
51
  factory: () => DEFAULT_IDB_DB_NAME
265
52
  });
266
53
  /**
@@ -271,20 +58,20 @@ const DEFAULT_IDB_DB_VERSION = 1;
271
58
  * Token to provide `indexedDB` database version.
272
59
  * Must be an unsigned **integer**.
273
60
  */
274
- const IDB_DB_VERSION = new InjectionToken('localStorageIDBDBVersion', {
275
- providedIn: 'root',
61
+ const IDB_DB_VERSION = new InjectionToken("localStorageIDBDBVersion", {
62
+ providedIn: "root",
276
63
  factory: () => DEFAULT_IDB_DB_VERSION
277
64
  });
278
65
  /**
279
66
  * Default name used for `indexedDB` object store.
280
67
  */
281
- const DEFAULT_IDB_STORE_NAME = 'localStorage';
68
+ const DEFAULT_IDB_STORE_NAME = "localStorage";
282
69
  /**
283
70
  * Token to provide `indexedDB` store name.
284
71
  * For backward compatibility, the default can't be set now, `IndexedDBDatabase` will do it at runtime.
285
72
  */
286
- const IDB_STORE_NAME = new InjectionToken('localStorageIDBStoreName', {
287
- providedIn: 'root',
73
+ const IDB_STORE_NAME = new InjectionToken("localStorageIDBStoreName", {
74
+ providedIn: "root",
288
75
  factory: () => DEFAULT_IDB_STORE_NAME
289
76
  });
290
77
  /**
@@ -298,40 +85,12 @@ const DEFAULT_IDB_NO_WRAP = true;
298
85
  * Defaults to `true`. Change to `false` for backward compatiblity in existing applications.
299
86
  * **DO NOT CHANGE THIS BEHAVIOR ONCE IN PRODUCTION**, as it would break with existing data.
300
87
  */
301
- const IDB_NO_WRAP = new InjectionToken('localStorageIDBWrap', {
302
- providedIn: 'root',
88
+ const IDB_NO_WRAP = new InjectionToken("localStorageIDBWrap", {
89
+ providedIn: "root",
303
90
  factory: () => DEFAULT_IDB_NO_WRAP
304
91
  });
305
92
 
306
- /**
307
- * Exception message when `indexedDB` is not working
308
- */
309
- const IDB_BROKEN_ERROR = 'indexedDB is not working';
310
- /**
311
- * Exception raised when `indexedDB` is not working
312
- */
313
- class IDBBrokenError extends Error {
314
- constructor() {
315
- super(...arguments);
316
- this.message = IDB_BROKEN_ERROR;
317
- }
318
- }
319
- /**
320
- * Exception message when a value can't be serialized for `localStorage`
321
- */
322
- const SERIALIZATION_ERROR = `The storage is currently localStorage,
323
- where data must be serialized, and the provided data can't be serialized.`;
324
- /**
325
- * Exception raised when a value can't be serialized for `localStorage`
326
- */
327
- class SerializationError extends Error {
328
- constructor() {
329
- super(...arguments);
330
- this.message = SERIALIZATION_ERROR;
331
- }
332
- }
333
-
334
- class IndexedDBDatabase {
93
+ class IndexedDBDatabase {
335
94
  constructor() {
336
95
  /**
337
96
  * `indexedDB` database connection, wrapped in a RxJS `ReplaySubject` to be able to access the connection
@@ -341,7 +100,7 @@ class IndexedDBDatabase {
341
100
  /**
342
101
  * Index used when wrapping value. *For backward compatibility only.*
343
102
  */
344
- this.wrapIndex = 'value';
103
+ this.wrapIndex = "value";
345
104
  this.dbName = inject(IDB_DB_NAME);
346
105
  this.storeName = inject(IDB_STORE_NAME);
347
106
  this.dbVersion = inject(IDB_DB_VERSION);
@@ -365,7 +124,7 @@ class IndexedDBDatabase {
365
124
  */
366
125
  get size() {
367
126
  /* Open a transaction in read-only mode */
368
- return this.transaction('readonly').pipe(mergeMap((transactionData) => {
127
+ return this.transaction("readonly").pipe(mergeMap((transactionData) => {
369
128
  const { store, events } = transactionData;
370
129
  /* Request to know the number of items */
371
130
  const request = store.count();
@@ -382,7 +141,7 @@ class IndexedDBDatabase {
382
141
  */
383
142
  get(key) {
384
143
  /* Open a transaction in read-only mode */
385
- return this.transaction('readonly').pipe(mergeMap((transactionData) => {
144
+ return this.transaction("readonly").pipe(mergeMap((transactionData) => {
386
145
  const { store, events } = transactionData;
387
146
  /* Request the value with the key provided by the user */
388
147
  const request = store.get(key);
@@ -390,7 +149,7 @@ class IndexedDBDatabase {
390
149
  return events.pipe(map(() => {
391
150
  if ((request.result !== undefined) && (request.result !== null)) {
392
151
  /* Prior to v8, the value was wrapped in an `{ value: ...}` object */
393
- if (!this.noWrap && (typeof request.result === 'object') && (this.wrapIndex in request.result) &&
152
+ if (!this.noWrap && (typeof request.result === "object") && (this.wrapIndex in request.result) &&
394
153
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
395
154
  (request.result[this.wrapIndex] !== undefined) && (request.result[this.wrapIndex] !== null)) {
396
155
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
@@ -420,7 +179,7 @@ class IndexedDBDatabase {
420
179
  return this.delete(key);
421
180
  }
422
181
  /* Open a transaction in write mode */
423
- return this.transaction('readwrite').pipe(mergeMap((transactionData) => {
182
+ return this.transaction("readwrite").pipe(mergeMap((transactionData) => {
424
183
  const { store, events } = transactionData;
425
184
  /* Prior to v8, data was wrapped in a `{ value: ... }` object */
426
185
  const dataToStore = this.noWrap ? data : { [this.wrapIndex]: data };
@@ -439,7 +198,7 @@ class IndexedDBDatabase {
439
198
  */
440
199
  delete(key) {
441
200
  /* Open a transaction in write mode */
442
- return this.transaction('readwrite').pipe(mergeMap((transactionData) => {
201
+ return this.transaction("readwrite").pipe(mergeMap((transactionData) => {
443
202
  const { store, events } = transactionData;
444
203
  /* Delete the item in store */
445
204
  store.delete(key);
@@ -455,7 +214,7 @@ class IndexedDBDatabase {
455
214
  */
456
215
  clear() {
457
216
  /* Open a transaction in write mode */
458
- return this.transaction('readwrite').pipe(mergeMap((transactionData) => {
217
+ return this.transaction("readwrite").pipe(mergeMap((transactionData) => {
459
218
  const { store, events } = transactionData;
460
219
  /* Delete all items in object store */
461
220
  store.clear();
@@ -471,7 +230,7 @@ class IndexedDBDatabase {
471
230
  */
472
231
  keys() {
473
232
  /* Open a transaction in read-only mode */
474
- return this.transaction('readonly').pipe(
233
+ return this.transaction("readonly").pipe(
475
234
  /* `first()` is used as the final operator in other methods to complete the `Observable`
476
235
  * (as it all starts from a `ReplaySubject` which never ends),
477
236
  * but as this method is iterating over multiple values, `first()` **must** be used here */
@@ -481,7 +240,7 @@ class IndexedDBDatabase {
481
240
  * Avoid issues like https://github.com/cyrilletuzi/angular-async-local-storage/issues/69 */
482
241
  const request = store.openKeyCursor();
483
242
  /* Listen to success event */
484
- const success$ = fromEvent(request, 'success').pipe(
243
+ const success$ = fromEvent(request, "success").pipe(
485
244
  /* Stop the `Observable` when the cursor is `null` */
486
245
  takeWhile(() => (request.result !== null)),
487
246
  /* This lib only allows string keys, but user could have added other types of keys from outside
@@ -501,7 +260,7 @@ class IndexedDBDatabase {
501
260
  */
502
261
  has(key) {
503
262
  /* Open a transaction in read-only mode */
504
- return this.transaction('readonly').pipe(mergeMap((transactionData) => {
263
+ return this.transaction("readonly").pipe(mergeMap((transactionData) => {
505
264
  const { store, events } = transactionData;
506
265
  /* Check if the key exists in the store
507
266
  * Fixes https://github.com/cyrilletuzi/angular-async-local-storage/issues/69
@@ -532,7 +291,7 @@ class IndexedDBDatabase {
532
291
  /* Create store on first connection */
533
292
  this.createStore(request);
534
293
  /* Listen to success and error events */
535
- const success$ = fromEvent(request, 'success');
294
+ const success$ = fromEvent(request, "success");
536
295
  const error$ = this.listenError(request);
537
296
  /* Choose the first to occur */
538
297
  race([success$, error$])
@@ -557,7 +316,7 @@ class IndexedDBDatabase {
557
316
  */
558
317
  createStore(request) {
559
318
  /* Listen to the event fired on first connection */
560
- fromEvent(request, 'upgradeneeded')
319
+ fromEvent(request, "upgradeneeded")
561
320
  /* The observable will complete */
562
321
  .pipe(first())
563
322
  .subscribe({
@@ -600,7 +359,7 @@ class IndexedDBDatabase {
600
359
  * @returns An `Observable` listening to errors
601
360
  */
602
361
  listenError(transactionOrRequest) {
603
- return fromEvent(transactionOrRequest, 'error').pipe(
362
+ return fromEvent(transactionOrRequest, "error").pipe(
604
363
  /* Throw on error to be able to catch errors in RxJS way.
605
364
  * Here `event.target` must be used, as `transactionOrRequest.error` will be `null`
606
365
  * if we are on the request and the error is only triggered later by the transaction */
@@ -613,27 +372,27 @@ class IndexedDBDatabase {
613
372
  */
614
373
  listenTransactionEvents(transaction) {
615
374
  /* Listen to the `complete` event */
616
- const complete$ = fromEvent(transaction, 'complete');
375
+ const complete$ = fromEvent(transaction, "complete");
617
376
  /* Listen to the `error` event */
618
377
  const error$ = this.listenError(transaction);
619
378
  /* Choose the first event to occur */
620
379
  return race([complete$, error$]);
621
380
  }
381
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: IndexedDBDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
382
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: IndexedDBDatabase, providedIn: "root" }); }
622
383
  }
623
- IndexedDBDatabase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: IndexedDBDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
624
- IndexedDBDatabase.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: IndexedDBDatabase, providedIn: 'root' });
625
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: IndexedDBDatabase, decorators: [{
384
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: IndexedDBDatabase, decorators: [{
626
385
  type: Injectable,
627
386
  args: [{
628
- providedIn: 'root'
387
+ providedIn: "root"
629
388
  }]
630
389
  }], ctorParameters: function () { return []; } });
631
390
 
632
391
  class LocalStorageDatabase {
633
- // `inject()` cannot be used here, as `LocalStorageDatabase` is instanciated at runtime in some scenarios
634
- constructor(prefix = '') {
392
+ constructor() {
393
+ console.log('test');
635
394
  /* Prefix if asked, or no prefix otherwise */
636
- this.prefix = prefix || '';
395
+ this.prefix = inject(LS_PREFIX) || "";
637
396
  }
638
397
  /**
639
398
  * Number of items in `localStorage`
@@ -674,7 +433,7 @@ class LocalStorageDatabase {
674
433
  let serializedData = null;
675
434
  /* Check if data can be serialized */
676
435
  const dataPrototype = Object.getPrototypeOf(data);
677
- if ((typeof data === 'object') && (data !== null) && !Array.isArray(data) &&
436
+ if ((typeof data === "object") && (data !== null) && !Array.isArray(data) &&
678
437
  !((dataPrototype === Object.prototype) || (dataPrototype === null))) {
679
438
  return throwError(() => new SerializationError());
680
439
  }
@@ -758,7 +517,7 @@ class LocalStorageDatabase {
758
517
  const prefixedKey = localStorage.key(index);
759
518
  if (prefixedKey !== null) {
760
519
  /* If no prefix, the key is already good, otherwrite strip the prefix */
761
- return !this.prefix ? prefixedKey : prefixedKey.substr(this.prefix.length);
520
+ return !this.prefix ? prefixedKey : prefixedKey.substring(this.prefix.length);
762
521
  }
763
522
  return null;
764
523
  }
@@ -770,18 +529,15 @@ class LocalStorageDatabase {
770
529
  prefixKey(key) {
771
530
  return `${this.prefix}${key}`;
772
531
  }
532
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorageDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
533
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorageDatabase, providedIn: "root" }); }
773
534
  }
774
- LocalStorageDatabase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalStorageDatabase, deps: [{ token: LS_PREFIX }], target: i0.ɵɵFactoryTarget.Injectable });
775
- LocalStorageDatabase.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalStorageDatabase, providedIn: 'root' });
776
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalStorageDatabase, decorators: [{
535
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorageDatabase, decorators: [{
777
536
  type: Injectable,
778
537
  args: [{
779
- providedIn: 'root'
538
+ providedIn: "root"
780
539
  }]
781
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
782
- type: Inject,
783
- args: [LS_PREFIX]
784
- }] }]; } });
540
+ }], ctorParameters: function () { return []; } });
785
541
 
786
542
  class MemoryDatabase {
787
543
  constructor() {
@@ -828,116 +584,465 @@ class MemoryDatabase {
828
584
  return of(undefined);
829
585
  }
830
586
  /**
831
- * Deletes all items in memory
832
- * @returns A RxJS `Observable` to wait the end of the operation
587
+ * Deletes all items in memory
588
+ * @returns A RxJS `Observable` to wait the end of the operation
589
+ */
590
+ clear() {
591
+ this.memoryStorage.clear();
592
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
593
+ return of(undefined);
594
+ }
595
+ /**
596
+ * Get all keys in memory
597
+ * @returns A RxJS `Observable` iterating on keys
598
+ */
599
+ keys() {
600
+ /* Create an `Observable` from keys */
601
+ return from(this.memoryStorage.keys());
602
+ }
603
+ /**
604
+ * Check if a key exists in memory
605
+ * @param key Key name
606
+ * @returns a RxJS `Observable` telling if the key exists or not
607
+ */
608
+ has(key) {
609
+ /* Wrap in a RxJS `Observable` to be consistent with other storages */
610
+ return of(this.memoryStorage.has(key));
611
+ }
612
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MemoryDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
613
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MemoryDatabase, providedIn: "root" }); }
614
+ }
615
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MemoryDatabase, decorators: [{
616
+ type: Injectable,
617
+ args: [{
618
+ providedIn: "root"
619
+ }]
620
+ }] });
621
+
622
+ /**
623
+ * Factory to create a storage according to browser support
624
+ * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/BROWSERS_SUPPORT.md}
625
+ */
626
+ function localDatabaseFactory() {
627
+ const platformId = inject(PLATFORM_ID);
628
+ /* When storage is fully disabled in browser (via the "Block all cookies" option),
629
+ * just trying to check `indexedDB` or `localStorage` variables causes a security exception.
630
+ * Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118
631
+ */
632
+ try {
633
+ // Do not explicit `window` here, as the global object is not the same in web workers
634
+ if (isPlatformBrowser(platformId) && (indexedDB !== undefined) && (indexedDB !== null) && ("open" in indexedDB)) {
635
+ /* Check:
636
+ * - if we are in a browser context (issue: server-side rendering)
637
+ * - it could exist but be `undefined` or `null`
638
+ * - it could exists but not having a working API
639
+ * Will be the case for:
640
+ * - All other browsers in normal mode
641
+ * - Chromium / Safari private mode, but in this case, data will be swiped when the user leaves the app */
642
+ return new IndexedDBDatabase();
643
+ }
644
+ else if (isPlatformBrowser(platformId)
645
+ && (localStorage !== undefined) && (localStorage !== null) && ("getItem" in localStorage)) {
646
+ /* Check:
647
+ * - if we are in a browser context (issue: server-side rendering)
648
+ * - if `localStorage` exists (to be sure)
649
+ * - it could exists but not having a working API
650
+ * Will be the case for:
651
+ * - Safari cross-origin iframes, detected later in `IndexedDBDatabase.connect()`
652
+ * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/42}
653
+ * - Firefox private mode, but in this case, data will be swiped when the user leaves the app
654
+ * For Firefox, can only be detected later in `IndexedDBDatabase.connect()`
655
+ * @see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=781982}
656
+ */
657
+ return new LocalStorageDatabase();
658
+ }
659
+ }
660
+ catch {
661
+ // Nothing to do
662
+ }
663
+ /* Will be the case for:
664
+ * - In browsers if storage has been fully disabled (via the "Block all cookies" option)
665
+ * - Server-side rendering
666
+ * - All other non-browser context
667
+ */
668
+ return new MemoryDatabase();
669
+ }
670
+ class LocalDatabase {
671
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
672
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalDatabase, providedIn: "root", useFactory: localDatabaseFactory }); }
673
+ }
674
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalDatabase, decorators: [{
675
+ type: Injectable,
676
+ args: [{
677
+ providedIn: "root",
678
+ useFactory: localDatabaseFactory,
679
+ }]
680
+ }] });
681
+
682
+ /**
683
+ * Allows to add a prefix before `localStorage` keys.
684
+ * *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
685
+ * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
686
+ *
687
+ * @example
688
+ * bootstrapApplication(AppComponent, {
689
+ * providers: [provideLocalStoragePrefix('custom_')]
690
+ * });
691
+ *
692
+ * @example
693
+ * NgModule({
694
+ * providers: [provideLocalStoragePrefix('custom_')]
695
+ * })
696
+ * export class AppModule
697
+ */
698
+ function provideLocalStoragePrefix(prefix) {
699
+ return makeEnvironmentProviders([{ provide: LS_PREFIX, useValue: prefix }]);
700
+ }
701
+ /**
702
+ * Allows to change the name used for `indexedDB` database.
703
+ * *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
704
+ * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
705
+ *
706
+ * @example
707
+ * bootstrapApplication(AppComponent, {
708
+ * providers: [provideIndexedDBDataBaseName('custom')]
709
+ * });
710
+ *
711
+ * @example
712
+ * NgModule({
713
+ * providers: [provideIndexedDBDataBaseName('custom')]
714
+ * })
715
+ * export class AppModule
716
+ */
717
+ function provideIndexedDBDataBaseName(name) {
718
+ return makeEnvironmentProviders([{ provide: IDB_DB_NAME, useValue: name }]);
719
+ }
720
+ /**
721
+ * Allows to change the database version used for `indexedDB` database.
722
+ * Must be an unsigned **integer**.
723
+ * **Use with caution as the creation of the store depends on the version.**
724
+ * *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
725
+ * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
726
+ *
727
+ * @example
728
+ * bootstrapApplication(AppComponent, {
729
+ * providers: [provideIndexedDBDataBaseVersion(2)]
730
+ * });
731
+ *
732
+ * @example
733
+ * NgModule({
734
+ * providers: [provideIndexedDBDataBaseVersion(2)]
735
+ * })
736
+ * export class AppModule
737
+ */
738
+ function provideIndexedDBDataBaseVersion(version) {
739
+ return makeEnvironmentProviders([{ provide: IDB_DB_VERSION, useValue: version }]);
740
+ }
741
+ /**
742
+ * Allows to change the name used for `indexedDB` object store.
743
+ * *Use only* for interoperability with other APIs.
744
+ * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
745
+ *
746
+ * @example
747
+ * bootstrapApplication(AppComponent, {
748
+ * providers: [provideIndexedDBStoreName('custom')]
749
+ * });
750
+ *
751
+ * @example
752
+ * NgModule({
753
+ * providers: [provideIndexedDBStoreName('custom')]
754
+ * })
755
+ * export class AppModule
756
+ */
757
+ function provideIndexedDBStoreName(name) {
758
+ return makeEnvironmentProviders([{ provide: IDB_STORE_NAME, useValue: name }]);
759
+ }
760
+
761
+ /**
762
+ * This module is only here for backward compatibility, do not add it by yourself
763
+ */
764
+ class StorageModule {
765
+ /**
766
+ * Only useful to provide options, otherwise it does nothing.
767
+ * **Must be used at initialization, ie. in `AppModule`, and must not be loaded again in another module.**
768
+ *
769
+ */
770
+ static forRoot(config) {
771
+ return {
772
+ ngModule: StorageModule,
773
+ providers: [
774
+ config.LSPrefix ? { provide: LS_PREFIX, useValue: config.LSPrefix } : [],
775
+ config.IDBDBName ? { provide: IDB_DB_NAME, useValue: config.IDBDBName } : [],
776
+ config.IDBStoreName ? { provide: IDB_STORE_NAME, useValue: config.IDBStoreName } : [],
777
+ config.IDBDBVersion ? { provide: IDB_DB_VERSION, useValue: config.IDBDBVersion } : [],
778
+ (config.IDBNoWrap === false) ? { provide: IDB_NO_WRAP, useValue: config.IDBNoWrap } : [],
779
+ ],
780
+ };
781
+ }
782
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
783
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.0", ngImport: i0, type: StorageModule }); }
784
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule }); }
785
+ }
786
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule, decorators: [{
787
+ type: NgModule
788
+ }] });
789
+
790
+ /**
791
+ * Exception message when a value is not valid against the JSON schema
792
+ */
793
+ const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.
794
+ Check your JSON schema, otherwise it means data has been corrupted.`;
795
+ /**
796
+ * Exception raised when a value is not valid against the JSON schema
797
+ */
798
+ class ValidationError extends Error {
799
+ constructor() {
800
+ super(...arguments);
801
+ this.message = VALIDATION_ERROR;
802
+ }
803
+ }
804
+
805
+ class JSONValidator {
806
+ /**
807
+ * Validate a JSON data against a Jsubset of the JSON Schema standard.
808
+ * Types are enforced to validate everything: each schema must
809
+ * @param data JSON data to validate
810
+ * @param schema Subset of JSON Schema. Must have a `type`.
811
+ * @returns If data is valid: `true`, if it is invalid: `false`
812
+ * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/VALIDATION.md}
813
+ */
814
+ validate(data, schema) {
815
+ switch (schema.type) {
816
+ case "string":
817
+ return this.validateString(data, schema);
818
+ case "number":
819
+ case "integer":
820
+ return this.validateNumber(data, schema);
821
+ case "boolean":
822
+ return this.validateBoolean(data, schema);
823
+ case "array":
824
+ return this.validateArray(data, schema);
825
+ case "object":
826
+ return this.validateObject(data, schema);
827
+ }
828
+ }
829
+ /**
830
+ * Validate a string
831
+ * @param data Data to validate
832
+ * @param schema Schema describing the string
833
+ * @returns If data is valid: `true`, if it is invalid: `false`
834
+ */
835
+ validateString(data, schema) {
836
+ if (typeof data !== "string") {
837
+ return false;
838
+ }
839
+ if (!this.validateConst(data, schema)) {
840
+ return false;
841
+ }
842
+ if (!this.validateEnum(data, schema)) {
843
+ return false;
844
+ }
845
+ if ((schema.maxLength !== undefined) && (data.length > schema.maxLength)) {
846
+ return false;
847
+ }
848
+ if ((schema.minLength !== undefined) && (data.length < schema.minLength)) {
849
+ return false;
850
+ }
851
+ if (schema.pattern) {
852
+ let regularExpression = null;
853
+ try {
854
+ regularExpression = new RegExp(schema.pattern);
855
+ }
856
+ catch {
857
+ // Nothing to do
858
+ }
859
+ if (regularExpression && !regularExpression.test(data)) {
860
+ return false;
861
+ }
862
+ }
863
+ return true;
864
+ }
865
+ /**
866
+ * Validate a number or an integer
867
+ * @param data Data to validate
868
+ * @param schema Schema describing the number or integer
869
+ * @returns If data is valid: `true`, if it is invalid: `false`
870
+ */
871
+ validateNumber(data, schema) {
872
+ if (typeof data !== "number") {
873
+ return false;
874
+ }
875
+ if ((schema.type === "integer") && !Number.isInteger(data)) {
876
+ return false;
877
+ }
878
+ if (!this.validateConst(data, schema)) {
879
+ return false;
880
+ }
881
+ if (!this.validateEnum(data, schema)) {
882
+ return false;
883
+ }
884
+ /* Test is done this way to not divide by 0 */
885
+ if (schema.multipleOf && !Number.isInteger(data / schema.multipleOf)) {
886
+ return false;
887
+ }
888
+ if ((schema.maximum !== undefined) && (data > schema.maximum)) {
889
+ return false;
890
+ }
891
+ if ((schema.exclusiveMaximum !== undefined) && (data >= schema.exclusiveMaximum)) {
892
+ return false;
893
+ }
894
+ if ((schema.minimum !== undefined) && (data < schema.minimum)) {
895
+ return false;
896
+ }
897
+ if ((schema.exclusiveMinimum !== undefined) && (data <= schema.exclusiveMinimum)) {
898
+ return false;
899
+ }
900
+ return true;
901
+ }
902
+ /**
903
+ * Validate a boolean
904
+ * @param data Data to validate
905
+ * @param schema Schema describing the boolean
906
+ * @returns If data is valid: `true`, if it is invalid: `false`
907
+ */
908
+ validateBoolean(data, schema) {
909
+ if (typeof data !== "boolean") {
910
+ return false;
911
+ }
912
+ if (!this.validateConst(data, schema)) {
913
+ return false;
914
+ }
915
+ return true;
916
+ }
917
+ /**
918
+ * Validate an array
919
+ * @param data Data to validate
920
+ * @param schema Schema describing the array
921
+ * @returns If data is valid: `true`, if it is invalid: `false`
922
+ */
923
+ validateArray(data, schema) {
924
+ if (!Array.isArray(data)) {
925
+ return false;
926
+ }
927
+ if ((schema.maxItems !== undefined) && (data.length > schema.maxItems)) {
928
+ return false;
929
+ }
930
+ if ((schema.minItems !== undefined) && (data.length < schema.minItems)) {
931
+ return false;
932
+ }
933
+ if (schema.uniqueItems) {
934
+ /* Create a set to eliminate values with multiple occurences */
935
+ const dataSet = new Set(data);
936
+ if (data.length !== dataSet.size) {
937
+ return false;
938
+ }
939
+ }
940
+ /* Specific test for tuples */
941
+ if (Array.isArray(schema.items)) {
942
+ // TODO: cast should not be needed here
943
+ return this.validateTuple(data, schema.items);
944
+ }
945
+ /* Validate all the values in array */
946
+ for (const value of data) {
947
+ // TODO: remove when TypeScript 4.1 is available
948
+ // (currently the narrowed type from `Array.isArray()` is lost on readonly arrays)
949
+ if (!this.validate(value, schema.items)) {
950
+ return false;
951
+ }
952
+ }
953
+ return true;
954
+ }
955
+ /**
956
+ * Validate a tuple (array with fixed length and multiple types)
957
+ * @param data Data to validate
958
+ * @param schemas Schemas describing the tuple
959
+ * @returns If data is valid: `true`, if it is invalid: `false`
960
+ */
961
+ validateTuple(data, schemas) {
962
+ /* Tuples have a fixed length */
963
+ if (data.length !== schemas.length) {
964
+ return false;
965
+ }
966
+ for (let i = 0; i < schemas.length; i += 1) {
967
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
968
+ if (!this.validate(data[i], schemas[i])) {
969
+ return false;
970
+ }
971
+ }
972
+ return true;
973
+ }
974
+ /**
975
+ * Validate an object
976
+ * @param data Data to validate
977
+ * @param schema JSON schema describing the object
978
+ * @returns If data is valid: `true`, if it is invalid: `false`
833
979
  */
834
- clear() {
835
- this.memoryStorage.clear();
836
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
837
- return of(undefined);
980
+ validateObject(data, schema) {
981
+ /* Check the type and if not `null` as `null` also have the type `object` in old browsers */
982
+ if ((typeof data !== "object") || (data === null)) {
983
+ return false;
984
+ }
985
+ /* Check if the object doesn't have more properties than expected
986
+ * Equivalent of `additionalProperties: false`
987
+ */
988
+ if (Object.keys(schema.properties).length < Object.keys(data).length) {
989
+ return false;
990
+ }
991
+ /* Validate required properties */
992
+ if (schema.required) {
993
+ for (const requiredProp of schema.required) {
994
+ if (!Object.prototype.hasOwnProperty.call(data, requiredProp)) {
995
+ return false;
996
+ }
997
+ }
998
+ }
999
+ /* Recursively validate all properties */
1000
+ for (const property in schema.properties) {
1001
+ /* Filter to keep only real properties (no internal JS stuff) and check if the data has the property too */
1002
+ if (Object.prototype.hasOwnProperty.call(schema.properties, property) && Object.prototype.hasOwnProperty.call(data, property)) {
1003
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1004
+ if (!this.validate(data[property], schema.properties[property])) {
1005
+ return false;
1006
+ }
1007
+ }
1008
+ }
1009
+ return true;
838
1010
  }
839
1011
  /**
840
- * Get all keys in memory
841
- * @returns A RxJS `Observable` iterating on keys
1012
+ * Validate a constant
1013
+ * @param data Data ta validate
1014
+ * @param schema JSON schema describing the constant
1015
+ * @returns If data is valid: `true`, if it is invalid: `false`
842
1016
  */
843
- keys() {
844
- /* Create an `Observable` from keys */
845
- return from(this.memoryStorage.keys());
1017
+ validateConst(data, schema) {
1018
+ if (!schema.const) {
1019
+ return true;
1020
+ }
1021
+ return (data === schema.const);
846
1022
  }
847
1023
  /**
848
- * Check if a key exists in memory
849
- * @param key Key name
850
- * @returns a RxJS `Observable` telling if the key exists or not
851
- */
852
- has(key) {
853
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
854
- return of(this.memoryStorage.has(key));
855
- }
856
- }
857
- MemoryDatabase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: MemoryDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
858
- MemoryDatabase.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: MemoryDatabase, providedIn: 'root' });
859
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: MemoryDatabase, decorators: [{
860
- type: Injectable,
861
- args: [{
862
- providedIn: 'root'
863
- }]
864
- }] });
865
-
866
- /**
867
- * Factory to create a storage according to browser support
868
- * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/BROWSERS_SUPPORT.md}
869
- */
870
- function localDatabaseFactory() {
871
- const platformId = inject(PLATFORM_ID);
872
- /* When storage is fully disabled in browser (via the "Block all cookies" option),
873
- * just trying to check `indexedDB` or `localStorage` variables causes a security exception.
874
- * Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118
1024
+ * Validate an enum
1025
+ * @param data Data ta validate
1026
+ * @param schema JSON schema describing the enum
1027
+ * @returns If data is valid: `true`, if it is invalid: `false`
875
1028
  */
876
- try {
877
- // Do not explicit `window` here, as the global object is not the same in web workers
878
- if (isPlatformBrowser(platformId) && (indexedDB !== undefined) && (indexedDB !== null) && ('open' in indexedDB)) {
879
- /* Check:
880
- * - if we are in a browser context (issue: server-side rendering)
881
- * - it could exist but be `undefined` or `null`
882
- * - it could exists but not having a working API
883
- * Will be the case for:
884
- * - All other browsers in normal mode
885
- * - Chromium / Safari private mode, but in this case, data will be swiped when the user leaves the app */
886
- return new IndexedDBDatabase();
887
- }
888
- else if (isPlatformBrowser(platformId)
889
- && (localStorage !== undefined) && (localStorage !== null) && ('getItem' in localStorage)) {
890
- /* Check:
891
- * - if we are in a browser context (issue: server-side rendering)
892
- * - if `localStorage` exists (to be sure)
893
- * - it could exists but not having a working API
894
- * Will be the case for:
895
- * - Safari cross-origin iframes, detected later in `IndexedDBDatabase.connect()`
896
- * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/42}
897
- * - Firefox private mode, but in this case, data will be swiped when the user leaves the app
898
- * For Firefox, can only be detected later in `IndexedDBDatabase.connect()`
899
- * @see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=781982}
900
- */
901
- return new LocalStorageDatabase();
1029
+ validateEnum(data, schema) {
1030
+ if (!schema.enum) {
1031
+ return true;
902
1032
  }
1033
+ /* Cast as the data can be of multiple types, and so TypeScript is lost */
1034
+ return (schema.enum.includes(data));
903
1035
  }
904
- catch {
905
- // Nothing to do
906
- }
907
- /* Will be the case for:
908
- * - In browsers if storage has been fully disabled (via the "Block all cookies" option)
909
- * - Server-side rendering
910
- * - All other non-browser context
911
- */
912
- return new MemoryDatabase();
913
- }
914
- class LocalDatabase {
1036
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1037
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, providedIn: "root" }); }
915
1038
  }
916
- LocalDatabase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
917
- LocalDatabase.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalDatabase, providedIn: 'root', useFactory: localDatabaseFactory });
918
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalDatabase, decorators: [{
1039
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, decorators: [{
919
1040
  type: Injectable,
920
1041
  args: [{
921
- providedIn: 'root',
922
- useFactory: localDatabaseFactory,
1042
+ providedIn: "root"
923
1043
  }]
924
1044
  }] });
925
1045
 
926
- /**
927
- * Exception message when a value is not valid against the JSON schema
928
- */
929
- const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.
930
- Check your JSON schema, otherwise it means data has been corrupted.`;
931
- /**
932
- * Exception raised when a value is not valid against the JSON schema
933
- */
934
- class ValidationError extends Error {
935
- constructor() {
936
- super(...arguments);
937
- this.message = VALIDATION_ERROR;
938
- }
939
- }
940
-
941
1046
  class StorageMap {
942
1047
  /**
943
1048
  * Constructor params are provided by Angular (but can also be passed manually in tests)
@@ -945,12 +1050,9 @@ class StorageMap {
945
1050
  * @param jsonValidator Validator service
946
1051
  * @param LSPrefix Prefix for `localStorage` keys to avoid collision for multiple apps on the same subdomain or for interoperability
947
1052
  */
948
- constructor(database, jsonValidator = new JSONValidator(),
949
- // `inject()` cannot be used here, as `StorageMap` needs other manual params
950
- LSPrefix = '') {
1053
+ constructor(database, jsonValidator = new JSONValidator()) {
951
1054
  this.database = database;
952
1055
  this.jsonValidator = jsonValidator;
953
- this.LSPrefix = LSPrefix;
954
1056
  this.notifiers = new Map();
955
1057
  }
956
1058
  /**
@@ -982,16 +1084,16 @@ class StorageMap {
982
1084
  */
983
1085
  get backingEngine() {
984
1086
  if (this.database instanceof IndexedDBDatabase) {
985
- return 'indexedDB';
1087
+ return "indexedDB";
986
1088
  }
987
1089
  else if (this.database instanceof LocalStorageDatabase) {
988
- return 'localStorage';
1090
+ return "localStorage";
989
1091
  }
990
1092
  else if (this.database instanceof MemoryDatabase) {
991
- return 'memory';
1093
+ return "memory";
992
1094
  }
993
1095
  else {
994
- return 'unknown';
1096
+ return "unknown";
995
1097
  }
996
1098
  }
997
1099
  /**
@@ -1010,7 +1112,7 @@ class StorageMap {
1010
1112
  get backingStore() {
1011
1113
  return (this.database instanceof IndexedDBDatabase) ?
1012
1114
  this.database.backingStore :
1013
- { database: '', store: '', version: 0 };
1115
+ { database: "", store: "", version: 0 };
1014
1116
  }
1015
1117
  /**
1016
1118
  * Info about `localStorage` fallback storage. *Only useful for interoperability.*
@@ -1028,7 +1130,7 @@ class StorageMap {
1028
1130
  get fallbackBackingStore() {
1029
1131
  return (this.database instanceof LocalStorageDatabase) ?
1030
1132
  { prefix: this.database.prefix } :
1031
- { prefix: '' };
1133
+ { prefix: "" };
1032
1134
  }
1033
1135
  get(key, schema) {
1034
1136
  /* Get the data in storage */
@@ -1180,7 +1282,7 @@ class StorageMap {
1180
1282
  return catchError((error) => {
1181
1283
  /* Check if `indexedDB` is broken based on error message (the specific error class seems to be lost in the process) */
1182
1284
  if ((error !== undefined) && (error !== null)
1183
- && (typeof error === 'object') && ('message' in error)
1285
+ && (typeof error === "object") && ("message" in error)
1184
1286
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1185
1287
  && (error.message === IDB_BROKEN_ERROR)) {
1186
1288
  /* When storage is fully disabled in browser (via the "Block all cookies" option),
@@ -1188,9 +1290,9 @@ class StorageMap {
1188
1290
  * Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118
1189
1291
  */
1190
1292
  try {
1191
- if ('getItem' in localStorage) {
1293
+ if ("getItem" in localStorage) {
1192
1294
  /* Fallback to `localStorage` if available */
1193
- this.database = new LocalStorageDatabase(this.LSPrefix);
1295
+ this.database = new LocalStorageDatabase();
1194
1296
  }
1195
1297
  else {
1196
1298
  /* Fallback to memory storage otherwise */
@@ -1211,24 +1313,21 @@ class StorageMap {
1211
1313
  }
1212
1314
  });
1213
1315
  }
1316
+ 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 }); }
1317
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageMap, providedIn: "root" }); }
1214
1318
  }
1215
- StorageMap.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageMap, deps: [{ token: LocalDatabase }, { token: JSONValidator }, { token: LS_PREFIX }], target: i0.ɵɵFactoryTarget.Injectable });
1216
- StorageMap.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageMap, providedIn: 'root' });
1217
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageMap, decorators: [{
1319
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageMap, decorators: [{
1218
1320
  type: Injectable,
1219
1321
  args: [{
1220
- providedIn: 'root'
1322
+ providedIn: "root"
1221
1323
  }]
1222
- }], ctorParameters: function () { return [{ type: LocalDatabase }, { type: JSONValidator }, { type: undefined, decorators: [{
1223
- type: Inject,
1224
- args: [LS_PREFIX]
1225
- }] }]; } });
1324
+ }], ctorParameters: function () { return [{ type: LocalDatabase }, { type: JSONValidator }]; } });
1226
1325
 
1326
+ /**
1327
+ * @deprecated Will be removed in v17
1328
+ * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/MIGRATION_TO_V16.md}
1329
+ */
1227
1330
  class LocalStorage {
1228
- /* Use the `StorageMap` service to avoid code duplication */
1229
- constructor(storageMap) {
1230
- this.storageMap = storageMap;
1231
- }
1232
1331
  /**
1233
1332
  * Number of items in storage wrapped in an `Observable`
1234
1333
  *
@@ -1240,10 +1339,14 @@ class LocalStorage {
1240
1339
  get length() {
1241
1340
  return this.storageMap.size;
1242
1341
  }
1342
+ /* Use the `StorageMap` service to avoid code duplication */
1343
+ constructor(storageMap) {
1344
+ this.storageMap = storageMap;
1345
+ }
1243
1346
  getItem(key, schema) {
1244
1347
  if (schema) {
1245
1348
  /* Backward compatibility with version <= 7 */
1246
- schema = ('schema' in schema) ? schema.schema : schema;
1349
+ schema = ("schema" in schema) ? schema.schema : schema;
1247
1350
  }
1248
1351
  return (schema ? this.storageMap.get(key, schema) : this.storageMap.get(key)).pipe(
1249
1352
  /* Transform `undefined` into `null` to align with `localStorage` API */
@@ -1290,131 +1393,16 @@ class LocalStorage {
1290
1393
  /* Transform `undefined` into `true` for backward compatibility with v7 */
1291
1394
  map(() => true));
1292
1395
  }
1396
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, deps: [{ token: StorageMap }], target: i0.ɵɵFactoryTarget.Injectable }); }
1397
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, providedIn: "root" }); }
1293
1398
  }
1294
- LocalStorage.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalStorage, deps: [{ token: StorageMap }], target: i0.ɵɵFactoryTarget.Injectable });
1295
- LocalStorage.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalStorage, providedIn: 'root' });
1296
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalStorage, decorators: [{
1399
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, decorators: [{
1297
1400
  type: Injectable,
1298
1401
  args: [{
1299
- providedIn: 'root'
1402
+ providedIn: "root"
1300
1403
  }]
1301
1404
  }], ctorParameters: function () { return [{ type: StorageMap }]; } });
1302
1405
 
1303
- /**
1304
- * This module does not contain anything, it's only useful to provide options via `.forRoot()`.
1305
- */
1306
- class StorageModule {
1307
- /**
1308
- * Only useful to provide options, otherwise it does nothing.
1309
- * **Must be used at initialization, ie. in `AppModule`, and must not be loaded again in another module.**
1310
- *
1311
- * @example
1312
- * NgModule({
1313
- * imports: [StorageModule.forRoot({
1314
- * LSPrefix: 'custom_',
1315
- * })]
1316
- * })
1317
- * export class AppModule
1318
- */
1319
- static forRoot(config) {
1320
- return {
1321
- ngModule: StorageModule,
1322
- providers: [
1323
- config.LSPrefix ? { provide: LS_PREFIX, useValue: config.LSPrefix } : [],
1324
- config.IDBDBName ? { provide: IDB_DB_NAME, useValue: config.IDBDBName } : [],
1325
- config.IDBStoreName ? { provide: IDB_STORE_NAME, useValue: config.IDBStoreName } : [],
1326
- config.IDBDBVersion ? { provide: IDB_DB_VERSION, useValue: config.IDBDBVersion } : [],
1327
- (config.IDBNoWrap === false) ? { provide: IDB_NO_WRAP, useValue: config.IDBNoWrap } : [],
1328
- ],
1329
- };
1330
- }
1331
- }
1332
- StorageModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1333
- StorageModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: StorageModule });
1334
- StorageModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageModule });
1335
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageModule, decorators: [{
1336
- type: NgModule
1337
- }] });
1338
-
1339
- /**
1340
- * Allows to add a prefix before `localStorage` keys.
1341
- * *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
1342
- * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
1343
- *
1344
- * @example
1345
- * bootstrapApplication(AppComponent, {
1346
- * providers: [provideLocalStoragePrefix('custom_')]
1347
- * });
1348
- *
1349
- * @example
1350
- * NgModule({
1351
- * providers: [provideLocalStoragePrefix('custom_')]
1352
- * })
1353
- * export class AppModule
1354
- */
1355
- function provideLocalStoragePrefix(prefix) {
1356
- return makeEnvironmentProviders([{ provide: LS_PREFIX, useValue: prefix }]);
1357
- }
1358
- /**
1359
- * Allows to change the name used for `indexedDB` database.
1360
- * *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
1361
- * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
1362
- *
1363
- * @example
1364
- * bootstrapApplication(AppComponent, {
1365
- * providers: [provideIndexedDBDataBaseName('custom')]
1366
- * });
1367
- *
1368
- * @example
1369
- * NgModule({
1370
- * providers: [provideIndexedDBDataBaseName('custom')]
1371
- * })
1372
- * export class AppModule
1373
- */
1374
- function provideIndexedDBDataBaseName(name) {
1375
- return makeEnvironmentProviders([{ provide: IDB_DB_NAME, useValue: name }]);
1376
- }
1377
- /**
1378
- * Allows to change the database version used for `indexedDB` database.
1379
- * Must be an unsigned **integer**.
1380
- * **Use with caution as the creation of the store depends on the version.**
1381
- * *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
1382
- * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
1383
- *
1384
- * @example
1385
- * bootstrapApplication(AppComponent, {
1386
- * providers: [provideIndexedDBDataBaseVersion(2)]
1387
- * });
1388
- *
1389
- * @example
1390
- * NgModule({
1391
- * providers: [provideIndexedDBDataBaseVersion(2)]
1392
- * })
1393
- * export class AppModule
1394
- */
1395
- function provideIndexedDBDataBaseVersion(version) {
1396
- return makeEnvironmentProviders([{ provide: IDB_DB_VERSION, useValue: version }]);
1397
- }
1398
- /**
1399
- * Allows to change the name used for `indexedDB` object store.
1400
- * *Use only* for interoperability with other APIs.
1401
- * **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
1402
- *
1403
- * @example
1404
- * bootstrapApplication(AppComponent, {
1405
- * providers: [provideIndexedDBStoreName('custom')]
1406
- * });
1407
- *
1408
- * @example
1409
- * NgModule({
1410
- * providers: [provideIndexedDBStoreName('custom')]
1411
- * })
1412
- * export class AppModule
1413
- */
1414
- function provideIndexedDBStoreName(name) {
1415
- return makeEnvironmentProviders([{ provide: IDB_STORE_NAME, useValue: name }]);
1416
- }
1417
-
1418
1406
  /*
1419
1407
  * Public API Surface of local-storage
1420
1408
  */
@@ -1425,4 +1413,3 @@ function provideIndexedDBStoreName(name) {
1425
1413
 
1426
1414
  export { JSONValidator, LocalDatabase, LocalStorage, SERIALIZATION_ERROR, SerializationError, StorageMap, StorageModule, VALIDATION_ERROR, ValidationError, provideIndexedDBDataBaseName, provideIndexedDBDataBaseVersion, provideIndexedDBStoreName, provideLocalStoragePrefix };
1427
1415
  //# sourceMappingURL=ngx-pwa-local-storage.mjs.map
1428
- //# sourceMappingURL=ngx-pwa-local-storage.mjs.map