@ngx-pwa/local-storage 15.0.0 → 16.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 (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 +40 -0
  8. package/esm2022/lib/storages/local-storage.service.mjs +81 -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 +543 -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 +2 -2
  22. package/lib/storages/local-storage.service.d.ts +3 -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,472 @@ 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 does not contain anything, it's only useful to provide options via `.forRoot()`.
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
+ * @example
770
+ * NgModule({
771
+ * imports: [StorageModule.forRoot({
772
+ * LSPrefix: 'custom_',
773
+ * })]
774
+ * })
775
+ * export class AppModule
776
+ */
777
+ static forRoot(config) {
778
+ return {
779
+ ngModule: StorageModule,
780
+ providers: [
781
+ config.LSPrefix ? { provide: LS_PREFIX, useValue: config.LSPrefix } : [],
782
+ config.IDBDBName ? { provide: IDB_DB_NAME, useValue: config.IDBDBName } : [],
783
+ config.IDBStoreName ? { provide: IDB_STORE_NAME, useValue: config.IDBStoreName } : [],
784
+ config.IDBDBVersion ? { provide: IDB_DB_VERSION, useValue: config.IDBDBVersion } : [],
785
+ (config.IDBNoWrap === false) ? { provide: IDB_NO_WRAP, useValue: config.IDBNoWrap } : [],
786
+ ],
787
+ };
788
+ }
789
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
790
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.0", ngImport: i0, type: StorageModule }); }
791
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule }); }
792
+ }
793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule, decorators: [{
794
+ type: NgModule
795
+ }] });
796
+
797
+ /**
798
+ * Exception message when a value is not valid against the JSON schema
799
+ */
800
+ const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.
801
+ Check your JSON schema, otherwise it means data has been corrupted.`;
802
+ /**
803
+ * Exception raised when a value is not valid against the JSON schema
804
+ */
805
+ class ValidationError extends Error {
806
+ constructor() {
807
+ super(...arguments);
808
+ this.message = VALIDATION_ERROR;
809
+ }
810
+ }
811
+
812
+ class JSONValidator {
813
+ /**
814
+ * Validate a JSON data against a Jsubset of the JSON Schema standard.
815
+ * Types are enforced to validate everything: each schema must
816
+ * @param data JSON data to validate
817
+ * @param schema Subset of JSON Schema. Must have a `type`.
818
+ * @returns If data is valid: `true`, if it is invalid: `false`
819
+ * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/VALIDATION.md}
820
+ */
821
+ validate(data, schema) {
822
+ switch (schema.type) {
823
+ case "string":
824
+ return this.validateString(data, schema);
825
+ case "number":
826
+ case "integer":
827
+ return this.validateNumber(data, schema);
828
+ case "boolean":
829
+ return this.validateBoolean(data, schema);
830
+ case "array":
831
+ return this.validateArray(data, schema);
832
+ case "object":
833
+ return this.validateObject(data, schema);
834
+ }
835
+ }
836
+ /**
837
+ * Validate a string
838
+ * @param data Data to validate
839
+ * @param schema Schema describing the string
840
+ * @returns If data is valid: `true`, if it is invalid: `false`
841
+ */
842
+ validateString(data, schema) {
843
+ if (typeof data !== "string") {
844
+ return false;
845
+ }
846
+ if (!this.validateConst(data, schema)) {
847
+ return false;
848
+ }
849
+ if (!this.validateEnum(data, schema)) {
850
+ return false;
851
+ }
852
+ if ((schema.maxLength !== undefined) && (data.length > schema.maxLength)) {
853
+ return false;
854
+ }
855
+ if ((schema.minLength !== undefined) && (data.length < schema.minLength)) {
856
+ return false;
857
+ }
858
+ if (schema.pattern) {
859
+ let regularExpression = null;
860
+ try {
861
+ regularExpression = new RegExp(schema.pattern);
862
+ }
863
+ catch {
864
+ // Nothing to do
865
+ }
866
+ if (regularExpression && !regularExpression.test(data)) {
867
+ return false;
868
+ }
869
+ }
870
+ return true;
871
+ }
872
+ /**
873
+ * Validate a number or an integer
874
+ * @param data Data to validate
875
+ * @param schema Schema describing the number or integer
876
+ * @returns If data is valid: `true`, if it is invalid: `false`
877
+ */
878
+ validateNumber(data, schema) {
879
+ if (typeof data !== "number") {
880
+ return false;
881
+ }
882
+ if ((schema.type === "integer") && !Number.isInteger(data)) {
883
+ return false;
884
+ }
885
+ if (!this.validateConst(data, schema)) {
886
+ return false;
887
+ }
888
+ if (!this.validateEnum(data, schema)) {
889
+ return false;
890
+ }
891
+ /* Test is done this way to not divide by 0 */
892
+ if (schema.multipleOf && !Number.isInteger(data / schema.multipleOf)) {
893
+ return false;
894
+ }
895
+ if ((schema.maximum !== undefined) && (data > schema.maximum)) {
896
+ return false;
897
+ }
898
+ if ((schema.exclusiveMaximum !== undefined) && (data >= schema.exclusiveMaximum)) {
899
+ return false;
900
+ }
901
+ if ((schema.minimum !== undefined) && (data < schema.minimum)) {
902
+ return false;
903
+ }
904
+ if ((schema.exclusiveMinimum !== undefined) && (data <= schema.exclusiveMinimum)) {
905
+ return false;
906
+ }
907
+ return true;
908
+ }
909
+ /**
910
+ * Validate a boolean
911
+ * @param data Data to validate
912
+ * @param schema Schema describing the boolean
913
+ * @returns If data is valid: `true`, if it is invalid: `false`
914
+ */
915
+ validateBoolean(data, schema) {
916
+ if (typeof data !== "boolean") {
917
+ return false;
918
+ }
919
+ if (!this.validateConst(data, schema)) {
920
+ return false;
921
+ }
922
+ return true;
923
+ }
924
+ /**
925
+ * Validate an array
926
+ * @param data Data to validate
927
+ * @param schema Schema describing the array
928
+ * @returns If data is valid: `true`, if it is invalid: `false`
929
+ */
930
+ validateArray(data, schema) {
931
+ if (!Array.isArray(data)) {
932
+ return false;
933
+ }
934
+ if ((schema.maxItems !== undefined) && (data.length > schema.maxItems)) {
935
+ return false;
936
+ }
937
+ if ((schema.minItems !== undefined) && (data.length < schema.minItems)) {
938
+ return false;
939
+ }
940
+ if (schema.uniqueItems) {
941
+ /* Create a set to eliminate values with multiple occurences */
942
+ const dataSet = new Set(data);
943
+ if (data.length !== dataSet.size) {
944
+ return false;
945
+ }
946
+ }
947
+ /* Specific test for tuples */
948
+ if (Array.isArray(schema.items)) {
949
+ // TODO: cast should not be needed here
950
+ return this.validateTuple(data, schema.items);
951
+ }
952
+ /* Validate all the values in array */
953
+ for (const value of data) {
954
+ // TODO: remove when TypeScript 4.1 is available
955
+ // (currently the narrowed type from `Array.isArray()` is lost on readonly arrays)
956
+ if (!this.validate(value, schema.items)) {
957
+ return false;
958
+ }
959
+ }
960
+ return true;
961
+ }
962
+ /**
963
+ * Validate a tuple (array with fixed length and multiple types)
964
+ * @param data Data to validate
965
+ * @param schemas Schemas describing the tuple
966
+ * @returns If data is valid: `true`, if it is invalid: `false`
967
+ */
968
+ validateTuple(data, schemas) {
969
+ /* Tuples have a fixed length */
970
+ if (data.length !== schemas.length) {
971
+ return false;
972
+ }
973
+ for (let i = 0; i < schemas.length; i += 1) {
974
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
975
+ if (!this.validate(data[i], schemas[i])) {
976
+ return false;
977
+ }
978
+ }
979
+ return true;
980
+ }
981
+ /**
982
+ * Validate an object
983
+ * @param data Data to validate
984
+ * @param schema JSON schema describing the object
985
+ * @returns If data is valid: `true`, if it is invalid: `false`
833
986
  */
834
- clear() {
835
- this.memoryStorage.clear();
836
- /* Wrap in a RxJS `Observable` to be consistent with other storages */
837
- return of(undefined);
987
+ validateObject(data, schema) {
988
+ /* Check the type and if not `null` as `null` also have the type `object` in old browsers */
989
+ if ((typeof data !== "object") || (data === null)) {
990
+ return false;
991
+ }
992
+ /* Check if the object doesn't have more properties than expected
993
+ * Equivalent of `additionalProperties: false`
994
+ */
995
+ if (Object.keys(schema.properties).length < Object.keys(data).length) {
996
+ return false;
997
+ }
998
+ /* Validate required properties */
999
+ if (schema.required) {
1000
+ for (const requiredProp of schema.required) {
1001
+ if (!Object.prototype.hasOwnProperty.call(data, requiredProp)) {
1002
+ return false;
1003
+ }
1004
+ }
1005
+ }
1006
+ /* Recursively validate all properties */
1007
+ for (const property in schema.properties) {
1008
+ /* 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
1011
+ if (!this.validate(data[property], schema.properties[property])) {
1012
+ return false;
1013
+ }
1014
+ }
1015
+ }
1016
+ return true;
838
1017
  }
839
1018
  /**
840
- * Get all keys in memory
841
- * @returns A RxJS `Observable` iterating on keys
1019
+ * Validate a constant
1020
+ * @param data Data ta validate
1021
+ * @param schema JSON schema describing the constant
1022
+ * @returns If data is valid: `true`, if it is invalid: `false`
842
1023
  */
843
- keys() {
844
- /* Create an `Observable` from keys */
845
- return from(this.memoryStorage.keys());
1024
+ validateConst(data, schema) {
1025
+ if (!schema.const) {
1026
+ return true;
1027
+ }
1028
+ return (data === schema.const);
846
1029
  }
847
1030
  /**
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
1031
+ * Validate an enum
1032
+ * @param data Data ta validate
1033
+ * @param schema JSON schema describing the enum
1034
+ * @returns If data is valid: `true`, if it is invalid: `false`
875
1035
  */
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();
1036
+ validateEnum(data, schema) {
1037
+ if (!schema.enum) {
1038
+ return true;
902
1039
  }
1040
+ /* Cast as the data can be of multiple types, and so TypeScript is lost */
1041
+ return (schema.enum.includes(data));
903
1042
  }
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 {
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" }); }
915
1045
  }
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: [{
1046
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, decorators: [{
919
1047
  type: Injectable,
920
1048
  args: [{
921
- providedIn: 'root',
922
- useFactory: localDatabaseFactory,
1049
+ providedIn: "root"
923
1050
  }]
924
1051
  }] });
925
1052
 
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
1053
  class StorageMap {
942
1054
  /**
943
1055
  * Constructor params are provided by Angular (but can also be passed manually in tests)
@@ -945,12 +1057,9 @@ class StorageMap {
945
1057
  * @param jsonValidator Validator service
946
1058
  * @param LSPrefix Prefix for `localStorage` keys to avoid collision for multiple apps on the same subdomain or for interoperability
947
1059
  */
948
- constructor(database, jsonValidator = new JSONValidator(),
949
- // `inject()` cannot be used here, as `StorageMap` needs other manual params
950
- LSPrefix = '') {
1060
+ constructor(database, jsonValidator = new JSONValidator()) {
951
1061
  this.database = database;
952
1062
  this.jsonValidator = jsonValidator;
953
- this.LSPrefix = LSPrefix;
954
1063
  this.notifiers = new Map();
955
1064
  }
956
1065
  /**
@@ -982,16 +1091,16 @@ class StorageMap {
982
1091
  */
983
1092
  get backingEngine() {
984
1093
  if (this.database instanceof IndexedDBDatabase) {
985
- return 'indexedDB';
1094
+ return "indexedDB";
986
1095
  }
987
1096
  else if (this.database instanceof LocalStorageDatabase) {
988
- return 'localStorage';
1097
+ return "localStorage";
989
1098
  }
990
1099
  else if (this.database instanceof MemoryDatabase) {
991
- return 'memory';
1100
+ return "memory";
992
1101
  }
993
1102
  else {
994
- return 'unknown';
1103
+ return "unknown";
995
1104
  }
996
1105
  }
997
1106
  /**
@@ -1010,7 +1119,7 @@ class StorageMap {
1010
1119
  get backingStore() {
1011
1120
  return (this.database instanceof IndexedDBDatabase) ?
1012
1121
  this.database.backingStore :
1013
- { database: '', store: '', version: 0 };
1122
+ { database: "", store: "", version: 0 };
1014
1123
  }
1015
1124
  /**
1016
1125
  * Info about `localStorage` fallback storage. *Only useful for interoperability.*
@@ -1028,7 +1137,7 @@ class StorageMap {
1028
1137
  get fallbackBackingStore() {
1029
1138
  return (this.database instanceof LocalStorageDatabase) ?
1030
1139
  { prefix: this.database.prefix } :
1031
- { prefix: '' };
1140
+ { prefix: "" };
1032
1141
  }
1033
1142
  get(key, schema) {
1034
1143
  /* Get the data in storage */
@@ -1180,7 +1289,7 @@ class StorageMap {
1180
1289
  return catchError((error) => {
1181
1290
  /* Check if `indexedDB` is broken based on error message (the specific error class seems to be lost in the process) */
1182
1291
  if ((error !== undefined) && (error !== null)
1183
- && (typeof error === 'object') && ('message' in error)
1292
+ && (typeof error === "object") && ("message" in error)
1184
1293
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1185
1294
  && (error.message === IDB_BROKEN_ERROR)) {
1186
1295
  /* When storage is fully disabled in browser (via the "Block all cookies" option),
@@ -1188,9 +1297,9 @@ class StorageMap {
1188
1297
  * Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118
1189
1298
  */
1190
1299
  try {
1191
- if ('getItem' in localStorage) {
1300
+ if ("getItem" in localStorage) {
1192
1301
  /* Fallback to `localStorage` if available */
1193
- this.database = new LocalStorageDatabase(this.LSPrefix);
1302
+ this.database = new LocalStorageDatabase();
1194
1303
  }
1195
1304
  else {
1196
1305
  /* Fallback to memory storage otherwise */
@@ -1211,24 +1320,17 @@ class StorageMap {
1211
1320
  }
1212
1321
  });
1213
1322
  }
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" }); }
1214
1325
  }
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: [{
1326
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageMap, decorators: [{
1218
1327
  type: Injectable,
1219
1328
  args: [{
1220
- providedIn: 'root'
1329
+ providedIn: "root"
1221
1330
  }]
1222
- }], ctorParameters: function () { return [{ type: LocalDatabase }, { type: JSONValidator }, { type: undefined, decorators: [{
1223
- type: Inject,
1224
- args: [LS_PREFIX]
1225
- }] }]; } });
1331
+ }], ctorParameters: function () { return [{ type: LocalDatabase }, { type: JSONValidator }]; } });
1226
1332
 
1227
1333
  class LocalStorage {
1228
- /* Use the `StorageMap` service to avoid code duplication */
1229
- constructor(storageMap) {
1230
- this.storageMap = storageMap;
1231
- }
1232
1334
  /**
1233
1335
  * Number of items in storage wrapped in an `Observable`
1234
1336
  *
@@ -1240,10 +1342,14 @@ class LocalStorage {
1240
1342
  get length() {
1241
1343
  return this.storageMap.size;
1242
1344
  }
1345
+ /* Use the `StorageMap` service to avoid code duplication */
1346
+ constructor(storageMap) {
1347
+ this.storageMap = storageMap;
1348
+ }
1243
1349
  getItem(key, schema) {
1244
1350
  if (schema) {
1245
1351
  /* Backward compatibility with version <= 7 */
1246
- schema = ('schema' in schema) ? schema.schema : schema;
1352
+ schema = ("schema" in schema) ? schema.schema : schema;
1247
1353
  }
1248
1354
  return (schema ? this.storageMap.get(key, schema) : this.storageMap.get(key)).pipe(
1249
1355
  /* Transform `undefined` into `null` to align with `localStorage` API */
@@ -1290,131 +1396,16 @@ class LocalStorage {
1290
1396
  /* Transform `undefined` into `true` for backward compatibility with v7 */
1291
1397
  map(() => true));
1292
1398
  }
1399
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, deps: [{ token: StorageMap }], target: i0.ɵɵFactoryTarget.Injectable }); }
1400
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, providedIn: "root" }); }
1293
1401
  }
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: [{
1402
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, decorators: [{
1297
1403
  type: Injectable,
1298
1404
  args: [{
1299
- providedIn: 'root'
1405
+ providedIn: "root"
1300
1406
  }]
1301
1407
  }], ctorParameters: function () { return [{ type: StorageMap }]; } });
1302
1408
 
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
1409
  /*
1419
1410
  * Public API Surface of local-storage
1420
1411
  */
@@ -1425,4 +1416,3 @@ function provideIndexedDBStoreName(name) {
1425
1416
 
1426
1417
  export { JSONValidator, LocalDatabase, LocalStorage, SERIALIZATION_ERROR, SerializationError, StorageMap, StorageModule, VALIDATION_ERROR, ValidationError, provideIndexedDBDataBaseName, provideIndexedDBDataBaseVersion, provideIndexedDBStoreName, provideLocalStoragePrefix };
1427
1418
  //# sourceMappingURL=ngx-pwa-local-storage.mjs.map
1428
- //# sourceMappingURL=ngx-pwa-local-storage.mjs.map