ng-secure-storage 1.1.0 → 2.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/fesm2022/ng-secure-storage.mjs +247 -35
- package/fesm2022/ng-secure-storage.mjs.map +1 -1
- package/index.d.ts +60 -11
- package/package.json +1 -1
- package/index.d.ts.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, Inject, Injectable, signal, Optional, NgModule } from '@angular/core';
|
|
2
|
+
import { InjectionToken, Inject, Injectable, signal, effect, Optional, NgModule } from '@angular/core';
|
|
3
|
+
import { signalStore, withState, withMethods, withHooks } from '@ngrx/signals';
|
|
3
4
|
import { BehaviorSubject } from 'rxjs';
|
|
4
5
|
|
|
5
6
|
const SECURE_STORAGE_CONFIG = new InjectionToken('SecureStorageConfig');
|
|
@@ -173,45 +174,163 @@ class SecureStorageService {
|
|
|
173
174
|
this.db = db;
|
|
174
175
|
}
|
|
175
176
|
now = signal(new Date(), ...(ngDevMode ? [{ debugName: "now" }] : []));
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
177
|
+
//#region main function
|
|
178
|
+
persistSignalStorage(initial) {
|
|
179
|
+
let result = signalStore(withState(initial), withMethods((state) => ({
|
|
180
|
+
load: async () => {
|
|
181
|
+
let result = new Promise(() => null);
|
|
182
|
+
switch (state.storageType()) {
|
|
183
|
+
case 'db':
|
|
184
|
+
result = this.loadFromDb(state);
|
|
185
|
+
break;
|
|
186
|
+
case 'session':
|
|
187
|
+
result = this.loadFromSession(state);
|
|
188
|
+
break;
|
|
189
|
+
case 'local':
|
|
190
|
+
result = this.loadFromLocalStorage(state);
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
return await result;
|
|
191
194
|
},
|
|
192
|
-
update: (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
update: async (data) => {
|
|
196
|
+
switch (state.storageType()) {
|
|
197
|
+
case 'db':
|
|
198
|
+
await this.updateFromDb(state, data);
|
|
199
|
+
break;
|
|
200
|
+
case 'session':
|
|
201
|
+
await this.updateFromSession(state, data);
|
|
202
|
+
break;
|
|
203
|
+
case 'local':
|
|
204
|
+
await this.updateFromLocalStorage(state, data);
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
197
207
|
},
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
208
|
+
})), withHooks({
|
|
209
|
+
onInit(state) {
|
|
210
|
+
effect(async () => {
|
|
211
|
+
if (!(await state.load()))
|
|
212
|
+
await state.update(state.init());
|
|
213
|
+
});
|
|
202
214
|
},
|
|
203
|
-
};
|
|
215
|
+
}));
|
|
216
|
+
return new result();
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region manage with session storage
|
|
220
|
+
/**
|
|
221
|
+
* handle loading data from session storage
|
|
222
|
+
* @param name
|
|
223
|
+
*/
|
|
224
|
+
async loadFromSession(state) {
|
|
225
|
+
const encrypted = JSON.parse(sessionStorage.getItem(state.name()));
|
|
226
|
+
if (!encrypted)
|
|
227
|
+
return state.init();
|
|
228
|
+
else {
|
|
229
|
+
try {
|
|
230
|
+
const decrypted = await this.cryptoX.decrypt(this.hexStringToUint8Array(encrypted.encrypted), this.hexStringToUint8Array(encrypted.iv));
|
|
231
|
+
let item = JSON.parse(decrypted);
|
|
232
|
+
if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {
|
|
233
|
+
await this.db.delete(state.name());
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
return item.value;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
console.error('Decryption failed', err);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* set & update data to session
|
|
248
|
+
* @param name
|
|
249
|
+
* @param state
|
|
250
|
+
* @param expiration
|
|
251
|
+
*/
|
|
252
|
+
async updateFromSession(state, data) {
|
|
253
|
+
try {
|
|
254
|
+
if (state.expiresAt()) {
|
|
255
|
+
state.expiresAt.set(this.now().getMinutes() + state.expiresAt());
|
|
256
|
+
}
|
|
257
|
+
let itemToSave = { value: data ?? state.init(), expiresAt: state.expiresAt() };
|
|
258
|
+
const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));
|
|
259
|
+
sessionStorage.setItem(state.name(), JSON.stringify({
|
|
260
|
+
iv: this.arrayBufferToHexString(iv),
|
|
261
|
+
encrypted: this.arrayBufferToHexString(encrypted),
|
|
262
|
+
}));
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
console.error('Encryption failed', err);
|
|
266
|
+
}
|
|
204
267
|
}
|
|
205
|
-
|
|
206
|
-
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region manage with local storage
|
|
270
|
+
/**
|
|
271
|
+
* handle loading data from local storage
|
|
272
|
+
* @param name
|
|
273
|
+
*/
|
|
274
|
+
async loadFromLocalStorage(state) {
|
|
275
|
+
const encrypted = JSON.parse(localStorage.getItem(state.name()));
|
|
207
276
|
if (!encrypted)
|
|
208
|
-
return;
|
|
277
|
+
return state.init();
|
|
278
|
+
else {
|
|
279
|
+
try {
|
|
280
|
+
const decrypted = await this.cryptoX.decrypt(this.hexStringToUint8Array(encrypted.encrypted), this.hexStringToUint8Array(encrypted.iv));
|
|
281
|
+
let item = JSON.parse(decrypted);
|
|
282
|
+
if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {
|
|
283
|
+
await this.db.delete(state.name());
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
return item.value;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
console.error('Decryption failed', err);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* set & update data to local storage
|
|
298
|
+
* @param name
|
|
299
|
+
* @param state
|
|
300
|
+
* @param expiration
|
|
301
|
+
*/
|
|
302
|
+
async updateFromLocalStorage(state, data) {
|
|
303
|
+
try {
|
|
304
|
+
if (state.expiresAt()) {
|
|
305
|
+
state.expiresAt.set(this.now().getMinutes() + state.expiresAt());
|
|
306
|
+
}
|
|
307
|
+
let itemToSave = { value: data ?? state.init(), expiresAt: state.expiresAt() };
|
|
308
|
+
const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));
|
|
309
|
+
localStorage.setItem(state.name(), JSON.stringify({
|
|
310
|
+
iv: this.arrayBufferToHexString(iv),
|
|
311
|
+
encrypted: this.arrayBufferToHexString(encrypted),
|
|
312
|
+
}));
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
console.error('Encryption failed', err);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
//#endregion
|
|
319
|
+
//#region manage with indexedDB
|
|
320
|
+
/**
|
|
321
|
+
* handle loading data from indexedDB
|
|
322
|
+
* @param name
|
|
323
|
+
*/
|
|
324
|
+
async loadFromDb(state) {
|
|
325
|
+
const encrypted = await this.db.get(state.name());
|
|
326
|
+
if (!encrypted)
|
|
327
|
+
return state.init();
|
|
209
328
|
else {
|
|
210
329
|
try {
|
|
211
330
|
const decrypted = await this.cryptoX.decrypt(encrypted.encrypted, encrypted.iv);
|
|
212
331
|
let item = JSON.parse(decrypted);
|
|
213
332
|
if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {
|
|
214
|
-
await this.db.delete(
|
|
333
|
+
await this.db.delete(state.name());
|
|
215
334
|
return;
|
|
216
335
|
}
|
|
217
336
|
else {
|
|
@@ -224,25 +343,118 @@ class SecureStorageService {
|
|
|
224
343
|
}
|
|
225
344
|
}
|
|
226
345
|
}
|
|
227
|
-
|
|
346
|
+
/**
|
|
347
|
+
* set & update data to indexedDB
|
|
348
|
+
* @param name
|
|
349
|
+
* @param state
|
|
350
|
+
* @param expiration
|
|
351
|
+
*/
|
|
352
|
+
async updateFromDb(state, data) {
|
|
228
353
|
try {
|
|
229
|
-
if (
|
|
230
|
-
|
|
354
|
+
if (state.expiresAt()) {
|
|
355
|
+
state.expiresAt.set(this.now().getMinutes() + state.expiresAt());
|
|
231
356
|
}
|
|
232
|
-
let itemToSave = { value, expiresAt:
|
|
357
|
+
let itemToSave = { value: data, expiresAt: state.expiresAt() };
|
|
233
358
|
const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));
|
|
234
|
-
await this.db.set(
|
|
359
|
+
await this.db.set(state.name(), { iv, encrypted });
|
|
235
360
|
}
|
|
236
361
|
catch (err) {
|
|
237
362
|
console.error('Encryption failed', err);
|
|
238
363
|
}
|
|
239
364
|
}
|
|
365
|
+
//#endregion
|
|
366
|
+
// signal<T>(key: string, initial: T, expiration: number = 1440): PersistedSignalStore<T> {
|
|
367
|
+
// const _state = signal<T>(initial);
|
|
368
|
+
// // 🔹 Hydrate once
|
|
369
|
+
// this.load(key).then((value: any) => {
|
|
370
|
+
// if (value !== undefined) {
|
|
371
|
+
// _state.set(value ?? initial);
|
|
372
|
+
// }
|
|
373
|
+
// });
|
|
374
|
+
// return {
|
|
375
|
+
// state: _state,
|
|
376
|
+
// set: (val: T) => {
|
|
377
|
+
// _state.set(val); // instant
|
|
378
|
+
// this.save(key, val, expiration); // async persist
|
|
379
|
+
// },
|
|
380
|
+
// update: (updater: (curr: T) => T) => {
|
|
381
|
+
// const next = updater(_state());
|
|
382
|
+
// _state.set(next);
|
|
383
|
+
// this.save(key, next, expiration);
|
|
384
|
+
// },
|
|
385
|
+
// remove: () => {
|
|
386
|
+
// _state.set(initial);
|
|
387
|
+
// this.save(key, null);
|
|
388
|
+
// },
|
|
389
|
+
// };
|
|
390
|
+
// }
|
|
391
|
+
// async load<T>(key: string) {
|
|
392
|
+
// const encrypted = await this.db.get<any>(key);
|
|
393
|
+
// if (!encrypted) return;
|
|
394
|
+
// else {
|
|
395
|
+
// try {
|
|
396
|
+
// const decrypted = await this.cryptoX.decrypt(encrypted.encrypted, encrypted.iv);
|
|
397
|
+
// let item = JSON.parse(decrypted) as StoredItem<T>;
|
|
398
|
+
// if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {
|
|
399
|
+
// await this.db.delete(key);
|
|
400
|
+
// return;
|
|
401
|
+
// } else {
|
|
402
|
+
// return item.value;
|
|
403
|
+
// }
|
|
404
|
+
// } catch (err) {
|
|
405
|
+
// console.error('Decryption failed', err);
|
|
406
|
+
// return;
|
|
407
|
+
// }
|
|
408
|
+
// }
|
|
409
|
+
// }
|
|
410
|
+
// private async save<T>(key: string, value: T, expiration?: number) {
|
|
411
|
+
// try {
|
|
412
|
+
// if (expiration) {
|
|
413
|
+
// expiration = this.now().getMinutes() + expiration;
|
|
414
|
+
// }
|
|
415
|
+
// let itemToSave: StoredItem<T> = { value, expiresAt: expiration };
|
|
416
|
+
// const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));
|
|
417
|
+
// await this.db.set(key, { iv, encrypted });
|
|
418
|
+
// } catch (err) {
|
|
419
|
+
// console.error('Encryption failed', err);
|
|
420
|
+
// }
|
|
421
|
+
// }
|
|
422
|
+
arrayBufferToHexString(buffer) {
|
|
423
|
+
const uint8Array = new Uint8Array(buffer);
|
|
424
|
+
return Array.from(uint8Array)
|
|
425
|
+
.map((byte) => byte.toString(16).padStart(2, '0'))
|
|
426
|
+
.join('');
|
|
427
|
+
}
|
|
428
|
+
hexStringToUint8Array(hexString) {
|
|
429
|
+
// Clean hex string
|
|
430
|
+
hexString = hexString.replace(/^0x|\s|:/g, '');
|
|
431
|
+
// Handle odd length by padding with leading zero
|
|
432
|
+
if (hexString.length % 2 !== 0) {
|
|
433
|
+
hexString = '0' + hexString;
|
|
434
|
+
}
|
|
435
|
+
// Create Uint8Array
|
|
436
|
+
const byteLength = hexString.length / 2;
|
|
437
|
+
const uint8Array = new Uint8Array(byteLength);
|
|
438
|
+
// Convert each hex pair to byte
|
|
439
|
+
for (let i = 0; i < byteLength; i++) {
|
|
440
|
+
const byteHex = hexString.substr(i * 2, 2);
|
|
441
|
+
uint8Array[i] = parseInt(byteHex, 16);
|
|
442
|
+
}
|
|
443
|
+
return uint8Array;
|
|
444
|
+
}
|
|
240
445
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageService, deps: [{ token: CryptoService }, { token: IndexeddbService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
241
446
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageService });
|
|
242
447
|
}
|
|
243
448
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageService, decorators: [{
|
|
244
449
|
type: Injectable
|
|
245
450
|
}], ctorParameters: () => [{ type: CryptoService }, { type: IndexeddbService }] });
|
|
451
|
+
//#region inerfaces
|
|
452
|
+
class ExtendedT {
|
|
453
|
+
init;
|
|
454
|
+
name = null;
|
|
455
|
+
expiresAt;
|
|
456
|
+
storageType = 'session';
|
|
457
|
+
}
|
|
246
458
|
|
|
247
459
|
class SecureStorageModule {
|
|
248
460
|
static forRoot(config) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-secure-storage.mjs","sources":["../../../projects/ng-secure-storage/src/lib/tokens/secure-storage.config.ts","../../../projects/ng-secure-storage/src/lib/services/crypto.service.ts","../../../projects/ng-secure-storage/src/lib/services/indexeddb.service.ts","../../../projects/ng-secure-storage/src/lib/services/secure-storage.service.ts","../../../projects/ng-secure-storage/src/lib/public.module.ts","../../../projects/ng-secure-storage/src/ng-secure-storage.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\n\r\nexport interface SecureStorageConfig {\r\n dbName?: string;\r\n storeName?: string;\r\n iterations?: number;\r\n version?: number;\r\n}\r\n\r\nexport const SECURE_STORAGE_CONFIG = new InjectionToken<SecureStorageConfig>('SecureStorageConfig');\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { SECURE_STORAGE_CONFIG, SecureStorageConfig } from '../tokens/secure-storage.config';\r\n\r\n@Injectable()\r\nexport class CryptoService {\r\n private encoder = new TextEncoder();\r\n private decoder = new TextDecoder();\r\n constructor(@Inject(SECURE_STORAGE_CONFIG) private readonly config?: SecureStorageConfig) {\r\n if (!config) {\r\n throw new Error('SecureStorageConfig is missing. Did you forget provideSecureStorage()?');\r\n }\r\n }\r\n\r\n getOrCreateSalt(): Uint8Array<ArrayBuffer> {\r\n let salt = this.encoder.encode(localStorage.getItem('cs_r')!);\r\n\r\n if (!salt) {\r\n salt = crypto.getRandomValues(new Uint8Array(16)); // 16 bytes is standard\r\n localStorage.setItem('cs_r', this.decoder.decode(salt));\r\n }\r\n\r\n return salt;\r\n }\r\n\r\n async derivedKey() {\r\n let salt = this.getOrCreateSalt();\r\n const cryptokey = await crypto.subtle.importKey(\r\n 'raw',\r\n this.encoder.encode(this.config?.storeName),\r\n 'PBKDF2',\r\n false,\r\n ['deriveKey']\r\n );\r\n return crypto.subtle.deriveKey(\r\n {\r\n name: 'PBKDF2',\r\n salt,\r\n iterations: this.config?.iterations || 100_000,\r\n hash: 'SHA-256',\r\n },\r\n cryptokey,\r\n { name: 'AES-GCM', length: 256 },\r\n false,\r\n ['encrypt', 'decrypt']\r\n );\r\n }\r\n\r\n async encrypt(data: string) {\r\n const iv = this.getOrCreateSalt();\r\n const key = await this.derivedKey();\r\n const encrypted = await crypto.subtle.encrypt(\r\n { name: 'AES-GCM', iv },\r\n key,\r\n this.encoder.encode(data)\r\n );\r\n return { iv, encrypted };\r\n }\r\n\r\n async decrypt(payload: Uint8Array<ArrayBuffer>, iv: Uint8Array) {\r\n const key = await this.derivedKey();\r\n const decrypted = await crypto.subtle.decrypt(\r\n { name: 'AES-GCM', iv: iv as Uint8Array<ArrayBuffer> },\r\n key,\r\n payload\r\n );\r\n return this.decoder.decode(decrypted);\r\n }\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { SECURE_STORAGE_CONFIG, SecureStorageConfig } from '../tokens/secure-storage.config';\r\nimport { BehaviorSubject } from 'rxjs';\r\n\r\n@Injectable()\r\nexport class IndexeddbService {\r\n private dbName: string;\r\n private storeName: string;\r\n private db!: IDBDatabase;\r\n private dbPromise!: Promise<IDBDatabase>;\r\n public isReady = new BehaviorSubject<boolean>(false);\r\n\r\n constructor(@Inject(SECURE_STORAGE_CONFIG) private readonly config?: SecureStorageConfig) {\r\n if (!config) {\r\n throw new Error('SecureStorageConfig is missing. Did you forget provideSecureStorage()?');\r\n }\r\n this.dbName = config?.dbName || 'secure-storage-db';\r\n this.storeName = config?.storeName || 'data';\r\n this.dbPromise = this.initDb();\r\n }\r\n\r\n private initDb(): Promise<IDBDatabase> {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(this.dbName);\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n this.isReady.next(true);\r\n resolve(this.db);\r\n };\r\n\r\n request.onupgradeneeded = (event) => {\r\n const db = request.result;\r\n if (!db.objectStoreNames.contains(this.storeName)) {\r\n db.createObjectStore(this.storeName);\r\n }\r\n };\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n private async getDb(): Promise<IDBDatabase> {\r\n if (this.db) return this.db;\r\n\r\n // Wait for DB ready\r\n const db = await this.dbPromise;\r\n\r\n // Double-check the store exists (for old DB versions)\r\n if (!db.objectStoreNames.contains(this.storeName)) {\r\n db.close();\r\n // Increase version to trigger onupgradeneeded\r\n const newVersion = (db.version || 1) + 1;\r\n this.dbPromise = new Promise<IDBDatabase>((resolve, reject) => {\r\n const request = indexedDB.open(this.dbName, newVersion);\r\n request.onupgradeneeded = () => {\r\n const upgradedDb = request.result;\r\n if (!upgradedDb.objectStoreNames.contains(this.storeName)) {\r\n upgradedDb.createObjectStore(this.storeName);\r\n }\r\n };\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n resolve(this.db);\r\n };\r\n request.onerror = () => reject(request.error);\r\n });\r\n return this.dbPromise;\r\n }\r\n\r\n return db;\r\n }\r\n\r\n async set(key: string, value: any): Promise<void> {\r\n const db = await this.getDb();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n const store = tx.objectStore(this.storeName);\r\n const request = store.put(value, key); // use put instead of add\r\n request.onsuccess = () => resolve();\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n const db = await this.getDb();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readonly');\r\n const store = tx.objectStore(this.storeName);\r\n const request = store.get(key);\r\n request.onsuccess = () => resolve((request.result as T) ?? null);\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n const db = await this.getDb();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n const store = tx.objectStore(this.storeName);\r\n const request = store.delete(key);\r\n request.onsuccess = () => resolve();\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n}\r\n","import { Injectable, signal, WritableSignal } from '@angular/core';\r\nimport { CryptoService } from './crypto.service';\r\nimport { IndexeddbService } from './indexeddb.service';\r\n\r\n/**\r\n * this service provides secure storage capabilities using encryption and IndexedDB.\r\n * It allows storing, retrieving, and managing data with optional expiration times.\r\n * The service uses signals to manage state reactively.\r\n * @example\r\n * const userSettings = secureStorageService.signal<UserSettings>('userSettings', defaultSettings, 60);\r\n * userSettings.set({ theme: 'dark', notifications: true });\r\n * const settings = userSettings.state();\r\n * userSettings.remove();\r\n *\r\n */\r\n@Injectable()\r\nexport class SecureStorageService {\r\n constructor(private readonly cryptoX: CryptoService, private readonly db: IndexeddbService) {}\r\n now = signal<Date>(new Date());\r\n hydration = signal<boolean>(false);\r\n signal<T>(key: string, initial: T, expiration: number = 1440): PersistedSignalStore<T> {\r\n const _state = signal<T>(initial);\r\n\r\n // 🔹 Hydrate once\r\n this.load(key).then((value: any) => {\r\n if (!this.hydration() && value !== undefined) {\r\n _state.set(value ?? initial);\r\n }\r\n });\r\n\r\n return {\r\n state: _state,\r\n set: (val: T) => {\r\n _state.set(val); // instant\r\n this.save(key, val, expiration); // async persist\r\n this.hydration.set(true);\r\n },\r\n update: (updater: (curr: T) => T) => {\r\n const next = updater(_state());\r\n _state.set(next);\r\n this.save(key, next, expiration);\r\n this.hydration.set(true);\r\n },\r\n\r\n remove: () => {\r\n _state.set(initial);\r\n this.save(key, null);\r\n this.hydration.set(true);\r\n },\r\n };\r\n }\r\n async load<T>(key: string) {\r\n const encrypted = await this.db.get<any>(key);\r\n if (!encrypted) return;\r\n else {\r\n try {\r\n const decrypted = await this.cryptoX.decrypt(encrypted.encrypted, encrypted.iv);\r\n let item = JSON.parse(decrypted) as StoredItem<T>;\r\n if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {\r\n await this.db.delete(key);\r\n return;\r\n } else {\r\n return item.value;\r\n }\r\n } catch (err) {\r\n console.error('Decryption failed', err);\r\n return;\r\n }\r\n }\r\n }\r\n\r\n private async save<T>(key: string, value: T, expiration?: number) {\r\n try {\r\n if (expiration) {\r\n expiration = this.now().getMinutes() + expiration;\r\n }\r\n let itemToSave: StoredItem<T> = { value, expiresAt: expiration };\r\n const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));\r\n await this.db.set(key, { iv, encrypted });\r\n } catch (err) {\r\n console.error('Encryption failed', err);\r\n }\r\n }\r\n}\r\n\r\ninterface PersistedSignalStore<T> {\r\n state: WritableSignal<T>;\r\n set: (val: T) => void;\r\n update: (updater: (curr: T) => T) => void;\r\n remove: () => void;\r\n}\r\n\r\ninterface StoredItem<T> {\r\n value: T;\r\n expiresAt?: number;\r\n}\r\n","import { NgModule, ModuleWithProviders, Optional } from '@angular/core';\r\nimport { SECURE_STORAGE_CONFIG, SecureStorageConfig } from './tokens/secure-storage.config';\r\nimport { CryptoService } from './services/crypto.service';\r\nimport { IndexeddbService } from './services/indexeddb.service';\r\nimport { SecureStorageService } from '../public-api';\r\n\r\n@NgModule({})\r\nexport class SecureStorageModule {\r\n static forRoot(config: SecureStorageConfig): ModuleWithProviders<SecureStorageModule> {\r\n return {\r\n ngModule: SecureStorageModule,\r\n providers: [\r\n { provide: SECURE_STORAGE_CONFIG, useValue: config },\r\n { provide: CryptoService, deps: [[new Optional(), SECURE_STORAGE_CONFIG]] },\r\n { provide: IndexeddbService, deps: [[new Optional(), SECURE_STORAGE_CONFIG]] },\r\n {\r\n provide: SecureStorageService,\r\n deps: [CryptoService, IndexeddbService],\r\n },\r\n ],\r\n };\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.CryptoService","i2.IndexeddbService"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ng-secure-storage.mjs","sources":["../../../projects/ng-secure-storage/src/lib/tokens/secure-storage.config.ts","../../../projects/ng-secure-storage/src/lib/services/crypto.service.ts","../../../projects/ng-secure-storage/src/lib/services/indexeddb.service.ts","../../../projects/ng-secure-storage/src/lib/services/secure-storage.service.ts","../../../projects/ng-secure-storage/src/lib/public.module.ts","../../../projects/ng-secure-storage/src/ng-secure-storage.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\n\r\nexport interface SecureStorageConfig {\r\n dbName?: string;\r\n storeName?: string;\r\n iterations?: number;\r\n version?: number;\r\n}\r\n\r\nexport const SECURE_STORAGE_CONFIG = new InjectionToken<SecureStorageConfig>('SecureStorageConfig');\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { SECURE_STORAGE_CONFIG, SecureStorageConfig } from '../tokens/secure-storage.config';\r\n\r\n@Injectable()\r\nexport class CryptoService {\r\n private encoder = new TextEncoder();\r\n private decoder = new TextDecoder();\r\n constructor(@Inject(SECURE_STORAGE_CONFIG) private readonly config?: SecureStorageConfig) {\r\n if (!config) {\r\n throw new Error('SecureStorageConfig is missing. Did you forget provideSecureStorage()?');\r\n }\r\n }\r\n\r\n getOrCreateSalt(): Uint8Array<ArrayBuffer> {\r\n let salt = this.encoder.encode(localStorage.getItem('cs_r')!);\r\n\r\n if (!salt) {\r\n salt = crypto.getRandomValues(new Uint8Array(16)); // 16 bytes is standard\r\n localStorage.setItem('cs_r', this.decoder.decode(salt));\r\n }\r\n\r\n return salt;\r\n }\r\n\r\n async derivedKey() {\r\n let salt = this.getOrCreateSalt();\r\n const cryptokey = await crypto.subtle.importKey(\r\n 'raw',\r\n this.encoder.encode(this.config?.storeName),\r\n 'PBKDF2',\r\n false,\r\n ['deriveKey']\r\n );\r\n return crypto.subtle.deriveKey(\r\n {\r\n name: 'PBKDF2',\r\n salt,\r\n iterations: this.config?.iterations || 100_000,\r\n hash: 'SHA-256',\r\n },\r\n cryptokey,\r\n { name: 'AES-GCM', length: 256 },\r\n false,\r\n ['encrypt', 'decrypt']\r\n );\r\n }\r\n\r\n async encrypt(data: string) {\r\n const iv = this.getOrCreateSalt();\r\n const key = await this.derivedKey();\r\n const encrypted = await crypto.subtle.encrypt(\r\n { name: 'AES-GCM', iv },\r\n key,\r\n this.encoder.encode(data)\r\n );\r\n return { iv, encrypted };\r\n }\r\n\r\n async decrypt(payload: Uint8Array<ArrayBuffer>, iv: Uint8Array) {\r\n const key = await this.derivedKey();\r\n const decrypted = await crypto.subtle.decrypt(\r\n { name: 'AES-GCM', iv: iv as Uint8Array<ArrayBuffer> },\r\n key,\r\n payload\r\n );\r\n return this.decoder.decode(decrypted);\r\n }\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { SECURE_STORAGE_CONFIG, SecureStorageConfig } from '../tokens/secure-storage.config';\r\nimport { BehaviorSubject } from 'rxjs';\r\n\r\n@Injectable()\r\nexport class IndexeddbService {\r\n private dbName: string;\r\n private storeName: string;\r\n private db!: IDBDatabase;\r\n private dbPromise!: Promise<IDBDatabase>;\r\n public isReady = new BehaviorSubject<boolean>(false);\r\n\r\n constructor(@Inject(SECURE_STORAGE_CONFIG) private readonly config?: SecureStorageConfig) {\r\n if (!config) {\r\n throw new Error('SecureStorageConfig is missing. Did you forget provideSecureStorage()?');\r\n }\r\n this.dbName = config?.dbName || 'secure-storage-db';\r\n this.storeName = config?.storeName || 'data';\r\n this.dbPromise = this.initDb();\r\n }\r\n\r\n private initDb(): Promise<IDBDatabase> {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(this.dbName);\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n this.isReady.next(true);\r\n resolve(this.db);\r\n };\r\n\r\n request.onupgradeneeded = (event) => {\r\n const db = request.result;\r\n if (!db.objectStoreNames.contains(this.storeName)) {\r\n db.createObjectStore(this.storeName);\r\n }\r\n };\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n private async getDb(): Promise<IDBDatabase> {\r\n if (this.db) return this.db;\r\n\r\n // Wait for DB ready\r\n const db = await this.dbPromise;\r\n\r\n // Double-check the store exists (for old DB versions)\r\n if (!db.objectStoreNames.contains(this.storeName)) {\r\n db.close();\r\n // Increase version to trigger onupgradeneeded\r\n const newVersion = (db.version || 1) + 1;\r\n this.dbPromise = new Promise<IDBDatabase>((resolve, reject) => {\r\n const request = indexedDB.open(this.dbName, newVersion);\r\n request.onupgradeneeded = () => {\r\n const upgradedDb = request.result;\r\n if (!upgradedDb.objectStoreNames.contains(this.storeName)) {\r\n upgradedDb.createObjectStore(this.storeName);\r\n }\r\n };\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n resolve(this.db);\r\n };\r\n request.onerror = () => reject(request.error);\r\n });\r\n return this.dbPromise;\r\n }\r\n\r\n return db;\r\n }\r\n\r\n async set(key: string, value: any): Promise<void> {\r\n const db = await this.getDb();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n const store = tx.objectStore(this.storeName);\r\n const request = store.put(value, key); // use put instead of add\r\n request.onsuccess = () => resolve();\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n const db = await this.getDb();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readonly');\r\n const store = tx.objectStore(this.storeName);\r\n const request = store.get(key);\r\n request.onsuccess = () => resolve((request.result as T) ?? null);\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n const db = await this.getDb();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n const store = tx.objectStore(this.storeName);\r\n const request = store.delete(key);\r\n request.onsuccess = () => resolve();\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n}\r\n","import { effect, Injectable, signal } from '@angular/core';\r\nimport { CryptoService } from './crypto.service';\r\nimport { IndexeddbService } from './indexeddb.service';\r\nimport { signalStore, withHooks, withMethods, withState } from '@ngrx/signals';\r\n\r\n/**\r\n * this service provides secure storage capabilities using encryption and IndexedDB.\r\n * It allows storing, retrieving, and managing data with optional expiration times.\r\n * The service uses signals to manage state reactively.\r\n * @example\r\n * const userSettings = secureStorageService.signal<UserSettings>('userSettings', defaultSettings, 60);\r\n * userSettings.set({ theme: 'dark', notifications: true });\r\n * const settings = userSettings.state();\r\n * userSettings.remove();\r\n *\r\n */\r\n@Injectable()\r\nexport class SecureStorageService {\r\n constructor(\r\n private readonly cryptoX: CryptoService,\r\n private readonly db: IndexeddbService,\r\n ) {}\r\n private now = signal<Date>(new Date());\r\n\r\n //#region main function\r\n persistSignalStorage<T>(initial: ExtendedT<T>) {\r\n let result = signalStore(\r\n withState<ExtendedT<T>>(initial),\r\n withMethods((state: any) => ({\r\n load: async () => {\r\n let result: Promise<T | null> = new Promise(() => null);\r\n switch (state.storageType()) {\r\n case 'db':\r\n result = this.loadFromDb<T>(state);\r\n break;\r\n case 'session':\r\n result = this.loadFromSession<T>(state);\r\n break;\r\n case 'local':\r\n result = this.loadFromLocalStorage<T>(state);\r\n break;\r\n }\r\n return await result;\r\n },\r\n update: async (data: T) => {\r\n switch (state.storageType()) {\r\n case 'db':\r\n await this.updateFromDb<T>(state, data);\r\n break;\r\n case 'session':\r\n await this.updateFromSession<T>(state, data);\r\n break;\r\n case 'local':\r\n await this.updateFromLocalStorage<T>(state, data);\r\n break;\r\n }\r\n },\r\n })),\r\n withHooks({\r\n onInit(state: any) {\r\n effect(async () => {\r\n if (!(await state.load())) await state.update(state.init());\r\n });\r\n },\r\n }),\r\n );\r\n return new result();\r\n }\r\n //#endregion\r\n\r\n //#region manage with session storage\r\n /**\r\n * handle loading data from session storage\r\n * @param name\r\n */\r\n private async loadFromSession<T>(state: any) {\r\n const encrypted = JSON.parse(sessionStorage.getItem(state.name()!)!);\r\n if (!encrypted) return state.init();\r\n else {\r\n try {\r\n const decrypted = await this.cryptoX.decrypt(\r\n this.hexStringToUint8Array(encrypted.encrypted),\r\n this.hexStringToUint8Array(encrypted.iv),\r\n );\r\n let item = JSON.parse(decrypted) as StoredItem<T>;\r\n\r\n if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {\r\n await this.db.delete(state.name()!);\r\n return;\r\n } else {\r\n return item.value;\r\n }\r\n } catch (err) {\r\n console.error('Decryption failed', err);\r\n return;\r\n }\r\n }\r\n }\r\n /**\r\n * set & update data to session\r\n * @param name\r\n * @param state\r\n * @param expiration\r\n */\r\n private async updateFromSession<T>(state: any, data: any) {\r\n try {\r\n if (state.expiresAt()) {\r\n state.expiresAt.set(this.now().getMinutes() + state.expiresAt());\r\n }\r\n let itemToSave: StoredItem<T> = { value: data ?? state.init(), expiresAt: state.expiresAt() };\r\n\r\n const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));\r\n sessionStorage.setItem(\r\n state.name(),\r\n JSON.stringify({\r\n iv: this.arrayBufferToHexString(iv),\r\n encrypted: this.arrayBufferToHexString(encrypted),\r\n }),\r\n );\r\n } catch (err) {\r\n console.error('Encryption failed', err);\r\n }\r\n }\r\n //#endregion\r\n\r\n //#region manage with local storage\r\n /**\r\n * handle loading data from local storage\r\n * @param name\r\n */\r\n private async loadFromLocalStorage<T>(state: any) {\r\n const encrypted = JSON.parse(localStorage.getItem(state.name()!)!);\r\n if (!encrypted) return state.init();\r\n else {\r\n try {\r\n const decrypted = await this.cryptoX.decrypt(\r\n this.hexStringToUint8Array(encrypted.encrypted),\r\n this.hexStringToUint8Array(encrypted.iv),\r\n );\r\n let item = JSON.parse(decrypted) as StoredItem<T>;\r\n\r\n if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {\r\n await this.db.delete(state.name()!);\r\n return;\r\n } else {\r\n return item.value;\r\n }\r\n } catch (err) {\r\n console.error('Decryption failed', err);\r\n return;\r\n }\r\n }\r\n }\r\n /**\r\n * set & update data to local storage\r\n * @param name\r\n * @param state\r\n * @param expiration\r\n */\r\n private async updateFromLocalStorage<T>(state: any, data: any) {\r\n try {\r\n if (state.expiresAt()) {\r\n state.expiresAt.set(this.now().getMinutes() + state.expiresAt());\r\n }\r\n let itemToSave: StoredItem<T> = { value: data ?? state.init(), expiresAt: state.expiresAt() };\r\n\r\n const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));\r\n localStorage.setItem(\r\n state.name(),\r\n JSON.stringify({\r\n iv: this.arrayBufferToHexString(iv),\r\n encrypted: this.arrayBufferToHexString(encrypted),\r\n }),\r\n );\r\n } catch (err) {\r\n console.error('Encryption failed', err);\r\n }\r\n }\r\n //#endregion\r\n\r\n //#region manage with indexedDB\r\n\r\n /**\r\n * handle loading data from indexedDB\r\n * @param name\r\n */\r\n private async loadFromDb<T>(state: any) {\r\n const encrypted = await this.db.get<any>(state.name()!);\r\n if (!encrypted) return state.init();\r\n else {\r\n try {\r\n const decrypted = await this.cryptoX.decrypt(encrypted.encrypted, encrypted.iv);\r\n let item = JSON.parse(decrypted) as StoredItem<T>;\r\n if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {\r\n await this.db.delete(state.name()!);\r\n return;\r\n } else {\r\n return item.value;\r\n }\r\n } catch (err) {\r\n console.error('Decryption failed', err);\r\n return;\r\n }\r\n }\r\n }\r\n /**\r\n * set & update data to indexedDB\r\n * @param name\r\n * @param state\r\n * @param expiration\r\n */\r\n private async updateFromDb<T>(state: any, data: any) {\r\n try {\r\n if (state.expiresAt()) {\r\n state.expiresAt.set(this.now().getMinutes() + state.expiresAt());\r\n }\r\n let itemToSave: StoredItem<T> = { value: data, expiresAt: state.expiresAt() };\r\n const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));\r\n await this.db.set(state.name(), { iv, encrypted });\r\n } catch (err) {\r\n console.error('Encryption failed', err);\r\n }\r\n }\r\n //#endregion\r\n\r\n // signal<T>(key: string, initial: T, expiration: number = 1440): PersistedSignalStore<T> {\r\n // const _state = signal<T>(initial);\r\n\r\n // // 🔹 Hydrate once\r\n // this.load(key).then((value: any) => {\r\n // if (value !== undefined) {\r\n // _state.set(value ?? initial);\r\n // }\r\n // });\r\n\r\n // return {\r\n // state: _state,\r\n // set: (val: T) => {\r\n // _state.set(val); // instant\r\n // this.save(key, val, expiration); // async persist\r\n // },\r\n // update: (updater: (curr: T) => T) => {\r\n // const next = updater(_state());\r\n // _state.set(next);\r\n // this.save(key, next, expiration);\r\n // },\r\n\r\n // remove: () => {\r\n // _state.set(initial);\r\n // this.save(key, null);\r\n // },\r\n // };\r\n // }\r\n // async load<T>(key: string) {\r\n // const encrypted = await this.db.get<any>(key);\r\n // if (!encrypted) return;\r\n // else {\r\n // try {\r\n // const decrypted = await this.cryptoX.decrypt(encrypted.encrypted, encrypted.iv);\r\n // let item = JSON.parse(decrypted) as StoredItem<T>;\r\n // if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {\r\n // await this.db.delete(key);\r\n // return;\r\n // } else {\r\n // return item.value;\r\n // }\r\n // } catch (err) {\r\n // console.error('Decryption failed', err);\r\n // return;\r\n // }\r\n // }\r\n // }\r\n\r\n // private async save<T>(key: string, value: T, expiration?: number) {\r\n // try {\r\n // if (expiration) {\r\n // expiration = this.now().getMinutes() + expiration;\r\n // }\r\n // let itemToSave: StoredItem<T> = { value, expiresAt: expiration };\r\n // const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));\r\n // await this.db.set(key, { iv, encrypted });\r\n // } catch (err) {\r\n // console.error('Encryption failed', err);\r\n // }\r\n // }\r\n\r\n private arrayBufferToHexString(buffer: any) {\r\n const uint8Array = new Uint8Array(buffer);\r\n return Array.from(uint8Array)\r\n .map((byte) => byte.toString(16).padStart(2, '0'))\r\n .join('');\r\n }\r\n private hexStringToUint8Array(hexString: any) {\r\n // Clean hex string\r\n hexString = hexString.replace(/^0x|\\s|:/g, '');\r\n\r\n // Handle odd length by padding with leading zero\r\n if (hexString.length % 2 !== 0) {\r\n hexString = '0' + hexString;\r\n }\r\n\r\n // Create Uint8Array\r\n const byteLength = hexString.length / 2;\r\n const uint8Array = new Uint8Array(byteLength);\r\n\r\n // Convert each hex pair to byte\r\n for (let i = 0; i < byteLength; i++) {\r\n const byteHex = hexString.substr(i * 2, 2);\r\n uint8Array[i] = parseInt(byteHex, 16);\r\n }\r\n\r\n return uint8Array;\r\n }\r\n}\r\n\r\n//#region inerfaces\r\nclass ExtendedT<T> {\r\n init?: T;\r\n name: string | null = null;\r\n expiresAt?: number;\r\n storageType: 'session' | 'local' | 'db' = 'session';\r\n}\r\n\r\n// interface PersistedSignalStore<T> {\r\n// state: WritableSignal<T>;\r\n// set: (val: T) => void;\r\n// update: (updater: (curr: T) => T) => void;\r\n// remove: () => void;\r\n// }\r\n\r\ninterface StoredItem<T> {\r\n value: T;\r\n expiresAt?: number;\r\n}\r\n//#endregion\r\n","import { NgModule, ModuleWithProviders, Optional } from '@angular/core';\r\nimport { SECURE_STORAGE_CONFIG, SecureStorageConfig } from './tokens/secure-storage.config';\r\nimport { CryptoService } from './services/crypto.service';\r\nimport { IndexeddbService } from './services/indexeddb.service';\r\nimport { SecureStorageService } from '../public-api';\r\n\r\n@NgModule({})\r\nexport class SecureStorageModule {\r\n static forRoot(config: SecureStorageConfig): ModuleWithProviders<SecureStorageModule> {\r\n return {\r\n ngModule: SecureStorageModule,\r\n providers: [\r\n { provide: SECURE_STORAGE_CONFIG, useValue: config },\r\n { provide: CryptoService, deps: [[new Optional(), SECURE_STORAGE_CONFIG]] },\r\n { provide: IndexeddbService, deps: [[new Optional(), SECURE_STORAGE_CONFIG]] },\r\n {\r\n provide: SecureStorageService,\r\n deps: [CryptoService, IndexeddbService],\r\n },\r\n ],\r\n };\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.CryptoService","i2.IndexeddbService"],"mappings":";;;;;AASO,MAAM,qBAAqB,GAAG,IAAI,cAAc,CAAsB,qBAAqB,CAAC;;MCLtF,aAAa,CAAA;AAGoC,IAAA,MAAA;AAFpD,IAAA,OAAO,GAAG,IAAI,WAAW,EAAE;AAC3B,IAAA,OAAO,GAAG,IAAI,WAAW,EAAE;AACnC,IAAA,WAAA,CAA4D,MAA4B,EAAA;QAA5B,IAAA,CAAA,MAAM,GAAN,MAAM;QAChE,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC;QAC3F;IACF;IAEA,eAAe,GAAA;AACb,QAAA,IAAI,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAE,CAAC;QAE7D,IAAI,CAAC,IAAI,EAAE;AACT,YAAA,IAAI,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;AAClD,YAAA,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzD;AAEA,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,IAAI,IAAI,GAAG,IAAI,CAAC,eAAe,EAAE;AACjC,QAAA,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAC7C,KAAK,EACL,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,EAC3C,QAAQ,EACR,KAAK,EACL,CAAC,WAAW,CAAC,CACd;AACD,QAAA,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAC5B;AACE,YAAA,IAAI,EAAE,QAAQ;YACd,IAAI;AACJ,YAAA,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,IAAI,OAAO;AAC9C,YAAA,IAAI,EAAE,SAAS;SAChB,EACD,SAAS,EACT,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,EAChC,KAAK,EACL,CAAC,SAAS,EAAE,SAAS,CAAC,CACvB;IACH;IAEA,MAAM,OAAO,CAAC,IAAY,EAAA;AACxB,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,eAAe,EAAE;AACjC,QAAA,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE;AACnC,QAAA,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAC3C,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EACvB,GAAG,EACH,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAC1B;AACD,QAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE;IAC1B;AAEA,IAAA,MAAM,OAAO,CAAC,OAAgC,EAAE,EAAc,EAAA;AAC5D,QAAA,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE;QACnC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAC3C,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAA6B,EAAE,EACtD,GAAG,EACH,OAAO,CACR;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;IACvC;AA9DW,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,aAAa,kBAGJ,qBAAqB,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;4GAH9B,aAAa,EAAA,CAAA;;4FAAb,aAAa,EAAA,UAAA,EAAA,CAAA;kBADzB;;0BAIc,MAAM;2BAAC,qBAAqB;;;MCF9B,gBAAgB,CAAA;AAOiC,IAAA,MAAA;AANpD,IAAA,MAAM;AACN,IAAA,SAAS;AACT,IAAA,EAAE;AACF,IAAA,SAAS;AACV,IAAA,OAAO,GAAG,IAAI,eAAe,CAAU,KAAK,CAAC;AAEpD,IAAA,WAAA,CAA4D,MAA4B,EAAA;QAA5B,IAAA,CAAA,MAAM,GAAN,MAAM;QAChE,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC;QAC3F;QACA,IAAI,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,IAAI,mBAAmB;QACnD,IAAI,CAAC,SAAS,GAAG,MAAM,EAAE,SAAS,IAAI,MAAM;AAC5C,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE;IAChC;IAEQ,MAAM,GAAA;QACZ,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;YACrC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAC3C,YAAA,OAAO,CAAC,SAAS,GAAG,MAAK;AACvB,gBAAA,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM;AACxB,gBAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;AACvB,gBAAA,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;AAClB,YAAA,CAAC;AAED,YAAA,OAAO,CAAC,eAAe,GAAG,CAAC,KAAK,KAAI;AAClC,gBAAA,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM;AACzB,gBAAA,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AACjD,oBAAA,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC;gBACtC;AACF,YAAA,CAAC;AAED,YAAA,OAAO,CAAC,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/C,QAAA,CAAC,CAAC;IACJ;AAEQ,IAAA,MAAM,KAAK,GAAA;QACjB,IAAI,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC,EAAE;;AAG3B,QAAA,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS;;AAG/B,QAAA,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;YACjD,EAAE,CAAC,KAAK,EAAE;;YAEV,MAAM,UAAU,GAAG,CAAC,EAAE,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC;YACxC,IAAI,CAAC,SAAS,GAAG,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,MAAM,KAAI;AAC5D,gBAAA,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC;AACvD,gBAAA,OAAO,CAAC,eAAe,GAAG,MAAK;AAC7B,oBAAA,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM;AACjC,oBAAA,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AACzD,wBAAA,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC;oBAC9C;AACF,gBAAA,CAAC;AACD,gBAAA,OAAO,CAAC,SAAS,GAAG,MAAK;AACvB,oBAAA,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM;AACxB,oBAAA,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;AAClB,gBAAA,CAAC;AACD,gBAAA,OAAO,CAAC,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/C,YAAA,CAAC,CAAC;YACF,OAAO,IAAI,CAAC,SAAS;QACvB;AAEA,QAAA,OAAO,EAAE;IACX;AAEA,IAAA,MAAM,GAAG,CAAC,GAAW,EAAE,KAAU,EAAA;AAC/B,QAAA,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE;QAC7B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;AACrC,YAAA,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC;YACtD,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC;AAC5C,YAAA,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACtC,OAAO,CAAC,SAAS,GAAG,MAAM,OAAO,EAAE;AACnC,YAAA,OAAO,CAAC,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/C,QAAA,CAAC,CAAC;IACJ;IAEA,MAAM,GAAG,CAAI,GAAW,EAAA;AACtB,QAAA,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE;QAC7B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;AACrC,YAAA,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;YACrD,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC;YAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;AAC9B,YAAA,OAAO,CAAC,SAAS,GAAG,MAAM,OAAO,CAAE,OAAO,CAAC,MAAY,IAAI,IAAI,CAAC;AAChE,YAAA,OAAO,CAAC,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/C,QAAA,CAAC,CAAC;IACJ;IAEA,MAAM,MAAM,CAAC,GAAW,EAAA;AACtB,QAAA,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE;QAC7B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;AACrC,YAAA,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC;YACtD,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC;YAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;YACjC,OAAO,CAAC,SAAS,GAAG,MAAM,OAAO,EAAE;AACnC,YAAA,OAAO,CAAC,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/C,QAAA,CAAC,CAAC;IACJ;AAlGW,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,kBAOP,qBAAqB,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;4GAP9B,gBAAgB,EAAA,CAAA;;4FAAhB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAD5B;;0BAQc,MAAM;2BAAC,qBAAqB;;;ACP3C;;;;;;;;;;AAUG;MAEU,oBAAoB,CAAA;AAEZ,IAAA,OAAA;AACA,IAAA,EAAA;IAFnB,WAAA,CACmB,OAAsB,EACtB,EAAoB,EAAA;QADpB,IAAA,CAAA,OAAO,GAAP,OAAO;QACP,IAAA,CAAA,EAAE,GAAF,EAAE;IAClB;AACK,IAAA,GAAG,GAAG,MAAM,CAAO,IAAI,IAAI,EAAE,+CAAC;;AAGtC,IAAA,oBAAoB,CAAI,OAAqB,EAAA;AAC3C,QAAA,IAAI,MAAM,GAAG,WAAW,CACtB,SAAS,CAAe,OAAO,CAAC,EAChC,WAAW,CAAC,CAAC,KAAU,MAAM;YAC3B,IAAI,EAAE,YAAW;gBACf,IAAI,MAAM,GAAsB,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC;AACvD,gBAAA,QAAQ,KAAK,CAAC,WAAW,EAAE;AACzB,oBAAA,KAAK,IAAI;AACP,wBAAA,MAAM,GAAG,IAAI,CAAC,UAAU,CAAI,KAAK,CAAC;wBAClC;AACF,oBAAA,KAAK,SAAS;AACZ,wBAAA,MAAM,GAAG,IAAI,CAAC,eAAe,CAAI,KAAK,CAAC;wBACvC;AACF,oBAAA,KAAK,OAAO;AACV,wBAAA,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAI,KAAK,CAAC;wBAC5C;;gBAEJ,OAAO,MAAM,MAAM;YACrB,CAAC;AACD,YAAA,MAAM,EAAE,OAAO,IAAO,KAAI;AACxB,gBAAA,QAAQ,KAAK,CAAC,WAAW,EAAE;AACzB,oBAAA,KAAK,IAAI;wBACP,MAAM,IAAI,CAAC,YAAY,CAAI,KAAK,EAAE,IAAI,CAAC;wBACvC;AACF,oBAAA,KAAK,SAAS;wBACZ,MAAM,IAAI,CAAC,iBAAiB,CAAI,KAAK,EAAE,IAAI,CAAC;wBAC5C;AACF,oBAAA,KAAK,OAAO;wBACV,MAAM,IAAI,CAAC,sBAAsB,CAAI,KAAK,EAAE,IAAI,CAAC;wBACjD;;YAEN,CAAC;SACF,CAAC,CAAC,EACH,SAAS,CAAC;AACR,YAAA,MAAM,CAAC,KAAU,EAAA;gBACf,MAAM,CAAC,YAAW;AAChB,oBAAA,IAAI,EAAE,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;wBAAE,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;AAC7D,gBAAA,CAAC,CAAC;YACJ,CAAC;AACF,SAAA,CAAC,CACH;QACD,OAAO,IAAI,MAAM,EAAE;IACrB;;;AAIA;;;AAGG;IACK,MAAM,eAAe,CAAI,KAAU,EAAA;AACzC,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAG,CAAE,CAAC;AACpE,QAAA,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,KAAK,CAAC,IAAI,EAAE;aAC9B;AACH,YAAA,IAAI;gBACF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAC1C,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,SAAS,CAAC,EAC/C,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC,CACzC;gBACD,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAkB;AAEjD,gBAAA,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE;oBAC9D,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAG,CAAC;oBACnC;gBACF;qBAAO;oBACL,OAAO,IAAI,CAAC,KAAK;gBACnB;YACF;YAAE,OAAO,GAAG,EAAE;AACZ,gBAAA,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC;gBACvC;YACF;QACF;IACF;AACA;;;;;AAKG;AACK,IAAA,MAAM,iBAAiB,CAAI,KAAU,EAAE,IAAS,EAAA;AACtD,QAAA,IAAI;AACF,YAAA,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE;AACrB,gBAAA,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YAClE;AACA,YAAA,IAAI,UAAU,GAAkB,EAAE,KAAK,EAAE,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE;YAE7F,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;YAChF,cAAc,CAAC,OAAO,CACpB,KAAK,CAAC,IAAI,EAAE,EACZ,IAAI,CAAC,SAAS,CAAC;AACb,gBAAA,EAAE,EAAE,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC;AACnC,gBAAA,SAAS,EAAE,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC;AAClD,aAAA,CAAC,CACH;QACH;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC;QACzC;IACF;;;AAIA;;;AAGG;IACK,MAAM,oBAAoB,CAAI,KAAU,EAAA;AAC9C,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAG,CAAE,CAAC;AAClE,QAAA,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,KAAK,CAAC,IAAI,EAAE;aAC9B;AACH,YAAA,IAAI;gBACF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAC1C,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,SAAS,CAAC,EAC/C,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC,CACzC;gBACD,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAkB;AAEjD,gBAAA,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE;oBAC9D,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAG,CAAC;oBACnC;gBACF;qBAAO;oBACL,OAAO,IAAI,CAAC,KAAK;gBACnB;YACF;YAAE,OAAO,GAAG,EAAE;AACZ,gBAAA,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC;gBACvC;YACF;QACF;IACF;AACA;;;;;AAKG;AACK,IAAA,MAAM,sBAAsB,CAAI,KAAU,EAAE,IAAS,EAAA;AAC3D,QAAA,IAAI;AACF,YAAA,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE;AACrB,gBAAA,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YAClE;AACA,YAAA,IAAI,UAAU,GAAkB,EAAE,KAAK,EAAE,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE;YAE7F,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;YAChF,YAAY,CAAC,OAAO,CAClB,KAAK,CAAC,IAAI,EAAE,EACZ,IAAI,CAAC,SAAS,CAAC;AACb,gBAAA,EAAE,EAAE,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC;AACnC,gBAAA,SAAS,EAAE,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC;AAClD,aAAA,CAAC,CACH;QACH;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC;QACzC;IACF;;;AAKA;;;AAGG;IACK,MAAM,UAAU,CAAI,KAAU,EAAA;AACpC,QAAA,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAM,KAAK,CAAC,IAAI,EAAG,CAAC;AACvD,QAAA,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,KAAK,CAAC,IAAI,EAAE;aAC9B;AACH,YAAA,IAAI;AACF,gBAAA,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC;gBAC/E,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAkB;AACjD,gBAAA,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE;oBAC9D,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAG,CAAC;oBACnC;gBACF;qBAAO;oBACL,OAAO,IAAI,CAAC,KAAK;gBACnB;YACF;YAAE,OAAO,GAAG,EAAE;AACZ,gBAAA,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC;gBACvC;YACF;QACF;IACF;AACA;;;;;AAKG;AACK,IAAA,MAAM,YAAY,CAAI,KAAU,EAAE,IAAS,EAAA;AACjD,QAAA,IAAI;AACF,YAAA,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE;AACrB,gBAAA,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YAClE;AACA,YAAA,IAAI,UAAU,GAAkB,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE;YAC7E,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AAChF,YAAA,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;QACpD;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC;QACzC;IACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEQ,IAAA,sBAAsB,CAAC,MAAW,EAAA;AACxC,QAAA,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC;AACzC,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU;AACzB,aAAA,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;aAChD,IAAI,CAAC,EAAE,CAAC;IACb;AACQ,IAAA,qBAAqB,CAAC,SAAc,EAAA;;QAE1C,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;;QAG9C,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE;AAC9B,YAAA,SAAS,GAAG,GAAG,GAAG,SAAS;QAC7B;;AAGA,QAAA,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC;AACvC,QAAA,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC;;AAG7C,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE;AACnC,YAAA,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC1C,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QACvC;AAEA,QAAA,OAAO,UAAU;IACnB;wGAvSW,oBAAoB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAA,aAAA,EAAA,EAAA,EAAA,KAAA,EAAAC,gBAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;4GAApB,oBAAoB,EAAA,CAAA;;4FAApB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBADhC;;AA2SD;AACA,MAAM,SAAS,CAAA;AACb,IAAA,IAAI;IACJ,IAAI,GAAkB,IAAI;AAC1B,IAAA,SAAS;IACT,WAAW,GAA+B,SAAS;AACpD;;MC1TY,mBAAmB,CAAA;IAC9B,OAAO,OAAO,CAAC,MAA2B,EAAA;QACxC,OAAO;AACL,YAAA,QAAQ,EAAE,mBAAmB;AAC7B,YAAA,SAAS,EAAE;AACT,gBAAA,EAAE,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,EAAE;AACpD,gBAAA,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,QAAQ,EAAE,EAAE,qBAAqB,CAAC,CAAC,EAAE;AAC3E,gBAAA,EAAE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,QAAQ,EAAE,EAAE,qBAAqB,CAAC,CAAC,EAAE;AAC9E,gBAAA;AACE,oBAAA,OAAO,EAAE,oBAAoB;AAC7B,oBAAA,IAAI,EAAE,CAAC,aAAa,EAAE,gBAAgB,CAAC;AACxC,iBAAA;AACF,aAAA;SACF;IACH;wGAdW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA;yGAAnB,mBAAmB,EAAA,CAAA;yGAAnB,mBAAmB,EAAA,CAAA;;4FAAnB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAD/B,QAAQ;mBAAC,EAAE;;;ACNZ;;AAEG;;;;"}
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
2
|
+
import { ModuleWithProviders } from '@angular/core';
|
|
3
|
+
import * as _ngrx_signals from '@ngrx/signals';
|
|
4
|
+
import * as _ngrx_signals_src_ts_helpers from '@ngrx/signals/src/ts-helpers';
|
|
3
5
|
import { BehaviorSubject } from 'rxjs';
|
|
4
6
|
|
|
5
7
|
interface SecureStorageConfig {
|
|
@@ -57,19 +59,66 @@ declare class SecureStorageService {
|
|
|
57
59
|
private readonly cryptoX;
|
|
58
60
|
private readonly db;
|
|
59
61
|
constructor(cryptoX: CryptoService, db: IndexeddbService);
|
|
60
|
-
now
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
private now;
|
|
63
|
+
persistSignalStorage<T>(initial: ExtendedT<T>): {
|
|
64
|
+
init?: (_ngrx_signals_src_ts_helpers.IsKnownRecord<T | undefined> extends true ? _ngrx_signals.DeepSignal<T | undefined> : i0.Signal<T | undefined>) | undefined;
|
|
65
|
+
name: i0.Signal<string | null>;
|
|
66
|
+
expiresAt?: i0.Signal<number | undefined> | undefined;
|
|
67
|
+
storageType: i0.Signal<"session" | "local" | "db">;
|
|
68
|
+
load: () => Promise<T | null>;
|
|
69
|
+
update: (data: T) => Promise<void>;
|
|
70
|
+
} & _ngrx_signals.StateSource<{
|
|
71
|
+
init?: T | undefined;
|
|
72
|
+
name: string | null;
|
|
73
|
+
expiresAt?: number | undefined;
|
|
74
|
+
storageType: "session" | "local" | "db";
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* handle loading data from session storage
|
|
78
|
+
* @param name
|
|
79
|
+
*/
|
|
80
|
+
private loadFromSession;
|
|
81
|
+
/**
|
|
82
|
+
* set & update data to session
|
|
83
|
+
* @param name
|
|
84
|
+
* @param state
|
|
85
|
+
* @param expiration
|
|
86
|
+
*/
|
|
87
|
+
private updateFromSession;
|
|
88
|
+
/**
|
|
89
|
+
* handle loading data from local storage
|
|
90
|
+
* @param name
|
|
91
|
+
*/
|
|
92
|
+
private loadFromLocalStorage;
|
|
93
|
+
/**
|
|
94
|
+
* set & update data to local storage
|
|
95
|
+
* @param name
|
|
96
|
+
* @param state
|
|
97
|
+
* @param expiration
|
|
98
|
+
*/
|
|
99
|
+
private updateFromLocalStorage;
|
|
100
|
+
/**
|
|
101
|
+
* handle loading data from indexedDB
|
|
102
|
+
* @param name
|
|
103
|
+
*/
|
|
104
|
+
private loadFromDb;
|
|
105
|
+
/**
|
|
106
|
+
* set & update data to indexedDB
|
|
107
|
+
* @param name
|
|
108
|
+
* @param state
|
|
109
|
+
* @param expiration
|
|
110
|
+
*/
|
|
111
|
+
private updateFromDb;
|
|
112
|
+
private arrayBufferToHexString;
|
|
113
|
+
private hexStringToUint8Array;
|
|
65
114
|
static ɵfac: i0.ɵɵFactoryDeclaration<SecureStorageService, never>;
|
|
66
115
|
static ɵprov: i0.ɵɵInjectableDeclaration<SecureStorageService>;
|
|
67
116
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
117
|
+
declare class ExtendedT<T> {
|
|
118
|
+
init?: T;
|
|
119
|
+
name: string | null;
|
|
120
|
+
expiresAt?: number;
|
|
121
|
+
storageType: 'session' | 'local' | 'db';
|
|
73
122
|
}
|
|
74
123
|
|
|
75
124
|
declare class SecureStorageModule {
|
package/package.json
CHANGED
package/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sources":["../../projects/ng-secure-storage/src/lib/tokens/secure-storage.config.ts","../../projects/ng-secure-storage/src/lib/services/crypto.service.ts","../../projects/ng-secure-storage/src/lib/services/indexeddb.service.ts","../../projects/ng-secure-storage/src/lib/services/secure-storage.service.ts","../../projects/ng-secure-storage/src/lib/public.module.ts"],"sourcesContent":[null,null,null,null,null],"names":[],"mappings":";;;;;;;;;AAOC;;ACJD,cAAA,aAAA;AAI6C;;;;AAM3C,uBAAA,UAAA,CAAA,WAAA;;;;;;;;;AAsDD;;AC/DD,cAAA,gBAAA;AAQ6C;;;;;AAFpC,aAAA,eAAA;;AAWP;;AAmDM,kCAAA,OAAA;AAWA,yBAAA,OAAA;;;;AAqBP;;ACpGD;;;;;;;;;;AAUG;AACH,cAAA,oBAAA;;;AAE+B,yBAAA,aAAA,MAAA,gBAAA;AAC7B,SAAA,cAAA,CAAA,IAAA;AACA,eAAA,cAAA;AACA,6DAAA,oBAAA;AA+BM,0BAAA,OAAA;;;;AAgCP;AAED,UAAA,oBAAA;AACE,WAAA,cAAA;AACA;AACA;;AAED;;ACpFD,cAAA,mBAAA;;;;;AAgBC;;;;"}
|