http-request-manager 0.0.1 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +262 -13
  2. package/esm2022/http-request-manager.mjs +5 -0
  3. package/esm2022/lib/interceptors/credentials.interceptor.mjs +14 -0
  4. package/esm2022/lib/interceptors/index.mjs +5 -0
  5. package/esm2022/lib/interceptors/models/error-settings.model.mjs +10 -0
  6. package/esm2022/lib/interceptors/request-error.interceptor.mjs +49 -0
  7. package/esm2022/lib/interceptors/request-header.interceptor.mjs +41 -0
  8. package/esm2022/lib/models/data-type.enum.mjs +7 -0
  9. package/esm2022/lib/models/database-storage.model.mjs +10 -0
  10. package/esm2022/lib/models/index.mjs +4 -0
  11. package/esm2022/lib/models/retry-options.model.mjs +10 -0
  12. package/esm2022/lib/services/index.mjs +6 -0
  13. package/esm2022/lib/services/local-storage-manager-service/index.mjs +3 -0
  14. package/esm2022/lib/services/local-storage-manager-service/local-storage-manager.service.mjs +275 -0
  15. package/esm2022/lib/services/local-storage-manager-service/models/global-store-options.model.mjs +13 -0
  16. package/esm2022/lib/services/local-storage-manager-service/models/index.mjs +7 -0
  17. package/esm2022/lib/services/local-storage-manager-service/models/setting-options.model.mjs +13 -0
  18. package/esm2022/lib/services/local-storage-manager-service/models/storage-data.model.mjs +10 -0
  19. package/esm2022/lib/services/local-storage-manager-service/models/storage-option-settings.model.mjs +13 -0
  20. package/esm2022/lib/services/local-storage-manager-service/models/storage-option.model.mjs +12 -0
  21. package/esm2022/lib/services/local-storage-manager-service/models/storage-type.enum.mjs +7 -0
  22. package/esm2022/lib/services/request-manager-services/http-manager.service.mjs +172 -0
  23. package/esm2022/lib/services/request-manager-services/index.mjs +5 -0
  24. package/esm2022/lib/services/request-manager-services/request.service.mjs +159 -0
  25. package/esm2022/lib/services/request-manager-services/rxjs-operators/countdown.mjs +9 -0
  26. package/esm2022/lib/services/request-manager-services/rxjs-operators/delay-retry.mjs +8 -0
  27. package/esm2022/lib/services/request-manager-services/rxjs-operators/index.mjs +5 -0
  28. package/esm2022/lib/services/request-manager-services/rxjs-operators/request-polling.mjs +14 -0
  29. package/esm2022/lib/services/request-manager-services/rxjs-operators/request-streaming.mjs +19 -0
  30. package/esm2022/lib/services/request-manager-state-service/http-manager-state.store.mjs +299 -0
  31. package/esm2022/lib/services/request-manager-state-service/index.mjs +3 -0
  32. package/esm2022/lib/services/request-manager-state-service/models/api-request.model.mjs +20 -0
  33. package/esm2022/lib/services/request-manager-state-service/models/index.mjs +3 -0
  34. package/esm2022/lib/services/request-manager-state-service/models/request-options.model.mjs +10 -0
  35. package/esm2022/lib/services/utils/app.service.mjs +20 -0
  36. package/esm2022/lib/services/utils/encryption/asymmetrical-encryption.service.mjs +186 -0
  37. package/esm2022/lib/services/utils/encryption/encryption-test.service.mjs +35 -0
  38. package/esm2022/lib/services/utils/encryption/index.mjs +4 -0
  39. package/esm2022/lib/services/utils/encryption/random.mjs +52 -0
  40. package/esm2022/lib/services/utils/encryption/symmetrical-encryption.service.mjs +77 -0
  41. package/esm2022/lib/services/utils/headers.service.mjs +21 -0
  42. package/esm2022/lib/services/utils/index.mjs +6 -0
  43. package/esm2022/lib/services/utils/path-query.service.mjs +53 -0
  44. package/esm2022/lib/services/utils/utils.service.mjs +134 -0
  45. package/esm2022/public-api.mjs +7 -0
  46. package/fesm2022/http-request-manager.mjs +1715 -0
  47. package/fesm2022/http-request-manager.mjs.map +1 -0
  48. package/http-request-manager-0.0.20.tgz +0 -0
  49. package/index.d.ts +5 -0
  50. package/lib/interceptors/credentials.interceptor.d.ts +8 -0
  51. package/lib/interceptors/index.d.ts +4 -0
  52. package/lib/interceptors/models/error-settings.model.d.ts +10 -0
  53. package/lib/interceptors/request-error.interceptor.d.ts +10 -0
  54. package/lib/interceptors/request-header.interceptor.d.ts +15 -0
  55. package/lib/models/data-type.enum.d.ts +5 -0
  56. package/lib/models/database-storage.model.d.ts +10 -0
  57. package/lib/models/index.d.ts +3 -0
  58. package/lib/models/retry-options.model.d.ts +10 -0
  59. package/lib/services/index.d.ts +4 -0
  60. package/lib/services/local-storage-manager-service/index.d.ts +2 -0
  61. package/lib/services/local-storage-manager-service/local-storage-manager.service.d.ts +81 -0
  62. package/lib/services/local-storage-manager-service/models/global-store-options.model.d.ts +15 -0
  63. package/lib/services/local-storage-manager-service/models/index.d.ts +6 -0
  64. package/lib/services/local-storage-manager-service/models/setting-options.model.d.ts +15 -0
  65. package/lib/services/local-storage-manager-service/models/storage-data.model.d.ts +10 -0
  66. package/lib/services/local-storage-manager-service/models/storage-option-settings.model.d.ts +15 -0
  67. package/lib/services/local-storage-manager-service/models/storage-option.model.d.ts +13 -0
  68. package/lib/services/local-storage-manager-service/models/storage-type.enum.d.ts +5 -0
  69. package/lib/services/request-manager-services/http-manager.service.d.ts +35 -0
  70. package/lib/services/request-manager-services/index.d.ts +3 -0
  71. package/lib/services/request-manager-services/request.service.d.ts +27 -0
  72. package/lib/services/request-manager-services/rxjs-operators/countdown.d.ts +2 -0
  73. package/lib/services/request-manager-services/rxjs-operators/delay-retry.d.ts +2 -0
  74. package/lib/services/request-manager-services/rxjs-operators/index.d.ts +4 -0
  75. package/lib/services/request-manager-services/rxjs-operators/request-polling.d.ts +7 -0
  76. package/lib/services/request-manager-services/rxjs-operators/request-streaming.d.ts +2 -0
  77. package/lib/services/request-manager-state-service/http-manager-state.store.d.ts +55 -0
  78. package/lib/services/request-manager-state-service/index.d.ts +2 -0
  79. package/lib/services/request-manager-state-service/models/api-request.model.d.ts +25 -0
  80. package/lib/services/request-manager-state-service/models/index.d.ts +2 -0
  81. package/lib/services/request-manager-state-service/models/request-options.model.d.ts +10 -0
  82. package/lib/services/utils/app.service.d.ts +8 -0
  83. package/lib/services/utils/encryption/asymmetrical-encryption.service.d.ts +17 -0
  84. package/lib/services/utils/encryption/encryption-test.service.d.ts +10 -0
  85. package/lib/services/utils/encryption/index.d.ts +3 -0
  86. package/lib/services/utils/encryption/random.d.ts +7 -0
  87. package/lib/services/utils/encryption/symmetrical-encryption.service.d.ts +14 -0
  88. package/lib/services/utils/headers.service.d.ts +10 -0
  89. package/lib/services/utils/index.d.ts +5 -0
  90. package/lib/services/utils/path-query.service.d.ts +11 -0
  91. package/lib/services/utils/utils.service.d.ts +24 -0
  92. package/package.json +24 -10
  93. package/public-api.d.ts +3 -0
  94. package/ng-package.json +0 -7
  95. package/src/lib/http-request-manager.component.spec.ts +0 -21
  96. package/src/lib/http-request-manager.component.ts +0 -15
  97. package/src/lib/http-request-manager.module.ts +0 -16
  98. package/src/lib/http-request-manager.service.spec.ts +0 -16
  99. package/src/lib/http-request-manager.service.ts +0 -9
  100. package/src/public-api.ts +0 -7
  101. package/tsconfig.lib.json +0 -14
  102. package/tsconfig.lib.prod.json +0 -10
  103. package/tsconfig.spec.json +0 -14
