@ngx-pwa/local-storage 15.0.0 → 16.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +33 -0
- package/esm2022/lib/storages/local-storage.service.mjs +85 -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 +540 -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 +3 -10
- package/lib/storages/local-storage.service.d.ts +7 -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,465 @@ class MemoryDatabase {
|
|
|
828
584
|
return of(undefined);
|
|
829
585
|
}
|
|
830
586
|
/**
|
|
831
|
-
* Deletes all items in memory
|
|
832
|
-
* @returns A RxJS `Observable` to wait the end of the operation
|
|
587
|
+
* Deletes all items in memory
|
|
588
|
+
* @returns A RxJS `Observable` to wait the end of the operation
|
|
589
|
+
*/
|
|
590
|
+
clear() {
|
|
591
|
+
this.memoryStorage.clear();
|
|
592
|
+
/* Wrap in a RxJS `Observable` to be consistent with other storages */
|
|
593
|
+
return of(undefined);
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Get all keys in memory
|
|
597
|
+
* @returns A RxJS `Observable` iterating on keys
|
|
598
|
+
*/
|
|
599
|
+
keys() {
|
|
600
|
+
/* Create an `Observable` from keys */
|
|
601
|
+
return from(this.memoryStorage.keys());
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Check if a key exists in memory
|
|
605
|
+
* @param key Key name
|
|
606
|
+
* @returns a RxJS `Observable` telling if the key exists or not
|
|
607
|
+
*/
|
|
608
|
+
has(key) {
|
|
609
|
+
/* Wrap in a RxJS `Observable` to be consistent with other storages */
|
|
610
|
+
return of(this.memoryStorage.has(key));
|
|
611
|
+
}
|
|
612
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MemoryDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
613
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MemoryDatabase, providedIn: "root" }); }
|
|
614
|
+
}
|
|
615
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MemoryDatabase, decorators: [{
|
|
616
|
+
type: Injectable,
|
|
617
|
+
args: [{
|
|
618
|
+
providedIn: "root"
|
|
619
|
+
}]
|
|
620
|
+
}] });
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Factory to create a storage according to browser support
|
|
624
|
+
* @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/BROWSERS_SUPPORT.md}
|
|
625
|
+
*/
|
|
626
|
+
function localDatabaseFactory() {
|
|
627
|
+
const platformId = inject(PLATFORM_ID);
|
|
628
|
+
/* When storage is fully disabled in browser (via the "Block all cookies" option),
|
|
629
|
+
* just trying to check `indexedDB` or `localStorage` variables causes a security exception.
|
|
630
|
+
* Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118
|
|
631
|
+
*/
|
|
632
|
+
try {
|
|
633
|
+
// Do not explicit `window` here, as the global object is not the same in web workers
|
|
634
|
+
if (isPlatformBrowser(platformId) && (indexedDB !== undefined) && (indexedDB !== null) && ("open" in indexedDB)) {
|
|
635
|
+
/* Check:
|
|
636
|
+
* - if we are in a browser context (issue: server-side rendering)
|
|
637
|
+
* - it could exist but be `undefined` or `null`
|
|
638
|
+
* - it could exists but not having a working API
|
|
639
|
+
* Will be the case for:
|
|
640
|
+
* - All other browsers in normal mode
|
|
641
|
+
* - Chromium / Safari private mode, but in this case, data will be swiped when the user leaves the app */
|
|
642
|
+
return new IndexedDBDatabase();
|
|
643
|
+
}
|
|
644
|
+
else if (isPlatformBrowser(platformId)
|
|
645
|
+
&& (localStorage !== undefined) && (localStorage !== null) && ("getItem" in localStorage)) {
|
|
646
|
+
/* Check:
|
|
647
|
+
* - if we are in a browser context (issue: server-side rendering)
|
|
648
|
+
* - if `localStorage` exists (to be sure)
|
|
649
|
+
* - it could exists but not having a working API
|
|
650
|
+
* Will be the case for:
|
|
651
|
+
* - Safari cross-origin iframes, detected later in `IndexedDBDatabase.connect()`
|
|
652
|
+
* @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/42}
|
|
653
|
+
* - Firefox private mode, but in this case, data will be swiped when the user leaves the app
|
|
654
|
+
* For Firefox, can only be detected later in `IndexedDBDatabase.connect()`
|
|
655
|
+
* @see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=781982}
|
|
656
|
+
*/
|
|
657
|
+
return new LocalStorageDatabase();
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
catch {
|
|
661
|
+
// Nothing to do
|
|
662
|
+
}
|
|
663
|
+
/* Will be the case for:
|
|
664
|
+
* - In browsers if storage has been fully disabled (via the "Block all cookies" option)
|
|
665
|
+
* - Server-side rendering
|
|
666
|
+
* - All other non-browser context
|
|
667
|
+
*/
|
|
668
|
+
return new MemoryDatabase();
|
|
669
|
+
}
|
|
670
|
+
class LocalDatabase {
|
|
671
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalDatabase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
672
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalDatabase, providedIn: "root", useFactory: localDatabaseFactory }); }
|
|
673
|
+
}
|
|
674
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalDatabase, decorators: [{
|
|
675
|
+
type: Injectable,
|
|
676
|
+
args: [{
|
|
677
|
+
providedIn: "root",
|
|
678
|
+
useFactory: localDatabaseFactory,
|
|
679
|
+
}]
|
|
680
|
+
}] });
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Allows to add a prefix before `localStorage` keys.
|
|
684
|
+
* *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
|
|
685
|
+
* **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
|
|
686
|
+
*
|
|
687
|
+
* @example
|
|
688
|
+
* bootstrapApplication(AppComponent, {
|
|
689
|
+
* providers: [provideLocalStoragePrefix('custom_')]
|
|
690
|
+
* });
|
|
691
|
+
*
|
|
692
|
+
* @example
|
|
693
|
+
* NgModule({
|
|
694
|
+
* providers: [provideLocalStoragePrefix('custom_')]
|
|
695
|
+
* })
|
|
696
|
+
* export class AppModule
|
|
697
|
+
*/
|
|
698
|
+
function provideLocalStoragePrefix(prefix) {
|
|
699
|
+
return makeEnvironmentProviders([{ provide: LS_PREFIX, useValue: prefix }]);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Allows to change the name used for `indexedDB` database.
|
|
703
|
+
* *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
|
|
704
|
+
* **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
|
|
705
|
+
*
|
|
706
|
+
* @example
|
|
707
|
+
* bootstrapApplication(AppComponent, {
|
|
708
|
+
* providers: [provideIndexedDBDataBaseName('custom')]
|
|
709
|
+
* });
|
|
710
|
+
*
|
|
711
|
+
* @example
|
|
712
|
+
* NgModule({
|
|
713
|
+
* providers: [provideIndexedDBDataBaseName('custom')]
|
|
714
|
+
* })
|
|
715
|
+
* export class AppModule
|
|
716
|
+
*/
|
|
717
|
+
function provideIndexedDBDataBaseName(name) {
|
|
718
|
+
return makeEnvironmentProviders([{ provide: IDB_DB_NAME, useValue: name }]);
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Allows to change the database version used for `indexedDB` database.
|
|
722
|
+
* Must be an unsigned **integer**.
|
|
723
|
+
* **Use with caution as the creation of the store depends on the version.**
|
|
724
|
+
* *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
|
|
725
|
+
* **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* bootstrapApplication(AppComponent, {
|
|
729
|
+
* providers: [provideIndexedDBDataBaseVersion(2)]
|
|
730
|
+
* });
|
|
731
|
+
*
|
|
732
|
+
* @example
|
|
733
|
+
* NgModule({
|
|
734
|
+
* providers: [provideIndexedDBDataBaseVersion(2)]
|
|
735
|
+
* })
|
|
736
|
+
* export class AppModule
|
|
737
|
+
*/
|
|
738
|
+
function provideIndexedDBDataBaseVersion(version) {
|
|
739
|
+
return makeEnvironmentProviders([{ provide: IDB_DB_VERSION, useValue: version }]);
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Allows to change the name used for `indexedDB` object store.
|
|
743
|
+
* *Use only* for interoperability with other APIs.
|
|
744
|
+
* **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
|
|
745
|
+
*
|
|
746
|
+
* @example
|
|
747
|
+
* bootstrapApplication(AppComponent, {
|
|
748
|
+
* providers: [provideIndexedDBStoreName('custom')]
|
|
749
|
+
* });
|
|
750
|
+
*
|
|
751
|
+
* @example
|
|
752
|
+
* NgModule({
|
|
753
|
+
* providers: [provideIndexedDBStoreName('custom')]
|
|
754
|
+
* })
|
|
755
|
+
* export class AppModule
|
|
756
|
+
*/
|
|
757
|
+
function provideIndexedDBStoreName(name) {
|
|
758
|
+
return makeEnvironmentProviders([{ provide: IDB_STORE_NAME, useValue: name }]);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* This module is only here for backward compatibility, do not add it by yourself
|
|
763
|
+
*/
|
|
764
|
+
class StorageModule {
|
|
765
|
+
/**
|
|
766
|
+
* Only useful to provide options, otherwise it does nothing.
|
|
767
|
+
* **Must be used at initialization, ie. in `AppModule`, and must not be loaded again in another module.**
|
|
768
|
+
*
|
|
769
|
+
*/
|
|
770
|
+
static forRoot(config) {
|
|
771
|
+
return {
|
|
772
|
+
ngModule: StorageModule,
|
|
773
|
+
providers: [
|
|
774
|
+
config.LSPrefix ? { provide: LS_PREFIX, useValue: config.LSPrefix } : [],
|
|
775
|
+
config.IDBDBName ? { provide: IDB_DB_NAME, useValue: config.IDBDBName } : [],
|
|
776
|
+
config.IDBStoreName ? { provide: IDB_STORE_NAME, useValue: config.IDBStoreName } : [],
|
|
777
|
+
config.IDBDBVersion ? { provide: IDB_DB_VERSION, useValue: config.IDBDBVersion } : [],
|
|
778
|
+
(config.IDBNoWrap === false) ? { provide: IDB_NO_WRAP, useValue: config.IDBNoWrap } : [],
|
|
779
|
+
],
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
783
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.0", ngImport: i0, type: StorageModule }); }
|
|
784
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule }); }
|
|
785
|
+
}
|
|
786
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageModule, decorators: [{
|
|
787
|
+
type: NgModule
|
|
788
|
+
}] });
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Exception message when a value is not valid against the JSON schema
|
|
792
|
+
*/
|
|
793
|
+
const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.
|
|
794
|
+
Check your JSON schema, otherwise it means data has been corrupted.`;
|
|
795
|
+
/**
|
|
796
|
+
* Exception raised when a value is not valid against the JSON schema
|
|
797
|
+
*/
|
|
798
|
+
class ValidationError extends Error {
|
|
799
|
+
constructor() {
|
|
800
|
+
super(...arguments);
|
|
801
|
+
this.message = VALIDATION_ERROR;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
class JSONValidator {
|
|
806
|
+
/**
|
|
807
|
+
* Validate a JSON data against a Jsubset of the JSON Schema standard.
|
|
808
|
+
* Types are enforced to validate everything: each schema must
|
|
809
|
+
* @param data JSON data to validate
|
|
810
|
+
* @param schema Subset of JSON Schema. Must have a `type`.
|
|
811
|
+
* @returns If data is valid: `true`, if it is invalid: `false`
|
|
812
|
+
* @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/VALIDATION.md}
|
|
813
|
+
*/
|
|
814
|
+
validate(data, schema) {
|
|
815
|
+
switch (schema.type) {
|
|
816
|
+
case "string":
|
|
817
|
+
return this.validateString(data, schema);
|
|
818
|
+
case "number":
|
|
819
|
+
case "integer":
|
|
820
|
+
return this.validateNumber(data, schema);
|
|
821
|
+
case "boolean":
|
|
822
|
+
return this.validateBoolean(data, schema);
|
|
823
|
+
case "array":
|
|
824
|
+
return this.validateArray(data, schema);
|
|
825
|
+
case "object":
|
|
826
|
+
return this.validateObject(data, schema);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Validate a string
|
|
831
|
+
* @param data Data to validate
|
|
832
|
+
* @param schema Schema describing the string
|
|
833
|
+
* @returns If data is valid: `true`, if it is invalid: `false`
|
|
834
|
+
*/
|
|
835
|
+
validateString(data, schema) {
|
|
836
|
+
if (typeof data !== "string") {
|
|
837
|
+
return false;
|
|
838
|
+
}
|
|
839
|
+
if (!this.validateConst(data, schema)) {
|
|
840
|
+
return false;
|
|
841
|
+
}
|
|
842
|
+
if (!this.validateEnum(data, schema)) {
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
if ((schema.maxLength !== undefined) && (data.length > schema.maxLength)) {
|
|
846
|
+
return false;
|
|
847
|
+
}
|
|
848
|
+
if ((schema.minLength !== undefined) && (data.length < schema.minLength)) {
|
|
849
|
+
return false;
|
|
850
|
+
}
|
|
851
|
+
if (schema.pattern) {
|
|
852
|
+
let regularExpression = null;
|
|
853
|
+
try {
|
|
854
|
+
regularExpression = new RegExp(schema.pattern);
|
|
855
|
+
}
|
|
856
|
+
catch {
|
|
857
|
+
// Nothing to do
|
|
858
|
+
}
|
|
859
|
+
if (regularExpression && !regularExpression.test(data)) {
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
return true;
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Validate a number or an integer
|
|
867
|
+
* @param data Data to validate
|
|
868
|
+
* @param schema Schema describing the number or integer
|
|
869
|
+
* @returns If data is valid: `true`, if it is invalid: `false`
|
|
870
|
+
*/
|
|
871
|
+
validateNumber(data, schema) {
|
|
872
|
+
if (typeof data !== "number") {
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
if ((schema.type === "integer") && !Number.isInteger(data)) {
|
|
876
|
+
return false;
|
|
877
|
+
}
|
|
878
|
+
if (!this.validateConst(data, schema)) {
|
|
879
|
+
return false;
|
|
880
|
+
}
|
|
881
|
+
if (!this.validateEnum(data, schema)) {
|
|
882
|
+
return false;
|
|
883
|
+
}
|
|
884
|
+
/* Test is done this way to not divide by 0 */
|
|
885
|
+
if (schema.multipleOf && !Number.isInteger(data / schema.multipleOf)) {
|
|
886
|
+
return false;
|
|
887
|
+
}
|
|
888
|
+
if ((schema.maximum !== undefined) && (data > schema.maximum)) {
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
891
|
+
if ((schema.exclusiveMaximum !== undefined) && (data >= schema.exclusiveMaximum)) {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
if ((schema.minimum !== undefined) && (data < schema.minimum)) {
|
|
895
|
+
return false;
|
|
896
|
+
}
|
|
897
|
+
if ((schema.exclusiveMinimum !== undefined) && (data <= schema.exclusiveMinimum)) {
|
|
898
|
+
return false;
|
|
899
|
+
}
|
|
900
|
+
return true;
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* Validate a boolean
|
|
904
|
+
* @param data Data to validate
|
|
905
|
+
* @param schema Schema describing the boolean
|
|
906
|
+
* @returns If data is valid: `true`, if it is invalid: `false`
|
|
907
|
+
*/
|
|
908
|
+
validateBoolean(data, schema) {
|
|
909
|
+
if (typeof data !== "boolean") {
|
|
910
|
+
return false;
|
|
911
|
+
}
|
|
912
|
+
if (!this.validateConst(data, schema)) {
|
|
913
|
+
return false;
|
|
914
|
+
}
|
|
915
|
+
return true;
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Validate an array
|
|
919
|
+
* @param data Data to validate
|
|
920
|
+
* @param schema Schema describing the array
|
|
921
|
+
* @returns If data is valid: `true`, if it is invalid: `false`
|
|
922
|
+
*/
|
|
923
|
+
validateArray(data, schema) {
|
|
924
|
+
if (!Array.isArray(data)) {
|
|
925
|
+
return false;
|
|
926
|
+
}
|
|
927
|
+
if ((schema.maxItems !== undefined) && (data.length > schema.maxItems)) {
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
if ((schema.minItems !== undefined) && (data.length < schema.minItems)) {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
if (schema.uniqueItems) {
|
|
934
|
+
/* Create a set to eliminate values with multiple occurences */
|
|
935
|
+
const dataSet = new Set(data);
|
|
936
|
+
if (data.length !== dataSet.size) {
|
|
937
|
+
return false;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
/* Specific test for tuples */
|
|
941
|
+
if (Array.isArray(schema.items)) {
|
|
942
|
+
// TODO: cast should not be needed here
|
|
943
|
+
return this.validateTuple(data, schema.items);
|
|
944
|
+
}
|
|
945
|
+
/* Validate all the values in array */
|
|
946
|
+
for (const value of data) {
|
|
947
|
+
// TODO: remove when TypeScript 4.1 is available
|
|
948
|
+
// (currently the narrowed type from `Array.isArray()` is lost on readonly arrays)
|
|
949
|
+
if (!this.validate(value, schema.items)) {
|
|
950
|
+
return false;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return true;
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Validate a tuple (array with fixed length and multiple types)
|
|
957
|
+
* @param data Data to validate
|
|
958
|
+
* @param schemas Schemas describing the tuple
|
|
959
|
+
* @returns If data is valid: `true`, if it is invalid: `false`
|
|
960
|
+
*/
|
|
961
|
+
validateTuple(data, schemas) {
|
|
962
|
+
/* Tuples have a fixed length */
|
|
963
|
+
if (data.length !== schemas.length) {
|
|
964
|
+
return false;
|
|
965
|
+
}
|
|
966
|
+
for (let i = 0; i < schemas.length; i += 1) {
|
|
967
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
968
|
+
if (!this.validate(data[i], schemas[i])) {
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
return true;
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Validate an object
|
|
976
|
+
* @param data Data to validate
|
|
977
|
+
* @param schema JSON schema describing the object
|
|
978
|
+
* @returns If data is valid: `true`, if it is invalid: `false`
|
|
833
979
|
*/
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
980
|
+
validateObject(data, schema) {
|
|
981
|
+
/* Check the type and if not `null` as `null` also have the type `object` in old browsers */
|
|
982
|
+
if ((typeof data !== "object") || (data === null)) {
|
|
983
|
+
return false;
|
|
984
|
+
}
|
|
985
|
+
/* Check if the object doesn't have more properties than expected
|
|
986
|
+
* Equivalent of `additionalProperties: false`
|
|
987
|
+
*/
|
|
988
|
+
if (Object.keys(schema.properties).length < Object.keys(data).length) {
|
|
989
|
+
return false;
|
|
990
|
+
}
|
|
991
|
+
/* Validate required properties */
|
|
992
|
+
if (schema.required) {
|
|
993
|
+
for (const requiredProp of schema.required) {
|
|
994
|
+
if (!Object.prototype.hasOwnProperty.call(data, requiredProp)) {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
/* Recursively validate all properties */
|
|
1000
|
+
for (const property in schema.properties) {
|
|
1001
|
+
/* Filter to keep only real properties (no internal JS stuff) and check if the data has the property too */
|
|
1002
|
+
if (Object.prototype.hasOwnProperty.call(schema.properties, property) && Object.prototype.hasOwnProperty.call(data, property)) {
|
|
1003
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1004
|
+
if (!this.validate(data[property], schema.properties[property])) {
|
|
1005
|
+
return false;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
return true;
|
|
838
1010
|
}
|
|
839
1011
|
/**
|
|
840
|
-
*
|
|
841
|
-
* @
|
|
1012
|
+
* Validate a constant
|
|
1013
|
+
* @param data Data ta validate
|
|
1014
|
+
* @param schema JSON schema describing the constant
|
|
1015
|
+
* @returns If data is valid: `true`, if it is invalid: `false`
|
|
842
1016
|
*/
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
1017
|
+
validateConst(data, schema) {
|
|
1018
|
+
if (!schema.const) {
|
|
1019
|
+
return true;
|
|
1020
|
+
}
|
|
1021
|
+
return (data === schema.const);
|
|
846
1022
|
}
|
|
847
1023
|
/**
|
|
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
|
|
1024
|
+
* Validate an enum
|
|
1025
|
+
* @param data Data ta validate
|
|
1026
|
+
* @param schema JSON schema describing the enum
|
|
1027
|
+
* @returns If data is valid: `true`, if it is invalid: `false`
|
|
875
1028
|
*/
|
|
876
|
-
|
|
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();
|
|
1029
|
+
validateEnum(data, schema) {
|
|
1030
|
+
if (!schema.enum) {
|
|
1031
|
+
return true;
|
|
902
1032
|
}
|
|
1033
|
+
/* Cast as the data can be of multiple types, and so TypeScript is lost */
|
|
1034
|
+
return (schema.enum.includes(data));
|
|
903
1035
|
}
|
|
904
|
-
|
|
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 {
|
|
1036
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1037
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, providedIn: "root" }); }
|
|
915
1038
|
}
|
|
916
|
-
|
|
917
|
-
LocalDatabase.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalDatabase, providedIn: 'root', useFactory: localDatabaseFactory });
|
|
918
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalDatabase, decorators: [{
|
|
1039
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: JSONValidator, decorators: [{
|
|
919
1040
|
type: Injectable,
|
|
920
1041
|
args: [{
|
|
921
|
-
providedIn:
|
|
922
|
-
useFactory: localDatabaseFactory,
|
|
1042
|
+
providedIn: "root"
|
|
923
1043
|
}]
|
|
924
1044
|
}] });
|
|
925
1045
|
|
|
926
|
-
/**
|
|
927
|
-
* Exception message when a value is not valid against the JSON schema
|
|
928
|
-
*/
|
|
929
|
-
const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.
|
|
930
|
-
Check your JSON schema, otherwise it means data has been corrupted.`;
|
|
931
|
-
/**
|
|
932
|
-
* Exception raised when a value is not valid against the JSON schema
|
|
933
|
-
*/
|
|
934
|
-
class ValidationError extends Error {
|
|
935
|
-
constructor() {
|
|
936
|
-
super(...arguments);
|
|
937
|
-
this.message = VALIDATION_ERROR;
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
|
|
941
1046
|
class StorageMap {
|
|
942
1047
|
/**
|
|
943
1048
|
* Constructor params are provided by Angular (but can also be passed manually in tests)
|
|
@@ -945,12 +1050,9 @@ class StorageMap {
|
|
|
945
1050
|
* @param jsonValidator Validator service
|
|
946
1051
|
* @param LSPrefix Prefix for `localStorage` keys to avoid collision for multiple apps on the same subdomain or for interoperability
|
|
947
1052
|
*/
|
|
948
|
-
constructor(database, jsonValidator = new JSONValidator()
|
|
949
|
-
// `inject()` cannot be used here, as `StorageMap` needs other manual params
|
|
950
|
-
LSPrefix = '') {
|
|
1053
|
+
constructor(database, jsonValidator = new JSONValidator()) {
|
|
951
1054
|
this.database = database;
|
|
952
1055
|
this.jsonValidator = jsonValidator;
|
|
953
|
-
this.LSPrefix = LSPrefix;
|
|
954
1056
|
this.notifiers = new Map();
|
|
955
1057
|
}
|
|
956
1058
|
/**
|
|
@@ -982,16 +1084,16 @@ class StorageMap {
|
|
|
982
1084
|
*/
|
|
983
1085
|
get backingEngine() {
|
|
984
1086
|
if (this.database instanceof IndexedDBDatabase) {
|
|
985
|
-
return
|
|
1087
|
+
return "indexedDB";
|
|
986
1088
|
}
|
|
987
1089
|
else if (this.database instanceof LocalStorageDatabase) {
|
|
988
|
-
return
|
|
1090
|
+
return "localStorage";
|
|
989
1091
|
}
|
|
990
1092
|
else if (this.database instanceof MemoryDatabase) {
|
|
991
|
-
return
|
|
1093
|
+
return "memory";
|
|
992
1094
|
}
|
|
993
1095
|
else {
|
|
994
|
-
return
|
|
1096
|
+
return "unknown";
|
|
995
1097
|
}
|
|
996
1098
|
}
|
|
997
1099
|
/**
|
|
@@ -1010,7 +1112,7 @@ class StorageMap {
|
|
|
1010
1112
|
get backingStore() {
|
|
1011
1113
|
return (this.database instanceof IndexedDBDatabase) ?
|
|
1012
1114
|
this.database.backingStore :
|
|
1013
|
-
{ database:
|
|
1115
|
+
{ database: "", store: "", version: 0 };
|
|
1014
1116
|
}
|
|
1015
1117
|
/**
|
|
1016
1118
|
* Info about `localStorage` fallback storage. *Only useful for interoperability.*
|
|
@@ -1028,7 +1130,7 @@ class StorageMap {
|
|
|
1028
1130
|
get fallbackBackingStore() {
|
|
1029
1131
|
return (this.database instanceof LocalStorageDatabase) ?
|
|
1030
1132
|
{ prefix: this.database.prefix } :
|
|
1031
|
-
{ prefix:
|
|
1133
|
+
{ prefix: "" };
|
|
1032
1134
|
}
|
|
1033
1135
|
get(key, schema) {
|
|
1034
1136
|
/* Get the data in storage */
|
|
@@ -1180,7 +1282,7 @@ class StorageMap {
|
|
|
1180
1282
|
return catchError((error) => {
|
|
1181
1283
|
/* Check if `indexedDB` is broken based on error message (the specific error class seems to be lost in the process) */
|
|
1182
1284
|
if ((error !== undefined) && (error !== null)
|
|
1183
|
-
&& (typeof error ===
|
|
1285
|
+
&& (typeof error === "object") && ("message" in error)
|
|
1184
1286
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
1185
1287
|
&& (error.message === IDB_BROKEN_ERROR)) {
|
|
1186
1288
|
/* When storage is fully disabled in browser (via the "Block all cookies" option),
|
|
@@ -1188,9 +1290,9 @@ class StorageMap {
|
|
|
1188
1290
|
* Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118
|
|
1189
1291
|
*/
|
|
1190
1292
|
try {
|
|
1191
|
-
if (
|
|
1293
|
+
if ("getItem" in localStorage) {
|
|
1192
1294
|
/* Fallback to `localStorage` if available */
|
|
1193
|
-
this.database = new LocalStorageDatabase(
|
|
1295
|
+
this.database = new LocalStorageDatabase();
|
|
1194
1296
|
}
|
|
1195
1297
|
else {
|
|
1196
1298
|
/* Fallback to memory storage otherwise */
|
|
@@ -1211,24 +1313,21 @@ class StorageMap {
|
|
|
1211
1313
|
}
|
|
1212
1314
|
});
|
|
1213
1315
|
}
|
|
1316
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageMap, deps: [{ token: LocalDatabase }, { token: JSONValidator }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1317
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageMap, providedIn: "root" }); }
|
|
1214
1318
|
}
|
|
1215
|
-
|
|
1216
|
-
StorageMap.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageMap, providedIn: 'root' });
|
|
1217
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageMap, decorators: [{
|
|
1319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: StorageMap, decorators: [{
|
|
1218
1320
|
type: Injectable,
|
|
1219
1321
|
args: [{
|
|
1220
|
-
providedIn:
|
|
1322
|
+
providedIn: "root"
|
|
1221
1323
|
}]
|
|
1222
|
-
}], ctorParameters: function () { return [{ type: LocalDatabase }, { type: JSONValidator }
|
|
1223
|
-
type: Inject,
|
|
1224
|
-
args: [LS_PREFIX]
|
|
1225
|
-
}] }]; } });
|
|
1324
|
+
}], ctorParameters: function () { return [{ type: LocalDatabase }, { type: JSONValidator }]; } });
|
|
1226
1325
|
|
|
1326
|
+
/**
|
|
1327
|
+
* @deprecated Will be removed in v17
|
|
1328
|
+
* @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/MIGRATION_TO_V16.md}
|
|
1329
|
+
*/
|
|
1227
1330
|
class LocalStorage {
|
|
1228
|
-
/* Use the `StorageMap` service to avoid code duplication */
|
|
1229
|
-
constructor(storageMap) {
|
|
1230
|
-
this.storageMap = storageMap;
|
|
1231
|
-
}
|
|
1232
1331
|
/**
|
|
1233
1332
|
* Number of items in storage wrapped in an `Observable`
|
|
1234
1333
|
*
|
|
@@ -1240,10 +1339,14 @@ class LocalStorage {
|
|
|
1240
1339
|
get length() {
|
|
1241
1340
|
return this.storageMap.size;
|
|
1242
1341
|
}
|
|
1342
|
+
/* Use the `StorageMap` service to avoid code duplication */
|
|
1343
|
+
constructor(storageMap) {
|
|
1344
|
+
this.storageMap = storageMap;
|
|
1345
|
+
}
|
|
1243
1346
|
getItem(key, schema) {
|
|
1244
1347
|
if (schema) {
|
|
1245
1348
|
/* Backward compatibility with version <= 7 */
|
|
1246
|
-
schema = (
|
|
1349
|
+
schema = ("schema" in schema) ? schema.schema : schema;
|
|
1247
1350
|
}
|
|
1248
1351
|
return (schema ? this.storageMap.get(key, schema) : this.storageMap.get(key)).pipe(
|
|
1249
1352
|
/* Transform `undefined` into `null` to align with `localStorage` API */
|
|
@@ -1290,131 +1393,16 @@ class LocalStorage {
|
|
|
1290
1393
|
/* Transform `undefined` into `true` for backward compatibility with v7 */
|
|
1291
1394
|
map(() => true));
|
|
1292
1395
|
}
|
|
1396
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, deps: [{ token: StorageMap }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1397
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, providedIn: "root" }); }
|
|
1293
1398
|
}
|
|
1294
|
-
|
|
1295
|
-
LocalStorage.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalStorage, providedIn: 'root' });
|
|
1296
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: LocalStorage, decorators: [{
|
|
1399
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: LocalStorage, decorators: [{
|
|
1297
1400
|
type: Injectable,
|
|
1298
1401
|
args: [{
|
|
1299
|
-
providedIn:
|
|
1402
|
+
providedIn: "root"
|
|
1300
1403
|
}]
|
|
1301
1404
|
}], ctorParameters: function () { return [{ type: StorageMap }]; } });
|
|
1302
1405
|
|
|
1303
|
-
/**
|
|
1304
|
-
* This module does not contain anything, it's only useful to provide options via `.forRoot()`.
|
|
1305
|
-
*/
|
|
1306
|
-
class StorageModule {
|
|
1307
|
-
/**
|
|
1308
|
-
* Only useful to provide options, otherwise it does nothing.
|
|
1309
|
-
* **Must be used at initialization, ie. in `AppModule`, and must not be loaded again in another module.**
|
|
1310
|
-
*
|
|
1311
|
-
* @example
|
|
1312
|
-
* NgModule({
|
|
1313
|
-
* imports: [StorageModule.forRoot({
|
|
1314
|
-
* LSPrefix: 'custom_',
|
|
1315
|
-
* })]
|
|
1316
|
-
* })
|
|
1317
|
-
* export class AppModule
|
|
1318
|
-
*/
|
|
1319
|
-
static forRoot(config) {
|
|
1320
|
-
return {
|
|
1321
|
-
ngModule: StorageModule,
|
|
1322
|
-
providers: [
|
|
1323
|
-
config.LSPrefix ? { provide: LS_PREFIX, useValue: config.LSPrefix } : [],
|
|
1324
|
-
config.IDBDBName ? { provide: IDB_DB_NAME, useValue: config.IDBDBName } : [],
|
|
1325
|
-
config.IDBStoreName ? { provide: IDB_STORE_NAME, useValue: config.IDBStoreName } : [],
|
|
1326
|
-
config.IDBDBVersion ? { provide: IDB_DB_VERSION, useValue: config.IDBDBVersion } : [],
|
|
1327
|
-
(config.IDBNoWrap === false) ? { provide: IDB_NO_WRAP, useValue: config.IDBNoWrap } : [],
|
|
1328
|
-
],
|
|
1329
|
-
};
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
StorageModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1333
|
-
StorageModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: StorageModule });
|
|
1334
|
-
StorageModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageModule });
|
|
1335
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: StorageModule, decorators: [{
|
|
1336
|
-
type: NgModule
|
|
1337
|
-
}] });
|
|
1338
|
-
|
|
1339
|
-
/**
|
|
1340
|
-
* Allows to add a prefix before `localStorage` keys.
|
|
1341
|
-
* *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
|
|
1342
|
-
* **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
|
|
1343
|
-
*
|
|
1344
|
-
* @example
|
|
1345
|
-
* bootstrapApplication(AppComponent, {
|
|
1346
|
-
* providers: [provideLocalStoragePrefix('custom_')]
|
|
1347
|
-
* });
|
|
1348
|
-
*
|
|
1349
|
-
* @example
|
|
1350
|
-
* NgModule({
|
|
1351
|
-
* providers: [provideLocalStoragePrefix('custom_')]
|
|
1352
|
-
* })
|
|
1353
|
-
* export class AppModule
|
|
1354
|
-
*/
|
|
1355
|
-
function provideLocalStoragePrefix(prefix) {
|
|
1356
|
-
return makeEnvironmentProviders([{ provide: LS_PREFIX, useValue: prefix }]);
|
|
1357
|
-
}
|
|
1358
|
-
/**
|
|
1359
|
-
* Allows to change the name used for `indexedDB` database.
|
|
1360
|
-
* *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
|
|
1361
|
-
* **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
|
|
1362
|
-
*
|
|
1363
|
-
* @example
|
|
1364
|
-
* bootstrapApplication(AppComponent, {
|
|
1365
|
-
* providers: [provideIndexedDBDataBaseName('custom')]
|
|
1366
|
-
* });
|
|
1367
|
-
*
|
|
1368
|
-
* @example
|
|
1369
|
-
* NgModule({
|
|
1370
|
-
* providers: [provideIndexedDBDataBaseName('custom')]
|
|
1371
|
-
* })
|
|
1372
|
-
* export class AppModule
|
|
1373
|
-
*/
|
|
1374
|
-
function provideIndexedDBDataBaseName(name) {
|
|
1375
|
-
return makeEnvironmentProviders([{ provide: IDB_DB_NAME, useValue: name }]);
|
|
1376
|
-
}
|
|
1377
|
-
/**
|
|
1378
|
-
* Allows to change the database version used for `indexedDB` database.
|
|
1379
|
-
* Must be an unsigned **integer**.
|
|
1380
|
-
* **Use with caution as the creation of the store depends on the version.**
|
|
1381
|
-
* *Use only* for interoperability with other APIs or to avoid collision for multiple apps on the same subdomain.
|
|
1382
|
-
* **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
|
|
1383
|
-
*
|
|
1384
|
-
* @example
|
|
1385
|
-
* bootstrapApplication(AppComponent, {
|
|
1386
|
-
* providers: [provideIndexedDBDataBaseVersion(2)]
|
|
1387
|
-
* });
|
|
1388
|
-
*
|
|
1389
|
-
* @example
|
|
1390
|
-
* NgModule({
|
|
1391
|
-
* providers: [provideIndexedDBDataBaseVersion(2)]
|
|
1392
|
-
* })
|
|
1393
|
-
* export class AppModule
|
|
1394
|
-
*/
|
|
1395
|
-
function provideIndexedDBDataBaseVersion(version) {
|
|
1396
|
-
return makeEnvironmentProviders([{ provide: IDB_DB_VERSION, useValue: version }]);
|
|
1397
|
-
}
|
|
1398
|
-
/**
|
|
1399
|
-
* Allows to change the name used for `indexedDB` object store.
|
|
1400
|
-
* *Use only* for interoperability with other APIs.
|
|
1401
|
-
* **WARNING: do not change this option in an app already deployed in production, as previously stored data would be lost.**
|
|
1402
|
-
*
|
|
1403
|
-
* @example
|
|
1404
|
-
* bootstrapApplication(AppComponent, {
|
|
1405
|
-
* providers: [provideIndexedDBStoreName('custom')]
|
|
1406
|
-
* });
|
|
1407
|
-
*
|
|
1408
|
-
* @example
|
|
1409
|
-
* NgModule({
|
|
1410
|
-
* providers: [provideIndexedDBStoreName('custom')]
|
|
1411
|
-
* })
|
|
1412
|
-
* export class AppModule
|
|
1413
|
-
*/
|
|
1414
|
-
function provideIndexedDBStoreName(name) {
|
|
1415
|
-
return makeEnvironmentProviders([{ provide: IDB_STORE_NAME, useValue: name }]);
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
1406
|
/*
|
|
1419
1407
|
* Public API Surface of local-storage
|
|
1420
1408
|
*/
|
|
@@ -1425,4 +1413,3 @@ function provideIndexedDBStoreName(name) {
|
|
|
1425
1413
|
|
|
1426
1414
|
export { JSONValidator, LocalDatabase, LocalStorage, SERIALIZATION_ERROR, SerializationError, StorageMap, StorageModule, VALIDATION_ERROR, ValidationError, provideIndexedDBDataBaseName, provideIndexedDBDataBaseVersion, provideIndexedDBStoreName, provideLocalStoragePrefix };
|
|
1427
1415
|
//# sourceMappingURL=ngx-pwa-local-storage.mjs.map
|
|
1428
|
-
//# sourceMappingURL=ngx-pwa-local-storage.mjs.map
|