@ngx-pwa/local-storage 14.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.
- package/{esm2020 → esm2022}/lib/databases/exceptions.mjs +2 -2
- package/esm2022/lib/databases/indexeddb-database.mjs +305 -0
- package/esm2022/lib/databases/local-database.mjs +67 -0
- package/esm2022/lib/databases/localstorage-database.mjs +158 -0
- package/esm2022/lib/databases/memory-database.mjs +84 -0
- package/{esm2020 → esm2022}/lib/providers.mjs +3 -3
- package/esm2022/lib/storage.module.mjs +40 -0
- package/esm2022/lib/storages/local-storage.service.mjs +81 -0
- package/esm2022/lib/storages/storage-map.service.mjs +293 -0
- package/esm2022/lib/tokens.mjs +59 -0
- package/esm2022/lib/validation/json-schema.mjs +5 -0
- package/esm2022/lib/validation/json-validator.mjs +244 -0
- package/esm2022/public-api.mjs +12 -0
- package/{fesm2020 → fesm2022}/ngx-pwa-local-storage.mjs +543 -553
- package/fesm2022/ngx-pwa-local-storage.mjs.map +1 -0
- package/lib/databases/indexeddb-database.d.ts +2 -2
- package/lib/databases/local-database.d.ts +1 -1
- package/lib/databases/localstorage-database.d.ts +3 -3
- package/lib/databases/memory-database.d.ts +2 -2
- package/lib/providers.d.ts +1 -1
- package/lib/storage.module.d.ts +2 -2
- package/lib/storages/local-storage.service.d.ts +3 -3
- package/lib/storages/storage-map.service.d.ts +6 -7
- package/lib/tokens.d.ts +1 -1
- package/lib/validation/json-schema.d.ts +8 -8
- package/lib/validation/json-validator.d.ts +1 -1
- package/package.json +10 -16
- package/public-api.d.ts +10 -10
- package/schematics/collection.json +1 -1
- package/schematics/migration.json +1 -1
- package/schematics/ng-add/index.d.ts +1 -1
- package/schematics/ng-add/index.js +7 -7
- package/schematics/ng-add/index.js.map +1 -1
- package/schematics/ng-add/schema.json +2 -2
- package/schematics/ng-update/index.d.ts +1 -1
- package/schematics/ng-update/index.js +3 -3
- package/schematics/ng-update/index.js.map +1 -1
- package/schematics/utility/config.d.ts +1 -1
- package/schematics/utility/config.js +7 -7
- package/schematics/utility/module.d.ts +1 -1
- package/schematics/utility/module.js +6 -6
- package/schematics/utility/module.js.map +1 -1
- package/esm2020/lib/databases/indexeddb-database.mjs +0 -304
- package/esm2020/lib/databases/local-database.mjs +0 -66
- package/esm2020/lib/databases/localstorage-database.mjs +0 -160
- package/esm2020/lib/databases/memory-database.mjs +0 -83
- package/esm2020/lib/storage.module.mjs +0 -39
- package/esm2020/lib/storages/local-storage.service.mjs +0 -80
- package/esm2020/lib/storages/storage-map.service.mjs +0 -299
- package/esm2020/lib/tokens.mjs +0 -59
- package/esm2020/lib/validation/json-schema.mjs +0 -5
- package/esm2020/lib/validation/json-validator.mjs +0 -243
- package/esm2020/public-api.mjs +0 -12
- package/fesm2015/ngx-pwa-local-storage.mjs +0 -1432
- package/fesm2015/ngx-pwa-local-storage.mjs.map +0 -1
- package/fesm2020/ngx-pwa-local-storage.mjs.map +0 -1
- /package/{esm2020 → esm2022}/lib/storages/exceptions.mjs +0 -0
- /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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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(
|
|
252
|
-
providedIn:
|
|
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 =
|
|
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(
|
|
263
|
-
providedIn:
|
|
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(
|
|
275
|
-
providedIn:
|
|
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 =
|
|
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(
|
|
287
|
-
providedIn:
|
|
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(
|
|
302
|
-
providedIn:
|
|
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 =
|
|
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(
|
|
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(
|
|
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 ===
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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:
|
|
387
|
+
providedIn: "root"
|
|
629
388
|
}]
|
|
630
389
|
}], ctorParameters: function () { return []; } });
|
|
631
390
|
|
|
632
391
|
class LocalStorageDatabase {
|
|
633
|
-
|
|
634
|
-
|
|
392
|
+
constructor() {
|
|
393
|
+
console.log('test');
|
|
635
394
|
/* Prefix if asked, or no prefix otherwise */
|
|
636
|
-
this.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 ===
|
|
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.
|
|
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
|
-
|
|
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:
|
|
538
|
+
providedIn: "root"
|
|
780
539
|
}]
|
|
781
|
-
}], ctorParameters: function () { return [
|
|
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
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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
|
-
*
|
|
841
|
-
* @
|
|
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
|
-
|
|
844
|
-
|
|
845
|
-
|
|
1024
|
+
validateConst(data, schema) {
|
|
1025
|
+
if (!schema.const) {
|
|
1026
|
+
return true;
|
|
1027
|
+
}
|
|
1028
|
+
return (data === schema.const);
|
|
846
1029
|
}
|
|
847
1030
|
/**
|
|
848
|
-
*
|
|
849
|
-
* @param
|
|
850
|
-
* @
|
|
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
|
-
|
|
877
|
-
|
|
878
|
-
|
|
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
|
-
|
|
905
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
1094
|
+
return "indexedDB";
|
|
986
1095
|
}
|
|
987
1096
|
else if (this.database instanceof LocalStorageDatabase) {
|
|
988
|
-
return
|
|
1097
|
+
return "localStorage";
|
|
989
1098
|
}
|
|
990
1099
|
else if (this.database instanceof MemoryDatabase) {
|
|
991
|
-
return
|
|
1100
|
+
return "memory";
|
|
992
1101
|
}
|
|
993
1102
|
else {
|
|
994
|
-
return
|
|
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:
|
|
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 ===
|
|
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 (
|
|
1300
|
+
if ("getItem" in localStorage) {
|
|
1192
1301
|
/* Fallback to `localStorage` if available */
|
|
1193
|
-
this.database = new LocalStorageDatabase(
|
|
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
|
-
|
|
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:
|
|
1329
|
+
providedIn: "root"
|
|
1221
1330
|
}]
|
|
1222
|
-
}], ctorParameters: function () { return [{ type: LocalDatabase }, { type: JSONValidator }
|
|
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 = (
|
|
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
|
-
|
|
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:
|
|
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
|