@@ -0,0 +1,1715 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, Injectable, APP_ID, Inject, Injector, InjectionToken } from '@angular/core';
3
+ import { ComponentStore } from '@ngrx/component-store';
4
+ import { withLatestFrom, map, tap, catchError, filter, finalize, takeWhile, retryWhen, delay, mergeMap, startWith, takeUntil, switchMap, concatMap, scan, expand } from 'rxjs/operators';
5
+ import { HttpClient, HttpHeaders, HttpEventType, HttpErrorResponse } from '@angular/common/http';
6
+ import * as CryptoJS from 'crypto-js';
7
+ import { interval, from, BehaviorSubject, EMPTY, defer, of, throwError, Subject, Subscription, catchError as catchError$1 } from 'rxjs';
8
+ import { ToastDisplay, ToastColors, ToastMessageService as ToastMessageService$1 } from 'toast-message';
9
+ import { ToastMessageService } from 'toast-message-display';
10
+ import * as i1 from '@ngx-translate/core';
11
+
12
+ var StorageType;
13
+ (function (StorageType) {
14
+ StorageType[StorageType["GLOBAL"] = 0] = "GLOBAL";
15
+ StorageType[StorageType["SESSION"] = 1] = "SESSION";
16
+ StorageType[StorageType["DB"] = 2] = "DB";
17
+ })(StorageType || (StorageType = {}));
18
+
19
+ class StorageOptionSettings {
20
+ constructor(storage = StorageType.GLOBAL, expires, expiresIn, encrypted) {
21
+ this.storage = storage;
22
+ this.expires = expires;
23
+ this.expiresIn = expiresIn;
24
+ this.encrypted = encrypted;
25
+ }
26
+ static adapt(item) {
27
+ return new StorageOptionSettings((item?.storage) ? item.storage : StorageType.GLOBAL, (item?.expires) ? item.expires : 0, (item?.expiresIn) ? item.expiresIn : '', (item?.encrypted) ? item.encrypted : false);
28
+ }
29
+ }
30
+
31
+ class StorageOption {
32
+ constructor(id, name = 'untitled', options) {
33
+ this.id = id;
34
+ this.name = name;
35
+ this.options = options;
36
+ }
37
+ static adapt(item) {
38
+ return new StorageOption((item?.id) ? item.id : crypto.randomUUID(), item?.name, (item?.options) ? StorageOptionSettings.adapt(item.options) : StorageOptionSettings.adapt());
39
+ }
40
+ }
41
+
42
+ class GlobalStoreOptions {
43
+ constructor(encryption = false, expiresIn, expires, stores = []) {
44
+ this.encryption = encryption;
45
+ this.expiresIn = expiresIn;
46
+ this.expires = expires;
47
+ this.stores = stores;
48
+ }
49
+ static adapt(item) {
50
+ return new GlobalStoreOptions((item?.encryption) ? item.encryption : false, (item?.expiresIn) ? item.expiresIn : '', (item?.expires) ? item.expires : 0, (item?.stores) ? item.stores.map((item) => StorageOption.adapt(item)) : []);
51
+ }
52
+ }
53
+
54
+ class SettingOptions {
55
+ constructor(storage = StorageType.GLOBAL, expires, expiresIn, encrypted) {
56
+ this.storage = storage;
57
+ this.expires = expires;
58
+ this.expiresIn = expiresIn;
59
+ this.encrypted = encrypted;
60
+ }
61
+ static adapt(item) {
62
+ return new SettingOptions((item?.storage) ? item.storage : StorageType.GLOBAL, (item?.expires) ? item.expires : 0, (item?.expiresIn) ? item.expiresIn : '', (item?.encrypted) ? item?.encrypted : false);
63
+ }
64
+ }
65
+
66
+ class StorageData {
67
+ constructor(id, data) {
68
+ this.id = id;
69
+ this.data = data;
70
+ }
71
+ static adapt(item) {
72
+ return new StorageData((item?.id) ? item.id : crypto.randomUUID(), (item?.data) ? item.data : null);
73
+ }
74
+ }
75
+
76
+ class UtilsService {
77
+ constructor() {
78
+ this.http = inject(HttpClient);
79
+ this.lc = (str) => str.toLowerCase().replace(/[^\w\s]/g, '').replace(/\s+/g, '_');
80
+ }
81
+ isString(x) {
82
+ return Object.prototype.toString.call(x) === '[object String]';
83
+ }
84
+ isObject(obj) {
85
+ return Object.prototype.toString.call(obj) === '[object Object]';
86
+ }
87
+ JSONToString(value) {
88
+ return (this.isObject(value)) ? JSON.stringify(value) : value;
89
+ }
90
+ stringToJSON(value) {
91
+ return (this.isJSON(value)) ? JSON.parse(value) : value;
92
+ }
93
+ isJSON(str) {
94
+ try {
95
+ JSON.parse(str);
96
+ }
97
+ catch (e) {
98
+ return false;
99
+ }
100
+ return true;
101
+ }
102
+ getValueByProp(obj, prop) {
103
+ if (typeof obj === 'undefined')
104
+ return false;
105
+ return obj[prop];
106
+ }
107
+ objectsEqual(x, y) {
108
+ const ok = Object.keys, tx = typeof x, ty = typeof y;
109
+ return x && y && tx === 'object' && tx === ty ? (ok(x).length === ok(y).length &&
110
+ ok(x).every((key) => this.objectsEqual(x[key], y[key]))) : (x === y);
111
+ }
112
+ getJSON(file) {
113
+ return this.http.get(`assets/data/${file}`);
114
+ }
115
+ get today() {
116
+ return new Date().getMilliseconds() / 1000;
117
+ }
118
+ base32ToHex(base32) {
119
+ const base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
120
+ const charToValue = (char) => base32chars.indexOf(char.toUpperCase());
121
+ let bits = '';
122
+ let hex = '';
123
+ for (let i = 0; i < base32.length; i++) {
124
+ const val = charToValue(base32.charAt(i));
125
+ bits += val.toString(2).padStart(5, '0');
126
+ }
127
+ for (let i = 0; i + 4 <= bits.length; i += 4) {
128
+ const chunk = bits.substr(i, 4);
129
+ hex += parseInt(chunk, 2).toString(16);
130
+ }
131
+ return hex.toUpperCase();
132
+ }
133
+ binaryToHex(binary) {
134
+ let hex = '';
135
+ for (let i = 0; i < binary.length; i += 8) {
136
+ const byte = binary.substr(i, 8);
137
+ const decimal = parseInt(byte, 2);
138
+ hex += decimal.toString(16).padStart(2, '0');
139
+ }
140
+ return hex.padStart(32, '0').substr(0, 32);
141
+ }
142
+ // y = years, m = months, w = weeks, d = days, hr = hours, mn = minutes else seconds
143
+ expires(str) {
144
+ if (!str)
145
+ return;
146
+ const match = str.match(/[^0-9]+$/);
147
+ const type = (match) ? str.slice(-match[0].length) : 0;
148
+ const now = Math.floor(new Date().getTime() / 1000);
149
+ let value = 0;
150
+ switch (type) {
151
+ case 'y':
152
+ const years = parseInt(str.slice(0, -1));
153
+ value = now + (years * 31556926);
154
+ break;
155
+ case 'm':
156
+ const months = parseInt(str.slice(0, -1));
157
+ value = now + (months * 2629743);
158
+ break;
159
+ case 'w':
160
+ const weeks = parseInt(str.slice(0, -1));
161
+ value = now + (weeks * 604800);
162
+ break;
163
+ case 'd':
164
+ const days = parseInt(str.slice(0, -1));
165
+ value = now + (days * 86400);
166
+ break;
167
+ case 'hr':
168
+ const hrs = parseInt(str.slice(0, -2));
169
+ value = now + (hrs * 3600);
170
+ break;
171
+ case 'mn':
172
+ const min = parseInt(str.slice(0, -2));
173
+ value = now + (min * 60);
174
+ break;
175
+ default: //seconds
176
+ const sec = parseInt(str.slice(0, -1));
177
+ value = now + (sec);
178
+ break;
179
+ }
180
+ return value;
181
+ }
182
+ hasExpired(expiryDate) {
183
+ if (!expiryDate || expiryDate === 0)
184
+ return false;
185
+ const currentTime = Math.floor(new Date().getTime() / 1000);
186
+ return expiryDate < currentTime;
187
+ }
188
+ hasExpiry(setting) {
189
+ return (setting?.expires) ? true : false;
190
+ }
191
+ expiresIn(expiryDate) {
192
+ if (!expiryDate)
193
+ return;
194
+ const now = Math.floor(new Date().getTime() / 1000);
195
+ return expiryDate - now;
196
+ }
197
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
198
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, providedIn: 'root' }); }
199
+ }
200
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, decorators: [{
201
+ type: Injectable,
202
+ args: [{
203
+ providedIn: 'root'
204
+ }]
205
+ }], ctorParameters: function () { return []; } });
206
+
207
+ const Random = () => {
208
+ const typedArray = new Uint8Array(1);
209
+ const randomValue = crypto.getRandomValues(typedArray)[0];
210
+ const randomFloat = randomValue / Math.pow(2, 8);
211
+ return randomFloat;
212
+ };
213
+ const RandomNumber = (min, max) => {
214
+ return Math.floor(Random() * max) + min;
215
+ };
216
+ const RandomNumbers = (min, max, length) => {
217
+ const numbers = [];
218
+ for (let i = 0; i < length; i++)
219
+ numbers.push(Math.floor(Random() * max) + min);
220
+ return numbers;
221
+ };
222
+ const RandomNumbersUnique = (min, max, length) => {
223
+ let count = 0;
224
+ // Adjust the length if it exceeds the number of unique numbers possible in the range
225
+ if (length > (max - min + 1)) {
226
+ console.error('error encountered');
227
+ length = max - min + 1;
228
+ }
229
+ console.log('length', length);
230
+ const numbers = [];
231
+ const maxAttempts = length * 100; // Safeguard to prevent infinite loops
232
+ while (numbers.length < length && count < maxAttempts) {
233
+ const num = Math.floor(Random() * max) + min;
234
+ if (!numbers.includes(num)) {
235
+ numbers.push(num);
236
+ }
237
+ }
238
+ if (count >= maxAttempts) {
239
+ throw new Error('Maximum attempts exceeded while generating unique numbers');
240
+ }
241
+ return numbers;
242
+ };
243
+ const RandomStr = () => {
244
+ const typedArray = new Uint8Array(8);
245
+ const array = new Uint32Array(1);
246
+ crypto.getRandomValues(array);
247
+ return array[0].toString(36);
248
+ };
249
+ const RandomSignature = () => {
250
+ const typedArray = new Uint8Array(8);
251
+ const array = new Uint32Array(1);
252
+ crypto.getRandomValues(array);
253
+ return array[0];
254
+ };
255
+ const UUID = () => {
256
+ return self.crypto.randomUUID();
257
+ };
258
+
259
+ class AppService {
260
+ constructor(id) {
261
+ this.id = id;
262
+ this.appID = this.id;
263
+ }
264
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppService, deps: [{ token: APP_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
265
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppService, providedIn: 'root' }); }
266
+ }
267
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppService, decorators: [{
268
+ type: Injectable,
269
+ args: [{
270
+ providedIn: 'root'
271
+ }]
272
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
273
+ type: Inject,
274
+ args: [APP_ID]
275
+ }] }]; } });
276
+
277
+ class SymmetricalEncryptionService {
278
+ constructor() {
279
+ this.appService = inject(AppService);
280
+ // TODO: The APP ID is not a string, it is a function
281
+ this.appID = (this.appService.appID) ? this.appService.appID : '';
282
+ if (this.appID === '')
283
+ console.warn('No App Key has been define');
284
+ }
285
+ generateCipherKey() {
286
+ return (RandomSignature().toString() + RandomSignature().toString()).substring(0, 8);
287
+ }
288
+ encrypt(str, key = this.appID) {
289
+ if (!str || key === '')
290
+ return '';
291
+ let _key = CryptoJS.enc.Utf8.parse(key);
292
+ let _iv = CryptoJS.enc.Utf8.parse(key);
293
+ try {
294
+ const encrypted = CryptoJS.AES.encrypt(JSON.stringify(str), _key, {
295
+ keySize: 16,
296
+ iv: _iv,
297
+ mode: CryptoJS.mode.ECB,
298
+ padding: CryptoJS.pad.Pkcs7
299
+ });
300
+ return encrypted.toString();
301
+ }
302
+ catch (error) {
303
+ console.log(error);
304
+ }
305
+ return;
306
+ }
307
+ decrypt(str, key = this.appID) {
308
+ if (!str || key === '')
309
+ return;
310
+ let _key = CryptoJS.enc.Utf8.parse(key);
311
+ let _iv = CryptoJS.enc.Utf8.parse(key);
312
+ try {
313
+ return CryptoJS.AES.decrypt(str, _key, {
314
+ keySize: 16,
315
+ iv: _iv,
316
+ mode: CryptoJS.mode.ECB,
317
+ padding: CryptoJS.pad.Pkcs7
318
+ }).toString(CryptoJS.enc.Utf8);
319
+ }
320
+ catch (error) {
321
+ console.log(error);
322
+ }
323
+ return;
324
+ }
325
+ createSignature(url, len = 16) {
326
+ const sig = CryptoJS.SHA256(url).toString(CryptoJS.enc.Hex);
327
+ return sig.substring(0, len).toUpperCase();
328
+ }
329
+ normalizeURL(url) {
330
+ const normalizedURL = url.replace(/(https?:\/\/)?(www\.)?/, '').replace(/\/+$/, '');
331
+ return normalizedURL;
332
+ }
333
+ generateSignature(url) {
334
+ const normalizedURL = this.normalizeURL(url);
335
+ const hash = CryptoJS.SHA256(normalizedURL);
336
+ const signature = hash.toString(CryptoJS.enc.Hex);
337
+ return signature;
338
+ }
339
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SymmetricalEncryptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
340
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SymmetricalEncryptionService, providedIn: 'root' }); }
341
+ }
342
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SymmetricalEncryptionService, decorators: [{
343
+ type: Injectable,
344
+ args: [{
345
+ providedIn: 'root'
346
+ }]
347
+ }], ctorParameters: function () { return []; } });
348
+
349
+ class EncryptionTestService {
350
+ constructor() { }
351
+ isBase64(str) {
352
+ const base64Pattern = /^(?:[A-Z0-9+/]{4})*(?:[A-Z0-9+/]{2}==|[A-Z0-9+/]{3}=)?$/i;
353
+ return base64Pattern.test(str);
354
+ }
355
+ isHexadecimal(str) {
356
+ const hexPattern = /^[0-9a-fA-F]+$/;
357
+ return hexPattern.test(str) && (str.length % 2 === 0);
358
+ }
359
+ hasHighEntropy(str) {
360
+ const uniqueChars = new Set(str).size;
361
+ return uniqueChars > str.length * 0.6;
362
+ }
363
+ isEncrypted(str) {
364
+ if (typeof str !== 'string') {
365
+ return false;
366
+ }
367
+ if (this.isBase64(str) || this.isHexadecimal(str)) {
368
+ return true;
369
+ }
370
+ return this.hasHighEntropy(str);
371
+ }
372
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EncryptionTestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
373
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EncryptionTestService, providedIn: 'root' }); }
374
+ }
375
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EncryptionTestService, decorators: [{
376
+ type: Injectable,
377
+ args: [{
378
+ providedIn: 'root'
379
+ }]
380
+ }], ctorParameters: function () { return []; } });
381
+
382
+ const storage = {
383
+ localStores: [],
384
+ sessionStores: [],
385
+ settings: [],
386
+ };
387
+ class LocalStorageManagerService extends ComponentStore {
388
+ startTimer() {
389
+ const timer$ = interval(1000 * 3).pipe(withLatestFrom(this.data$), map(([_, state]) => state), tap((state) => {
390
+ const expired = this.expired(state) ? this.expired(state) : [];
391
+ if (expired.length > 0) {
392
+ const ids = expired.map((item) => item.id);
393
+ const updatedState = {
394
+ ...state,
395
+ localStores: state.localStores.filter((item) => !ids.includes(item.id)),
396
+ sessionStores: state.sessionStores.filter((item) => !ids.includes(item.id)),
397
+ settings: state.settings.filter((item) => !ids.includes(item.id)),
398
+ };
399
+ this.persistState(updatedState);
400
+ this.updateState(updatedState);
401
+ }
402
+ }));
403
+ timer$.subscribe();
404
+ }
405
+ constructor() {
406
+ super(storage);
407
+ this.storageName = 'storage';
408
+ this.storageSettingsName = 'global-storage';
409
+ this.stateRetrieved = false;
410
+ this.encrypted = false;
411
+ this.app = inject(AppService);
412
+ this.utils = inject(UtilsService);
413
+ this.encryption = inject(SymmetricalEncryptionService);
414
+ this.encryptionTest = inject(EncryptionTestService);
415
+ // SELECTORS
416
+ this.data$ = this.select((state) => state);
417
+ this.stores$ = this.select((state) => state.settings);
418
+ this.storeExists$ = (store) => this.select(this.data$, (data) => data.settings.find(item => item.name === store) ? true : false);
419
+ this.store$ = (store) => this.select(this.data$, (data) => {
420
+ const foundStore = data.settings.find(item => item.name === store);
421
+ if (foundStore) {
422
+ const options = SettingOptions.adapt(foundStore.options);
423
+ const found = foundStore.options?.storage === StorageType.GLOBAL
424
+ ? data.localStores.find(item => item.id === foundStore.id)
425
+ : data.sessionStores.find(item => item.id === foundStore.id);
426
+ if (!found) {
427
+ this.deleteStore({ name: store });
428
+ return;
429
+ }
430
+ const storageData = (options.encrypted) ? this.encryption.decrypt(found.data, this.app.appID) : found.data;
431
+ return (this.isString(storageData)) ? JSON.parse(storageData) : storageData;
432
+ }
433
+ else {
434
+ return null;
435
+ }
436
+ });
437
+ this.settings$ = this.select((state) => state.settings);
438
+ this.setting$ = (store) => this.select(this.data$, (state) => {
439
+ const foundSetting = state.settings.find(item => item.name === store);
440
+ return (foundSetting) ? foundSetting : null;
441
+ });
442
+ this.persistence$ = this.data$
443
+ .subscribe(data => {
444
+ if (this.stateRetrieved)
445
+ this.persistState(data);
446
+ });
447
+ this.updateState = this.updater((state, updatedState) => ({
448
+ ...updatedState,
449
+ }));
450
+ this.setStore = this.updater((state, store) => {
451
+ const settings = StorageOption.adapt(store);
452
+ const type = store.options.storage;
453
+ const hasStore = this.hasGlobalStorage(type, store.id);
454
+ store.name = this.validStoreName(store.name);
455
+ if (!hasStore) {
456
+ console.warn(`No such Store: ${store.name}`);
457
+ return state;
458
+ }
459
+ else {
460
+ const str = this.encryptionTest.isEncrypted(store.data) ? store.data : JSON.stringify(store.data);
461
+ const dataStr = (this.isObjectOrArray(str)) ? (store.options.encrypted) ? this.encryption.encrypt(str, this.app.appID) : store.data : store.data;
462
+ const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
463
+ const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
464
+ return {
465
+ ...state,
466
+ localStores: [...state.localStores, ...localData],
467
+ sessionStores: [...state.sessionStores, ...sessionData],
468
+ settings: [...state.settings, ...[settings]],
469
+ };
470
+ }
471
+ });
472
+ this.createStore = this.updater((state, store) => {
473
+ const settings = StorageOption.adapt(store);
474
+ const foundStore = state?.settings.some(item => item.name === store.name);
475
+ const expires = (settings.options?.expiresIn) ? this.utils.expires(settings.options?.expiresIn) : 0;
476
+ if (settings.options)
477
+ settings.options.expires = expires;
478
+ store.name = this.validStoreName(store.name);
479
+ if (foundStore) {
480
+ return state;
481
+ }
482
+ else {
483
+ if (!this.isObjectOrArray(store.data)) {
484
+ console.warn('Data must ba an Object or Array');
485
+ return;
486
+ }
487
+ store.data = (this.isString(store.data)) ? JSON.parse(store.data) : store.data;
488
+ const dataStr = (store.options.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data;
489
+ const localData = (settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
490
+ const sessionData = (settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
491
+ return {
492
+ ...state,
493
+ localStores: [...state.localStores, ...localData],
494
+ sessionStores: [...state.sessionStores, ...sessionData],
495
+ settings: [...state.settings, ...[settings]],
496
+ };
497
+ }
498
+ });
499
+ this.updateStore = this.updater((state, store) => {
500
+ store.name = this.validStoreName(store.name);
501
+ const settings = state.settings.find(item => item.name === store.name);
502
+ if (settings) {
503
+ const type = settings.options?.storage;
504
+ const hasStore = this.hasGlobalStorage(type, settings.id || '');
505
+ if (!hasStore) {
506
+ console.warn(`No such Store: ${store.name}`);
507
+ }
508
+ else {
509
+ const dataStr = (settings.options?.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data;
510
+ const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
511
+ const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
512
+ state.localStores = state.localStores.filter(item => item.id !== settings.id);
513
+ state.sessionStores = state.sessionStores.filter(item => item.id !== settings.id);
514
+ return {
515
+ ...state,
516
+ localStores: [...state.localStores, ...localData],
517
+ sessionStores: [...state.sessionStores, ...sessionData],
518
+ };
519
+ }
520
+ }
521
+ return state;
522
+ });
523
+ this.deleteStore = this.updater((state, store) => {
524
+ store.name = this.validStoreName(store.name);
525
+ const id = state.settings.find(item => item.name === store.name)?.id;
526
+ if (id) {
527
+ const settings = state.settings.filter(item => item.id !== id);
528
+ const localData = state.localStores.filter(item => item.id !== id);
529
+ const sessionData = state.sessionStores.filter(item => item.id !== id);
530
+ return {
531
+ ...state,
532
+ localStores: [...localData],
533
+ sessionStores: [...sessionData],
534
+ settings: [...settings],
535
+ };
536
+ }
537
+ else {
538
+ console.warn(`No such Store: ${store.name}`);
539
+ return state;
540
+ }
541
+ });
542
+ this.isObjectOrArray = (obj) => {
543
+ try {
544
+ //obj = (Object.prototype.toString.call(obj) === '[object Object]') ? JSON.parse(obj) : obj
545
+ return typeof obj === 'object' || Array.isArray(obj);
546
+ }
547
+ catch (error) {
548
+ return false;
549
+ }
550
+ };
551
+ this.retrieveState();
552
+ this.startTimer();
553
+ }
554
+ resetStore() {
555
+ const newState = {
556
+ localStores: [],
557
+ sessionStores: [],
558
+ settings: [],
559
+ };
560
+ this.updateState(newState);
561
+ this.persistState(newState);
562
+ }
563
+ persistState(state) {
564
+ if (!state)
565
+ return;
566
+ const strLocal = JSON.stringify(state.localStores);
567
+ localStorage.setItem(this.storageName, strLocal);
568
+ const strSession = JSON.stringify(state.sessionStores);
569
+ sessionStorage.setItem(this.storageName, strSession);
570
+ const settingsStr = this.encryption.encrypt(state.settings, this.app.appID);
571
+ localStorage.setItem(this.storageSettingsName, settingsStr || '');
572
+ }
573
+ expired(state) {
574
+ if (!state)
575
+ return [];
576
+ return state.settings?.filter(item => (item.options?.expires || 0) > 0 && this.utils.hasExpired(item.options?.expires || 0));
577
+ }
578
+ retrieveState() {
579
+ const str = localStorage.getItem(this.storageSettingsName);
580
+ const localStr = localStorage.getItem(this.storageName);
581
+ const sessionStr = sessionStorage.getItem(this.storageName);
582
+ const localData = (localStr) ? JSON.parse(localStr) : null;
583
+ const sessionData = (sessionStr) ? JSON.parse(sessionStr) : null;
584
+ const decryptedStr = str ? this.encryption.decrypt(str, this.app.appID) : null;
585
+ const settings = (decryptedStr && decryptedStr !== null) ? JSON.parse(decryptedStr) : [];
586
+ settings.forEach(store => {
587
+ const expired = (store.options?.expires || 0) > 0 && this.utils.hasExpired(store.options?.expires || 0);
588
+ if (!expired) {
589
+ const hasStorage = this.hasGlobalStorage(store.options?.storage, store.id || '');
590
+ if (!hasStorage) {
591
+ this.createStore({ id: store.id, name: store.name, data: [], options: SettingOptions.adapt(store.options) });
592
+ }
593
+ else {
594
+ const storeData = (store.options?.storage === StorageType.GLOBAL) ? localData.find(item => item.id === store.id) : sessionData.find(item => item.id === store.id);
595
+ this.setStore({ id: store.id || '', name: store.name, data: storeData?.data, options: SettingOptions.adapt(store.options) });
596
+ }
597
+ }
598
+ });
599
+ this.stateRetrieved = true;
600
+ }
601
+ isString(obj) {
602
+ return (Object.prototype.toString.call(obj) === '[object String]');
603
+ }
604
+ fixAndParseJSON(jsonString) {
605
+ const fixedString = jsonString
606
+ .replace(/'/g, '"')
607
+ .replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":')
608
+ .replace(/,\s*(\}|\])/g, '$1');
609
+ try {
610
+ return JSON.parse(fixedString);
611
+ }
612
+ catch (error) {
613
+ throw new Error('Failed to parse JSON: ' + error.message);
614
+ }
615
+ }
616
+ validStoreName(str) {
617
+ return str
618
+ .toLowerCase() // Convert to lowercase
619
+ .replace(/\s+/g, '_') // Replace spaces with underscores
620
+ .replace(/[^ -~]/g, ''); // Remove non-ASCII characters
621
+ }
622
+ hasGlobalStorage(type = StorageType.GLOBAL, id) {
623
+ const strData = [];
624
+ if (type === StorageType.GLOBAL) {
625
+ const str = localStorage.getItem(this.storageName);
626
+ strData.push(...(str ? JSON.parse(str) : []));
627
+ }
628
+ else {
629
+ const str = sessionStorage.getItem(this.storageName);
630
+ strData.push(...(str ? JSON.parse(str) : []));
631
+ }
632
+ const found = strData.find(store => store.id === id);
633
+ return (found) ? true : false;
634
+ }
635
+ ngOnDestroy() {
636
+ this.persistence$.unsubscribe();
637
+ }
638
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
639
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, providedIn: 'root' }); }
640
+ }
641
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, decorators: [{
642
+ type: Injectable,
643
+ args: [{ providedIn: 'root' }]
644
+ }], ctorParameters: function () { return []; } });
645
+
646
+ class HeadersService {
647
+ constructor() {
648
+ this.headers = {};
649
+ }
650
+ generateHeaders(headers) {
651
+ const allHeaders = headers ? { ...this.headers, ...headers } : {};
652
+ return { headers: new HttpHeaders(allHeaders) };
653
+ }
654
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeadersService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
655
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeadersService, providedIn: 'root' }); }
656
+ }
657
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeadersService, decorators: [{
658
+ type: Injectable,
659
+ args: [{
660
+ providedIn: 'root'
661
+ }]
662
+ }] });
663
+
664
+ class PathQueryService {
665
+ constructor() {
666
+ this.removeEmptyParams = (obj) => Object.fromEntries(Object.entries(obj)
667
+ .map(([key, value]) => [key, value && typeof value === 'object' ? this.removeEmptyParams(value) : value])
668
+ .filter(([_, value]) => value !== undefined && value !== ""));
669
+ }
670
+ buildAPIPath(server, params) {
671
+ server = (Array.isArray(server)) ? server.join('/') : server;
672
+ const pathObjects = (params) ? params.filter((path) => (!this.isObject(path))) : [];
673
+ const queryObjects = (params) ? params.filter((path) => (this.isObject(path))) : [];
674
+ const query = this.removeEmptyParams(queryObjects.reduce((r, c) => {
675
+ Object.entries(c).forEach(([key, value]) => {
676
+ r[key] = Array.isArray(value) ? value.join(',') : value;
677
+ });
678
+ return r;
679
+ }, {}));
680
+ let path = this.buildRestPath(server, pathObjects);
681
+ return (Object.keys(query).length > 0) ? path + '?' + this.buildQueryPath(query) : path;
682
+ }
683
+ buildRestPath(server, params) {
684
+ server = (server.charAt(0) === '/') ? server.substring(1) : server;
685
+ return this.cleanUrlPath(server + '/' + params.join('/'));
686
+ }
687
+ buildQueryPath(params) {
688
+ const searchParams = new URLSearchParams();
689
+ for (const key in params) {
690
+ if (Array.isArray(params[key])) {
691
+ params[key].forEach((value) => searchParams.append(key, value));
692
+ }
693
+ else {
694
+ searchParams.append(key, params[key]);
695
+ }
696
+ }
697
+ return searchParams.toString();
698
+ }
699
+ cleanUrlPath(str) {
700
+ return str.replace(/([^:]\/)\/+/g, "$1").replace(/\/$/, '');
701
+ }
702
+ isObject(val) {
703
+ return (val === null) ? false : ((typeof val === 'function') || (typeof val === 'object'));
704
+ }
705
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PathQueryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
706
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PathQueryService, providedIn: 'root' }); }
707
+ }
708
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PathQueryService, decorators: [{
709
+ type: Injectable,
710
+ args: [{
711
+ providedIn: 'root'
712
+ }]
713
+ }] });
714
+
715
+ class AsymmetricalEncryptionService {
716
+ constructor() { }
717
+ generateKeyPair(modulusLength = 2048) {
718
+ // modulusLength - 1024, 2048, 4096
719
+ // hash - SHA-256
720
+ return from(crypto.subtle.generateKey({
721
+ name: "RSA-OAEP",
722
+ modulusLength,
723
+ publicExponent: new Uint8Array([1, 0, 1]),
724
+ hash: { name: "SHA-256" }
725
+ }, true, // Extractable keys
726
+ ["encrypt", "decrypt"]));
727
+ }
728
+ encryptData(publicKey, data) {
729
+ const encodedData = new TextEncoder().encode(data);
730
+ return from(crypto.subtle.encrypt({
731
+ name: "RSA-OAEP"
732
+ }, publicKey, encodedData)).pipe(map(enc => this.arrayBufferToBase64(enc)));
733
+ }
734
+ decryptData(privateKey, encryptedData) {
735
+ const encStr = this.base64ToArrayBuffer(encryptedData);
736
+ return from(crypto.subtle.decrypt({
737
+ name: "RSA-OAEP"
738
+ }, privateKey, encStr).then(decryptedData => {
739
+ return new TextDecoder().decode(decryptedData);
740
+ }));
741
+ }
742
+ pemToArrayBuffer(pem) {
743
+ const b64 = pem.replace(/(-----BEGIN (RSA )?(PRIVATE|PUBLIC) KEY-----|-----END (RSA )?(PRIVATE|PUBLIC) KEY-----|\n)/g, '');
744
+ const binaryString = atob(b64);
745
+ const len = binaryString.length;
746
+ const buffer = new ArrayBuffer(len);
747
+ const view = new Uint8Array(buffer);
748
+ for (let i = 0; i < len; i++) {
749
+ view[i] = binaryString.charCodeAt(i);
750
+ }
751
+ return buffer;
752
+ }
753
+ base64ToArrayBuffer(base64) {
754
+ const binaryString = atob(base64);
755
+ const len = binaryString.length;
756
+ const buffer = new ArrayBuffer(len);
757
+ const view = new Uint8Array(buffer);
758
+ for (let i = 0; i < len; i++) {
759
+ view[i] = binaryString.charCodeAt(i);
760
+ }
761
+ return buffer;
762
+ }
763
+ arrayBufferToBase64(buffer) {
764
+ let binary = '';
765
+ const bytes = new Uint8Array(buffer);
766
+ const len = bytes.byteLength;
767
+ for (let i = 0; i < len; i++) {
768
+ binary += String.fromCharCode(bytes[i]);
769
+ }
770
+ return window.btoa(binary);
771
+ }
772
+ base64ToPEM(base64Key, publicKey = true) {
773
+ const keyType = (publicKey) ? 'PUBLIC' : 'PRIVATE';
774
+ const header = `-----BEGIN ${keyType} KEY-----\n`;
775
+ const footer = `\n-----END ${keyType} KEY-----`;
776
+ const keyBody = base64Key.match(/.{1,64}/g)?.join("\n") || "";
777
+ return header + keyBody + footer;
778
+ }
779
+ pemToCryptoKey(pem, algorithm, extractable, keyUsages, format = "pkcs8" //"raw" | "pkcs8" | "spki"
780
+ ) {
781
+ const buffer = this.pemToArrayBuffer(pem);
782
+ console.log('buffer found ', buffer);
783
+ return from(crypto.subtle.importKey(format, buffer, algorithm, extractable, keyUsages));
784
+ }
785
+ // TESTING
786
+ testGenerateKeys() {
787
+ const testSequence = new BehaviorSubject("");
788
+ const testSequence$ = testSequence.asObservable();
789
+ testSequence.next("Test Generating Keys");
790
+ // GENERATE KEYS
791
+ this.generateKeyPair().subscribe((data) => {
792
+ console.log("GEN-GENERATED KEYS: ", data);
793
+ crypto.subtle.exportKey('spki', data.publicKey)
794
+ .then(key => {
795
+ const publicKeyBase64 = this.arrayBufferToBase64(key);
796
+ console.log("GEN-EXPORT PUBLIC KEY: ", this.base64ToPEM(publicKeyBase64, true));
797
+ });
798
+ crypto.subtle.exportKey('pkcs8', data.privateKey)
799
+ .then(key => {
800
+ const privateKeyBase64 = this.arrayBufferToBase64(key);
801
+ console.log("GEN-EXPORT PRIVATE KEY: ", this.base64ToPEM(privateKeyBase64, false));
802
+ });
803
+ // TEST WITH GENERATED KEYS
804
+ this.encryptData(data.publicKey, "Sample Data here - Mike Bonifacio")
805
+ .subscribe((enc) => {
806
+ console.log("GEN-ENCRYPT==>: ", enc);
807
+ this.decryptData(data.privateKey, enc).subscribe((dec) => {
808
+ testSequence.next('Test Passed');
809
+ testSequence.complete();
810
+ });
811
+ });
812
+ });
813
+ return testSequence$;
814
+ }
815
+ testDecryptionWithKeys() {
816
+ const testSequence = new BehaviorSubject("");
817
+ const testSequence$ = testSequence.asObservable();
818
+ testSequence.next("Test Generating Keys");
819
+ const privateKey = `-----BEGIN PRIVATE KEY-----
820
+ MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDKVBkCWNb9eHVF
821
+ twAA5mdAyvXFix3WavdrsoYRkvtCl8ogDBQf8f6N0bRkDF1zcVHRrNAEyozXDtuD
822
+ kFgSiivBFREI7fiS3sOvduq6FaGXzX0IY6oaVMu8oOPgDvC0yvoohR+0Qxq2d6lP
823
+ SPyHeKQaxP4KxzCJJzB1XAcbd2eFzUUDv25mNlwdVkmW8FI/sAxnJLgPTW78dzfX
824
+ Ddfk+nxdIqxVKSLATnL0kMN7aGJx24UozioAIpzvvvF5/+7HTd1gi6NeCqrAYr3g
825
+ iP364AE26CFwFvHnafO9uNQhlQ+uiNnOoInXByfFGVP+RidSpfLzaxDjs6RDwpol
826
+ h098btONAgMBAAECggEAAVhHM2OD5IkUtuowwcKNaCTKGmrClRE3gMuzJeBsSJEy
827
+ uAReUFILZylcnhegDytSti2vDA9T7xqtO6CU0p3V8LpU89JMOPRb/deirI4UXSpx
828
+ xbNyjirOO6bnrNlOWfKexdQQsikYPzF2iM1Scpr1u9ZDCHZOl1ZYSrkve5My4coP
829
+ 3Gx6tTBqL0jQBfcpf4ES8BH3JSawR/MgqzDS74+bI2VH+kvuPAC1L4fBgaV3VUv0
830
+ nFzim5A3s5VaXPgJbEIghP9BkYGFkeT9ma3nliEZWc96AzsmowFn1ayCvrNVPo9R
831
+ ECD2NnttBiCJZt3H93sR9+OTeA8Bls+aZGlKd5mLAQKBgQDpf8nIYUm/Zmls7/lQ
832
+ QBUSGHEYrbjNsEejQsPgNDtg2EVSxdUkvTn7Wb+HExTk09Z5bNvhaO2532/FH9y8
833
+ ahSXafiMXpfR2olwXdOB9yXXl4F5C0LGnmzGim4OSeWzAX0JCL470KaS0QN3EmoG
834
+ 9F0YCfMnZXNTweSSx4xvlO6ggQKBgQDd01uIolm7z1DIWCwNERAXP2GDwcvxyzYK
835
+ YqJfKDeHt2t6yIzZMMotnPDy+OlcdGspIIHkB5a+SZN5Nt7DUKg/MnyOZ3KbVq41
836
+ k7dR4Ka3LRnGkesy7lSr7ef1rfquyR75OXJQcPWvkFcLu0TMiQhvptatZ8VN+F4n
837
+ fDQELRotDQKBgQCgN+AUT7VT0QjcCBnRV/ddUEoiPenFsYSmYMSYzh5ESIHg1wB2
838
+ 0iS79Iw4Of6nOTg8X1bM57vfQ5Kk90T2P+/bKYqzfqC8DTErWiYsUpKzyTC9Bt4N
839
+ /Vz0Kr5zrX8ggg/yp/4oevYhXav8AzWfigNq4EDpMnKc8TlPAf+5/L50gQKBgQC2
840
+ mLPhPhr1gUszD3l7bA89w7uGlLFHoQoj9FtKTzWervp3QLzIT+QtNeIVb5XQuDg5
841
+ y3uAdEq+6pvNjMBEMJG+K9Xh9v+dJPYUPjsJ2A4D/MkZ7qWX8B2cxSJK1uLim8W2
842
+ S3ZxBvsGgJ9WldmlMCvUlJZkeWYtr4P5psC+q02/xQKBgQCDII/jcV2+lRM2iNTe
843
+ vBijZSaNMEWOK/Y+/HFK8GYKXnB+xNWhrm8rKgWGzpDJAUPMh9Tt+leW9LKEBuzF
844
+ Y1bGblmGm1zsPWpIx05Fdtv9eOJmFnXbGzIsYyhadZnPcQOWhqxtpVxSuul0Jc7Q
845
+ XNq4qPaPXhbQAshgtyBt75DMkw==
846
+ -----END PRIVATE KEY-----`;
847
+ const pubKey = `-----BEGIN PUBLIC KEY-----
848
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylQZAljW/Xh1RbcAAOZn
849
+ QMr1xYsd1mr3a7KGEZL7QpfKIAwUH/H+jdG0ZAxdc3FR0azQBMqM1w7bg5BYEoor
850
+ wRURCO34kt7Dr3bquhWhl819CGOqGlTLvKDj4A7wtMr6KIUftEMatnepT0j8h3ik
851
+ GsT+CscwiScwdVwHG3dnhc1FA79uZjZcHVZJlvBSP7AMZyS4D01u/Hc31w3X5Pp8
852
+ XSKsVSkiwE5y9JDDe2hicduFKM4qACKc777xef/ux03dYIujXgqqwGK94Ij9+uAB
853
+ NughcBbx52nzvbjUIZUProjZzqCJ1wcnxRlT/kYnUqXy82sQ47OkQ8KaJYdPfG7T
854
+ jQIDAQAB
855
+ -----END PUBLIC KEY-----`;
856
+ const algorithm = {
857
+ name: "RSA-OAEP",
858
+ modulusLength: 2048,
859
+ publicExponent: new Uint8Array([1, 0, 1]),
860
+ hash: "SHA-256"
861
+ };
862
+ // ENCRYPT
863
+ this.pemToCryptoKey(pubKey, algorithm, true, ["encrypt"], "spki").subscribe((keyPublic) => {
864
+ // console.log("PUBLIC KEY: ", keyPublic)
865
+ this.encryptData(keyPublic, "Sample Data here - Mike Bonifacio")
866
+ .subscribe((str) => {
867
+ console.log("ENCRYPTED STRING: ", str);
868
+ testSequence.next('encrypted string success');
869
+ });
870
+ });
871
+ const enc = "r7UOuEGBZ6jbVTOIBuv9jFOEtRiedmS27hfW40k7XKCTsQ5VhWup0qu2BA2ANZaGKii/uehJ/RSPiyfGbJ6leJrat0mA1hPqH/XodaBzLMDigvdYM1NSXFZMDa40OpLUIXbPlAvybjcGu7Bal+LMA8htHrFu/OmM/fHI66xOzzpuXSYx0OkWjtY81rUQ1FFkvrkx2jGFPZ0p+Nw/v3Q4cJnet6V63vCueFlD749VMcVXo7pvz4AIPpB+IOy3kbxaYTPakLVioJERU6GFMXWkECuRvohhS9CETcORZtRVRkvhcHk3lxgIhfqojUKYgD6K5dDELDPsWIS+iTG1XIQIlg==";
872
+ // DECRYPTION
873
+ this.pemToCryptoKey(privateKey, algorithm, false, ["decrypt"], "pkcs8").subscribe((key) => {
874
+ // console.log("DECRYPT ===", key)
875
+ this.decryptData(key, enc)
876
+ .pipe(catchError(err => {
877
+ console.log("ERROR: ", err);
878
+ return EMPTY;
879
+ })).subscribe((str) => {
880
+ console.log("DECRYPTED STRING: ", str);
881
+ testSequence.next('decrypted string success');
882
+ });
883
+ });
884
+ return testSequence$;
885
+ }
886
+ ;
887
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AsymmetricalEncryptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
888
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AsymmetricalEncryptionService, providedIn: 'root' }); }
889
+ }
890
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AsymmetricalEncryptionService, decorators: [{
891
+ type: Injectable,
892
+ args: [{
893
+ providedIn: 'root'
894
+ }]
895
+ }], ctorParameters: function () { return []; } });
896
+
897
+ function requestStreaming() {
898
+ return input$ => input$.pipe(filter((event) => event.type === HttpEventType.DownloadProgress || event.type === HttpEventType.Response), map((event) => {
899
+ if (event.type === HttpEventType.DownloadProgress) {
900
+ return event.partialText || '';
901
+ }
902
+ else if (event.type === HttpEventType.Response) {
903
+ return event.body;
904
+ }
905
+ }), map((data) => {
906
+ if (typeof data === 'string') {
907
+ const matches = data.match(/{[^}]+}/g) || [];
908
+ return (matches.length > 0) ? matches.map(match => JSON.parse(match)) : data;
909
+ }
910
+ return data;
911
+ }));
912
+ }
913
+
914
+ class RequestService {
915
+ constructor() {
916
+ this.http = inject(HttpClient);
917
+ this.pathQueryService = inject(PathQueryService);
918
+ this.headersService = inject(HeadersService);
919
+ this.isPending = new BehaviorSubject(false);
920
+ this.isPending$ = this.isPending.asObservable();
921
+ this.progress = new BehaviorSubject(0);
922
+ this.progress$ = this.progress.asObservable();
923
+ }
924
+ getRecordRequest(options) {
925
+ this.isPending.next(true);
926
+ const urlPath = this.buildUrlPath(options);
927
+ const headers = this.buildCombinedHeaders(options);
928
+ return (options.stream)
929
+ ? this.http.get(urlPath, headers).pipe(requestStreaming(), this.handleFinalize())
930
+ : this.http.get(urlPath, headers).pipe(this.request(options), this.handleFinalize());
931
+ }
932
+ createRecordRequest(options, data) {
933
+ this.isPending.next(true);
934
+ const urlPath = this.buildUrlPath(options);
935
+ const headers = this.buildCombinedHeaders(options);
936
+ return (options.stream)
937
+ ? this.http.post(urlPath, data, headers).pipe(requestStreaming(), this.handleFinalize())
938
+ : this.http.post(urlPath, data, headers).pipe(this.request(options), this.handleFinalize());
939
+ }
940
+ updateRecordRequest(options, data) {
941
+ this.isPending.next(true);
942
+ const urlPath = this.buildUrlPath(options);
943
+ const headers = this.buildHeaders(options);
944
+ return this.http.put(urlPath, data, headers).pipe(this.request(options), this.handleFinalize());
945
+ }
946
+ deleteRecordRequest(options) {
947
+ this.isPending.next(true);
948
+ const urlPath = this.buildUrlPath(options);
949
+ const headers = this.buildHeaders(options);
950
+ return this.http.delete(urlPath, headers).pipe(this.handleFinalize());
951
+ }
952
+ // Helper functions
953
+ buildUrlPath(options) {
954
+ return this.pathQueryService.buildAPIPath(options.server, options.path);
955
+ }
956
+ buildHeaders(options) {
957
+ return this.headersService.generateHeaders(options.headers);
958
+ }
959
+ buildCombinedHeaders(options) {
960
+ const headers = this.headersService.generateHeaders(options.headers);
961
+ return this.combineHeaders(headers, options.stream);
962
+ }
963
+ request(options) {
964
+ return (source$) => {
965
+ return source$.pipe(map(data => {
966
+ if (options.adapter) {
967
+ return Array.isArray(data)
968
+ ? data.map((item) => options.adapter(item))
969
+ : options.adapter(data);
970
+ }
971
+ return data;
972
+ }));
973
+ };
974
+ }
975
+ downloadFileRequest(options) {
976
+ this.isPending.next(true);
977
+ const urlPath = this.buildUrlPath(options);
978
+ return this.http.get(urlPath, { responseType: 'blob', observe: 'events', reportProgress: true })
979
+ .pipe(map((event) => {
980
+ this.isPending.next(true);
981
+ switch (event.type) {
982
+ case HttpEventType.DownloadProgress:
983
+ const status = (event.total) ? Math.round(event.loaded / (event.total || 1) * 100) : 100;
984
+ this.progress.next(status);
985
+ return status;
986
+ case HttpEventType.Response:
987
+ const header_content = event.headers.get('Content-Disposition') || '';
988
+ const file = header_content.split('=')[1].substring(0, header_content.split('=')[1].length);
989
+ this.downloadFile(file, event.body);
990
+ this.isPending.next(false);
991
+ return 100;
992
+ default:
993
+ this.isPending.next(false);
994
+ return 0;
995
+ }
996
+ }));
997
+ }
998
+ handleFinalize() {
999
+ return finalize(() => this.isPending.next(false));
1000
+ }
1001
+ downloadFile(file, fileData) {
1002
+ const navigatorAny = window.navigator;
1003
+ const extension = file.split('.')[1].toLowerCase();
1004
+ var newBlob = new Blob([fileData], { type: this.createFileType(extension) });
1005
+ if (navigatorAny.msSaveOrOpenBlob) {
1006
+ navigatorAny.msSaveOrOpenBlob(newBlob, file);
1007
+ }
1008
+ else {
1009
+ const link = document.createElement('a');
1010
+ const url = window.URL.createObjectURL(newBlob);
1011
+ link.href = url;
1012
+ link.download = file;
1013
+ link.click();
1014
+ window.URL.revokeObjectURL(url);
1015
+ }
1016
+ }
1017
+ createFileType(ext) {
1018
+ let fileType = "";
1019
+ if (ext == 'pdf' || ext == 'csv') {
1020
+ fileType = `application/${ext}`;
1021
+ }
1022
+ else if (ext == 'jpeg' || ext == 'jpg' || ext == 'png') {
1023
+ fileType = `image/${ext}`;
1024
+ }
1025
+ else if (ext == 'txt') {
1026
+ fileType = 'text/plain';
1027
+ }
1028
+ else if (ext == 'ppt' || ext == 'pot' || ext == 'pps' || ext == 'ppa') {
1029
+ fileType = 'application/vnd.ms-powerpoint';
1030
+ }
1031
+ else if (ext == 'pptx') {
1032
+ fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
1033
+ }
1034
+ else if (ext == 'doc' || ext == 'dot') {
1035
+ fileType = 'application/msword';
1036
+ }
1037
+ else if (ext == 'docx') {
1038
+ fileType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
1039
+ }
1040
+ else if (ext == 'xls' || ext == 'xlt' || ext == 'xla') {
1041
+ fileType = 'application/vnd.ms-excel';
1042
+ }
1043
+ else if (ext == 'xlsx') {
1044
+ fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
1045
+ }
1046
+ return fileType;
1047
+ }
1048
+ combineHeaders(headers, isStreaming) {
1049
+ const options = {
1050
+ observe: 'events',
1051
+ responseType: 'text',
1052
+ reportProgress: true,
1053
+ };
1054
+ return (isStreaming) ? { ...headers, ...options } : headers;
1055
+ }
1056
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1057
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, providedIn: 'root' }); }
1058
+ }
1059
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, decorators: [{
1060
+ type: Injectable,
1061
+ args: [{
1062
+ providedIn: 'root'
1063
+ }]
1064
+ }] });
1065
+
1066
+ function countdown(duration) {
1067
+ return defer(() => {
1068
+ const currentCount = { current: duration };
1069
+ return interval(1000).pipe(map(() => --currentCount.current), takeWhile(count => count >= 0));
1070
+ });
1071
+ }
1072
+
1073
+ const DEFAULT_MAX_RETRIES = 3;
1074
+ function delayedRetry(delayMs, maxRetry = DEFAULT_MAX_RETRIES) {
1075
+ let retries = maxRetry;
1076
+ return (src) => src.pipe(retryWhen((errors) => errors.pipe(delay(delayMs), mergeMap(error => retries-- > 0 ? of(error) : throwError(error)))));
1077
+ }
1078
+
1079
+ /**
1080
+ * @param pollInterval
1081
+ * @param stopCondition$
1082
+ * @param isPending$
1083
+ */
1084
+ function requestPolling(pollInterval, stopCondition$, isPending$) {
1085
+ return (source) => {
1086
+ return interval(pollInterval * 1000)
1087
+ .pipe(startWith(0), tap(() => isPending$.next(true)), mergeMap(() => source), tap(() => isPending$.next(false)), takeUntil(stopCondition$));
1088
+ };
1089
+ }
1090
+
1091
+ class HTTPManagerService extends RequestService {
1092
+ constructor() {
1093
+ super();
1094
+ this.toastMessage = inject(ToastMessageService);
1095
+ this.ng_injector = inject(Injector);
1096
+ this.countdown = new BehaviorSubject(0);
1097
+ this.countdown$ = this.countdown.asObservable();
1098
+ this.error = new BehaviorSubject(false);
1099
+ this.error$ = this.error.asObservable();
1100
+ this.data = new BehaviorSubject(null);
1101
+ this.data$ = this.data.asObservable();
1102
+ this.polling$ = new Subject();
1103
+ }
1104
+ // REQUESTS
1105
+ getRequest(options, params) {
1106
+ this.data.next(null);
1107
+ const updatedOptions = {
1108
+ ...options,
1109
+ path: params ? [...options.path, ...params] : options.path,
1110
+ };
1111
+ const func = this.getRecordRequest;
1112
+ const requests = this.createRequest(func, updatedOptions);
1113
+ return this.createObservable(options, requests, func.name).pipe(tap(data => this.data.next(data)));
1114
+ }
1115
+ postRequest(data, options, params) {
1116
+ this.data.next(null);
1117
+ const updatedOptions = {
1118
+ ...options,
1119
+ path: params ? [...options.path, ...params] : options.path,
1120
+ };
1121
+ const func = this.createRecordRequest;
1122
+ const requests = this.createRequest(func, updatedOptions, data);
1123
+ return this.createObservable(options, requests, func.name).pipe(tap(data => this.data.next(data)));
1124
+ }
1125
+ putRequest(data, options, params) {
1126
+ this.data.next(null);
1127
+ const updatedOptions = {
1128
+ ...options,
1129
+ path: params ? [...options.path, ...params] : options.path,
1130
+ };
1131
+ const func = this.updateRecordRequest;
1132
+ const requests = this.createRequest(func, updatedOptions, data);
1133
+ return this.createObservable(options, requests, func.name).pipe(tap(data => this.data.next(data)));
1134
+ }
1135
+ deleteRequest(options, params) {
1136
+ this.data.next(null);
1137
+ const updatedOptions = {
1138
+ ...options,
1139
+ path: params ? [...options.path, ...params] : options.path,
1140
+ };
1141
+ const func = this.deleteRecordRequest;
1142
+ const requests = this.createRequest(func, updatedOptions);
1143
+ return this.createObservable(options, requests, func.name).pipe(tap(data => this.data.next(data)));
1144
+ }
1145
+ downloadRequest(options, params) {
1146
+ const updatedOptions = {
1147
+ ...options,
1148
+ path: params ? [...options.path, ...params] : options.path,
1149
+ };
1150
+ const func = this.downloadFileRequest;
1151
+ const requests = this.createRequest(func, updatedOptions);
1152
+ return this.createObservable(options, requests, func.name)
1153
+ .pipe(tap(() => this.error.next(false)), catchError((err) => {
1154
+ this.error.next(true);
1155
+ return EMPTY;
1156
+ }));
1157
+ }
1158
+ // UTILS
1159
+ createObservable(options, request$, funcName) {
1160
+ const polling = options.polling ? (options.polling > 0 ? true : false) : false;
1161
+ const isPolling = polling &&
1162
+ !(funcName === 'deleteRecordRequest' || funcName === 'updateRecordRequest' || funcName === 'createRecordRequest')
1163
+ ? true
1164
+ : false;
1165
+ this.polling$.next();
1166
+ const polling$ = (isPolling && options.polling) || 0 >= 3
1167
+ ? request$.pipe(requestPolling((options.polling || 0) + 1, this.polling$, this.isPending), tap(() => this.countdown.next(0)), tap(() => {
1168
+ if (!options.polling)
1169
+ return;
1170
+ const count = options.polling ? options.polling : 0;
1171
+ console.log('COUNT:', count);
1172
+ countdown(count)
1173
+ .pipe(map((x) => {
1174
+ console.log('XX:', count, x);
1175
+ const pollingInSec = options.polling || 0;
1176
+ const percentageCompleted = ((pollingInSec - x) / pollingInSec) * 100;
1177
+ return Math.round(percentageCompleted);
1178
+ }))
1179
+ .subscribe((countDownValue) => {
1180
+ console.log(this.countdown.value, countDownValue);
1181
+ this.countdown.next(countDownValue);
1182
+ });
1183
+ }))
1184
+ : request$.pipe(catchError((err) => {
1185
+ if (err instanceof HttpErrorResponse) {
1186
+ this.error.next(true);
1187
+ if (options.displayError)
1188
+ this.handleErrorWithSnackBar(err);
1189
+ return this.handleError(err);
1190
+ }
1191
+ return throwError(() => err);
1192
+ }), finalize(() => this.isPending.next(false)));
1193
+ return polling$.pipe(catchError((err, caught) => {
1194
+ if (err instanceof HttpErrorResponse) {
1195
+ this.error.next(true);
1196
+ this.stopPolling();
1197
+ return this.handleError(err);
1198
+ }
1199
+ return throwError(() => err);
1200
+ }), options.retry.times > 0
1201
+ ? delayedRetry((options?.retry.delay || 3) * 1000, (options?.retry.times || 0) - 1)
1202
+ : (source) => source);
1203
+ }
1204
+ createRequest(func, options, data) {
1205
+ const dataItem = this.prepareRequestData(options, data, func.name);
1206
+ return func.bind(this)(dataItem.options, dataItem.data);
1207
+ }
1208
+ prepareRequestData(options, data, funcName) {
1209
+ if ((options.mapper && funcName === 'updateRecordRequest') || funcName === 'createRecordRequest') {
1210
+ data = options.mapper
1211
+ ? Array.isArray(data)
1212
+ ? map((item) => options.mapper(item))
1213
+ : options.mapper(data)
1214
+ : data;
1215
+ }
1216
+ else {
1217
+ data = options.adapter
1218
+ ? Array.isArray(data)
1219
+ ? map((item) => options.adapter(item))
1220
+ : options.adapter(data)
1221
+ : data;
1222
+ }
1223
+ return { options: options, data: data };
1224
+ }
1225
+ // MISC
1226
+ handleError(error) {
1227
+ this.isPending.next(false);
1228
+ return throwError(() => error);
1229
+ }
1230
+ handleErrorWithSnackBar(error) {
1231
+ const displayError = ToastDisplay.adapt({
1232
+ message: error.message || `${error.status} - ${error.statusText}`,
1233
+ action: 'OK',
1234
+ color: ToastColors.ERROR,
1235
+ icon: 'error',
1236
+ duration: 5 * 1000, //5 seconds
1237
+ });
1238
+ this.toastMessage.toastMessage(displayError);
1239
+ }
1240
+ stopPolling() {
1241
+ this.isPending.next(false);
1242
+ this.polling$.next();
1243
+ }
1244
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1245
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, providedIn: 'root' }); }
1246
+ }
1247
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, decorators: [{
1248
+ type: Injectable,
1249
+ args: [{
1250
+ providedIn: 'root',
1251
+ }]
1252
+ }], ctorParameters: function () { return []; } });
1253
+
1254
+ class DatabaseStorage {
1255
+ constructor(table = '', expiresIn) {
1256
+ this.table = table;
1257
+ this.expiresIn = expiresIn;
1258
+ }
1259
+ static adapt(item) {
1260
+ return new DatabaseStorage(item?.table, item?.expiresIn);
1261
+ }
1262
+ }
1263
+
1264
+ class RetryOptions {
1265
+ constructor(times = 0, delay = 0) {
1266
+ this.times = times;
1267
+ this.delay = delay;
1268
+ }
1269
+ static adapt(item) {
1270
+ return new RetryOptions(item?.times ? Math.floor(item.times) : 0, item?.delay ? Math.floor(item.delay) : 0);
1271
+ }
1272
+ }
1273
+
1274
+ var DataType;
1275
+ (function (DataType) {
1276
+ DataType[DataType["ANY"] = 0] = "ANY";
1277
+ DataType[DataType["ARRAY"] = 1] = "ARRAY";
1278
+ DataType[DataType["OBJECT"] = 2] = "OBJECT";
1279
+ })(DataType || (DataType = {}));
1280
+
1281
+ class ApiRequest {
1282
+ constructor(server = '', path = [], headers = {}, adapter, mapper, polling, retry = RetryOptions.adapt(), stream = false, displayError = false) {
1283
+ this.server = server;
1284
+ this.path = path;
1285
+ this.headers = headers;
1286
+ this.adapter = adapter;
1287
+ this.mapper = mapper;
1288
+ this.polling = polling;
1289
+ this.retry = retry;
1290
+ this.stream = stream;
1291
+ this.displayError = displayError;
1292
+ }
1293
+ static adapt(item) {
1294
+ const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
1295
+ const retryOptions = item?.retry ? RetryOptions.adapt(item.retry) : RetryOptions.adapt();
1296
+ return new ApiRequest(server, item?.path, (item?.headers) ? item.headers : {}, item?.adapter, item?.mapper, item?.polling ? Math.floor(item.polling) : 0, retryOptions, item?.stream, item?.displayError);
1297
+ }
1298
+ }
1299
+
1300
+ class RequestOptions {
1301
+ constructor(path = [], headers = {}) {
1302
+ this.path = path;
1303
+ this.headers = headers;
1304
+ }
1305
+ static adapt(item) {
1306
+ return new RequestOptions(item?.path, item?.headers);
1307
+ }
1308
+ }
1309
+
1310
+ const API_OPTS = new InjectionToken('API_OPTS');
1311
+ const defaultState = {
1312
+ data: [],
1313
+ dataObject: null,
1314
+ };
1315
+ class HTTPManagerStateService extends ComponentStore {
1316
+ constructor(apiOptions, dataType, database) {
1317
+ super(defaultState);
1318
+ this.apiOptions = apiOptions;
1319
+ this.dataType = dataType;
1320
+ this.database = database;
1321
+ this.httpManagerService = inject(HTTPManagerService);
1322
+ this.error$ = this.httpManagerService.error$;
1323
+ this.isPending$ = this.httpManagerService.isPending$;
1324
+ // PAGINATION
1325
+ this.page = new BehaviorSubject(0);
1326
+ this.page$ = this.page.asObservable();
1327
+ this.totalPages = new BehaviorSubject(0);
1328
+ this.totalPages$ = this.totalPages.asObservable();
1329
+ this.percentage = new BehaviorSubject(0);
1330
+ this.percentage$ = this.percentage.asObservable();
1331
+ // ----------
1332
+ this.hasDatabase = false;
1333
+ this.streamedResponse = [];
1334
+ // --------------------------------------------------------------------------------------------------
1335
+ // SELECTORS
1336
+ this.data$ = this.select(({ data, dataObject }) => {
1337
+ const isArray = (this.dataType === DataType.ARRAY) ? true : false;
1338
+ return (isArray) ? data : dataObject;
1339
+ });
1340
+ this.selectRecord$ = (id) => this.select(this.data$, (data) => {
1341
+ if (this.dataType === DataType.ARRAY && Array.isArray(data)) {
1342
+ return data.find(item => item.id === id);
1343
+ }
1344
+ else {
1345
+ return data.id === id ? data : null;
1346
+ }
1347
+ });
1348
+ // --------------------------------------------------------------------------------------------------
1349
+ // UPDATERS
1350
+ this.resetData$ = this.updater((state) => {
1351
+ return { ...state, data: [], dataObject: null };
1352
+ });
1353
+ this.setData$ = this.updater((state, data) => {
1354
+ if (!data)
1355
+ return state;
1356
+ if (this.dataType === DataType.ARRAY) {
1357
+ const dataArray = Array.isArray(data) ? data : [data];
1358
+ const stateDataSample = (state.data.length > 0) ? Object.keys(state.data[0]) : [];
1359
+ const newDataSample = (dataArray.length > 0) ? Object.keys(dataArray[0]) : [];
1360
+ const isSame = (state.data.length === 0) ? false : stateDataSample.every((value, index) => value === newDataSample[index]);
1361
+ const updatedData = (!isSame && dataArray.length !== 0) ? this.updateArrayState([], dataArray) : this.updateArrayState(state.data, dataArray);
1362
+ return { ...state, data: updatedData, dataObject: null };
1363
+ }
1364
+ else {
1365
+ const dataObject = this.isEmpty(data) ? null : data;
1366
+ return { ...state, data: [], dataObject: dataObject };
1367
+ }
1368
+ });
1369
+ this.addData$ = this.updater((state, data) => {
1370
+ if (this.dataType === DataType.ARRAY) {
1371
+ const newState = [...state.data, data];
1372
+ return { ...state, ...{ data: newState } };
1373
+ }
1374
+ else {
1375
+ return { ...state, ...{ dataObject: data } };
1376
+ }
1377
+ });
1378
+ this.deleteData$ = this.updater((state, data) => {
1379
+ if (this.dataType === DataType.ARRAY) {
1380
+ const newState = state.data.filter(item => item.id !== data.id);
1381
+ return { ...state, ...{ data: newState } };
1382
+ }
1383
+ else {
1384
+ return { ...state, ...{ dataObject: null } };
1385
+ }
1386
+ });
1387
+ this.updateData$ = this.updater((state, data) => {
1388
+ if (this.dataType === DataType.ARRAY) {
1389
+ const objIndex = state.data.findIndex(item => item.id === data.id);
1390
+ if (objIndex > -1) {
1391
+ const newState = [...state.data];
1392
+ newState[objIndex] = data;
1393
+ return { ...state, ...{ data: newState } };
1394
+ }
1395
+ return state;
1396
+ }
1397
+ else {
1398
+ return { ...state, ...{ dataObject: data } };
1399
+ }
1400
+ });
1401
+ // --------------------------------------------------------------------------------------------------
1402
+ // EFFECTS
1403
+ this.clearRecords = this.effect(data => data.pipe(tap(() => {
1404
+ if (this.dataType === DataType.ARRAY) {
1405
+ this.setData$([]);
1406
+ }
1407
+ else {
1408
+ this.setData$({});
1409
+ }
1410
+ })));
1411
+ this.refreshData = this.effect(data => data.pipe(tap(() => {
1412
+ // this.apiService.flushDatabase(this.otherOptions.database?.table)
1413
+ this.fetchRecords();
1414
+ })));
1415
+ // --------------------------------------------------------------------------------------------------
1416
+ // CRUD OPERATIONS
1417
+ // FETCH RECORDS
1418
+ this.fetchRecords = (options) => this.effect(() => of(RequestOptions.adapt(options)).pipe(switchMap(() => {
1419
+ this.streamedResponse = [];
1420
+ const requestOptions = this.updateRequestOptions(options?.headers);
1421
+ return this.httpManagerService.getRequest(requestOptions, options?.path)
1422
+ .pipe(tap((data) => {
1423
+ data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
1424
+ this.setData$(data);
1425
+ }));
1426
+ })));
1427
+ // CREATE RECORD
1428
+ this.createRecord = (data, options) => this.effect(() => of(data).pipe(switchMap((data) => {
1429
+ this.streamedResponse = [];
1430
+ const requestOptions = this.updateRequestOptions(options?.headers);
1431
+ return this.httpManagerService.postRequest(data, requestOptions, options?.path)
1432
+ .pipe(tap((data) => {
1433
+ data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
1434
+ this.addData$(data);
1435
+ }));
1436
+ })));
1437
+ // UPDATE RECORD
1438
+ this.updateRecord = (data, options) => this.effect(() => of(data).pipe(concatMap((data) => {
1439
+ this.streamedResponse = [];
1440
+ const requestOptions = this.updateRequestOptions(options?.headers);
1441
+ return this.httpManagerService.putRequest(data, requestOptions, options?.path)
1442
+ .pipe(tap((data) => {
1443
+ data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
1444
+ this.updateData$(data);
1445
+ }));
1446
+ })));
1447
+ // DELETE RECORD
1448
+ this.deleteRecord = (options) => this.effect(() => of(options).pipe(concatMap((data) => {
1449
+ this.streamedResponse = [];
1450
+ const requestOptions = this.updateRequestOptions(options?.headers);
1451
+ return this.httpManagerService.deleteRequest(requestOptions, options?.path)
1452
+ .pipe(tap((data) => {
1453
+ data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
1454
+ this.deleteData$(data);
1455
+ }));
1456
+ })));
1457
+ // --------------------------------------------------------------------------------------------------
1458
+ // FETCH STREAM
1459
+ this.createStream = (data, options) => this.effect(() => of(data).pipe(tap(() => this.httpManagerService.isPending.next(true)), switchMap((data) => {
1460
+ const requestOptions = this.updateRequestOptions(options?.headers);
1461
+ return this.httpManagerService.postRequest(data, requestOptions, options?.path)
1462
+ .pipe(tap((res) => {
1463
+ if (res.length > 0)
1464
+ this.setData$(res);
1465
+ this.streamedResponse = res;
1466
+ }), scan((acc, res) => {
1467
+ const previous = acc.current;
1468
+ const current = res;
1469
+ return { previous, current };
1470
+ }, { previous: null, current: null }), tap(({ previous, current }) => {
1471
+ if (previous && JSON.stringify(previous) === JSON.stringify(current)) {
1472
+ this.httpManagerService.isPending.next(false);
1473
+ this.setData$([]);
1474
+ }
1475
+ else {
1476
+ this.httpManagerService.isPending.next(true);
1477
+ }
1478
+ }));
1479
+ })));
1480
+ this.fetchStream = (options) => this.effect(() => of(options).pipe(tap(() => this.httpManagerService.isPending.next(true)), switchMap((options) => {
1481
+ const requestOptions = this.updateRequestOptions(options?.headers);
1482
+ return this.httpManagerService.getRequest(requestOptions, options?.path)
1483
+ .pipe(tap((res) => {
1484
+ if (res.length > 0)
1485
+ this.setData$(res);
1486
+ this.streamedResponse = res;
1487
+ }), scan((acc, res) => {
1488
+ const previous = acc.current;
1489
+ const current = res;
1490
+ return { previous, current };
1491
+ }, { previous: null, current: null }), tap(({ previous, current }) => {
1492
+ if (previous && JSON.stringify(previous) === JSON.stringify(current)) {
1493
+ this.httpManagerService.isPending.next(false);
1494
+ this.setData$([]);
1495
+ }
1496
+ else {
1497
+ this.httpManagerService.isPending.next(true);
1498
+ }
1499
+ }));
1500
+ })));
1501
+ // FETCH PAGINATION
1502
+ this.fetchPaginationCancel$ = new Subject();
1503
+ this.fetchPaginationRecords = (size = 10, options) => this.effect(() => {
1504
+ this.fetchPaginationCancel$.next();
1505
+ return of(RequestOptions.adapt(options)).pipe(switchMap(() => {
1506
+ this.resetData$();
1507
+ const requestOptions = this.updateRequestOptions(options?.headers);
1508
+ const updatedPath = [...(options?.path ?? []), { size, page: 1 }];
1509
+ const firstRequestObservable = this.httpManagerService.getRequest(requestOptions, updatedPath).pipe(takeUntil(this.fetchPaginationCancel$), tap(() => this.httpManagerService.isPending.next(true)), tap((data) => {
1510
+ data = !data ? (this.dataType === DataType.ARRAY ? [] : {}) : data;
1511
+ this.setData$(data.results);
1512
+ }));
1513
+ return firstRequestObservable.pipe(takeUntil(this.fetchPaginationCancel$), expand((data) => {
1514
+ this.httpManagerService.isPending.next(true);
1515
+ const totalPages = data?.totalPages || 1;
1516
+ const currentPage = data?.page || 1;
1517
+ if (currentPage < totalPages) {
1518
+ const nextPage = currentPage + 1;
1519
+ const updatedPathWithNextPage = [...(options?.path ?? []), { size, page: nextPage }];
1520
+ const nextRequestObservable = this.httpManagerService.getRequest(requestOptions, updatedPathWithNextPage).pipe(takeUntil(this.fetchPaginationCancel$), tap(() => this.httpManagerService.isPending.next(true)), tap((nextData) => {
1521
+ nextData = !nextData ? (this.dataType === DataType.ARRAY ? [] : {}) : nextData;
1522
+ this.setData$(nextData.results);
1523
+ }));
1524
+ return nextRequestObservable;
1525
+ }
1526
+ return EMPTY;
1527
+ }), takeUntil(this.fetchPaginationCancel$), tap(() => this.httpManagerService.isPending.next(false)));
1528
+ }));
1529
+ });
1530
+ this.setApiRequestOptions(apiOptions, dataType, database);
1531
+ }
1532
+ setApiRequestOptions(apiOptions, dataType, database) {
1533
+ this.apiOptions = ApiRequest.adapt(apiOptions);
1534
+ this.dataType = (dataType) ? dataType : DataType.ARRAY;
1535
+ this.hasDatabase = this.database?.table === "" ? false : true;
1536
+ this.database = (this.hasDatabase) ? DatabaseStorage.adapt(database) : undefined;
1537
+ }
1538
+ get apiRequestOptions() {
1539
+ return this.apiOptions;
1540
+ }
1541
+ initStorage() {
1542
+ // if(this.otherOptions.database) {
1543
+ // console.log('Has Database Option:', this.otherOptions.database.table)
1544
+ // const schema = (this.otherOptions.adapters?.incoming) ? Object.keys(this.otherOptions.adapters.incoming({})).join() : '++id'
1545
+ // this.apiService.initDB(this.otherOptions.database.expiresIn, this.otherOptions.database.table, schema)
1546
+ // }
1547
+ }
1548
+ initializeState(data) {
1549
+ this.setData$(data);
1550
+ }
1551
+ updateArrayState(currentData, newData) {
1552
+ const filterCurrentData = () => {
1553
+ const ids = this.streamedResponse.map((obj) => obj.id);
1554
+ return currentData.filter(obj => (obj.id) ? ids.includes(obj.id) : obj);
1555
+ };
1556
+ const filteredCurrentData = (this.httpManagerService.isPending.value) ? currentData : filterCurrentData();
1557
+ const updatedData = filteredCurrentData.map(item => {
1558
+ const newItem = newData.find(newItem => {
1559
+ const hasId = (newItem?.id && item?.id) ? true : false;
1560
+ return (hasId) ? newItem.id === item.id : JSON.stringify(newItem) === JSON.stringify(item);
1561
+ });
1562
+ return (newItem) ? { ...item, ...newItem } : item;
1563
+ });
1564
+ const addedData = newData.filter(newItem => {
1565
+ return !filteredCurrentData.some(item => {
1566
+ const hasId = (newItem?.id && item?.id) ? true : false;
1567
+ return (hasId) ? item.id === newItem.id : JSON.stringify(newItem) === JSON.stringify(item);
1568
+ });
1569
+ });
1570
+ return [...updatedData, ...addedData];
1571
+ }
1572
+ // --------------------------------------------------------------------------------------------------
1573
+ // MISC
1574
+ isEmpty(obj) {
1575
+ return Object.keys(obj).length === 0;
1576
+ }
1577
+ updateRequestOptions(headers) {
1578
+ const options = ApiRequest.adapt({ ...this.apiOptions });
1579
+ options.headers = (headers)
1580
+ ? { ...options.headers, ...headers }
1581
+ : { ...options.headers };
1582
+ return options;
1583
+ }
1584
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerStateService, deps: [{ token: API_OPTS }, { token: "dataType" }, { token: "database" }], target: i0.ɵɵFactoryTarget.Injectable }); }
1585
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerStateService }); }
1586
+ }
1587
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerStateService, decorators: [{
1588
+ type: Injectable
1589
+ }], ctorParameters: function () { return [{ type: ApiRequest, decorators: [{
1590
+ type: Inject,
1591
+ args: [API_OPTS]
1592
+ }] }, { type: undefined, decorators: [{
1593
+ type: Inject,
1594
+ args: ["dataType"]
1595
+ }] }, { type: undefined, decorators: [{
1596
+ type: Inject,
1597
+ args: ["database"]
1598
+ }] }]; } });
1599
+
1600
+ // export * from "./database-manager-services/index";
1601
+
1602
+ class ErrorDisplaySettings {
1603
+ constructor(displayTime = 3 * 1000, position = 'top') {
1604
+ this.displayTime = displayTime;
1605
+ this.position = position;
1606
+ }
1607
+ static adapt(item) {
1608
+ return new ErrorDisplaySettings((item?.displayTime) ? item.displayTime * 1000 : 3 * 1000, item?.position);
1609
+ }
1610
+ }
1611
+
1612
+ class WithCredentialsInterceptor {
1613
+ intercept(req, next) {
1614
+ req = req.clone({ withCredentials: true });
1615
+ return next.handle(req);
1616
+ }
1617
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WithCredentialsInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1618
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WithCredentialsInterceptor }); }
1619
+ }
1620
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WithCredentialsInterceptor, decorators: [{
1621
+ type: Injectable
1622
+ }] });
1623
+
1624
+ class RequestHeadersInterceptor {
1625
+ get currentDate() {
1626
+ const date = new Date();
1627
+ const year = date.getFullYear();
1628
+ const month = String(date.getMonth() + 1).padStart(2, '0');
1629
+ const day = String(date.getDate()).padStart(2, '0');
1630
+ return `${year}-${month}-${day}`;
1631
+ }
1632
+ constructor(translate) {
1633
+ this.translate = translate;
1634
+ this.subscriptions = new Subscription();
1635
+ this.language = 'en-CA';
1636
+ this.subscriptions.add(this.translate.onLangChange
1637
+ .subscribe((params) => {
1638
+ this.language = `${params.lang}-CA`;
1639
+ }));
1640
+ }
1641
+ intercept(request, next) {
1642
+ request = request.clone({
1643
+ setHeaders: {
1644
+ 'Content-Type': 'application/json',
1645
+ 'Accept-Language': this.language || 'en-CA',
1646
+ 'Current-Date': this.currentDate
1647
+ }
1648
+ });
1649
+ return next.handle(request);
1650
+ }
1651
+ ngOnDestroy() {
1652
+ this.subscriptions.unsubscribe();
1653
+ }
1654
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestHeadersInterceptor, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1655
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestHeadersInterceptor }); }
1656
+ }
1657
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestHeadersInterceptor, decorators: [{
1658
+ type: Injectable
1659
+ }], ctorParameters: function () { return [{ type: i1.TranslateService }]; } });
1660
+
1661
+ class RequestErrorInterceptor {
1662
+ constructor() {
1663
+ this.toastMessage = inject(ToastMessageService$1);
1664
+ }
1665
+ intercept(req, next) {
1666
+ return next.handle(req).pipe(catchError$1((error) => {
1667
+ const displayError = ToastDisplay.adapt({
1668
+ message: 'This is a toast message. This is an Error!!',
1669
+ action: 'OK',
1670
+ color: ToastColors.SUCCESS,
1671
+ icon: 'info',
1672
+ duration: 5 * 1000, //5 seconds
1673
+ });
1674
+ if (error.status >= 400 && error.status < 500) {
1675
+ displayError.color = ToastColors.ERROR;
1676
+ displayError.message = `${error.status}: ${error.statusText}`;
1677
+ console.error('Client Error:', {
1678
+ status: error.status,
1679
+ message: error.message,
1680
+ error: error.error,
1681
+ text: error.statusText,
1682
+ });
1683
+ this.toastMessage.toastMessage(displayError);
1684
+ }
1685
+ else if (error.status >= 500) {
1686
+ displayError.color = ToastColors.ERROR;
1687
+ displayError.message = `${error.status}: ${error.statusText}`;
1688
+ console.error('Server Error:', {
1689
+ status: error.status,
1690
+ message: error.message,
1691
+ error: error.error,
1692
+ text: error.statusText,
1693
+ });
1694
+ this.toastMessage.toastMessage(displayError);
1695
+ }
1696
+ return throwError(() => error);
1697
+ }));
1698
+ }
1699
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestErrorInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1700
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestErrorInterceptor }); }
1701
+ }
1702
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestErrorInterceptor, decorators: [{
1703
+ type: Injectable
1704
+ }] });
1705
+
1706
+ /*
1707
+ * Public API Surface of http-request-manager
1708
+ */
1709
+
1710
+ /**
1711
+ * Generated bundle index. Do not edit.
1712
+ */
1713
+
1714
+ export { ApiRequest, AppService, AsymmetricalEncryptionService, DataType, DatabaseStorage, ErrorDisplaySettings, GlobalStoreOptions, HTTPManagerService, HTTPManagerStateService, HeadersService, LocalStorageManagerService, PathQueryService, Random, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomSignature, RandomStr, RequestErrorInterceptor, RequestHeadersInterceptor, RequestOptions, RetryOptions, SettingOptions, StorageData, StorageOption, StorageOptionSettings, StorageType, SymmetricalEncryptionService, UUID, UtilsService, WithCredentialsInterceptor, countdown, delayedRetry, requestPolling, requestStreaming };
1715
+ //# sourceMappingURL=http-request-manager.mjs.map