http-request-manager 0.0.2 → 4.1.2

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 (143) hide show
  1. package/README.md +53 -13
  2. package/esm2022/http-request-manager.mjs +5 -0
  3. package/esm2022/lib/http-request-manager.module.mjs +145 -0
  4. package/esm2022/lib/http-request-services-demo/http-request-services-demo.component.mjs +41 -0
  5. package/esm2022/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.mjs +175 -0
  6. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.mjs +80 -0
  7. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.mjs +42 -0
  8. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.mjs +85 -0
  9. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.mjs +11 -0
  10. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.mjs +29 -0
  11. package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.mjs +9 -0
  12. package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.mjs +12 -0
  13. package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.mjs +10 -0
  14. package/esm2022/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.mjs +276 -0
  15. package/esm2022/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.mjs +268 -0
  16. package/esm2022/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.mjs +75 -0
  17. package/esm2022/lib/index.mjs +4 -0
  18. package/esm2022/lib/interceptors/credentials.interceptor.mjs +14 -0
  19. package/esm2022/lib/interceptors/index.mjs +5 -0
  20. package/esm2022/lib/interceptors/models/error-settings.model.mjs +10 -0
  21. package/esm2022/lib/interceptors/proxy-debugger.interceptor.mjs +47 -0
  22. package/esm2022/lib/interceptors/request-error.interceptor.mjs +49 -0
  23. package/esm2022/lib/interceptors/request-header.interceptor.mjs +41 -0
  24. package/esm2022/lib/models/config-http-options.model.mjs +18 -0
  25. package/esm2022/lib/models/config-local-storage-options.model.mjs +12 -0
  26. package/esm2022/lib/models/config-options.model.mjs +12 -0
  27. package/esm2022/lib/models/config-token.model.mjs +8 -0
  28. package/esm2022/lib/models/data-type.enum.mjs +7 -0
  29. package/esm2022/lib/models/database-storage.model.mjs +10 -0
  30. package/esm2022/lib/models/index.mjs +7 -0
  31. package/esm2022/lib/models/retry-options.model.mjs +10 -0
  32. package/esm2022/lib/services/index.mjs +6 -0
  33. package/esm2022/lib/services/local-storage-manager-service/index.mjs +3 -0
  34. package/esm2022/lib/services/local-storage-manager-service/local-storage-manager.service.mjs +300 -0
  35. package/esm2022/lib/services/local-storage-manager-service/models/global-store-options.model.mjs +13 -0
  36. package/esm2022/lib/services/local-storage-manager-service/models/index.mjs +6 -0
  37. package/esm2022/lib/services/local-storage-manager-service/models/setting-options.model.mjs +13 -0
  38. package/esm2022/lib/services/local-storage-manager-service/models/storage-data.model.mjs +10 -0
  39. package/esm2022/lib/services/local-storage-manager-service/models/storage-option.model.mjs +12 -0
  40. package/esm2022/lib/services/local-storage-manager-service/models/storage-type.enum.mjs +7 -0
  41. package/esm2022/lib/services/request-manager-services/http-manager.service.mjs +208 -0
  42. package/esm2022/lib/services/request-manager-services/index.mjs +5 -0
  43. package/esm2022/lib/services/request-manager-services/request.service.mjs +201 -0
  44. package/esm2022/lib/services/request-manager-services/rxjs-operators/countdown.mjs +9 -0
  45. package/esm2022/lib/services/request-manager-services/rxjs-operators/delay-retry.mjs +10 -0
  46. package/esm2022/lib/services/request-manager-services/rxjs-operators/index.mjs +5 -0
  47. package/esm2022/lib/services/request-manager-services/rxjs-operators/request-polling.mjs +14 -0
  48. package/esm2022/lib/services/request-manager-services/rxjs-operators/request-streaming.mjs +19 -0
  49. package/esm2022/lib/services/request-manager-state-service/http-manager-state.store.mjs +266 -0
  50. package/esm2022/lib/services/request-manager-state-service/index.mjs +3 -0
  51. package/esm2022/lib/services/request-manager-state-service/models/api-request.model.mjs +20 -0
  52. package/esm2022/lib/services/request-manager-state-service/models/index.mjs +3 -0
  53. package/esm2022/lib/services/request-manager-state-service/models/request-options.model.mjs +10 -0
  54. package/esm2022/lib/services/utils/app.service.mjs +26 -0
  55. package/esm2022/lib/services/utils/encryption/asymmetrical-encryption.service.mjs +186 -0
  56. package/esm2022/lib/services/utils/encryption/encryption-test.service.mjs +35 -0
  57. package/esm2022/lib/services/utils/encryption/index.mjs +4 -0
  58. package/esm2022/lib/services/utils/encryption/random.mjs +52 -0
  59. package/esm2022/lib/services/utils/encryption/symmetrical-encryption.service.mjs +77 -0
  60. package/esm2022/lib/services/utils/headers.service.mjs +21 -0
  61. package/esm2022/lib/services/utils/index.mjs +6 -0
  62. package/esm2022/lib/services/utils/object-merger.service.mjs +34 -0
  63. package/esm2022/lib/services/utils/path-query.service.mjs +54 -0
  64. package/esm2022/lib/services/utils/utils.service.mjs +155 -0
  65. package/esm2022/public-api.mjs +7 -0
  66. package/fesm2022/http-request-manager.mjs +3062 -0
  67. package/fesm2022/http-request-manager.mjs.map +1 -0
  68. package/http-request-manager-4.1.2.tgz +0 -0
  69. package/index.d.ts +5 -0
  70. package/lib/http-request-manager.module.d.ts +33 -0
  71. package/lib/http-request-services-demo/http-request-services-demo.component.d.ts +24 -0
  72. package/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.d.ts +56 -0
  73. package/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.d.ts +26 -0
  74. package/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.d.ts +13 -0
  75. package/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.d.ts +26 -0
  76. package/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.d.ts +12 -0
  77. package/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.d.ts +16 -0
  78. package/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.d.ts +8 -0
  79. package/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.d.ts +14 -0
  80. package/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.d.ts +10 -0
  81. package/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.d.ts +98 -0
  82. package/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.d.ts +110 -0
  83. package/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.d.ts +16 -0
  84. package/lib/index.d.ts +3 -0
  85. package/lib/interceptors/credentials.interceptor.d.ts +8 -0
  86. package/lib/interceptors/index.d.ts +4 -0
  87. package/lib/interceptors/models/error-settings.model.d.ts +10 -0
  88. package/lib/interceptors/proxy-debugger.interceptor.d.ts +12 -0
  89. package/lib/interceptors/request-error.interceptor.d.ts +10 -0
  90. package/lib/interceptors/request-header.interceptor.d.ts +15 -0
  91. package/lib/models/config-http-options.model.d.ts +21 -0
  92. package/lib/models/config-local-storage-options.model.d.ts +13 -0
  93. package/lib/models/config-options.model.d.ts +12 -0
  94. package/lib/models/config-token.model.d.ts +8 -0
  95. package/lib/models/data-type.enum.d.ts +5 -0
  96. package/lib/models/database-storage.model.d.ts +10 -0
  97. package/lib/models/index.d.ts +6 -0
  98. package/lib/models/retry-options.model.d.ts +10 -0
  99. package/lib/services/index.d.ts +4 -0
  100. package/lib/services/local-storage-manager-service/index.d.ts +2 -0
  101. package/lib/services/local-storage-manager-service/local-storage-manager.service.d.ts +86 -0
  102. package/lib/services/local-storage-manager-service/models/global-store-options.model.d.ts +15 -0
  103. package/lib/services/local-storage-manager-service/models/index.d.ts +5 -0
  104. package/lib/services/local-storage-manager-service/models/setting-options.model.d.ts +15 -0
  105. package/lib/services/local-storage-manager-service/models/storage-data.model.d.ts +10 -0
  106. package/lib/services/local-storage-manager-service/models/storage-option.model.d.ts +13 -0
  107. package/lib/services/local-storage-manager-service/models/storage-type.enum.d.ts +5 -0
  108. package/lib/services/request-manager-services/http-manager.service.d.ts +40 -0
  109. package/lib/services/request-manager-services/index.d.ts +3 -0
  110. package/lib/services/request-manager-services/request.service.d.ts +28 -0
  111. package/lib/services/request-manager-services/rxjs-operators/countdown.d.ts +2 -0
  112. package/lib/services/request-manager-services/rxjs-operators/delay-retry.d.ts +2 -0
  113. package/lib/services/request-manager-services/rxjs-operators/index.d.ts +4 -0
  114. package/lib/services/request-manager-services/rxjs-operators/request-polling.d.ts +7 -0
  115. package/lib/services/request-manager-services/rxjs-operators/request-streaming.d.ts +2 -0
  116. package/lib/services/request-manager-state-service/http-manager-state.store.d.ts +51 -0
  117. package/lib/services/request-manager-state-service/index.d.ts +2 -0
  118. package/lib/services/request-manager-state-service/models/api-request.model.d.ts +25 -0
  119. package/lib/services/request-manager-state-service/models/index.d.ts +2 -0
  120. package/lib/services/request-manager-state-service/models/request-options.model.d.ts +10 -0
  121. package/lib/services/utils/app.service.d.ts +8 -0
  122. package/lib/services/utils/encryption/asymmetrical-encryption.service.d.ts +17 -0
  123. package/lib/services/utils/encryption/encryption-test.service.d.ts +10 -0
  124. package/lib/services/utils/encryption/index.d.ts +3 -0
  125. package/lib/services/utils/encryption/random.d.ts +7 -0
  126. package/lib/services/utils/encryption/symmetrical-encryption.service.d.ts +14 -0
  127. package/lib/services/utils/headers.service.d.ts +10 -0
  128. package/lib/services/utils/index.d.ts +5 -0
  129. package/lib/services/utils/object-merger.service.d.ts +7 -0
  130. package/lib/services/utils/path-query.service.d.ts +11 -0
  131. package/lib/services/utils/utils.service.d.ts +24 -0
  132. package/package.json +41 -18
  133. package/public-api.d.ts +3 -0
  134. package/ng-package.json +0 -7
  135. package/src/lib/http-request-manager.component.spec.ts +0 -21
  136. package/src/lib/http-request-manager.component.ts +0 -15
  137. package/src/lib/http-request-manager.module.ts +0 -16
  138. package/src/lib/http-request-manager.service.spec.ts +0 -16
  139. package/src/lib/http-request-manager.service.ts +0 -9
  140. package/src/public-api.ts +0 -7
  141. package/tsconfig.lib.json +0 -14
  142. package/tsconfig.lib.prod.json +0 -10
  143. package/tsconfig.spec.json +0 -14
@@ -0,0 +1,3062 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, Injectable, APP_ID, Inject, InjectionToken, Injector, Optional, EventEmitter, Component, ViewEncapsulation, Input, Output, NgModule, ViewChild } from '@angular/core';
3
+ import { ComponentStore } from '@ngrx/component-store';
4
+ import { map, catchError, filter, finalize, takeWhile, retry, startWith, tap, mergeMap, takeUntil, withLatestFrom, switchMap, concatMap, scan, distinctUntilChanged } from 'rxjs/operators';
5
+ import { HttpClient, HttpHeaders, HttpEventType, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
6
+ import * as CryptoJS from 'crypto-js';
7
+ import { from, BehaviorSubject, EMPTY, throwError, defer, interval, timer, Subject, of, Subscription, catchError as catchError$1 } from 'rxjs';
8
+ import { ToastMessageService, ToastDisplay, ToastColors, ToastMessageModule } from 'toast-message-display';
9
+ import * as i1 from '@ngx-translate/core';
10
+ import { TranslateModule } from '@ngx-translate/core';
11
+ import * as i1$1 from '@angular/common';
12
+ import { CommonModule } from '@angular/common';
13
+ import * as i2 from '@angular/forms';
14
+ import { FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
15
+ import { MatAutocompleteModule } from '@angular/material/autocomplete';
16
+ import * as i3$1 from '@angular/material/button';
17
+ import { MatButtonModule } from '@angular/material/button';
18
+ import { MatChipsModule } from '@angular/material/chips';
19
+ import * as i11 from '@angular/material/divider';
20
+ import { MatDividerModule } from '@angular/material/divider';
21
+ import * as i4 from '@angular/material/form-field';
22
+ import { MatFormFieldModule } from '@angular/material/form-field';
23
+ import * as i7 from '@angular/material/icon';
24
+ import { MatIconModule } from '@angular/material/icon';
25
+ import * as i12 from '@angular/material/input';
26
+ import { MatInputModule } from '@angular/material/input';
27
+ import * as i9 from '@angular/material/progress-bar';
28
+ import { MatProgressBarModule } from '@angular/material/progress-bar';
29
+ import * as i5 from '@angular/material/select';
30
+ import { MatSelectModule } from '@angular/material/select';
31
+ import { MatSidenavModule } from '@angular/material/sidenav';
32
+ import * as i10$1 from '@angular/material/slide-toggle';
33
+ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
34
+ import * as i3$2 from '@angular/material/menu';
35
+ import { MatMenuModule } from '@angular/material/menu';
36
+ import * as i4$1 from '@angular/material/toolbar';
37
+ import { MatToolbarModule } from '@angular/material/toolbar';
38
+ import * as i8 from '@angular/material/table';
39
+ import { MatTableModule } from '@angular/material/table';
40
+ import * as i10 from '@angular/material/button-toggle';
41
+ import { MatButtonToggleModule } from '@angular/material/button-toggle';
42
+ import * as i3 from '@angular/material/progress-spinner';
43
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
44
+ import * as i6 from '@angular/material/core';
45
+
46
+ var StorageType;
47
+ (function (StorageType) {
48
+ StorageType[StorageType["GLOBAL"] = 0] = "GLOBAL";
49
+ StorageType[StorageType["SESSION"] = 1] = "SESSION";
50
+ StorageType[StorageType["DB"] = 2] = "DB";
51
+ })(StorageType || (StorageType = {}));
52
+
53
+ class SettingOptions {
54
+ constructor(storage, expires, expiresIn, encrypted) {
55
+ this.storage = storage;
56
+ this.expires = expires;
57
+ this.expiresIn = expiresIn;
58
+ this.encrypted = encrypted;
59
+ }
60
+ static adapt(item) {
61
+ return new SettingOptions((item?.storage) ? item.storage : StorageType.GLOBAL, (item?.expires) ? item.expires : 0, (item?.expiresIn) ? item.expiresIn : '', (item?.encrypted) ? item?.encrypted : false);
62
+ }
63
+ }
64
+
65
+ class StorageOption {
66
+ constructor(id, name = 'untitled', options) {
67
+ this.id = id;
68
+ this.name = name;
69
+ this.options = options;
70
+ }
71
+ static adapt(item) {
72
+ return new StorageOption((item?.id) ? item.id : crypto.randomUUID(), item?.name, (item?.options) ? SettingOptions.adapt(item.options) : SettingOptions.adapt());
73
+ }
74
+ }
75
+
76
+ class GlobalStoreOptions {
77
+ constructor(encryption = false, expiresIn, expires, stores = []) {
78
+ this.encryption = encryption;
79
+ this.expiresIn = expiresIn;
80
+ this.expires = expires;
81
+ this.stores = stores;
82
+ }
83
+ static adapt(item) {
84
+ 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)) : []);
85
+ }
86
+ }
87
+
88
+ class StorageData {
89
+ constructor(id, data) {
90
+ this.id = id;
91
+ this.data = data;
92
+ }
93
+ static adapt(item) {
94
+ return new StorageData((item?.id) ? item.id : crypto.randomUUID(), (item?.data) ? item.data : null);
95
+ }
96
+ }
97
+
98
+ class UtilsService {
99
+ constructor() {
100
+ this.http = inject(HttpClient);
101
+ this.lc = (str) => str.toLowerCase().replace(/[^\w\s]/g, '').replace(/\s+/g, '_');
102
+ }
103
+ isString(x) {
104
+ return Object.prototype.toString.call(x) === '[object String]';
105
+ }
106
+ isObject(obj) {
107
+ return Object.prototype.toString.call(obj) === '[object Object]';
108
+ }
109
+ JSONToString(value) {
110
+ return (this.isObject(value)) ? JSON.stringify(value) : value;
111
+ }
112
+ stringToJSON(value) {
113
+ return (this.isJSON(value)) ? JSON.parse(value) : value;
114
+ }
115
+ isJSON(str) {
116
+ try {
117
+ JSON.parse(str);
118
+ }
119
+ catch (e) {
120
+ return false;
121
+ }
122
+ return true;
123
+ }
124
+ getValueByProp(obj, prop) {
125
+ if (typeof obj === 'undefined')
126
+ return false;
127
+ return obj[prop];
128
+ }
129
+ objectsEqual(x, y) {
130
+ const ok = Object.keys, tx = typeof x, ty = typeof y;
131
+ return x && y && tx === 'object' && tx === ty ? (ok(x).length === ok(y).length &&
132
+ ok(x).every((key) => this.objectsEqual(x[key], y[key]))) : (x === y);
133
+ }
134
+ getJSON(file) {
135
+ return this.http.get(`assets/data/${file}`);
136
+ }
137
+ get today() {
138
+ return new Date().getMilliseconds() / 1000;
139
+ }
140
+ base32ToHex(base32) {
141
+ const base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
142
+ const charToValue = (char) => base32chars.indexOf(char.toUpperCase());
143
+ let bits = '';
144
+ let hex = '';
145
+ for (let i = 0; i < base32.length; i++) {
146
+ const val = charToValue(base32.charAt(i));
147
+ bits += val.toString(2).padStart(5, '0');
148
+ }
149
+ for (let i = 0; i + 4 <= bits.length; i += 4) {
150
+ const chunk = bits.substr(i, 4);
151
+ hex += parseInt(chunk, 2).toString(16);
152
+ }
153
+ return hex.toUpperCase();
154
+ }
155
+ binaryToHex(binary) {
156
+ let hex = '';
157
+ for (let i = 0; i < binary.length; i += 8) {
158
+ const byte = binary.substr(i, 8);
159
+ const decimal = parseInt(byte, 2);
160
+ hex += decimal.toString(16).padStart(2, '0');
161
+ }
162
+ return hex.padStart(32, '0').substr(0, 32);
163
+ }
164
+ // y = years, m = months, w = weeks, d = days, hr = hours, mn = minutes else seconds
165
+ // returns epoch time corresponding to the expiry type
166
+ expires(str) {
167
+ if (!str)
168
+ return;
169
+ const match = str.match(/[^0-9]+$/);
170
+ const type = (match) ? str.slice(-match[0].length) : 0;
171
+ const now = Math.floor(new Date().getTime() / 1000);
172
+ let value = 0;
173
+ switch (type) {
174
+ case 'y':
175
+ const years = parseInt(str.slice(0, -1));
176
+ value = now + (years * 31556926);
177
+ break;
178
+ case 'm':
179
+ const months = parseInt(str.slice(0, -1));
180
+ value = now + (months * 2629743);
181
+ break;
182
+ case 'w':
183
+ const weeks = parseInt(str.slice(0, -1));
184
+ value = now + (weeks * 604800);
185
+ break;
186
+ case 'd':
187
+ const days = parseInt(str.slice(0, -1));
188
+ value = now + (days * 86400);
189
+ break;
190
+ case 'hr':
191
+ const hrs = parseInt(str.slice(0, -2));
192
+ value = now + (hrs * 3600);
193
+ break;
194
+ case 'mn':
195
+ const min = parseInt(str.slice(0, -2));
196
+ value = now + (min * 60);
197
+ break;
198
+ default: //seconds
199
+ const sec = parseInt(str.slice(0, -1));
200
+ value = now + (sec);
201
+ break;
202
+ }
203
+ return value;
204
+ }
205
+ hasExpired(expiryDate) {
206
+ if (!expiryDate || expiryDate === 0)
207
+ return false;
208
+ const currentTime = Math.floor(new Date().getTime() / 1000);
209
+ return expiryDate < currentTime;
210
+ }
211
+ hasExpiry(setting) {
212
+ return (setting?.expires) ? true : false;
213
+ }
214
+ expiresIn(expiryDate) {
215
+ if (!expiryDate)
216
+ return;
217
+ const now = Math.floor(new Date().getTime() / 1000);
218
+ let diff = expiryDate - now;
219
+ if (diff <= 0)
220
+ return "Expired";
221
+ const units = [
222
+ { label: 'y', seconds: 31536000 },
223
+ { label: 'm', seconds: 2592000 },
224
+ { label: 'w', seconds: 604800 },
225
+ { label: 'd', seconds: 86400 },
226
+ { label: 'h', seconds: 3600 },
227
+ { label: 'min', seconds: 60 },
228
+ { label: '', seconds: 1 },
229
+ ];
230
+ let result = [];
231
+ for (const unit of units) {
232
+ if (diff >= unit.seconds) {
233
+ const value = Math.floor(diff / unit.seconds);
234
+ diff %= unit.seconds;
235
+ result.push(`${value}${unit.label}${value > 1 ? 's' : ''}`);
236
+ }
237
+ }
238
+ return result.join(', ');
239
+ }
240
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
241
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, providedIn: 'root' }); }
242
+ }
243
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, decorators: [{
244
+ type: Injectable,
245
+ args: [{
246
+ providedIn: 'root'
247
+ }]
248
+ }], ctorParameters: function () { return []; } });
249
+
250
+ const Random = () => {
251
+ const typedArray = new Uint8Array(1);
252
+ const randomValue = crypto.getRandomValues(typedArray)[0];
253
+ const randomFloat = randomValue / Math.pow(2, 8);
254
+ return randomFloat;
255
+ };
256
+ const RandomNumber = (min, max) => {
257
+ return Math.floor(Random() * max) + min;
258
+ };
259
+ const RandomNumbers = (min, max, length) => {
260
+ const numbers = [];
261
+ for (let i = 0; i < length; i++)
262
+ numbers.push(Math.floor(Random() * max) + min);
263
+ return numbers;
264
+ };
265
+ const RandomNumbersUnique = (min, max, length) => {
266
+ let count = 0;
267
+ // Adjust the length if it exceeds the number of unique numbers possible in the range
268
+ if (length > (max - min + 1)) {
269
+ console.error('error encountered');
270
+ length = max - min + 1;
271
+ }
272
+ console.log('length', length);
273
+ const numbers = [];
274
+ const maxAttempts = length * 100; // Safeguard to prevent infinite loops
275
+ while (numbers.length < length && count < maxAttempts) {
276
+ const num = Math.floor(Random() * max) + min;
277
+ if (!numbers.includes(num)) {
278
+ numbers.push(num);
279
+ }
280
+ }
281
+ if (count >= maxAttempts) {
282
+ throw new Error('Maximum attempts exceeded while generating unique numbers');
283
+ }
284
+ return numbers;
285
+ };
286
+ const RandomStr = () => {
287
+ const typedArray = new Uint8Array(8);
288
+ const array = new Uint32Array(1);
289
+ crypto.getRandomValues(array);
290
+ return array[0].toString(36);
291
+ };
292
+ const RandomSignature = () => {
293
+ const typedArray = new Uint8Array(8);
294
+ const array = new Uint32Array(1);
295
+ crypto.getRandomValues(array);
296
+ return array[0];
297
+ };
298
+ const UUID = () => {
299
+ return self.crypto.randomUUID();
300
+ };
301
+
302
+ // Must provide a value for APP_ID in AppModule->Providers
303
+ // providers: [
304
+ // {
305
+ // provide: APP_ID,
306
+ // useValue: "056991ac-3537-43ab-b5b9-83edf6554eff",
307
+ // },
308
+ class AppService {
309
+ constructor(id) {
310
+ this.id = id;
311
+ this.appID = this.id;
312
+ }
313
+ 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 }); }
314
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppService, providedIn: 'root' }); }
315
+ }
316
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppService, decorators: [{
317
+ type: Injectable,
318
+ args: [{
319
+ providedIn: 'root'
320
+ }]
321
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
322
+ type: Inject,
323
+ args: [APP_ID]
324
+ }] }]; } });
325
+
326
+ class SymmetricalEncryptionService {
327
+ constructor() {
328
+ this.appService = inject(AppService);
329
+ // TODO: The APP ID is not a string, it is a function
330
+ this.appID = (this.appService.appID) ? this.appService.appID : '';
331
+ if (this.appID === '')
332
+ console.warn('No App Key has been define');
333
+ }
334
+ generateCipherKey() {
335
+ return (RandomSignature().toString() + RandomSignature().toString()).substring(0, 8);
336
+ }
337
+ encrypt(str, key = this.appID) {
338
+ if (!str || key === '')
339
+ return '';
340
+ let _key = CryptoJS.enc.Utf8.parse(key);
341
+ let _iv = CryptoJS.enc.Utf8.parse(key);
342
+ try {
343
+ const encrypted = CryptoJS.AES.encrypt(JSON.stringify(str), _key, {
344
+ keySize: 16,
345
+ iv: _iv,
346
+ mode: CryptoJS.mode.ECB,
347
+ padding: CryptoJS.pad.Pkcs7
348
+ });
349
+ return encrypted.toString();
350
+ }
351
+ catch (error) {
352
+ console.log(error);
353
+ }
354
+ return;
355
+ }
356
+ decrypt(str, key = this.appID) {
357
+ if (!str || key === '')
358
+ return;
359
+ let _key = CryptoJS.enc.Utf8.parse(key);
360
+ let _iv = CryptoJS.enc.Utf8.parse(key);
361
+ try {
362
+ return CryptoJS.AES.decrypt(str, _key, {
363
+ keySize: 16,
364
+ iv: _iv,
365
+ mode: CryptoJS.mode.ECB,
366
+ padding: CryptoJS.pad.Pkcs7
367
+ }).toString(CryptoJS.enc.Utf8);
368
+ }
369
+ catch (error) {
370
+ console.log(error);
371
+ }
372
+ return;
373
+ }
374
+ createSignature(url, len = 16) {
375
+ const sig = CryptoJS.SHA256(url).toString(CryptoJS.enc.Hex);
376
+ return sig.substring(0, len).toUpperCase();
377
+ }
378
+ normalizeURL(url) {
379
+ const normalizedURL = url.replace(/(https?:\/\/)?(www\.)?/, '').replace(/\/+$/, '');
380
+ return normalizedURL;
381
+ }
382
+ generateSignature(url) {
383
+ const normalizedURL = this.normalizeURL(url);
384
+ const hash = CryptoJS.SHA256(normalizedURL);
385
+ const signature = hash.toString(CryptoJS.enc.Hex);
386
+ return signature;
387
+ }
388
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SymmetricalEncryptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
389
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SymmetricalEncryptionService, providedIn: 'root' }); }
390
+ }
391
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SymmetricalEncryptionService, decorators: [{
392
+ type: Injectable,
393
+ args: [{
394
+ providedIn: 'root'
395
+ }]
396
+ }], ctorParameters: function () { return []; } });
397
+
398
+ class EncryptionTestService {
399
+ constructor() { }
400
+ isBase64(str) {
401
+ const base64Pattern = /^(?:[A-Z0-9+/]{4})*(?:[A-Z0-9+/]{2}==|[A-Z0-9+/]{3}=)?$/i;
402
+ return base64Pattern.test(str);
403
+ }
404
+ isHexadecimal(str) {
405
+ const hexPattern = /^[0-9a-fA-F]+$/;
406
+ return hexPattern.test(str) && (str.length % 2 === 0);
407
+ }
408
+ hasHighEntropy(str) {
409
+ const uniqueChars = new Set(str).size;
410
+ return uniqueChars > str.length * 0.6;
411
+ }
412
+ isEncrypted(str) {
413
+ if (typeof str !== 'string') {
414
+ return false;
415
+ }
416
+ if (this.isBase64(str) || this.isHexadecimal(str)) {
417
+ return true;
418
+ }
419
+ return this.hasHighEntropy(str);
420
+ }
421
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EncryptionTestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
422
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EncryptionTestService, providedIn: 'root' }); }
423
+ }
424
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EncryptionTestService, decorators: [{
425
+ type: Injectable,
426
+ args: [{
427
+ providedIn: 'root'
428
+ }]
429
+ }], ctorParameters: function () { return []; } });
430
+
431
+ /**
432
+ * An injection token that provides the configuration settings for the application.
433
+ * This token can be used to inject the `ConfigSettings` instance into components or services
434
+ * that require access to the application configuration.
435
+ */
436
+ const CONFIG_SETTINGS_TOKEN = new InjectionToken('http.config');
437
+
438
+ class ObjectMergerService {
439
+ mergeOptions(options, configForRoot) {
440
+ const merged = configForRoot ? { ...configForRoot } : {};
441
+ for (const key in options) {
442
+ if (Object.prototype.hasOwnProperty.call(options, key)) {
443
+ const value = options[key];
444
+ if (value !== null &&
445
+ value !== undefined &&
446
+ !(typeof value === 'number') &&
447
+ !(typeof value === 'boolean') &&
448
+ !(this.isNonEmptyString(value)) &&
449
+ !(Array.isArray(value) && value.length === 0) &&
450
+ !(typeof value === 'object' && !Array.isArray(value))) {
451
+ merged[key] = value;
452
+ }
453
+ }
454
+ }
455
+ return merged;
456
+ }
457
+ isNonEmptyString(value) {
458
+ return typeof value === 'string' && value.length === 0;
459
+ }
460
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ObjectMergerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
461
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ObjectMergerService, providedIn: 'root' }); }
462
+ }
463
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ObjectMergerService, decorators: [{
464
+ type: Injectable,
465
+ args: [{
466
+ providedIn: 'root'
467
+ }]
468
+ }] });
469
+
470
+ class ApiRequest {
471
+ constructor(server = '', path = [], headers = {}, adapter, mapper, polling, retry = RetryOptions.adapt(), stream = false, displayError = false) {
472
+ this.server = server;
473
+ this.path = path;
474
+ this.headers = headers;
475
+ this.adapter = adapter;
476
+ this.mapper = mapper;
477
+ this.polling = polling;
478
+ this.retry = retry;
479
+ this.stream = stream;
480
+ this.displayError = displayError;
481
+ }
482
+ static adapt(item) {
483
+ const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
484
+ const retryOptions = item?.retry ? RetryOptions.adapt(item.retry) : RetryOptions.adapt();
485
+ 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);
486
+ }
487
+ }
488
+
489
+ class HeadersService {
490
+ constructor() {
491
+ this.headers = {};
492
+ }
493
+ generateHeaders(headers) {
494
+ const allHeaders = headers ? { ...this.headers, ...headers } : {};
495
+ return { headers: new HttpHeaders(allHeaders) };
496
+ }
497
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeadersService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
498
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeadersService, providedIn: 'root' }); }
499
+ }
500
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeadersService, decorators: [{
501
+ type: Injectable,
502
+ args: [{
503
+ providedIn: 'root'
504
+ }]
505
+ }] });
506
+
507
+ class PathQueryService {
508
+ constructor() {
509
+ this.removeEmptyParams = (obj) => Object.fromEntries(Object.entries(obj)
510
+ .map(([key, value]) => [key, value && typeof value === 'object' ? this.removeEmptyParams(value) : value])
511
+ .filter(([_, value]) => value !== undefined && value !== ""));
512
+ }
513
+ buildAPIPath(server, params) {
514
+ server = (Array.isArray(server)) ? server.join('/') : server;
515
+ const pathObjects = (params) ? params.filter((path) => (!this.isObject(path))) : [];
516
+ const queryObjects = (params) ? params.filter((path) => (this.isObject(path))) : [];
517
+ const query = this.removeEmptyParams(queryObjects.reduce((r, c) => {
518
+ Object.entries(c).forEach(([key, value]) => {
519
+ r[key] = Array.isArray(value) ? value.join(',') : value;
520
+ });
521
+ return r;
522
+ }, {}));
523
+ let path = this.buildRestPath(server, pathObjects);
524
+ return (Object.keys(query).length > 0) ? path + '?' + this.buildQueryPath(query) : path;
525
+ }
526
+ buildRestPath(server, params) {
527
+ server = (server) ? server : '';
528
+ server = (server.charAt(0) === '/') ? server.substring(1) : server;
529
+ return this.cleanUrlPath(server + '/' + params.join('/'));
530
+ }
531
+ buildQueryPath(params) {
532
+ const searchParams = new URLSearchParams();
533
+ for (const key in params) {
534
+ if (Array.isArray(params[key])) {
535
+ params[key].forEach((value) => searchParams.append(key, value));
536
+ }
537
+ else {
538
+ searchParams.append(key, params[key]);
539
+ }
540
+ }
541
+ return searchParams.toString();
542
+ }
543
+ cleanUrlPath(str) {
544
+ return str.replace(/([^:]\/)\/+/g, "$1").replace(/\/$/, '');
545
+ }
546
+ isObject(val) {
547
+ return (val === null) ? false : ((typeof val === 'function') || (typeof val === 'object'));
548
+ }
549
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PathQueryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
550
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PathQueryService, providedIn: 'root' }); }
551
+ }
552
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PathQueryService, decorators: [{
553
+ type: Injectable,
554
+ args: [{
555
+ providedIn: 'root'
556
+ }]
557
+ }] });
558
+
559
+ class AsymmetricalEncryptionService {
560
+ constructor() { }
561
+ generateKeyPair(modulusLength = 2048) {
562
+ // modulusLength - 1024, 2048, 4096
563
+ // hash - SHA-256
564
+ return from(crypto.subtle.generateKey({
565
+ name: "RSA-OAEP",
566
+ modulusLength,
567
+ publicExponent: new Uint8Array([1, 0, 1]),
568
+ hash: { name: "SHA-256" }
569
+ }, true, // Extractable keys
570
+ ["encrypt", "decrypt"]));
571
+ }
572
+ encryptData(publicKey, data) {
573
+ const encodedData = new TextEncoder().encode(data);
574
+ return from(crypto.subtle.encrypt({
575
+ name: "RSA-OAEP"
576
+ }, publicKey, encodedData)).pipe(map(enc => this.arrayBufferToBase64(enc)));
577
+ }
578
+ decryptData(privateKey, encryptedData) {
579
+ const encStr = this.base64ToArrayBuffer(encryptedData);
580
+ return from(crypto.subtle.decrypt({
581
+ name: "RSA-OAEP"
582
+ }, privateKey, encStr).then(decryptedData => {
583
+ return new TextDecoder().decode(decryptedData);
584
+ }));
585
+ }
586
+ pemToArrayBuffer(pem) {
587
+ const b64 = pem.replace(/(-----BEGIN (RSA )?(PRIVATE|PUBLIC) KEY-----|-----END (RSA )?(PRIVATE|PUBLIC) KEY-----|\n)/g, '');
588
+ const binaryString = atob(b64);
589
+ const len = binaryString.length;
590
+ const buffer = new ArrayBuffer(len);
591
+ const view = new Uint8Array(buffer);
592
+ for (let i = 0; i < len; i++) {
593
+ view[i] = binaryString.charCodeAt(i);
594
+ }
595
+ return buffer;
596
+ }
597
+ base64ToArrayBuffer(base64) {
598
+ const binaryString = atob(base64);
599
+ const len = binaryString.length;
600
+ const buffer = new ArrayBuffer(len);
601
+ const view = new Uint8Array(buffer);
602
+ for (let i = 0; i < len; i++) {
603
+ view[i] = binaryString.charCodeAt(i);
604
+ }
605
+ return buffer;
606
+ }
607
+ arrayBufferToBase64(buffer) {
608
+ let binary = '';
609
+ const bytes = new Uint8Array(buffer);
610
+ const len = bytes.byteLength;
611
+ for (let i = 0; i < len; i++) {
612
+ binary += String.fromCharCode(bytes[i]);
613
+ }
614
+ return window.btoa(binary);
615
+ }
616
+ base64ToPEM(base64Key, publicKey = true) {
617
+ const keyType = (publicKey) ? 'PUBLIC' : 'PRIVATE';
618
+ const header = `-----BEGIN ${keyType} KEY-----\n`;
619
+ const footer = `\n-----END ${keyType} KEY-----`;
620
+ const keyBody = base64Key.match(/.{1,64}/g)?.join("\n") || "";
621
+ return header + keyBody + footer;
622
+ }
623
+ pemToCryptoKey(pem, algorithm, extractable, keyUsages, format = "pkcs8" //"raw" | "pkcs8" | "spki"
624
+ ) {
625
+ const buffer = this.pemToArrayBuffer(pem);
626
+ console.log('buffer found ', buffer);
627
+ return from(crypto.subtle.importKey(format, buffer, algorithm, extractable, keyUsages));
628
+ }
629
+ // TESTING
630
+ testGenerateKeys() {
631
+ const testSequence = new BehaviorSubject("");
632
+ const testSequence$ = testSequence.asObservable();
633
+ testSequence.next("Test Generating Keys");
634
+ // GENERATE KEYS
635
+ this.generateKeyPair().subscribe((data) => {
636
+ console.log("GEN-GENERATED KEYS: ", data);
637
+ crypto.subtle.exportKey('spki', data.publicKey)
638
+ .then(key => {
639
+ const publicKeyBase64 = this.arrayBufferToBase64(key);
640
+ console.log("GEN-EXPORT PUBLIC KEY: ", this.base64ToPEM(publicKeyBase64, true));
641
+ });
642
+ crypto.subtle.exportKey('pkcs8', data.privateKey)
643
+ .then(key => {
644
+ const privateKeyBase64 = this.arrayBufferToBase64(key);
645
+ console.log("GEN-EXPORT PRIVATE KEY: ", this.base64ToPEM(privateKeyBase64, false));
646
+ });
647
+ // TEST WITH GENERATED KEYS
648
+ this.encryptData(data.publicKey, "Sample Data here - Mike Bonifacio")
649
+ .subscribe((enc) => {
650
+ console.log("GEN-ENCRYPT==>: ", enc);
651
+ this.decryptData(data.privateKey, enc).subscribe((dec) => {
652
+ testSequence.next('Test Passed');
653
+ testSequence.complete();
654
+ });
655
+ });
656
+ });
657
+ return testSequence$;
658
+ }
659
+ testDecryptionWithKeys() {
660
+ const testSequence = new BehaviorSubject("");
661
+ const testSequence$ = testSequence.asObservable();
662
+ testSequence.next("Test Generating Keys");
663
+ const privateKey = `-----BEGIN PRIVATE KEY-----
664
+ MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDKVBkCWNb9eHVF
665
+ twAA5mdAyvXFix3WavdrsoYRkvtCl8ogDBQf8f6N0bRkDF1zcVHRrNAEyozXDtuD
666
+ kFgSiivBFREI7fiS3sOvduq6FaGXzX0IY6oaVMu8oOPgDvC0yvoohR+0Qxq2d6lP
667
+ SPyHeKQaxP4KxzCJJzB1XAcbd2eFzUUDv25mNlwdVkmW8FI/sAxnJLgPTW78dzfX
668
+ Ddfk+nxdIqxVKSLATnL0kMN7aGJx24UozioAIpzvvvF5/+7HTd1gi6NeCqrAYr3g
669
+ iP364AE26CFwFvHnafO9uNQhlQ+uiNnOoInXByfFGVP+RidSpfLzaxDjs6RDwpol
670
+ h098btONAgMBAAECggEAAVhHM2OD5IkUtuowwcKNaCTKGmrClRE3gMuzJeBsSJEy
671
+ uAReUFILZylcnhegDytSti2vDA9T7xqtO6CU0p3V8LpU89JMOPRb/deirI4UXSpx
672
+ xbNyjirOO6bnrNlOWfKexdQQsikYPzF2iM1Scpr1u9ZDCHZOl1ZYSrkve5My4coP
673
+ 3Gx6tTBqL0jQBfcpf4ES8BH3JSawR/MgqzDS74+bI2VH+kvuPAC1L4fBgaV3VUv0
674
+ nFzim5A3s5VaXPgJbEIghP9BkYGFkeT9ma3nliEZWc96AzsmowFn1ayCvrNVPo9R
675
+ ECD2NnttBiCJZt3H93sR9+OTeA8Bls+aZGlKd5mLAQKBgQDpf8nIYUm/Zmls7/lQ
676
+ QBUSGHEYrbjNsEejQsPgNDtg2EVSxdUkvTn7Wb+HExTk09Z5bNvhaO2532/FH9y8
677
+ ahSXafiMXpfR2olwXdOB9yXXl4F5C0LGnmzGim4OSeWzAX0JCL470KaS0QN3EmoG
678
+ 9F0YCfMnZXNTweSSx4xvlO6ggQKBgQDd01uIolm7z1DIWCwNERAXP2GDwcvxyzYK
679
+ YqJfKDeHt2t6yIzZMMotnPDy+OlcdGspIIHkB5a+SZN5Nt7DUKg/MnyOZ3KbVq41
680
+ k7dR4Ka3LRnGkesy7lSr7ef1rfquyR75OXJQcPWvkFcLu0TMiQhvptatZ8VN+F4n
681
+ fDQELRotDQKBgQCgN+AUT7VT0QjcCBnRV/ddUEoiPenFsYSmYMSYzh5ESIHg1wB2
682
+ 0iS79Iw4Of6nOTg8X1bM57vfQ5Kk90T2P+/bKYqzfqC8DTErWiYsUpKzyTC9Bt4N
683
+ /Vz0Kr5zrX8ggg/yp/4oevYhXav8AzWfigNq4EDpMnKc8TlPAf+5/L50gQKBgQC2
684
+ mLPhPhr1gUszD3l7bA89w7uGlLFHoQoj9FtKTzWervp3QLzIT+QtNeIVb5XQuDg5
685
+ y3uAdEq+6pvNjMBEMJG+K9Xh9v+dJPYUPjsJ2A4D/MkZ7qWX8B2cxSJK1uLim8W2
686
+ S3ZxBvsGgJ9WldmlMCvUlJZkeWYtr4P5psC+q02/xQKBgQCDII/jcV2+lRM2iNTe
687
+ vBijZSaNMEWOK/Y+/HFK8GYKXnB+xNWhrm8rKgWGzpDJAUPMh9Tt+leW9LKEBuzF
688
+ Y1bGblmGm1zsPWpIx05Fdtv9eOJmFnXbGzIsYyhadZnPcQOWhqxtpVxSuul0Jc7Q
689
+ XNq4qPaPXhbQAshgtyBt75DMkw==
690
+ -----END PRIVATE KEY-----`;
691
+ const pubKey = `-----BEGIN PUBLIC KEY-----
692
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylQZAljW/Xh1RbcAAOZn
693
+ QMr1xYsd1mr3a7KGEZL7QpfKIAwUH/H+jdG0ZAxdc3FR0azQBMqM1w7bg5BYEoor
694
+ wRURCO34kt7Dr3bquhWhl819CGOqGlTLvKDj4A7wtMr6KIUftEMatnepT0j8h3ik
695
+ GsT+CscwiScwdVwHG3dnhc1FA79uZjZcHVZJlvBSP7AMZyS4D01u/Hc31w3X5Pp8
696
+ XSKsVSkiwE5y9JDDe2hicduFKM4qACKc777xef/ux03dYIujXgqqwGK94Ij9+uAB
697
+ NughcBbx52nzvbjUIZUProjZzqCJ1wcnxRlT/kYnUqXy82sQ47OkQ8KaJYdPfG7T
698
+ jQIDAQAB
699
+ -----END PUBLIC KEY-----`;
700
+ const algorithm = {
701
+ name: "RSA-OAEP",
702
+ modulusLength: 2048,
703
+ publicExponent: new Uint8Array([1, 0, 1]),
704
+ hash: "SHA-256"
705
+ };
706
+ // ENCRYPT
707
+ this.pemToCryptoKey(pubKey, algorithm, true, ["encrypt"], "spki").subscribe((keyPublic) => {
708
+ // console.log("PUBLIC KEY: ", keyPublic)
709
+ this.encryptData(keyPublic, "Sample Data here - Mike Bonifacio")
710
+ .subscribe((str) => {
711
+ console.log("ENCRYPTED STRING: ", str);
712
+ testSequence.next('encrypted string success');
713
+ });
714
+ });
715
+ const enc = "r7UOuEGBZ6jbVTOIBuv9jFOEtRiedmS27hfW40k7XKCTsQ5VhWup0qu2BA2ANZaGKii/uehJ/RSPiyfGbJ6leJrat0mA1hPqH/XodaBzLMDigvdYM1NSXFZMDa40OpLUIXbPlAvybjcGu7Bal+LMA8htHrFu/OmM/fHI66xOzzpuXSYx0OkWjtY81rUQ1FFkvrkx2jGFPZ0p+Nw/v3Q4cJnet6V63vCueFlD749VMcVXo7pvz4AIPpB+IOy3kbxaYTPakLVioJERU6GFMXWkECuRvohhS9CETcORZtRVRkvhcHk3lxgIhfqojUKYgD6K5dDELDPsWIS+iTG1XIQIlg==";
716
+ // DECRYPTION
717
+ this.pemToCryptoKey(privateKey, algorithm, false, ["decrypt"], "pkcs8").subscribe((key) => {
718
+ // console.log("DECRYPT ===", key)
719
+ this.decryptData(key, enc)
720
+ .pipe(catchError(err => {
721
+ console.log("ERROR: ", err);
722
+ return EMPTY;
723
+ })).subscribe((str) => {
724
+ console.log("DECRYPTED STRING: ", str);
725
+ testSequence.next('decrypted string success');
726
+ });
727
+ });
728
+ return testSequence$;
729
+ }
730
+ ;
731
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AsymmetricalEncryptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
732
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AsymmetricalEncryptionService, providedIn: 'root' }); }
733
+ }
734
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AsymmetricalEncryptionService, decorators: [{
735
+ type: Injectable,
736
+ args: [{
737
+ providedIn: 'root'
738
+ }]
739
+ }], ctorParameters: function () { return []; } });
740
+
741
+ function requestStreaming() {
742
+ return input$ => input$.pipe(filter((event) => event.type === HttpEventType.DownloadProgress || event.type === HttpEventType.Response), map((event) => {
743
+ if (event.type === HttpEventType.DownloadProgress) {
744
+ return event.partialText || '';
745
+ }
746
+ else if (event.type === HttpEventType.Response) {
747
+ return event.body;
748
+ }
749
+ }), map((data) => {
750
+ if (typeof data === 'string') {
751
+ const matches = data.match(/{[^}]+}/g) || [];
752
+ return (matches.length > 0) ? matches.map(match => JSON.parse(match)) : data;
753
+ }
754
+ return data;
755
+ }));
756
+ }
757
+
758
+ class RequestService {
759
+ constructor() {
760
+ this.http = inject(HttpClient);
761
+ this.pathQueryService = inject(PathQueryService);
762
+ this.headersService = inject(HeadersService);
763
+ this.isPending = new BehaviorSubject(false);
764
+ this.isPending$ = this.isPending.asObservable();
765
+ this.progress = new BehaviorSubject(0);
766
+ this.progress$ = this.progress.asObservable();
767
+ }
768
+ getRecordRequest(options) {
769
+ const urlPath = this.buildUrlPath(options);
770
+ const headers = this.buildCombinedHeaders(options);
771
+ this.isPending.next(true);
772
+ return (options.stream)
773
+ ? this.http.get(urlPath, headers).pipe(requestStreaming(), this.handleFinalize())
774
+ : this.http.get(urlPath, headers).pipe(this.request(options));
775
+ }
776
+ createRecordRequest(options, data) {
777
+ const urlPath = this.buildUrlPath(options);
778
+ const headers = this.buildCombinedHeaders(options);
779
+ this.isPending.next(true);
780
+ return (options.stream)
781
+ ? this.http.post(urlPath, data, headers).pipe(requestStreaming(), this.handleFinalize())
782
+ : this.http.post(urlPath, data, headers).pipe(this.request(options));
783
+ }
784
+ updateRecordRequest(options, data) {
785
+ const urlPath = this.buildUrlPath(options);
786
+ const headers = this.buildHeaders(options);
787
+ this.isPending.next(true);
788
+ return this.http.put(urlPath, data, headers).pipe(this.request(options));
789
+ }
790
+ deleteRecordRequest(options) {
791
+ const urlPath = this.buildUrlPath(options);
792
+ const headers = this.buildHeaders(options);
793
+ this.isPending.next(true);
794
+ return this.http.delete(urlPath, headers).pipe(this.request(options));
795
+ }
796
+ // Helper functions
797
+ buildUrlPath(options) {
798
+ return this.pathQueryService.buildAPIPath(options.server, options.path);
799
+ }
800
+ buildHeaders(options) {
801
+ return this.headersService.generateHeaders(options.headers);
802
+ }
803
+ buildCombinedHeaders(options) {
804
+ const headers = this.combineHeaders(options.headers, options.stream);
805
+ return this.headersService.generateHeaders(headers);
806
+ }
807
+ request(options) {
808
+ return (source$) => {
809
+ return source$.pipe(map(data => {
810
+ if (options?.adapter) {
811
+ return Array.isArray(data)
812
+ ? data.map((item) => options.adapter(item))
813
+ : options.adapter(data);
814
+ }
815
+ return data;
816
+ }));
817
+ };
818
+ }
819
+ downloadFileRequest(options) {
820
+ this.isPending.next(true);
821
+ const urlPath = this.buildUrlPath(options);
822
+ return this.http.get(urlPath, { responseType: 'blob', observe: 'events', reportProgress: true })
823
+ .pipe(map((event) => {
824
+ this.isPending.next(true);
825
+ const info = event;
826
+ switch (event.type) {
827
+ case HttpEventType.DownloadProgress:
828
+ if (info.status !== 200) {
829
+ this.isPending.next(false);
830
+ throw new Error('Download failed');
831
+ return 0;
832
+ }
833
+ else {
834
+ const status = (event.total) ? Math.round(event.loaded / (event.total || 1) * 100) : 100;
835
+ this.progress.next(status);
836
+ return status;
837
+ }
838
+ case HttpEventType.Response:
839
+ try {
840
+ const header_content = event.headers.get('Content-Disposition') || '';
841
+ const fd = this.fileDetails(options.path);
842
+ if (!fd) {
843
+ this.isPending.next(false);
844
+ throw new Error('Save File: (file name and extension) not found in Headers or Path');
845
+ }
846
+ // checks if header_content is not empty and splits the header_content to get the file name
847
+ // otherwise, it will use the fileDownload - contains the file name and extension
848
+ const file = (header_content) ? header_content.split('=')[1].substring(0, header_content.split('=')[1].length) : `${fd.file}.${fd.ext}`;
849
+ this.downloadFile(file, event.body);
850
+ this.isPending.next(false);
851
+ return 100;
852
+ }
853
+ catch (error) {
854
+ throw new Error('Download failed');
855
+ }
856
+ default:
857
+ this.isPending.next(false);
858
+ return 0;
859
+ }
860
+ }), catchError(err => {
861
+ return throwError(() => err);
862
+ }));
863
+ }
864
+ fileDetails(path) {
865
+ const combinedPath = Array.isArray(path) ? path.join('/') : path;
866
+ if (!combinedPath || combinedPath.trim() === '') {
867
+ return;
868
+ }
869
+ const segments = combinedPath.split('/');
870
+ const fileNameWithExt = segments.pop() || '';
871
+ if (!fileNameWithExt.includes('.'))
872
+ return;
873
+ const dotIndex = fileNameWithExt.lastIndexOf('.');
874
+ if (fileNameWithExt.lastIndexOf('.') < 1)
875
+ return;
876
+ return {
877
+ file: fileNameWithExt.substring(0, dotIndex),
878
+ ext: fileNameWithExt.substring(dotIndex + 1),
879
+ };
880
+ }
881
+ handleFinalize() {
882
+ return finalize(() => this.isPending.next(false));
883
+ }
884
+ downloadFile(file, fileData) {
885
+ const navigatorAny = window.navigator;
886
+ const extension = file.split('.')[1].toLowerCase();
887
+ var newBlob = new Blob([fileData], { type: this.createFileType(extension) });
888
+ if (navigatorAny.msSaveOrOpenBlob) {
889
+ navigatorAny.msSaveOrOpenBlob(newBlob, file);
890
+ }
891
+ else {
892
+ const link = document.createElement('a');
893
+ const url = window.URL.createObjectURL(newBlob);
894
+ link.href = url;
895
+ link.download = file;
896
+ link.click();
897
+ window.URL.revokeObjectURL(url);
898
+ }
899
+ }
900
+ createFileType(ext) {
901
+ let fileType = "";
902
+ if (ext == 'pdf' || ext == 'csv') {
903
+ fileType = `application/${ext}`;
904
+ }
905
+ else if (ext == 'jpeg' || ext == 'jpg' || ext == 'png') {
906
+ fileType = `image/${ext}`;
907
+ }
908
+ else if (ext == 'txt') {
909
+ fileType = 'text/plain';
910
+ }
911
+ else if (ext == 'ppt' || ext == 'pot' || ext == 'pps' || ext == 'ppa') {
912
+ fileType = 'application/vnd.ms-powerpoint';
913
+ }
914
+ else if (ext == 'pptx') {
915
+ fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
916
+ }
917
+ else if (ext == 'doc' || ext == 'dot') {
918
+ fileType = 'application/msword';
919
+ }
920
+ else if (ext == 'docx') {
921
+ fileType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
922
+ }
923
+ else if (ext == 'xls' || ext == 'xlt' || ext == 'xla') {
924
+ fileType = 'application/vnd.ms-excel';
925
+ }
926
+ else if (ext == 'xlsx') {
927
+ fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
928
+ }
929
+ return fileType;
930
+ }
931
+ combineHeaders(headers, isStreaming) {
932
+ return (isStreaming) ?
933
+ {
934
+ ...headers,
935
+ observe: 'events',
936
+ responseType: 'text',
937
+ reportProgress: true,
938
+ Accept: 'text/event-stream'
939
+ }
940
+ : headers;
941
+ }
942
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
943
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, providedIn: 'root' }); }
944
+ }
945
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, decorators: [{
946
+ type: Injectable,
947
+ args: [{
948
+ providedIn: 'root'
949
+ }]
950
+ }] });
951
+
952
+ function countdown(duration) {
953
+ return defer(() => {
954
+ const currentCount = { current: duration };
955
+ return interval(1000).pipe(map(() => --currentCount.current), takeWhile(count => count >= 0));
956
+ });
957
+ }
958
+
959
+ const DEFAULT_MAX_RETRIES = 3;
960
+ function delayedRetry(delayMs, maxRetry = DEFAULT_MAX_RETRIES) {
961
+ return (src) => src.pipe(retry({
962
+ count: maxRetry,
963
+ delay: () => timer(delayMs)
964
+ }));
965
+ }
966
+
967
+ /**
968
+ * @param pollInterval
969
+ * @param stopCondition$
970
+ * @param isPending$
971
+ */
972
+ function requestPolling(pollInterval, stopCondition$, isPending$) {
973
+ return (source) => {
974
+ return interval(pollInterval * 1000)
975
+ .pipe(startWith(0), tap(() => isPending$.next(true)), mergeMap(() => source), tap(() => isPending$.next(false)), takeUntil(stopCondition$));
976
+ };
977
+ }
978
+
979
+ class DatabaseStorage {
980
+ constructor(table = '', expiresIn) {
981
+ this.table = table;
982
+ this.expiresIn = expiresIn;
983
+ }
984
+ static adapt(item) {
985
+ return new DatabaseStorage(item?.table, item?.expiresIn);
986
+ }
987
+ }
988
+
989
+ class RetryOptions {
990
+ constructor(times = 0, delay = 3) {
991
+ this.times = times;
992
+ this.delay = delay;
993
+ }
994
+ static adapt(item) {
995
+ return new RetryOptions(item?.times, item?.delay);
996
+ }
997
+ }
998
+
999
+ var DataType;
1000
+ (function (DataType) {
1001
+ DataType[DataType["ANY"] = 0] = "ANY";
1002
+ DataType[DataType["ARRAY"] = 1] = "ARRAY";
1003
+ DataType[DataType["OBJECT"] = 2] = "OBJECT";
1004
+ })(DataType || (DataType = {}));
1005
+
1006
+ class ConfigHTTPOptions {
1007
+ constructor(server = '', path, headers, polling, retry, stream, displayError) {
1008
+ this.server = server;
1009
+ this.path = path;
1010
+ this.headers = headers;
1011
+ this.polling = polling;
1012
+ this.retry = retry;
1013
+ this.stream = stream;
1014
+ this.displayError = displayError;
1015
+ }
1016
+ static adapt(item) {
1017
+ const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
1018
+ const retryOptions = item?.retry ? RetryOptions.adapt(item.retry) : RetryOptions.adapt();
1019
+ return new ConfigHTTPOptions(server, (item?.path) ? item.path : [], (item?.headers) ? item.headers : {}, item?.polling ? Math.floor(item.polling) : 0, retryOptions, (item?.stream) ? item.stream : false, (item?.displayError) ? item.displayError : false);
1020
+ }
1021
+ }
1022
+
1023
+ class LocalStorageOptions {
1024
+ constructor(storageName, storageSettingsName, options) {
1025
+ this.storageName = storageName;
1026
+ this.storageSettingsName = storageSettingsName;
1027
+ this.options = options;
1028
+ }
1029
+ static adapt(item) {
1030
+ return new LocalStorageOptions((item?.storageName) ? item.storageName : 'storage', (item?.storageSettingsName) ? item.storageSettingsName : 'global-storage', (item?.options) ? SettingOptions.adapt(item.options) : SettingOptions.adapt());
1031
+ }
1032
+ }
1033
+
1034
+ class ConfigOptions {
1035
+ constructor(httpRequestOptions, LocalStorageOptions) {
1036
+ this.httpRequestOptions = httpRequestOptions;
1037
+ this.LocalStorageOptions = LocalStorageOptions;
1038
+ }
1039
+ static adapt(item) {
1040
+ return new ConfigOptions((item?.httpRequestOptions) ? ConfigHTTPOptions.adapt(item.httpRequestOptions) : undefined, (item?.LocalStorageOptions) ? LocalStorageOptions.adapt(item.LocalStorageOptions) : undefined);
1041
+ }
1042
+ }
1043
+
1044
+ class HTTPManagerService extends RequestService {
1045
+ constructor(configOptions) {
1046
+ super();
1047
+ this.configOptions = configOptions;
1048
+ this.toastMessage = inject(ToastMessageService);
1049
+ this.ng_injector = inject(Injector);
1050
+ this.objectMergerService = inject(ObjectMergerService);
1051
+ this.countdown = new BehaviorSubject(0);
1052
+ this.countdown$ = this.countdown.asObservable();
1053
+ this.error = new BehaviorSubject(false);
1054
+ this.error$ = this.error.asObservable();
1055
+ this.data = new BehaviorSubject(null);
1056
+ this.data$ = this.data.asObservable();
1057
+ this.polling$ = new Subject();
1058
+ this.config = ConfigOptions.adapt();
1059
+ this.config = (configOptions) ? ConfigOptions.adapt(configOptions) : ConfigOptions.adapt();
1060
+ }
1061
+ // REQUESTS
1062
+ getRequest(options, params) {
1063
+ this.isPending.next(true);
1064
+ this.data.next(null);
1065
+ options = (options) ? options : ApiRequest.adapt();
1066
+ const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1067
+ const func = this.getRecordRequest;
1068
+ const requests = this.createRequest(func, updatedOptions);
1069
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.next(data)))
1070
+ .pipe(finalize(() => this.isPending.next(false)), catchError((err) => {
1071
+ if (updatedOptions.displayError)
1072
+ this.handleErrorWithSnackBar(err);
1073
+ this.isPending.next(false);
1074
+ return this.handleError(err);
1075
+ }));
1076
+ }
1077
+ postRequest(data, options, params) {
1078
+ this.isPending.next(true);
1079
+ this.data.next(null);
1080
+ options = (options) ? options : ApiRequest.adapt();
1081
+ const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1082
+ const func = this.createRecordRequest;
1083
+ const requests = this.createRequest(func, updatedOptions, data);
1084
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.next(data)))
1085
+ .pipe(finalize(() => this.isPending.next(false)), catchError((err) => {
1086
+ if (updatedOptions.displayError)
1087
+ this.handleErrorWithSnackBar(err);
1088
+ this.isPending.next(false);
1089
+ return this.handleError(err);
1090
+ }));
1091
+ }
1092
+ putRequest(data, options, params) {
1093
+ this.isPending.next(true);
1094
+ this.data.next(null);
1095
+ options = (options) ? options : ApiRequest.adapt();
1096
+ const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1097
+ const func = this.updateRecordRequest;
1098
+ const requests = this.createRequest(func, updatedOptions, data);
1099
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.next(data)))
1100
+ .pipe(finalize(() => this.isPending.next(false)), catchError((err) => {
1101
+ if (updatedOptions.displayError)
1102
+ this.handleErrorWithSnackBar(err);
1103
+ this.isPending.next(false);
1104
+ return this.handleError(err);
1105
+ }));
1106
+ }
1107
+ deleteRequest(options, params) {
1108
+ this.isPending.next(true);
1109
+ this.data.next(null);
1110
+ options = (options) ? options : ApiRequest.adapt();
1111
+ const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1112
+ const func = this.deleteRecordRequest;
1113
+ const requests = this.createRequest(func, updatedOptions);
1114
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.next(data)))
1115
+ .pipe(finalize(() => this.isPending.next(false)), catchError((err) => {
1116
+ if (updatedOptions.displayError)
1117
+ this.handleErrorWithSnackBar(err);
1118
+ this.isPending.next(false);
1119
+ return this.handleError(err);
1120
+ }));
1121
+ }
1122
+ downloadRequest(options, params) {
1123
+ this.isPending.next(true);
1124
+ options = (options) ? options : ApiRequest.adapt();
1125
+ const mergedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1126
+ const updatedOptions = {
1127
+ ...mergedOptions,
1128
+ path: params ? [...options.path, ...params] : options.path,
1129
+ };
1130
+ const func = this.downloadFileRequest;
1131
+ const requests = this.createRequest(func, updatedOptions);
1132
+ return this.createObservable(updatedOptions, requests, func.name)
1133
+ .pipe(catchError((err) => {
1134
+ this.error.next(true);
1135
+ this.isPending.next(false);
1136
+ return this.handleError(err);
1137
+ }));
1138
+ }
1139
+ createObservable(options, request$, funcName) {
1140
+ const polling = options.polling ? (options.polling > 0 ? true : false) : false;
1141
+ const isPolling = polling &&
1142
+ !(funcName === 'deleteRecordRequest' || funcName === 'updateRecordRequest' || funcName === 'createRecordRequest')
1143
+ ? true
1144
+ : false;
1145
+ this.polling$.next();
1146
+ const polling$ = (isPolling && options.polling) || 0 >= 3
1147
+ ? request$.pipe(requestPolling((options.polling || 0) + 1, this.polling$, this.isPending), tap(() => this.countdown.next(0)), tap(() => {
1148
+ if (!options.polling)
1149
+ return;
1150
+ const count = options.polling ? options.polling : 0;
1151
+ // console.log('COUNT:', count);
1152
+ countdown(count)
1153
+ .pipe(map((x) => {
1154
+ // console.log('XX:', count, x);
1155
+ const pollingInSec = options.polling || 0;
1156
+ const percentageCompleted = ((pollingInSec - x) / pollingInSec) * 100;
1157
+ return Math.round(percentageCompleted);
1158
+ }))
1159
+ .subscribe((countDownValue) => {
1160
+ // console.log(this.countdown.value, countDownValue);
1161
+ this.countdown.next(countDownValue);
1162
+ });
1163
+ }))
1164
+ : request$.pipe(catchError((err) => {
1165
+ if (err instanceof HttpErrorResponse) {
1166
+ this.error.next(true);
1167
+ return this.handleError(err);
1168
+ }
1169
+ return throwError(() => err);
1170
+ }));
1171
+ return polling$.pipe(catchError((err, caught) => {
1172
+ if (err instanceof HttpErrorResponse) {
1173
+ this.error.next(true);
1174
+ if (isPolling)
1175
+ this.stopPolling();
1176
+ return this.handleError(err);
1177
+ }
1178
+ return throwError(() => err);
1179
+ }), options.retry?.times > 0
1180
+ ? delayedRetry((options?.retry.delay || 3) * 1000, (options?.retry.times || 0) - 1)
1181
+ : (source) => source);
1182
+ }
1183
+ createRequest(func, options, data) {
1184
+ const dataItem = this.prepareRequestData(options, data, func.name);
1185
+ return func.bind(this)(dataItem.options, dataItem.data);
1186
+ }
1187
+ prepareRequestData(options, data, funcName) {
1188
+ if ((options.mapper && funcName === 'updateRecordRequest') || funcName === 'createRecordRequest') {
1189
+ if (options?.mapper) {
1190
+ data = options.mapper
1191
+ ? Array.isArray(data)
1192
+ ? map((item) => options.mapper(item))
1193
+ : options.mapper(data)
1194
+ : data;
1195
+ }
1196
+ }
1197
+ else {
1198
+ if (options?.adapter) {
1199
+ data = Array.isArray(data)
1200
+ ? map((item) => options.adapter(item))
1201
+ : options.adapter(data);
1202
+ }
1203
+ }
1204
+ return { options: options, data: data };
1205
+ }
1206
+ // MISC
1207
+ handleError(error) {
1208
+ return throwError(() => error);
1209
+ }
1210
+ handleErrorWithSnackBar(error) {
1211
+ const displayError = ToastDisplay.adapt({
1212
+ message: error.message || `${error.status} - ${error.statusText}`,
1213
+ action: 'OK',
1214
+ color: ToastColors.ERROR,
1215
+ icon: 'error',
1216
+ duration: 5 * 1000, //5 seconds
1217
+ });
1218
+ this.toastMessage.toastMessage(displayError);
1219
+ }
1220
+ stopPolling() {
1221
+ this.isPending.next(false);
1222
+ this.polling$.next();
1223
+ }
1224
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, deps: [{ token: CONFIG_SETTINGS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1225
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, providedIn: 'root' }); }
1226
+ }
1227
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, decorators: [{
1228
+ type: Injectable,
1229
+ args: [{
1230
+ providedIn: 'root',
1231
+ }]
1232
+ }], ctorParameters: function () { return [{ type: ConfigOptions, decorators: [{
1233
+ type: Optional
1234
+ }, {
1235
+ type: Inject,
1236
+ args: [CONFIG_SETTINGS_TOKEN]
1237
+ }] }]; } });
1238
+
1239
+ const storage = {
1240
+ localStores: [],
1241
+ sessionStores: [],
1242
+ settings: [],
1243
+ };
1244
+ class LocalStorageManagerService extends ComponentStore {
1245
+ startTimer() {
1246
+ const timer$ = interval(1000 * 3).pipe(withLatestFrom(this.data$), map(([_, state]) => state), tap((state) => {
1247
+ const expired = this.expired(state) ? this.expired(state) : [];
1248
+ if (expired.length > 0) {
1249
+ const ids = expired.map((item) => item.id);
1250
+ const updatedState = {
1251
+ ...state,
1252
+ localStores: state.localStores.filter((item) => !ids.includes(item.id)),
1253
+ sessionStores: state.sessionStores.filter((item) => !ids.includes(item.id)),
1254
+ settings: state.settings.filter((item) => !ids.includes(item.id)),
1255
+ };
1256
+ this.persistState(updatedState);
1257
+ this.updateState(updatedState);
1258
+ }
1259
+ }));
1260
+ timer$.subscribe();
1261
+ }
1262
+ constructor(config) {
1263
+ super(storage);
1264
+ this.config = config;
1265
+ this.storageName = 'storage';
1266
+ this.storageSettingsName = 'global-storage';
1267
+ this.defaultOptions = SettingOptions.adapt();
1268
+ this.stateRetrieved = false;
1269
+ this.encrypted = false;
1270
+ this.app = inject(AppService);
1271
+ this.utils = inject(UtilsService);
1272
+ this.objectMergerService = inject(ObjectMergerService);
1273
+ this.encryption = inject(SymmetricalEncryptionService);
1274
+ this.encryptionTest = inject(EncryptionTestService);
1275
+ // SELECTORS
1276
+ this.data$ = this.select((state) => state);
1277
+ this.stores$ = this.select((state) => state.settings);
1278
+ this.storeExists$ = (store) => this.select(this.data$, (data) => data.settings.find(item => item.name === store) ? true : false);
1279
+ this.store$ = (store) => this.select(this.data$, (data) => {
1280
+ const foundStore = data.settings.find(item => item.name === store);
1281
+ if (foundStore) {
1282
+ const options = SettingOptions.adapt(foundStore.options);
1283
+ const found = foundStore.options?.storage === StorageType.GLOBAL
1284
+ ? data.localStores.find(item => item.id === foundStore.id)
1285
+ : data.sessionStores.find(item => item.id === foundStore.id);
1286
+ if (!found) {
1287
+ this.deleteStore({ name: store });
1288
+ return;
1289
+ }
1290
+ if (!this.app?.appID) {
1291
+ console.warn('No App ID found - AppId not Provided');
1292
+ return;
1293
+ }
1294
+ const storageData = (options.encrypted) ? this.encryption.decrypt(found.data, this.app.appID) : found.data;
1295
+ return (this.isString(storageData)) ? JSON.parse(storageData) : storageData;
1296
+ }
1297
+ else {
1298
+ return null;
1299
+ }
1300
+ });
1301
+ this.settings$ = this.select(state => (state) ? state.settings : storage.settings);
1302
+ this.setting$ = (store) => this.select(this.data$, (state) => {
1303
+ const foundSetting = state.settings.find(item => item.name === store);
1304
+ return (foundSetting) ? foundSetting : null;
1305
+ });
1306
+ this.persistence$ = this.data$
1307
+ .subscribe(data => {
1308
+ if (this.stateRetrieved)
1309
+ this.persistState(data);
1310
+ });
1311
+ this.updateState = this.updater((state, updatedState) => ({
1312
+ ...updatedState,
1313
+ }));
1314
+ this.setStore = this.updater((state, store) => {
1315
+ const settings = StorageOption.adapt(store);
1316
+ settings.options = this.objectMergerService.mergeOptions(settings.options || this.defaultOptions, this.defaultOptions);
1317
+ const type = store.options.storage;
1318
+ const hasStore = this.hasGlobalStorage(type, store.id);
1319
+ store.name = this.validStoreName(store.name);
1320
+ if (!hasStore) {
1321
+ console.warn(`No such Store: ${store.name}`);
1322
+ return state;
1323
+ }
1324
+ else {
1325
+ const str = this.encryptionTest.isEncrypted(store.data) ? store.data : JSON.stringify(store.data);
1326
+ const dataStr = (this.isObjectOrArray(str)) ? (store.options.encrypted) ? this.encryption.encrypt(str, this.app.appID) : store.data : store.data;
1327
+ const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
1328
+ const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
1329
+ return {
1330
+ ...state,
1331
+ localStores: [...state.localStores, ...localData],
1332
+ sessionStores: [...state.sessionStores, ...sessionData],
1333
+ settings: [...state.settings, ...[settings]],
1334
+ };
1335
+ }
1336
+ });
1337
+ this.createStore = this.updater((state, store) => {
1338
+ const settings = StorageOption.adapt(store);
1339
+ settings.options = this.objectMergerService.mergeOptions(settings.options || this.defaultOptions, this.defaultOptions);
1340
+ const foundStore = state?.settings.some(item => item.name === store.name);
1341
+ const expires = (settings.options?.expiresIn) ? this.utils.expires(settings.options?.expiresIn) : 0;
1342
+ if (settings.options)
1343
+ settings.options.expires = expires;
1344
+ store.name = this.validStoreName(store.name);
1345
+ if (foundStore) {
1346
+ return state;
1347
+ }
1348
+ else {
1349
+ if (!this.isObjectOrArray(store.data)) {
1350
+ console.warn('Data must ba an Object or Array');
1351
+ return;
1352
+ }
1353
+ store.data = (this.isString(store.data)) ? JSON.parse(store.data) : store.data;
1354
+ const dataStr = (store.options.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data;
1355
+ const localData = (settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
1356
+ const sessionData = (settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
1357
+ return {
1358
+ ...state,
1359
+ localStores: [...state.localStores, ...localData],
1360
+ sessionStores: [...state.sessionStores, ...sessionData],
1361
+ settings: [...state.settings, ...[settings]],
1362
+ };
1363
+ }
1364
+ });
1365
+ this.updateStore = this.updater((state, store) => {
1366
+ store.name = this.validStoreName(store.name);
1367
+ const settings = state.settings.find(item => item.name === store.name);
1368
+ if (settings) {
1369
+ const type = settings.options?.storage;
1370
+ const hasStore = this.hasGlobalStorage(type, settings.id || '');
1371
+ if (!hasStore) {
1372
+ console.warn(`No such Store: ${store.name}`);
1373
+ }
1374
+ else {
1375
+ const dataStr = (settings.options?.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data;
1376
+ const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
1377
+ const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
1378
+ state.localStores = state.localStores.filter(item => item.id !== settings.id);
1379
+ state.sessionStores = state.sessionStores.filter(item => item.id !== settings.id);
1380
+ return {
1381
+ ...state,
1382
+ localStores: [...state.localStores, ...localData],
1383
+ sessionStores: [...state.sessionStores, ...sessionData],
1384
+ };
1385
+ }
1386
+ }
1387
+ return state;
1388
+ });
1389
+ this.deleteStore = this.updater((state, store) => {
1390
+ store.name = this.validStoreName(store.name);
1391
+ const id = state.settings.find(item => item.name === store.name)?.id;
1392
+ if (id) {
1393
+ const settings = state.settings.filter(item => item.id !== id);
1394
+ const localData = state.localStores.filter(item => item.id !== id);
1395
+ const sessionData = state.sessionStores.filter(item => item.id !== id);
1396
+ return {
1397
+ ...state,
1398
+ localStores: [...localData],
1399
+ sessionStores: [...sessionData],
1400
+ settings: [...settings],
1401
+ };
1402
+ }
1403
+ else {
1404
+ console.warn(`No such Store: ${store.name}`);
1405
+ return state;
1406
+ }
1407
+ });
1408
+ this.isObjectOrArray = (obj) => {
1409
+ let parsed;
1410
+ try {
1411
+ parsed = JSON.parse(obj);
1412
+ }
1413
+ catch (e) {
1414
+ return false;
1415
+ }
1416
+ if (Array.isArray(parsed)) {
1417
+ const allStringsOrObjectsOrNumbers = parsed.every(item => typeof item === 'string' ||
1418
+ typeof item === 'object' && item !== null ||
1419
+ typeof item === 'number');
1420
+ return allStringsOrObjectsOrNumbers;
1421
+ }
1422
+ return typeof parsed === 'object' && parsed !== null;
1423
+ };
1424
+ this.storageName = config.LocalStorageOptions?.storageName || this.storageName;
1425
+ this.storageSettingsName = config.LocalStorageOptions?.storageSettingsName || this.storageSettingsName;
1426
+ this.defaultOptions = config.LocalStorageOptions?.options || this.defaultOptions;
1427
+ this.retrieveState();
1428
+ this.startTimer();
1429
+ }
1430
+ resetStore() {
1431
+ const newState = {
1432
+ localStores: [],
1433
+ sessionStores: [],
1434
+ settings: [],
1435
+ };
1436
+ this.updateState(newState);
1437
+ this.persistState(newState);
1438
+ }
1439
+ persistState(state) {
1440
+ if (!state)
1441
+ return;
1442
+ const strLocal = JSON.stringify(state.localStores);
1443
+ localStorage.setItem(this.storageName, strLocal);
1444
+ const strSession = JSON.stringify(state.sessionStores);
1445
+ sessionStorage.setItem(this.storageName, strSession);
1446
+ const settingsStr = this.encryption.encrypt(state.settings, this.app.appID);
1447
+ localStorage.setItem(this.storageSettingsName, settingsStr || '');
1448
+ }
1449
+ expired(state) {
1450
+ if (!state)
1451
+ return [];
1452
+ return state.settings?.filter(item => (item.options?.expires || 0) > 0 && this.utils.hasExpired(item.options?.expires || 0));
1453
+ }
1454
+ retrieveState() {
1455
+ const str = localStorage.getItem(this.storageSettingsName);
1456
+ const localStr = localStorage.getItem(this.storageName);
1457
+ const sessionStr = sessionStorage.getItem(this.storageName);
1458
+ const localData = (localStr) ? JSON.parse(localStr) : null;
1459
+ const sessionData = (sessionStr) ? JSON.parse(sessionStr) : null;
1460
+ const decryptedStr = str ? this.encryption.decrypt(str, this.app.appID) : null;
1461
+ const settings = (decryptedStr && decryptedStr !== null) ? JSON.parse(decryptedStr) : [];
1462
+ settings.forEach(store => {
1463
+ const expired = (store.options?.expires || 0) > 0 && this.utils.hasExpired(store.options?.expires || 0);
1464
+ if (!expired) {
1465
+ const hasStorage = this.hasGlobalStorage(store.options?.storage, store.id || '');
1466
+ if (!hasStorage) {
1467
+ this.createStore({ id: store.id, name: store.name, data: [], options: SettingOptions.adapt(store.options) });
1468
+ }
1469
+ else {
1470
+ const storeData = (store.options?.storage === StorageType.GLOBAL) ? localData.find(item => item.id === store.id) : sessionData.find(item => item.id === store.id);
1471
+ this.setStore({ id: store.id || '', name: store.name, data: storeData?.data, options: SettingOptions.adapt(store.options) });
1472
+ }
1473
+ }
1474
+ });
1475
+ this.stateRetrieved = true;
1476
+ }
1477
+ isString(obj) {
1478
+ return (Object.prototype.toString.call(obj) === '[object String]');
1479
+ }
1480
+ fixAndParseJSON(jsonString) {
1481
+ const fixedString = jsonString
1482
+ .replace(/'/g, '"')
1483
+ .replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":')
1484
+ .replace(/,\s*(\}|\])/g, '$1');
1485
+ try {
1486
+ return JSON.parse(fixedString);
1487
+ }
1488
+ catch (error) {
1489
+ throw new Error('Failed to parse JSON: ' + error.message);
1490
+ }
1491
+ }
1492
+ validStoreName(str) {
1493
+ return str
1494
+ .toLowerCase() // Convert to lowercase
1495
+ .replace(/\s+/g, '_') // Replace spaces with underscores
1496
+ .replace(/[^ -~]/g, ''); // Remove non-ASCII characters
1497
+ }
1498
+ hasGlobalStorage(type = StorageType.GLOBAL, id) {
1499
+ const strData = [];
1500
+ if (type === StorageType.GLOBAL) {
1501
+ const str = localStorage.getItem(this.storageName);
1502
+ strData.push(...(str ? JSON.parse(str) : []));
1503
+ }
1504
+ else {
1505
+ const str = sessionStorage.getItem(this.storageName);
1506
+ strData.push(...(str ? JSON.parse(str) : []));
1507
+ }
1508
+ const found = strData.find(store => store.id === id);
1509
+ return (found) ? true : false;
1510
+ }
1511
+ ngOnDestroy() {
1512
+ this.persistence$.unsubscribe();
1513
+ }
1514
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable }); }
1515
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, providedIn: 'root' }); }
1516
+ }
1517
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, decorators: [{
1518
+ type: Injectable,
1519
+ args: [{ providedIn: 'root' }]
1520
+ }], ctorParameters: function () { return [{ type: ConfigOptions, decorators: [{
1521
+ type: Inject,
1522
+ args: [CONFIG_SETTINGS_TOKEN]
1523
+ }] }]; } });
1524
+
1525
+ class RequestOptions {
1526
+ constructor(path = [], headers = {}) {
1527
+ this.path = path;
1528
+ this.headers = headers;
1529
+ }
1530
+ static adapt(item) {
1531
+ return new RequestOptions(item?.path, item?.headers);
1532
+ }
1533
+ }
1534
+
1535
+ const API_OPTS = new InjectionToken('API_OPTS');
1536
+ const defaultState = {
1537
+ data: [],
1538
+ dataObject: null,
1539
+ };
1540
+ class HTTPManagerStateService extends ComponentStore {
1541
+ constructor(apiOptions = ApiRequest.adapt(), dataType, database) {
1542
+ super(defaultState);
1543
+ this.apiOptions = apiOptions;
1544
+ this.dataType = dataType;
1545
+ this.database = database;
1546
+ this.httpManagerService = inject(HTTPManagerService);
1547
+ this.error$ = this.httpManagerService.error$;
1548
+ this.isPending$ = this.httpManagerService.isPending$;
1549
+ // PAGINATION
1550
+ this.page = new BehaviorSubject(0);
1551
+ this.page$ = this.page.asObservable();
1552
+ this.totalPages = new BehaviorSubject(0);
1553
+ this.totalPages$ = this.totalPages.asObservable();
1554
+ this.percentage = new BehaviorSubject(0);
1555
+ this.percentage$ = this.percentage.asObservable();
1556
+ // ----------
1557
+ this.hasDatabase = false;
1558
+ this.streamedResponse = [];
1559
+ // --------------------------------------------------------------------------------------------------
1560
+ // SELECTORS
1561
+ this.data$ = this.select(({ data, dataObject }) => {
1562
+ const isArray = (this.dataType === DataType.ARRAY) ? true : false;
1563
+ return (isArray) ? data : dataObject;
1564
+ });
1565
+ this.selectRecord$ = (id) => this.select(this.data$, (data) => {
1566
+ if (this.dataType === DataType.ARRAY && Array.isArray(data)) {
1567
+ return data.find(item => item.id === id);
1568
+ }
1569
+ else {
1570
+ return data.id === id ? data : null;
1571
+ }
1572
+ });
1573
+ // --------------------------------------------------------------------------------------------------
1574
+ // UPDATERS
1575
+ this.setData$ = this.updater((state, data) => {
1576
+ if (!data)
1577
+ return state;
1578
+ if (this.dataType === DataType.ARRAY) {
1579
+ const dataArray = Array.isArray(data) ? data : [data];
1580
+ const stateDataSample = (state.data.length > 0) ? Object.keys(state.data[0]) : [];
1581
+ const newDataSample = (dataArray.length > 0) ? Object.keys(dataArray[0]) : [];
1582
+ const isSame = (state.data.length === 0) ? false : stateDataSample.every((value, index) => value === newDataSample[index]);
1583
+ const updatedData = (!isSame && dataArray.length !== 0) ? this.updateArrayState([], dataArray) : this.updateArrayState(state.data, dataArray);
1584
+ return { ...state, data: updatedData, dataObject: null };
1585
+ }
1586
+ else {
1587
+ const dataObject = this.isEmpty(data) ? null : data;
1588
+ return { ...state, data: [], dataObject: dataObject };
1589
+ }
1590
+ });
1591
+ this.addData$ = this.updater((state, data) => {
1592
+ if (this.dataType === DataType.ARRAY) {
1593
+ const newState = [...state.data, data];
1594
+ return { ...state, ...{ data: newState } };
1595
+ }
1596
+ else {
1597
+ return { ...state, ...{ dataObject: data } };
1598
+ }
1599
+ });
1600
+ this.deleteData$ = this.updater((state, data) => {
1601
+ if (this.dataType === DataType.ARRAY) {
1602
+ const newState = state.data.filter(item => item.id !== data.id);
1603
+ return { ...state, ...{ data: newState } };
1604
+ }
1605
+ else {
1606
+ return { ...state, ...{ dataObject: null } };
1607
+ }
1608
+ });
1609
+ this.updateData$ = this.updater((state, data) => {
1610
+ if (this.dataType === DataType.ARRAY) {
1611
+ const objIndex = state.data.findIndex(item => item.id === data.id);
1612
+ if (objIndex > -1) {
1613
+ const newState = [...state.data];
1614
+ newState[objIndex] = data;
1615
+ return { ...state, ...{ data: newState } };
1616
+ }
1617
+ return state;
1618
+ }
1619
+ else {
1620
+ return { ...state, ...{ dataObject: data } };
1621
+ }
1622
+ });
1623
+ // --------------------------------------------------------------------------------------------------
1624
+ // EFFECTS
1625
+ this.clearRecords = this.effect(data => data.pipe(tap(() => {
1626
+ if (this.dataType === DataType.ARRAY) {
1627
+ this.setData$([]);
1628
+ }
1629
+ else {
1630
+ this.setData$({});
1631
+ }
1632
+ })));
1633
+ this.refreshData = this.effect(data => data.pipe(tap(() => {
1634
+ // this.apiService.flushDatabase(this.otherOptions.database?.table)
1635
+ this.fetchRecords();
1636
+ })));
1637
+ // --------------------------------------------------------------------------------------------------
1638
+ // CRUD OPERATIONS
1639
+ // FETCH RECORDS
1640
+ this.fetchRecords = (options) => this.effect(() => of(RequestOptions.adapt(options)).pipe(switchMap(() => {
1641
+ this.streamedResponse = [];
1642
+ const requestOptions = this.updateRequestOptions(options?.headers);
1643
+ return this.httpManagerService.getRequest(requestOptions, options?.path)
1644
+ .pipe(tap((data) => {
1645
+ data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
1646
+ this.setData$(data);
1647
+ }));
1648
+ })));
1649
+ // CREATE RECORD
1650
+ this.createRecord = (data, options) => this.effect(() => of(data).pipe(switchMap((data) => {
1651
+ this.streamedResponse = [];
1652
+ const requestOptions = this.updateRequestOptions(options?.headers);
1653
+ return this.httpManagerService.postRequest(data, requestOptions, options?.path)
1654
+ .pipe(tap((data) => {
1655
+ data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
1656
+ this.addData$(data);
1657
+ }));
1658
+ })));
1659
+ // UPDATE RECORD
1660
+ this.updateRecord = (data, options) => this.effect(() => of(data).pipe(concatMap((data) => {
1661
+ this.streamedResponse = [];
1662
+ const requestOptions = this.updateRequestOptions(options?.headers);
1663
+ return this.httpManagerService.putRequest(data, requestOptions, options?.path)
1664
+ .pipe(tap((data) => {
1665
+ data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
1666
+ this.updateData$(data);
1667
+ }));
1668
+ })));
1669
+ // DELETE RECORD
1670
+ this.deleteRecord = (options) => this.effect(() => of(options).pipe(concatMap((data) => {
1671
+ this.streamedResponse = [];
1672
+ const requestOptions = this.updateRequestOptions(options?.headers);
1673
+ return this.httpManagerService.deleteRequest(requestOptions, options?.path)
1674
+ .pipe(tap((data) => {
1675
+ data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
1676
+ this.deleteData$(data);
1677
+ }));
1678
+ })));
1679
+ // --------------------------------------------------------------------------------------------------
1680
+ // FETCH STREAM
1681
+ this.createStream = (data, options) => this.effect(() => of(data).pipe(tap(() => this.httpManagerService.isPending.next(true)), switchMap((data) => {
1682
+ const requestOptions = this.updateRequestOptions(options?.headers);
1683
+ return this.httpManagerService.postRequest(data, requestOptions, options?.path)
1684
+ .pipe(tap((res) => {
1685
+ if (res.length > 0)
1686
+ this.setData$(res);
1687
+ this.streamedResponse = res;
1688
+ }), scan((acc, res) => {
1689
+ const previous = acc.current;
1690
+ const current = res;
1691
+ return { previous, current };
1692
+ }, { previous: null, current: null }), tap(({ previous, current }) => {
1693
+ if (previous && JSON.stringify(previous) === JSON.stringify(current)) {
1694
+ this.httpManagerService.isPending.next(false);
1695
+ this.setData$([]);
1696
+ }
1697
+ else {
1698
+ this.httpManagerService.isPending.next(true);
1699
+ }
1700
+ }));
1701
+ })));
1702
+ this.fetchStream = (options) => this.effect(() => of(options).pipe(tap(() => this.httpManagerService.isPending.next(true)), switchMap((options) => {
1703
+ const requestOptions = this.updateRequestOptions(options?.headers);
1704
+ return this.httpManagerService.getRequest(requestOptions, options?.path)
1705
+ .pipe(tap((res) => {
1706
+ if (res.length > 0)
1707
+ this.setData$(res);
1708
+ this.streamedResponse = res;
1709
+ }), scan((acc, res) => {
1710
+ const previous = acc.current;
1711
+ const current = res;
1712
+ return { previous, current };
1713
+ }, { previous: null, current: null }), tap(({ previous, current }) => {
1714
+ if (previous && JSON.stringify(previous) === JSON.stringify(current)) {
1715
+ this.httpManagerService.isPending.next(false);
1716
+ this.setData$([]);
1717
+ }
1718
+ else {
1719
+ this.httpManagerService.isPending.next(true);
1720
+ }
1721
+ }));
1722
+ })));
1723
+ this.setApiRequestOptions(apiOptions, dataType, database);
1724
+ }
1725
+ setApiRequestOptions(apiOptions, dataType, database) {
1726
+ this.apiOptions = ApiRequest.adapt(apiOptions);
1727
+ this.dataType = (dataType) ? dataType : DataType.ARRAY;
1728
+ this.hasDatabase = this.database?.table === "" ? false : true;
1729
+ this.database = (this.hasDatabase) ? DatabaseStorage.adapt(database) : undefined;
1730
+ }
1731
+ get ApiRequestOptions() {
1732
+ return this.apiOptions;
1733
+ }
1734
+ initStorage() {
1735
+ // if(this.otherOptions.database) {
1736
+ // console.log('Has Database Option:', this.otherOptions.database.table)
1737
+ // const schema = (this.otherOptions.adapters?.incoming) ? Object.keys(this.otherOptions.adapters.incoming({})).join() : '++id'
1738
+ // this.apiService.initDB(this.otherOptions.database.expiresIn, this.otherOptions.database.table, schema)
1739
+ // }
1740
+ }
1741
+ initializeState(data) {
1742
+ this.setData$(data);
1743
+ }
1744
+ updateArrayState(currentData, newData) {
1745
+ const filterCurrentData = () => {
1746
+ const ids = this.streamedResponse.map((obj) => obj.id);
1747
+ return currentData.filter(obj => (obj.id) ? ids.includes(obj.id) : obj);
1748
+ };
1749
+ const filteredCurrentData = (this.httpManagerService.isPending.value) ? currentData : filterCurrentData();
1750
+ const updatedData = filteredCurrentData.map(item => {
1751
+ const newItem = newData.find(newItem => {
1752
+ const hasId = (newItem?.id && item?.id) ? true : false;
1753
+ return (hasId) ? newItem.id === item.id : JSON.stringify(newItem) === JSON.stringify(item);
1754
+ });
1755
+ return (newItem) ? { ...item, ...newItem } : item;
1756
+ });
1757
+ const addedData = newData.filter(newItem => {
1758
+ return !filteredCurrentData.some(item => {
1759
+ const hasId = (newItem?.id && item?.id) ? true : false;
1760
+ return (hasId) ? item.id === newItem.id : JSON.stringify(newItem) === JSON.stringify(item);
1761
+ });
1762
+ });
1763
+ return [...updatedData, ...addedData];
1764
+ }
1765
+ // --------------------------------------------------------------------------------------------------
1766
+ // MISC
1767
+ isEmpty(obj) {
1768
+ return Object.keys(obj).length === 0;
1769
+ }
1770
+ updateRequestOptions(headers) {
1771
+ const options = ApiRequest.adapt({ ...this.apiOptions });
1772
+ options.headers = (headers)
1773
+ ? { ...options.headers, ...headers }
1774
+ : { ...options.headers };
1775
+ return options;
1776
+ }
1777
+ 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 }); }
1778
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerStateService }); }
1779
+ }
1780
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerStateService, decorators: [{
1781
+ type: Injectable
1782
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
1783
+ type: Inject,
1784
+ args: [API_OPTS]
1785
+ }] }, { type: undefined, decorators: [{
1786
+ type: Inject,
1787
+ args: ["dataType"]
1788
+ }] }, { type: undefined, decorators: [{
1789
+ type: Inject,
1790
+ args: ["database"]
1791
+ }] }]; } });
1792
+
1793
+ // export * from "./database-manager-services/index";
1794
+
1795
+ class ErrorDisplaySettings {
1796
+ constructor(displayTime = 3 * 1000, position = 'top') {
1797
+ this.displayTime = displayTime;
1798
+ this.position = position;
1799
+ }
1800
+ static adapt(item) {
1801
+ return new ErrorDisplaySettings((item?.displayTime) ? item.displayTime * 1000 : 3 * 1000, item?.position);
1802
+ }
1803
+ }
1804
+
1805
+ class WithCredentialsInterceptor {
1806
+ intercept(req, next) {
1807
+ req = req.clone({ withCredentials: true });
1808
+ return next.handle(req);
1809
+ }
1810
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WithCredentialsInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1811
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WithCredentialsInterceptor }); }
1812
+ }
1813
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WithCredentialsInterceptor, decorators: [{
1814
+ type: Injectable
1815
+ }] });
1816
+
1817
+ class RequestHeadersInterceptor {
1818
+ get currentDate() {
1819
+ const date = new Date();
1820
+ const year = date.getFullYear();
1821
+ const month = String(date.getMonth() + 1).padStart(2, '0');
1822
+ const day = String(date.getDate()).padStart(2, '0');
1823
+ return `${year}-${month}-${day}`;
1824
+ }
1825
+ constructor(translate) {
1826
+ this.translate = translate;
1827
+ this.subscriptions = new Subscription();
1828
+ this.language = 'en-CA';
1829
+ this.subscriptions.add(this.translate.onLangChange
1830
+ .subscribe((params) => {
1831
+ this.language = `${params.lang}-CA`;
1832
+ }));
1833
+ }
1834
+ intercept(request, next) {
1835
+ request = request.clone({
1836
+ setHeaders: {
1837
+ 'Content-Type': 'application/json',
1838
+ 'Accept-Language': this.language || 'en-CA',
1839
+ 'Current-Date': this.currentDate
1840
+ }
1841
+ });
1842
+ return next.handle(request);
1843
+ }
1844
+ ngOnDestroy() {
1845
+ this.subscriptions.unsubscribe();
1846
+ }
1847
+ 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 }); }
1848
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestHeadersInterceptor }); }
1849
+ }
1850
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestHeadersInterceptor, decorators: [{
1851
+ type: Injectable
1852
+ }], ctorParameters: function () { return [{ type: i1.TranslateService }]; } });
1853
+
1854
+ class RequestErrorInterceptor {
1855
+ constructor() {
1856
+ this.toastMessage = inject(ToastMessageService);
1857
+ }
1858
+ intercept(req, next) {
1859
+ return next.handle(req).pipe(catchError$1((error) => {
1860
+ const displayError = ToastDisplay.adapt({
1861
+ message: 'This is a toast message. This is an Error!!',
1862
+ action: 'OK',
1863
+ color: ToastColors.SUCCESS,
1864
+ icon: 'info',
1865
+ duration: 5 * 1000, //5 seconds
1866
+ });
1867
+ if (error.status >= 400 && error.status < 500) {
1868
+ displayError.color = ToastColors.WARN;
1869
+ displayError.message = error.error || `${error.status}: ${error.statusText}`;
1870
+ console.error('Client Error:', {
1871
+ status: error.status,
1872
+ message: error.message,
1873
+ error: error.error,
1874
+ text: error.statusText,
1875
+ });
1876
+ this.toastMessage.toastMessage(displayError);
1877
+ }
1878
+ else if (error.status >= 500) {
1879
+ displayError.color = ToastColors.ERROR;
1880
+ displayError.message = error.error || `${error.status}: ${error.statusText}`;
1881
+ console.error('Server Error:', {
1882
+ status: error.status,
1883
+ message: error.message,
1884
+ error: error.error,
1885
+ text: error.statusText,
1886
+ });
1887
+ this.toastMessage.toastMessage(displayError);
1888
+ }
1889
+ return throwError(() => error);
1890
+ }));
1891
+ }
1892
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestErrorInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1893
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestErrorInterceptor }); }
1894
+ }
1895
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestErrorInterceptor, decorators: [{
1896
+ type: Injectable
1897
+ }] });
1898
+
1899
+ const PROXY_CONFIG = new InjectionToken('PROXY_CONFIG');
1900
+ class ProxyDebuggerInterceptor {
1901
+ constructor(proxyConfig) {
1902
+ this.proxyConfig = proxyConfig;
1903
+ }
1904
+ intercept(req, next) {
1905
+ if (!this.proxyConfig) {
1906
+ return next.handle(req);
1907
+ }
1908
+ const headers = req.headers.keys().reduce((acc, key) => {
1909
+ acc[key] = req.headers.get(key) || '';
1910
+ return acc;
1911
+ }, {});
1912
+ for (const proxyPath in this.proxyConfig) {
1913
+ if (this.proxyConfig.hasOwnProperty(proxyPath)) {
1914
+ const proxyDetails = this.proxyConfig[proxyPath];
1915
+ const regex = new RegExp('^' + proxyPath.replace('/', '').replace('*', '(.*)'));
1916
+ if (regex.test(req.url)) {
1917
+ const target = proxyDetails.target;
1918
+ const endpoint = req.url.replace(regex, '$1');
1919
+ const actualPath = target + '/' + endpoint;
1920
+ console.log('Request Proxied:', {
1921
+ requestUrl: req.url,
1922
+ requestPayload: req.body,
1923
+ headers: headers,
1924
+ proxyPath: proxyPath,
1925
+ actualPath: actualPath,
1926
+ });
1927
+ }
1928
+ }
1929
+ }
1930
+ return next.handle(req);
1931
+ }
1932
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ProxyDebuggerInterceptor, deps: [{ token: PROXY_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1933
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ProxyDebuggerInterceptor }); }
1934
+ }
1935
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ProxyDebuggerInterceptor, decorators: [{
1936
+ type: Injectable
1937
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
1938
+ type: Optional
1939
+ }, {
1940
+ type: Inject,
1941
+ args: [PROXY_CONFIG]
1942
+ }] }]; } });
1943
+
1944
+ class DownloadFileComponent {
1945
+ constructor() {
1946
+ this.subscriptions = new Subscription();
1947
+ this.displayError = 3; // seconds
1948
+ this.diameter = 32;
1949
+ this.mode = 'determinate';
1950
+ this.isPending = false;
1951
+ this.active = false;
1952
+ this.disabled = false;
1953
+ this.error = new EventEmitter();
1954
+ this._progress = 0;
1955
+ this._hasError = false;
1956
+ this.errorTimerActive = false;
1957
+ }
1958
+ set progress(value) {
1959
+ this._progress = value ?? 0;
1960
+ }
1961
+ get progress() {
1962
+ return this._progress;
1963
+ }
1964
+ set hasError(value) {
1965
+ this._hasError = !!value;
1966
+ if (this._hasError && !this.errorTimerActive) {
1967
+ this.errorTimerActive = true;
1968
+ this.active = false;
1969
+ this.error.emit();
1970
+ this.subscriptions.add(timer(this.displayError * 1000)
1971
+ .subscribe((err) => {
1972
+ this._hasError = false;
1973
+ this.errorTimerActive = false;
1974
+ }));
1975
+ }
1976
+ }
1977
+ get hasError() {
1978
+ return this._hasError;
1979
+ }
1980
+ ngOnInit() { }
1981
+ onAction() {
1982
+ this.isPending = false;
1983
+ if (this.event)
1984
+ this.event();
1985
+ }
1986
+ ngOnDestroy() {
1987
+ this.subscriptions.unsubscribe();
1988
+ }
1989
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DownloadFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1990
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DownloadFileComponent, selector: "app-download-file", inputs: { event: "event", displayError: "displayError", diameter: "diameter", mode: "mode", isPending: "isPending", active: "active", disabled: "disabled", progress: "progress", hasError: "hasError" }, outputs: { error: "error" }, ngImport: i0, template: "<ng-container *ngIf=\"!isPending; else DOWNLOADING\">\n <ng-container *ngIf=\"hasError; else NORMAL\">\n <div class=\"width center-txt\" style=\"margin-bottom: 4px;\">\n <mat-icon color=\"warn\" class=\"warn-icon\">warning</mat-icon>\n </div>\n </ng-container>\n <ng-template #NORMAL>\n <ng-container *ngIf=\"active; else ACTION\">\n\n <div class=\"container-obj\">\n <div class=\"centered-obj-div\">\n <mat-progress-spinner\n color=\"primary\"\n mode=\"indeterminate\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n </div>\n\n </ng-container>\n <ng-template #ACTION>\n <button data-tracking=\"export-btn\" mat-icon-button (click)=\"onAction()\" class=\"icon-button\" [disabled]=\"disabled\">\n <mat-icon class=\"custom-icon\">file_download</mat-icon>\n </button>\n </ng-template>\n </ng-template>\n</ng-container>\n\n<ng-template #DOWNLOADING>\n <div\n class=\"spinner-container\"\n *ngIf=\"(progress > 0 && progress < 100); else INDETERMINATE\"\n >\n <div class=\"spinner-background\">\n {{progress}}%\n </div>\n <mat-progress-spinner\n color=\"primary\"\n [mode]=\"mode\"\n [value]=\"progress\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n <ng-template #INDETERMINATE>\n <div class=\"container-obj\">\n <div class=\"centered-obj-div\">\n <mat-progress-spinner\n color=\"primary\"\n mode=\"indeterminate\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n </div>\n </ng-template>\n\n</ng-template>\n\n\n\n", styles: [":not(spinner-container).spinner-container{position:relative}:not(spinner-container).spinner-container .spinner-background{position:absolute;width:44px;height:44px;font-size:12px;line-height:32px;text-align:center;overflow:hidden;border-radius:50%;border:solid 5px whitesmoke}.center-txt{align-content:center;text-align:-webkit-center}.width{width:48px;height:48px}.icon-button{display:flex;align-items:center;justify-content:center;width:48px;height:48px;padding:0}.container-obj{display:flex;justify-content:center;align-items:center;width:48px;height:48px}.centered-obj-div{text-align:center}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], encapsulation: i0.ViewEncapsulation.None }); }
1991
+ }
1992
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DownloadFileComponent, decorators: [{
1993
+ type: Component,
1994
+ args: [{ selector: 'app-download-file', encapsulation: ViewEncapsulation.None, template: "<ng-container *ngIf=\"!isPending; else DOWNLOADING\">\n <ng-container *ngIf=\"hasError; else NORMAL\">\n <div class=\"width center-txt\" style=\"margin-bottom: 4px;\">\n <mat-icon color=\"warn\" class=\"warn-icon\">warning</mat-icon>\n </div>\n </ng-container>\n <ng-template #NORMAL>\n <ng-container *ngIf=\"active; else ACTION\">\n\n <div class=\"container-obj\">\n <div class=\"centered-obj-div\">\n <mat-progress-spinner\n color=\"primary\"\n mode=\"indeterminate\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n </div>\n\n </ng-container>\n <ng-template #ACTION>\n <button data-tracking=\"export-btn\" mat-icon-button (click)=\"onAction()\" class=\"icon-button\" [disabled]=\"disabled\">\n <mat-icon class=\"custom-icon\">file_download</mat-icon>\n </button>\n </ng-template>\n </ng-template>\n</ng-container>\n\n<ng-template #DOWNLOADING>\n <div\n class=\"spinner-container\"\n *ngIf=\"(progress > 0 && progress < 100); else INDETERMINATE\"\n >\n <div class=\"spinner-background\">\n {{progress}}%\n </div>\n <mat-progress-spinner\n color=\"primary\"\n [mode]=\"mode\"\n [value]=\"progress\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n <ng-template #INDETERMINATE>\n <div class=\"container-obj\">\n <div class=\"centered-obj-div\">\n <mat-progress-spinner\n color=\"primary\"\n mode=\"indeterminate\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n </div>\n </ng-template>\n\n</ng-template>\n\n\n\n", styles: [":not(spinner-container).spinner-container{position:relative}:not(spinner-container).spinner-container .spinner-background{position:absolute;width:44px;height:44px;font-size:12px;line-height:32px;text-align:center;overflow:hidden;border-radius:50%;border:solid 5px whitesmoke}.center-txt{align-content:center;text-align:-webkit-center}.width{width:48px;height:48px}.icon-button{display:flex;align-items:center;justify-content:center;width:48px;height:48px;padding:0}.container-obj{display:flex;justify-content:center;align-items:center;width:48px;height:48px}.centered-obj-div{text-align:center}\n"] }]
1995
+ }], propDecorators: { event: [{
1996
+ type: Input
1997
+ }], displayError: [{
1998
+ type: Input
1999
+ }], diameter: [{
2000
+ type: Input
2001
+ }], mode: [{
2002
+ type: Input
2003
+ }], isPending: [{
2004
+ type: Input
2005
+ }], active: [{
2006
+ type: Input
2007
+ }], disabled: [{
2008
+ type: Input
2009
+ }], error: [{
2010
+ type: Output
2011
+ }], progress: [{
2012
+ type: Input
2013
+ }], hasError: [{
2014
+ type: Input
2015
+ }] } });
2016
+
2017
+ class DownloadLabels {
2018
+ constructor(error = '', action = '', icon = 'error') {
2019
+ this.error = error;
2020
+ this.action = action;
2021
+ this.icon = icon;
2022
+ }
2023
+ static adapt(item) {
2024
+ return new DownloadLabels(item?.error, item?.action, item?.icon);
2025
+ }
2026
+ }
2027
+
2028
+ class FileDownloaderComponent extends HTTPManagerService {
2029
+ set labels(value) {
2030
+ this._labels = (value) ? DownloadLabels.adapt(value) : DownloadLabels.adapt();
2031
+ }
2032
+ get labels() {
2033
+ return this._labels;
2034
+ }
2035
+ constructor() {
2036
+ super();
2037
+ this.delayError = 3;
2038
+ this.apiRequest = ApiRequest.adapt();
2039
+ this.displayErrorMessage = false;
2040
+ this._labels = DownloadLabels.adapt();
2041
+ this.active = false;
2042
+ this.subscription = new Subscription();
2043
+ this.completed = new EventEmitter();
2044
+ this.failed = new EventEmitter();
2045
+ this.disabled = false;
2046
+ }
2047
+ ngOnInit() {
2048
+ }
2049
+ onDownloadStreaming() {
2050
+ if (this.active)
2051
+ return;
2052
+ this.active = true;
2053
+ return this.downloadRequest(this.apiRequest)
2054
+ .pipe(distinctUntilChanged(), catchError((err) => {
2055
+ this.onError(err.message);
2056
+ this.active = false;
2057
+ this.failed.emit(err);
2058
+ return err;
2059
+ })).subscribe((res) => {
2060
+ if (res === 100) {
2061
+ this.active = false;
2062
+ this.completed.emit();
2063
+ }
2064
+ });
2065
+ }
2066
+ onError(message) {
2067
+ if (!message || !this.displayErrorMessage)
2068
+ return;
2069
+ const display = ToastDisplay.adapt({
2070
+ message,
2071
+ action: 'Ok',
2072
+ color: ToastColors.ERROR,
2073
+ icon: 'error',
2074
+ });
2075
+ this.active = false;
2076
+ this.toastMessage.toastMessage(display);
2077
+ }
2078
+ OnDestroy() {
2079
+ this.subscription.unsubscribe();
2080
+ }
2081
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2082
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: FileDownloaderComponent, selector: "app-file-downloader", inputs: { delayError: "delayError", apiRequest: "apiRequest", displayErrorMessage: "displayErrorMessage", labels: "labels", disabled: "disabled" }, outputs: { completed: "completed", failed: "failed" }, usesInheritance: true, ngImport: i0, template: "<app-download-file\n [disabled]=\"disabled\"\n [displayError]=\"3\"\n [event]=\"onDownloadStreaming.bind(this)\"\n [isPending]=\"(isPending$ | async) || false\"\n [progress]=\"(progress$ | async)\"\n [hasError]=\"(error$ | async)\"\n (error)=\"onError(labels.error)\"\n [active]=\"active\"\n></app-download-file>\n", styles: [".snackBarInfo{background-color:#f44336;color:#fff}.mat-simple-snackbar>span{font-weight:700}.mat-simple-snackbar-action .mat-button .mat-button-wrapper{color:#fff}.cdk-overlay-pane>.mat-snack-bar-container{width:100%}.mat-snack-bar-container{max-width:100%!important;width:100%}\n"], dependencies: [{ kind: "component", type: DownloadFileComponent, selector: "app-download-file", inputs: ["event", "displayError", "diameter", "mode", "isPending", "active", "disabled", "progress", "hasError"], outputs: ["error"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None }); }
2083
+ }
2084
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderComponent, decorators: [{
2085
+ type: Component,
2086
+ args: [{ selector: 'app-file-downloader', encapsulation: ViewEncapsulation.None, template: "<app-download-file\n [disabled]=\"disabled\"\n [displayError]=\"3\"\n [event]=\"onDownloadStreaming.bind(this)\"\n [isPending]=\"(isPending$ | async) || false\"\n [progress]=\"(progress$ | async)\"\n [hasError]=\"(error$ | async)\"\n (error)=\"onError(labels.error)\"\n [active]=\"active\"\n></app-download-file>\n", styles: [".snackBarInfo{background-color:#f44336;color:#fff}.mat-simple-snackbar>span{font-weight:700}.mat-simple-snackbar-action .mat-button .mat-button-wrapper{color:#fff}.cdk-overlay-pane>.mat-snack-bar-container{width:100%}.mat-snack-bar-container{max-width:100%!important;width:100%}\n"] }]
2087
+ }], ctorParameters: function () { return []; }, propDecorators: { delayError: [{
2088
+ type: Input
2089
+ }], apiRequest: [{
2090
+ type: Input
2091
+ }], displayErrorMessage: [{
2092
+ type: Input
2093
+ }], labels: [{
2094
+ type: Input
2095
+ }], completed: [{
2096
+ type: Output
2097
+ }], failed: [{
2098
+ type: Output
2099
+ }], disabled: [{
2100
+ type: Input
2101
+ }] } });
2102
+
2103
+ class SpinnerComponent {
2104
+ constructor() {
2105
+ this.value = 0;
2106
+ }
2107
+ ngOnInit() {
2108
+ }
2109
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2110
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SpinnerComponent, selector: "app-spinner", inputs: { color: "color", diameter: "diameter", display: "display", mode: "mode", strokeWidth: "strokeWidth", value: "value" }, ngImport: i0, template: "<div class=\"spinner-background\">{{display}}</div>\n<mat-progress-spinner\n [color]=\"color\"\n [diameter]=\"diameter\"\n [mode]=\"mode || 'indeterminate'\"\n [strokeWidth]=\"strokeWidth\"\n [value]=\"value\">\n</mat-progress-spinner>\n", styles: [".example-h2{margin:24px 0}:not(spinner-container).spinner-container{position:relative}:not(spinner-container).spinner-container .spinner-background{position:absolute;width:80px;height:80px;line-height:80px;text-align:center;overflow:hidden;border-color:#673ab71f;border-radius:50%;border-style:solid;border-width:10px}\n"], dependencies: [{ kind: "component", type: i3.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
2111
+ }
2112
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpinnerComponent, decorators: [{
2113
+ type: Component,
2114
+ args: [{ selector: 'app-spinner', template: "<div class=\"spinner-background\">{{display}}</div>\n<mat-progress-spinner\n [color]=\"color\"\n [diameter]=\"diameter\"\n [mode]=\"mode || 'indeterminate'\"\n [strokeWidth]=\"strokeWidth\"\n [value]=\"value\">\n</mat-progress-spinner>\n", styles: [".example-h2{margin:24px 0}:not(spinner-container).spinner-container{position:relative}:not(spinner-container).spinner-container .spinner-background{position:absolute;width:80px;height:80px;line-height:80px;text-align:center;overflow:hidden;border-color:#673ab71f;border-radius:50%;border-style:solid;border-width:10px}\n"] }]
2115
+ }], ctorParameters: function () { return []; }, propDecorators: { color: [{
2116
+ type: Input
2117
+ }], diameter: [{
2118
+ type: Input
2119
+ }], display: [{
2120
+ type: Input
2121
+ }], mode: [{
2122
+ type: Input
2123
+ }], strokeWidth: [{
2124
+ type: Input
2125
+ }], value: [{
2126
+ type: Input
2127
+ }] } });
2128
+
2129
+ class FileDownloaderModule {
2130
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2131
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderModule, declarations: [SpinnerComponent,
2132
+ DownloadFileComponent,
2133
+ FileDownloaderComponent], imports: [CommonModule,
2134
+ MatIconModule,
2135
+ MatProgressSpinnerModule,
2136
+ MatButtonModule], exports: [FileDownloaderComponent] }); }
2137
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderModule, imports: [CommonModule,
2138
+ MatIconModule,
2139
+ MatProgressSpinnerModule,
2140
+ MatButtonModule] }); }
2141
+ }
2142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderModule, decorators: [{
2143
+ type: NgModule,
2144
+ args: [{
2145
+ imports: [
2146
+ CommonModule,
2147
+ MatIconModule,
2148
+ MatProgressSpinnerModule,
2149
+ MatButtonModule,
2150
+ ],
2151
+ declarations: [
2152
+ SpinnerComponent,
2153
+ DownloadFileComponent,
2154
+ FileDownloaderComponent,
2155
+ ],
2156
+ exports: [
2157
+ FileDownloaderComponent
2158
+ ]
2159
+ }]
2160
+ }] });
2161
+
2162
+ class LocalStorageDemoComponent {
2163
+ get type() {
2164
+ return (this.typeControl.value) ? +this.typeControl.value : 0;
2165
+ }
2166
+ get isValid() {
2167
+ return this.newStoreForm.valid;
2168
+ }
2169
+ get isValidData() {
2170
+ return this.storageForm.valid;
2171
+ }
2172
+ constructor(configOptions) {
2173
+ this.configOptions = configOptions;
2174
+ this.fb = inject(FormBuilder);
2175
+ this.utils = inject(UtilsService);
2176
+ this.type$ = new BehaviorSubject(StorageType.GLOBAL);
2177
+ this.typeControl = this.fb.control(StorageType.GLOBAL.toString());
2178
+ this.localStorageManagerService = inject(LocalStorageManagerService);
2179
+ this.settings$ = this.localStorageManagerService.settings$;
2180
+ this.setting$ = (store) => this.localStorageManagerService.setting$(store);
2181
+ this.storageForm = this.fb.group({
2182
+ store: this.fb.control(null),
2183
+ type: 'local',
2184
+ settingType: 'local',
2185
+ encrypted: false,
2186
+ data: this.fb.control('', Validators.required),
2187
+ });
2188
+ this.newStoreForm = this.fb.group({
2189
+ name: this.fb.control(null, Validators.required),
2190
+ storage: 'local',
2191
+ encrypted: false,
2192
+ data: this.fb.control('', Validators.required),
2193
+ expiresIn: this.fb.control('0')
2194
+ });
2195
+ this.storeData$ = this.storageForm.get('store')?.valueChanges
2196
+ .pipe(switchMap((data) => {
2197
+ return data
2198
+ ? this.localStorageManagerService.store$(data.name)
2199
+ : of('');
2200
+ }), tap(data => {
2201
+ this.storageForm.get('data')?.patchValue(data, { emitEvent: false });
2202
+ }));
2203
+ this.expiresIn = (epoch) => this.utils.expiresIn(epoch);
2204
+ this.isValidJSON = (str) => {
2205
+ try {
2206
+ JSON.parse(str);
2207
+ return true;
2208
+ }
2209
+ catch (e) {
2210
+ return false;
2211
+ }
2212
+ };
2213
+ this.displayedColumns = ['name', 'id', 'encrypted', 'expires', "option"];
2214
+ this.filterData = (values) => {
2215
+ if (!values)
2216
+ return [];
2217
+ return values.filter((item) => item.options.storage === +this.type);
2218
+ };
2219
+ this.create = false;
2220
+ }
2221
+ ngOnInit() {
2222
+ this.storeProps = this.configOptions?.LocalStorageOptions;
2223
+ this.options = this.storeProps?.options;
2224
+ if (this.options?.storage) {
2225
+ this.typeControl.patchValue(this.options.storage.toString());
2226
+ this.typeControl.disable();
2227
+ }
2228
+ else {
2229
+ this.typeControl.enable();
2230
+ }
2231
+ if (this.options?.expiresIn) {
2232
+ this.newStoreForm.get('expiresIn')?.patchValue(this.options.expiresIn);
2233
+ this.newStoreForm.get('expiresIn')?.disable();
2234
+ }
2235
+ else {
2236
+ this.newStoreForm.get('expiresIn')?.enable();
2237
+ }
2238
+ if (this.options?.encrypted) {
2239
+ this.newStoreForm.get('encrypted')?.patchValue(this.options.encrypted);
2240
+ this.newStoreForm.get('encrypted')?.disable();
2241
+ }
2242
+ else {
2243
+ this.newStoreForm.get('encrypted')?.enable();
2244
+ }
2245
+ }
2246
+ onCreateStore() {
2247
+ if (!this.isValid)
2248
+ return;
2249
+ const store = this.newStoreForm.value;
2250
+ if (!store.name || store.name === '')
2251
+ return;
2252
+ const options = { storage: this.type, encrypted: store.encrypted, expiresIn: store.expiresIn };
2253
+ this.localStorageManagerService.createStore({
2254
+ name: store.name,
2255
+ data: store.data,
2256
+ options: SettingOptions.adapt(options)
2257
+ });
2258
+ this.newStoreForm.reset();
2259
+ this.create = false;
2260
+ }
2261
+ onUpdateStore(store) {
2262
+ if (!this.storageForm.valid)
2263
+ return;
2264
+ const storeData = this.storageForm.value;
2265
+ const data = JSON.parse(storeData.data || '');
2266
+ const type = (storeData.type === 'local') ? StorageType.GLOBAL : StorageType.SESSION;
2267
+ const options = { storage: type, encrypted: storeData.encrypted };
2268
+ this.localStorageManagerService.updateStore({
2269
+ name: store.name,
2270
+ data
2271
+ });
2272
+ }
2273
+ onSelectedRow(store) {
2274
+ this.store = store;
2275
+ this.data$ = this.localStorageManagerService.store$(store.name).pipe(map(item => JSON.stringify(item)));
2276
+ this.create = false;
2277
+ }
2278
+ onCreate() {
2279
+ this.onCancel();
2280
+ this.create = true;
2281
+ }
2282
+ onDelete(store) {
2283
+ console.log('DELETED STORE:', store);
2284
+ this.localStorageManagerService.deleteStore({
2285
+ name: store.name,
2286
+ });
2287
+ this.onCancel();
2288
+ }
2289
+ onCancel() {
2290
+ this.data$ = EMPTY;
2291
+ this.store = null;
2292
+ this.create = false;
2293
+ }
2294
+ onUpdate(store, data) {
2295
+ this.localStorageManagerService.updateStore({
2296
+ name: store.name,
2297
+ data: JSON.parse(data)
2298
+ });
2299
+ this.onCancel();
2300
+ }
2301
+ onReset() {
2302
+ this.localStorageManagerService.resetStore();
2303
+ }
2304
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageDemoComponent, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
2305
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: LocalStorageDemoComponent, selector: "app-local-storage-demo", ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <div style=\"display: flex; gap: 1rem\">\n <h2 style=\"padding-top: .5rem; display: flex;\">\n <div style=\"padding-top: .5rem;\">Local Storage Manager</div>\n <div>\n <button mat-icon-button [matMenuTriggerFor]=\"menu\">\n <mat-icon>info</mat-icon>\n </button>\n </div>\n </h2>\n <span style=\"flex:1\"></span>\n <div style=\"padding-top: .25rem;\">\n <mat-button-toggle-group name=\"storage\" [formControl]=\"typeControl\" (change)=\"onCancel()\">\n <mat-button-toggle value=\"0\">Local Storage</mat-button-toggle>\n <mat-button-toggle value=\"1\">Session Storage</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div style=\"margin-top: .25rem;\">\n <button mat-icon-button (click)=\"onCreate()\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n </div>\n\n <ng-container *ngIf=\"storeProps?.storageName || storeProps?.storageSettingsName\">\n <div style=\"display: flex; gap: .5rem; flex-direction: column; border: gray solid thin; background-color: whitesmoke; padding: 1rem;\"\n >\n <div style=\"display: flex;\">\n <div *ngIf=\"storeProps?.storageSettingsName\" style=\"flex:1\">\n Database: <b>{{ storeProps?.storageSettingsName }}</b>\n </div>\n <div *ngIf=\"storeProps?.storageName\" style=\"flex:1\">\n Data: <b>{{ storeProps?.storageName }}</b>\n </div>\n </div>\n </div>\n </ng-container>\n\n <div style=\"margin-top: 2rem;\" [formGroup]=\"newStoreForm\" *ngIf=\"create; else LIST\">\n\n <h2>Create Store</h2>\n\n <div style=\"display: flex; gap: 1rem;\">\n <div style=\"flex:1\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Store Name</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"name\">\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>Expires In...</mat-label>\n <mat-select formControlName=\"expiresIn\">\n <mat-option value=\"0\">None</mat-option>\n <mat-option value=\"30s\">30 Seconds</mat-option>\n <mat-option value=\"1mn\">1 Minute</mat-option>\n <mat-option value=\"1hr\">1 Hour</mat-option>\n <mat-option value=\"1d\">1 Day</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"margin-top: 1rem;\">\n <mat-slide-toggle formControlName=\"encrypted\">Encrypted</mat-slide-toggle>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" formControlName=\"data\" #json></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCreateStore()\" [disabled]=\"!(isValid && isValidJSON(json.value))\">\n Save Store\n </button>\n </div>\n\n </div>\n\n <ng-template #LIST>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n{{ settings$ | async | json }}\n <div *ngIf=\"filterData(settings$ | async) as data\">\n <ng-container *ngIf=\"data.length > 0; else NO_DATA\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> Store </th>\n <td mat-cell *matCellDef=\"let element\" style=\"font-weight: bold; text-transform: uppercase;\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"encrypted\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Encrypted </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.encrypted; else NO\">YES</ng-container>\n <ng-template #NO><span style=\"color:gray\">NO</span></ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"expires\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Expires </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.expires !== 0; else NO_DATA\">\n {{expiresIn(element.options.expires)}}\n </ng-container>\n <ng-template #NO_DATA>\n \u221E\n </ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"option\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let element\" style=\"padding-right: 0;\">\n <div style=\"display: flex;justify-content: flex-end;\">\n <button mat-icon-button color=\"warn\" (click)=\"onDelete(element); $event.stopPropagation()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" (click)=\"onSelectedRow(row)\"></tr>\n </table>\n </ng-container>\n\n <ng-template #NO_DATA>\n <h3 style=\"margin-top: 1rem;\">No Data</h3>\n </ng-template>\n\n <div *ngIf=\"(data$ | async) as data\" style=\"margin-top: 2rem;\">\n <div style=\"margin-bottom: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <h3>STORE: <span style=\"font-weight: bold;\">{{ store.name | uppercase }}</span></h3>\n <h3>SETTINGS: {{ setting$(store.name) | async | json }}</h3>\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" #json [value]=\"data\"></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex; gap: .5rem;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCancel()\">Cancel</button>\n <button mat-stroked-button (click)=\"onUpdate(store, json.value)\" [disabled]=\"!(isValidJSON(json.value))\">Update</button>\n </div>\n </div>\n </div>\n\n </ng-template>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <button mat-stroked-button (click)=\"onReset()\">Delete All Stores</button>\n </div>\n\n</div>\n\n\n<mat-menu #menu=\"matMenu\">\n <div style=\"padding: 1rem;\">\n <p>Please note that the LocalStorage (encryption) and management of data is dependant on initializing the APP_ID</p>\n <p>Must provide a value for <b>APP_ID</b> in AppModule->Providers</p>\n <mat-divider></mat-divider>\n <div style=\"font-size: smaller; margin-top: .5rem;\">\n <p>Example: UUID (self.crypto.randomUUID() to generate)</p>\n <div style=\"background-color: whitesmoke; padding: 1rem;\">\n &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i3$2.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "directive", type: i3$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i10.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i10.MatButtonToggle, selector: "mat-button-toggle", inputs: ["disableRipple", "aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "appearance", "checked", "disabled"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: i10$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i11.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }], encapsulation: i0.ViewEncapsulation.None }); }
2306
+ }
2307
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageDemoComponent, decorators: [{
2308
+ type: Component,
2309
+ args: [{ selector: 'app-local-storage-demo', encapsulation: ViewEncapsulation.None, template: "<div style=\"margin: 2rem;\">\n\n <div style=\"display: flex; gap: 1rem\">\n <h2 style=\"padding-top: .5rem; display: flex;\">\n <div style=\"padding-top: .5rem;\">Local Storage Manager</div>\n <div>\n <button mat-icon-button [matMenuTriggerFor]=\"menu\">\n <mat-icon>info</mat-icon>\n </button>\n </div>\n </h2>\n <span style=\"flex:1\"></span>\n <div style=\"padding-top: .25rem;\">\n <mat-button-toggle-group name=\"storage\" [formControl]=\"typeControl\" (change)=\"onCancel()\">\n <mat-button-toggle value=\"0\">Local Storage</mat-button-toggle>\n <mat-button-toggle value=\"1\">Session Storage</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div style=\"margin-top: .25rem;\">\n <button mat-icon-button (click)=\"onCreate()\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n </div>\n\n <ng-container *ngIf=\"storeProps?.storageName || storeProps?.storageSettingsName\">\n <div style=\"display: flex; gap: .5rem; flex-direction: column; border: gray solid thin; background-color: whitesmoke; padding: 1rem;\"\n >\n <div style=\"display: flex;\">\n <div *ngIf=\"storeProps?.storageSettingsName\" style=\"flex:1\">\n Database: <b>{{ storeProps?.storageSettingsName }}</b>\n </div>\n <div *ngIf=\"storeProps?.storageName\" style=\"flex:1\">\n Data: <b>{{ storeProps?.storageName }}</b>\n </div>\n </div>\n </div>\n </ng-container>\n\n <div style=\"margin-top: 2rem;\" [formGroup]=\"newStoreForm\" *ngIf=\"create; else LIST\">\n\n <h2>Create Store</h2>\n\n <div style=\"display: flex; gap: 1rem;\">\n <div style=\"flex:1\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Store Name</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"name\">\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>Expires In...</mat-label>\n <mat-select formControlName=\"expiresIn\">\n <mat-option value=\"0\">None</mat-option>\n <mat-option value=\"30s\">30 Seconds</mat-option>\n <mat-option value=\"1mn\">1 Minute</mat-option>\n <mat-option value=\"1hr\">1 Hour</mat-option>\n <mat-option value=\"1d\">1 Day</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"margin-top: 1rem;\">\n <mat-slide-toggle formControlName=\"encrypted\">Encrypted</mat-slide-toggle>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" formControlName=\"data\" #json></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCreateStore()\" [disabled]=\"!(isValid && isValidJSON(json.value))\">\n Save Store\n </button>\n </div>\n\n </div>\n\n <ng-template #LIST>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n{{ settings$ | async | json }}\n <div *ngIf=\"filterData(settings$ | async) as data\">\n <ng-container *ngIf=\"data.length > 0; else NO_DATA\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> Store </th>\n <td mat-cell *matCellDef=\"let element\" style=\"font-weight: bold; text-transform: uppercase;\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"encrypted\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Encrypted </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.encrypted; else NO\">YES</ng-container>\n <ng-template #NO><span style=\"color:gray\">NO</span></ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"expires\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Expires </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.expires !== 0; else NO_DATA\">\n {{expiresIn(element.options.expires)}}\n </ng-container>\n <ng-template #NO_DATA>\n \u221E\n </ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"option\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let element\" style=\"padding-right: 0;\">\n <div style=\"display: flex;justify-content: flex-end;\">\n <button mat-icon-button color=\"warn\" (click)=\"onDelete(element); $event.stopPropagation()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" (click)=\"onSelectedRow(row)\"></tr>\n </table>\n </ng-container>\n\n <ng-template #NO_DATA>\n <h3 style=\"margin-top: 1rem;\">No Data</h3>\n </ng-template>\n\n <div *ngIf=\"(data$ | async) as data\" style=\"margin-top: 2rem;\">\n <div style=\"margin-bottom: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <h3>STORE: <span style=\"font-weight: bold;\">{{ store.name | uppercase }}</span></h3>\n <h3>SETTINGS: {{ setting$(store.name) | async | json }}</h3>\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" #json [value]=\"data\"></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex; gap: .5rem;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCancel()\">Cancel</button>\n <button mat-stroked-button (click)=\"onUpdate(store, json.value)\" [disabled]=\"!(isValidJSON(json.value))\">Update</button>\n </div>\n </div>\n </div>\n\n </ng-template>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <button mat-stroked-button (click)=\"onReset()\">Delete All Stores</button>\n </div>\n\n</div>\n\n\n<mat-menu #menu=\"matMenu\">\n <div style=\"padding: 1rem;\">\n <p>Please note that the LocalStorage (encryption) and management of data is dependant on initializing the APP_ID</p>\n <p>Must provide a value for <b>APP_ID</b> in AppModule->Providers</p>\n <mat-divider></mat-divider>\n <div style=\"font-size: smaller; margin-top: .5rem;\">\n <p>Example: UUID (self.crypto.randomUUID() to generate)</p>\n <div style=\"background-color: whitesmoke; padding: 1rem;\">\n &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"] }]
2310
+ }], ctorParameters: function () { return [{ type: ConfigOptions, decorators: [{
2311
+ type: Inject,
2312
+ args: [CONFIG_SETTINGS_TOKEN]
2313
+ }] }]; } });
2314
+
2315
+ class ClientInfo {
2316
+ constructor(domain = '', service = '', id = 0, name = '') {
2317
+ this.domain = domain;
2318
+ this.service = service;
2319
+ this.id = id;
2320
+ this.name = name;
2321
+ }
2322
+ static adapt(item) {
2323
+ return new ClientInfo(item?.domain, item?.service, item?.id, item?.name);
2324
+ }
2325
+ }
2326
+
2327
+ class ClientInfoMapper {
2328
+ constructor(id = 0, name = '') {
2329
+ this.id = id;
2330
+ this.name = name;
2331
+ }
2332
+ static adapt(item) {
2333
+ return new ClientInfoMapper(item?.id, item?.name);
2334
+ }
2335
+ }
2336
+
2337
+ class AIPrompt {
2338
+ constructor(response = '') {
2339
+ this.response = response;
2340
+ }
2341
+ static adapt(item) {
2342
+ return new AIPrompt(item?.response);
2343
+ }
2344
+ }
2345
+
2346
+ class RequestManagerDemoComponent {
2347
+ get retry() {
2348
+ return this.requestForm.get('retry')?.value;
2349
+ }
2350
+ get headers() {
2351
+ return this.requestForm.get('headers');
2352
+ }
2353
+ get isValid() {
2354
+ this.requestForm.markAllAsTouched();
2355
+ return this.requestForm.valid;
2356
+ }
2357
+ constructor() {
2358
+ this.displayedColumns = ['id', 'name', 'lastName', 'age'];
2359
+ this.fb = inject(FormBuilder);
2360
+ this.toastMessage = inject(ToastMessageService);
2361
+ this.httpManagerService = inject(HTTPManagerService);
2362
+ this.isPending$ = this.httpManagerService.isPending$;
2363
+ this.countdown$ = this.httpManagerService.countdown$;
2364
+ this.GET_error$ = new BehaviorSubject('');
2365
+ this.POST_error$ = new BehaviorSubject('');
2366
+ this.PUT_error$ = new BehaviorSubject('');
2367
+ this.DELETE_error$ = new BehaviorSubject('');
2368
+ this.STREAM_error$ = new BehaviorSubject('');
2369
+ this.STREAM_AI_error$ = new BehaviorSubject('');
2370
+ this.requestParams = {
2371
+ GET: ApiRequest.adapt(),
2372
+ POST: ApiRequest.adapt(),
2373
+ PUT: ApiRequest.adapt(),
2374
+ DELETE: ApiRequest.adapt(),
2375
+ STREAM: ApiRequest.adapt(),
2376
+ };
2377
+ this.questionControl = this.fb.control("", [Validators.required]);
2378
+ this.downloadRequest = ApiRequest.adapt({
2379
+ server: 'http://localhost:4200/assets',
2380
+ path: ['icons1.svg']
2381
+ });
2382
+ this.sampleClientData = {
2383
+ id: 0,
2384
+ name: "Old School Dates",
2385
+ domain: "osd.com",
2386
+ service: "osd",
2387
+ spiffe: "osd.com/osd",
2388
+ secret: "SMOPECXP-OS4P-USOG-X2II-3XMD1FQDR3IJX",
2389
+ created: 1693003138,
2390
+ modified: 1693003138,
2391
+ icon: "",
2392
+ imageFile: "",
2393
+ };
2394
+ this.requestForm = this.fb.group({
2395
+ path: this.fb.control(""),
2396
+ headers: this.fb.array([]),
2397
+ adapter: [null],
2398
+ retry: this.fb.group({
2399
+ times: [3],
2400
+ delay: [3],
2401
+ }),
2402
+ polling: [3],
2403
+ });
2404
+ this.sampleAdaptors = [
2405
+ { label: "ClientInfo Basic", value: ClientInfo.adapt },
2406
+ { label: "AI Prompt", value: AIPrompt.adapt },
2407
+ ];
2408
+ this.sampleMappers = [
2409
+ { label: "Mapper Basic", value: ClientInfoMapper.adapt },
2410
+ { label: "AI Prompt", value: AIPrompt.adapt },
2411
+ ];
2412
+ // server = `http://sample-endpoint/as/authorization.oauth2`
2413
+ this.arrayObjectsToObjects = (arr) => {
2414
+ return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
2415
+ };
2416
+ }
2417
+ ngOnInit() {
2418
+ // const reqGet2 = ApiRequest.adapt({
2419
+ // server,
2420
+ // path: ['clients'],
2421
+ // headers: { authentication: "Bearer <KEY>" },
2422
+ // adapter: ClientInfo,
2423
+ // dataType: DataType.OBJECT,
2424
+ // // concurrent: false,
2425
+ // // polling: 3, //seconds
2426
+ // });
2427
+ // const req2 = [1024,1025,1026].map(item => {
2428
+ // return this.httpManagerService.getRequest<ClientInfo[]>(reqGet2, [item])
2429
+ // .pipe(
2430
+ // catchError(error => {
2431
+ // return throwError(() => new Error(error.error.message));
2432
+ // })
2433
+ // )
2434
+ // })
2435
+ // forkJoin(req2)
2436
+ // .subscribe(res => console.log(res))
2437
+ }
2438
+ addHeader() {
2439
+ const header = this.fb.group({
2440
+ key: ['', Validators.required],
2441
+ value: ['']
2442
+ });
2443
+ this.headers.push(header);
2444
+ }
2445
+ removeHeader(index) {
2446
+ this.headers.removeAt(index);
2447
+ }
2448
+ compileRequest() {
2449
+ const requestParams = this.requestForm.value;
2450
+ requestParams.headers = this.arrayObjectsToObjects(requestParams.headers || []);
2451
+ const pathReq = (requestParams.path === "") ? [] : (requestParams.path || "").split("/");
2452
+ if (!this.pollingState.checked)
2453
+ requestParams.polling = 0;
2454
+ if (!this.failedState.checked) {
2455
+ requestParams.retry = { times: 0, delay: 0 };
2456
+ }
2457
+ return ApiRequest.adapt({
2458
+ ...requestParams,
2459
+ // ...{ path: pathReq, server: this.server },
2460
+ ...{ path: pathReq },
2461
+ });
2462
+ }
2463
+ onGetRequest() {
2464
+ if (!this.isValid)
2465
+ return;
2466
+ const reqParams = this.compileRequest();
2467
+ this.requestParams.GET = reqParams;
2468
+ this.GET$ = EMPTY; //Cancels Previous
2469
+ this.GET_error$.next('');
2470
+ this.GET$ = this.httpManagerService.getRequest(reqParams)
2471
+ .pipe(
2472
+ // tap((data) => console.log("API GET response", data)),
2473
+ catchError(error => {
2474
+ return throwError(() => this.errorHandling(error, 'GET'));
2475
+ }));
2476
+ }
2477
+ onCreateRequest() {
2478
+ if (!this.isValid)
2479
+ return;
2480
+ const reqParams = this.compileRequest();
2481
+ this.requestParams.POST = reqParams;
2482
+ this.POST$ = EMPTY; //Cancels Previous
2483
+ this.POST_error$.next('');
2484
+ this.POST$ = this.httpManagerService.postRequest(this.sampleClientData, reqParams)
2485
+ .pipe(
2486
+ // tap((data) => console.log("API POST response", data)),
2487
+ catchError(error => {
2488
+ return throwError(() => this.errorHandling(error, 'POST'));
2489
+ }));
2490
+ }
2491
+ onUpdateRequest() {
2492
+ if (!this.isValid)
2493
+ return;
2494
+ const reqParams = this.compileRequest();
2495
+ this.sampleClientData.id = reqParams.path[reqParams.path.length - 1];
2496
+ this.requestParams.PUT = reqParams;
2497
+ this.PUT$ = EMPTY; //Cancels Previous
2498
+ this.PUT_error$.next('');
2499
+ this.PUT$ = this.httpManagerService.putRequest(this.sampleClientData, reqParams)
2500
+ .pipe(
2501
+ // tap((data) => console.log("API PUT response", data)),
2502
+ catchError(error => {
2503
+ return throwError(() => this.errorHandling(error, 'PUT'));
2504
+ }));
2505
+ }
2506
+ onDeleteRequest() {
2507
+ if (!this.isValid)
2508
+ return;
2509
+ const reqParams = this.compileRequest();
2510
+ this.requestParams.DELETE = reqParams;
2511
+ this.DELETE$ = EMPTY; //Cancels Previous
2512
+ this.DELETE_error$.next('');
2513
+ this.DELETE$ = this.httpManagerService.deleteRequest(reqParams)
2514
+ .pipe(
2515
+ // tap((data) => console.log("API DELETE response", data)),
2516
+ catchError(error => {
2517
+ return throwError(() => this.errorHandling(error, 'DELETE'));
2518
+ }));
2519
+ }
2520
+ onStreamPostRequest() {
2521
+ if (!this.isValid)
2522
+ return;
2523
+ const reqParams = this.compileRequest();
2524
+ reqParams.server = "http://localhost:11434/api";
2525
+ reqParams.path = ["generate"];
2526
+ reqParams.stream = true;
2527
+ const payload = {
2528
+ model: "mistral",
2529
+ prompt: this.questionControl.value,
2530
+ stream: reqParams.stream
2531
+ };
2532
+ this.requestParams.STREAM = reqParams;
2533
+ this.STREAM_AI$ = EMPTY;
2534
+ this.STREAM_AI_error$.next('');
2535
+ this.STREAM_AI$ = this.httpManagerService.postRequest(payload, reqParams)
2536
+ .pipe(map(items => items.map((word) => word.response).flat().join('')), tap(() => this.questionControl.reset()), catchError(error => {
2537
+ return throwError(() => this.errorHandling(error, 'STREAM'));
2538
+ }));
2539
+ }
2540
+ onStreamRequest() {
2541
+ if (!this.isValid)
2542
+ return;
2543
+ const reqParams = this.compileRequest();
2544
+ reqParams.server = "oidc";
2545
+ reqParams.stream = true;
2546
+ this.STREAM$ = this.httpManagerService.getRequest(reqParams)
2547
+ .pipe(
2548
+ // tap((data) => console.log("API STREAM response", data)),
2549
+ catchError(error => {
2550
+ return throwError(() => this.errorHandling(error, 'STREAM'));
2551
+ }));
2552
+ }
2553
+ onDownloadCompleted() {
2554
+ const message = "Download Completed";
2555
+ const display = ToastDisplay.adapt({
2556
+ message,
2557
+ action: 'Ok',
2558
+ color: ToastColors.SUCCESS,
2559
+ icon: 'sentiment_satisfied_alt',
2560
+ });
2561
+ this.toastMessage.toastMessage(display);
2562
+ }
2563
+ onDownloadFailed(err) {
2564
+ const message = "Download Failed";
2565
+ const display = ToastDisplay.adapt({
2566
+ message,
2567
+ action: 'Ok',
2568
+ color: ToastColors.ERROR,
2569
+ icon: 'warning',
2570
+ });
2571
+ this.toastMessage.toastMessage(display);
2572
+ }
2573
+ errorHandling(err, type) {
2574
+ if (type === 'GET')
2575
+ this.GET_error$.next(err.message);
2576
+ if (type === 'POST')
2577
+ this.POST_error$.next(err.message);
2578
+ if (type === 'PUT')
2579
+ this.PUT_error$.next(err.message);
2580
+ if (type === 'DELETE')
2581
+ this.DELETE_error$.next(err.message);
2582
+ if (type === 'STREAM')
2583
+ this.STREAM_error$.next(err.message);
2584
+ }
2585
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2586
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: RequestManagerDemoComponent, selector: "app-request-manager-demo", viewQueries: [{ propertyName: "failedState", first: true, predicate: ["failedState"], descendants: true, static: true }, { propertyName: "pollingState", first: true, predicate: ["pollingState"], descendants: true, static: true }], ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\" class=\"btn\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\"\n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <mat-progress-bar mode=\"determinate\"\n *ngIf=\"pollingState.checked && !(isPending$ | async)\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(GET$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(POST$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(PUT$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(DELETE$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">STREAMING POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_AI_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM_AI$ | async) as data\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div>\n <div style=\"display: flex;\">\n <h2 style=\"flex:1; margin-bottom: 0; padding-top: .5rem; display: flex;\">\n <div>\n Download File\n </div>\n <div style=\"flex:1; margin-left: 1rem;\">\n <mat-slide-toggle #disable>\n <span *ngIf=\"disable.checked; else DISABLE\">\n Enable\n </span>\n <ng-template #DISABLE>Disable</ng-template>\n </mat-slide-toggle>\n </div>\n </h2>\n <div>\n <app-file-downloader\n [disabled]=\"disable.checked\"\n [delayError]=\"3\"\n [apiRequest]=\"downloadRequest\"\n (completed)=\"onDownloadCompleted()\"\n (failed)=\"onDownloadFailed($event)\"\n ></app-file-downloader>\n </div>\n </div>\n </div>\n\n</div>\n", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i9.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i10$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i11.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: FileDownloaderComponent, selector: "app-file-downloader", inputs: ["delayError", "apiRequest", "displayErrorMessage", "labels", "disabled"], outputs: ["completed", "failed"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
2587
+ }
2588
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerDemoComponent, decorators: [{
2589
+ type: Component,
2590
+ args: [{ selector: 'app-request-manager-demo', template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\" class=\"btn\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\"\n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <mat-progress-bar mode=\"determinate\"\n *ngIf=\"pollingState.checked && !(isPending$ | async)\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(GET$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(POST$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(PUT$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(DELETE$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">STREAMING POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_AI_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM_AI$ | async) as data\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div>\n <div style=\"display: flex;\">\n <h2 style=\"flex:1; margin-bottom: 0; padding-top: .5rem; display: flex;\">\n <div>\n Download File\n </div>\n <div style=\"flex:1; margin-left: 1rem;\">\n <mat-slide-toggle #disable>\n <span *ngIf=\"disable.checked; else DISABLE\">\n Enable\n </span>\n <ng-template #DISABLE>Disable</ng-template>\n </mat-slide-toggle>\n </div>\n </h2>\n <div>\n <app-file-downloader\n [disabled]=\"disable.checked\"\n [delayError]=\"3\"\n [apiRequest]=\"downloadRequest\"\n (completed)=\"onDownloadCompleted()\"\n (failed)=\"onDownloadFailed($event)\"\n ></app-file-downloader>\n </div>\n </div>\n </div>\n\n</div>\n", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}\n"] }]
2591
+ }], ctorParameters: function () { return []; }, propDecorators: { failedState: [{
2592
+ type: ViewChild,
2593
+ args: ["failedState", { static: true }]
2594
+ }], pollingState: [{
2595
+ type: ViewChild,
2596
+ args: ["pollingState", { static: true }]
2597
+ }] } });
2598
+
2599
+ class StateManagerDemoService extends HTTPManagerStateService {
2600
+ constructor() {
2601
+ super(ApiRequest.adapt({
2602
+ server: "",
2603
+ path: [],
2604
+ headers: {},
2605
+ adapter: ClientInfo.adapt,
2606
+ mapper: ClientInfoMapper.adapt,
2607
+ stream: false,
2608
+ }), DataType.ARRAY, DatabaseStorage.adapt());
2609
+ }
2610
+ setAPIOptions(apiOptions, dataType, database) {
2611
+ this.setApiRequestOptions(apiOptions, dataType, database);
2612
+ }
2613
+ getClients() {
2614
+ // const headers = {
2615
+ // auth: "sample-auth-token"
2616
+ // }
2617
+ // const sampleOptions = RequestOptions.adapt({ path: ["id", 12], headers, sample: true })
2618
+ this.fetchRecords();
2619
+ }
2620
+ createClient(data) {
2621
+ // const headers = {
2622
+ // auth: "sample-auth-token"
2623
+ // }
2624
+ // const sampleOptions = RequestOptions.adapt({ path: ["id", 12], headers, sample: true })
2625
+ this.createRecord(data);
2626
+ }
2627
+ updateClient(data) {
2628
+ // const headers = {
2629
+ // auth: "sample-auth-token"
2630
+ // }
2631
+ data.id = 1031;
2632
+ const sampleOptions = RequestOptions.adapt({ path: [data.id] });
2633
+ this.updateRecord(data, sampleOptions);
2634
+ }
2635
+ deleteClient(data) {
2636
+ // const headers = {
2637
+ // auth: "sample-auth-token"
2638
+ // }
2639
+ data.id = 1031;
2640
+ const sampleOptions = RequestOptions.adapt({ path: [data.id] });
2641
+ this.deleteRecord(sampleOptions);
2642
+ }
2643
+ streamRequest() {
2644
+ const headers = {
2645
+ auth: "sample-auth-token"
2646
+ };
2647
+ // const sampleOptions = RequestOptions.adapt({ path: [1], headers })
2648
+ this.fetchStream();
2649
+ }
2650
+ streamAIRequest(data) {
2651
+ const headers = {
2652
+ auth: "sample-auth-token"
2653
+ };
2654
+ const sampleOptions = RequestOptions.adapt({ path: [data.id] });
2655
+ this.createStream(data, sampleOptions);
2656
+ // this.fetchStream(sampleOptions)
2657
+ }
2658
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: StateManagerDemoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2659
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: StateManagerDemoService, providedIn: 'root' }); }
2660
+ }
2661
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: StateManagerDemoService, decorators: [{
2662
+ type: Injectable,
2663
+ args: [{
2664
+ providedIn: 'root'
2665
+ }]
2666
+ }], ctorParameters: function () { return []; } });
2667
+
2668
+ class RequestManagerStateDemoComponent {
2669
+ get dataObservable$() {
2670
+ switch (this.requestType) {
2671
+ case 'GET':
2672
+ return this.GET$;
2673
+ case 'PUT':
2674
+ return this.PUT$;
2675
+ case 'POST':
2676
+ return this.POST$;
2677
+ case 'DELETE':
2678
+ return this.DELETE$;
2679
+ case 'STREAM':
2680
+ return this.STREAM;
2681
+ case 'STREAM_AI':
2682
+ return this.STREAM_AI;
2683
+ default:
2684
+ return this.GET$;
2685
+ break;
2686
+ }
2687
+ }
2688
+ get hasChanged() {
2689
+ return this.requestForm.dirty;
2690
+ }
2691
+ get dataType() {
2692
+ return this.requestForm.get("datatype")?.value;
2693
+ }
2694
+ get database() {
2695
+ return this.requestForm.get("database")?.value;
2696
+ }
2697
+ get retry() {
2698
+ return this.requestForm.get("retry")?.value;
2699
+ }
2700
+ get headers() {
2701
+ return this.requestForm.get('headers');
2702
+ }
2703
+ get isValid() {
2704
+ this.requestForm.markAllAsTouched();
2705
+ return this.requestForm.valid;
2706
+ }
2707
+ constructor() {
2708
+ this.stateManagerDemoService = inject(StateManagerDemoService);
2709
+ this.displayedColumns = ['id', 'name', 'lastName', 'age'];
2710
+ this.fb = inject(FormBuilder);
2711
+ this.httpManagerService = inject(HTTPManagerService);
2712
+ this.isPending$ = this.stateManagerDemoService.isPending$;
2713
+ this.error$ = this.stateManagerDemoService.error$;
2714
+ this.countdown$ = this.httpManagerService.countdown$;
2715
+ this.GET_error$ = new BehaviorSubject('');
2716
+ this.POST_error$ = new BehaviorSubject('');
2717
+ this.PUT_error$ = new BehaviorSubject('');
2718
+ this.DELETE_error$ = new BehaviorSubject('');
2719
+ this.STREAM_error$ = new BehaviorSubject('');
2720
+ this.GET$ = new BehaviorSubject(null);
2721
+ this.POST$ = new BehaviorSubject(null);
2722
+ this.PUT$ = new BehaviorSubject(null);
2723
+ this.DELETE$ = new BehaviorSubject(null);
2724
+ this.STREAM = new BehaviorSubject(null);
2725
+ this.STREAM$ = this.STREAM.asObservable();
2726
+ this.STREAM_AI = new BehaviorSubject(null);
2727
+ this.STREAM_AI$ = this.STREAM_AI.asObservable()
2728
+ .pipe(map((items) => (items) ? items.map((item) => item.response) : []), map((items) => items.join('').trim()));
2729
+ this.questionControl = this.fb.control("", [Validators.required]);
2730
+ this.requestType = '';
2731
+ this.sampleClientData = {
2732
+ id: 0,
2733
+ name: "Old School Dates",
2734
+ domain: "osd.com",
2735
+ service: "osd",
2736
+ spiffe: "osd.com/osd",
2737
+ secret: "SMOPECXP-OS4P-USOG-X2II-3XMD1FQDR3IJX",
2738
+ created: 1693003138,
2739
+ modified: 1693003138,
2740
+ icon: "",
2741
+ imageFile: "",
2742
+ };
2743
+ this.selectedRecord = this.fb.control(null);
2744
+ this.requestForm = this.fb.group({
2745
+ datatype: this.fb.control('ARRAY'),
2746
+ path: this.fb.control(""),
2747
+ headers: this.fb.array([]),
2748
+ adapter: [null],
2749
+ mapper: [null],
2750
+ retry: this.fb.group({
2751
+ times: [3],
2752
+ delay: [3],
2753
+ }),
2754
+ polling: [3],
2755
+ database: this.fb.group({
2756
+ table: [''],
2757
+ expiresIn: ['1m'],
2758
+ })
2759
+ });
2760
+ this.sampleAdaptors = [
2761
+ { label: "ClientInfo Basic", value: ClientInfo.adapt },
2762
+ { label: "AI Prompt", value: AIPrompt.adapt },
2763
+ ];
2764
+ this.sampleMappers = [
2765
+ { label: "Mapper Basic", value: ClientInfoMapper.adapt },
2766
+ { label: "AI Prompt", value: AIPrompt.adapt },
2767
+ ];
2768
+ // server = `http://sample-endpoint/as/authorization.oauth2`
2769
+ this.arrayObjectsToObjects = (arr) => {
2770
+ return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
2771
+ };
2772
+ }
2773
+ ngOnInit() {
2774
+ this.selectedRecord.valueChanges
2775
+ .subscribe((data) => {
2776
+ this.selectedRecord$ = (data) ? this.stateManagerDemoService.selectRecord$(data.id) : EMPTY;
2777
+ });
2778
+ this.stateManagerDemoService.data$
2779
+ .pipe(tap((data) => {
2780
+ switch (this.requestType) {
2781
+ case 'GET':
2782
+ this.GET$.next(data);
2783
+ break;
2784
+ case 'PUT':
2785
+ this.PUT$.next(data);
2786
+ break;
2787
+ case 'POST':
2788
+ this.POST$.next(data);
2789
+ break;
2790
+ case 'DELETE':
2791
+ this.DELETE$.next(data);
2792
+ break;
2793
+ case 'STREAM':
2794
+ this.STREAM.next(data);
2795
+ break;
2796
+ case 'STREAM_AI':
2797
+ this.STREAM_AI.next(data);
2798
+ break;
2799
+ default:
2800
+ break;
2801
+ }
2802
+ })).subscribe();
2803
+ }
2804
+ addHeader() {
2805
+ const header = this.fb.group({
2806
+ key: ['', Validators.required],
2807
+ value: ['']
2808
+ });
2809
+ this.headers.push(header);
2810
+ }
2811
+ removeHeader(index) {
2812
+ this.headers.removeAt(index);
2813
+ }
2814
+ compileRequest() {
2815
+ const requestParams = this.requestForm.value;
2816
+ requestParams.headers = this.arrayObjectsToObjects(requestParams.headers || []);
2817
+ const pathReq = (requestParams.path || "").split("/");
2818
+ if (!this.pollingState.checked)
2819
+ requestParams.polling = 0;
2820
+ if (!this.failedState.checked) {
2821
+ requestParams.retry = { times: 0, delay: 0 };
2822
+ }
2823
+ return ApiRequest.adapt({
2824
+ ...requestParams,
2825
+ // ...{ path: pathReq, server: this.server },
2826
+ ...{ path: pathReq },
2827
+ });
2828
+ }
2829
+ onSetStateOptions() {
2830
+ if (!this.isValid)
2831
+ return;
2832
+ const reqParams = this.compileRequest();
2833
+ const db = DatabaseStorage.adapt(this.database);
2834
+ const type = this.dataType === "ARRAY" ? DataType.ARRAY : DataType.OBJECT;
2835
+ this.stateManagerDemoService.setAPIOptions(reqParams, type, db);
2836
+ this.requestForm.markAsPristine();
2837
+ }
2838
+ onClearRecords() {
2839
+ this.stateManagerDemoService.clearRecords();
2840
+ }
2841
+ onRefreshRecords() {
2842
+ this.stateManagerDemoService.refreshData();
2843
+ }
2844
+ onGetRequest() {
2845
+ this.requestType = 'GET';
2846
+ this.stateManagerDemoService.getClients();
2847
+ }
2848
+ onCreateRequest() {
2849
+ this.requestType = 'POST';
2850
+ this.stateManagerDemoService.createClient(this.sampleClientData);
2851
+ }
2852
+ onUpdateRequest() {
2853
+ this.requestType = 'PUT';
2854
+ this.stateManagerDemoService.updateClient(this.sampleClientData);
2855
+ }
2856
+ onDeleteRequest() {
2857
+ this.requestType = 'DELETE';
2858
+ this.stateManagerDemoService.deleteClient(this.sampleClientData);
2859
+ }
2860
+ onStreamPostRequest() {
2861
+ if (!this.isValid)
2862
+ return;
2863
+ this.requestType = 'STREAM_AI';
2864
+ const reqParams = this.compileRequest();
2865
+ reqParams.server = "http://localhost:11434/api";
2866
+ reqParams.path = ["generate"];
2867
+ reqParams.stream = true;
2868
+ this.stateManagerDemoService.setAPIOptions(reqParams, DataType.ARRAY);
2869
+ const payload = {
2870
+ model: "mistral",
2871
+ prompt: this.questionControl.value,
2872
+ stream: reqParams.stream
2873
+ };
2874
+ this.stateManagerDemoService.streamAIRequest(payload);
2875
+ }
2876
+ onStreamRequest() {
2877
+ if (!this.isValid)
2878
+ return;
2879
+ this.requestType = 'STREAM';
2880
+ const reqParams = this.compileRequest();
2881
+ reqParams.server = "oidc";
2882
+ reqParams.stream = true;
2883
+ this.stateManagerDemoService.setAPIOptions(reqParams, DataType.ARRAY);
2884
+ this.stateManagerDemoService.streamRequest();
2885
+ }
2886
+ errorHandling(err, type) {
2887
+ if (type === 'GET')
2888
+ this.GET_error$.next(err.message);
2889
+ if (type === 'POST')
2890
+ this.POST_error$.next(err.message);
2891
+ if (type === 'PUT')
2892
+ this.PUT_error$.next(err.message);
2893
+ if (type === 'DELETE')
2894
+ this.DELETE_error$.next(err.message);
2895
+ if (type === 'STREAM')
2896
+ this.STREAM_error$.next(err.message);
2897
+ }
2898
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerStateDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2899
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: RequestManagerStateDemoComponent, selector: "app-request-manager-state-demo", viewQueries: [{ propertyName: "failedState", first: true, predicate: ["failedState"], descendants: true, static: true }, { propertyName: "pollingState", first: true, predicate: ["pollingState"], descendants: true, static: true }], ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request State Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>State Data Type</mat-label>\n <mat-select formControlName=\"datatype\">\n <mat-option value=\"ARRAY\">Array</mat-option>\n <mat-option value=\"OBJECT\">Object</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"mapper\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #DBState>Database Storage</mat-slide-toggle>\n <div *ngIf=\"DBState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem\" formGroupName=\"database\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Table Name</mat-label>\n <input matInput placeholder=\"table\" formControlName=\"table\" value=\"\">\n </mat-form-field>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>Expires In</mat-label>\n <mat-select formControlName=\"expiresIn\">\n <mat-option value=\"1m\">One Minute</mat-option>\n <mat-option value=\"1h\">One Hour</mat-option>\n <mat-option value=\"1d\">One Day</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n </div>\n <div style=\"margin-top: 1rem; display: flex;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onSetStateOptions()\" [disabled]=\"!hasChanged\">\n Set API Request Options\n </button>\n </div>\n <div>\n <mat-error *ngIf=\"(error$ | async) as error\">\n {{ error | json }}\n </mat-error>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\" \n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <div *ngIf=\"pollingState.checked\">\n <mat-progress-bar mode=\"determinate\" \n *ngIf=\"!(isPending$ | async) && (this.countdown$ | async) || -1 > 0\" \n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\" *ngIf=\"(GET$ | async) as data\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1;\">CURRENT STATE ({{ dataType }})</h2>\n </div>\n <div *ngIf=\"data.length > 1\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Records</mat-label>\n <mat-select [formControl]=\"selectedRecord\" [disabled]=\"data === null && data?.length === 0\">\n <mat-option [value]=\"\">None</mat-option>\n <mat-option *ngFor=\"let item of data\" [value]=\"item\">\n {{item.domain}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div *ngIf=\"(dataObservable$ | async) as dataRecord\">\n <div *ngIf=\"(selectedRecord$ | async) as record; else NO_RECORD\">\n {{ record | json }}\n </div>\n <ng-template #NO_RECORD>No Record Selected from State</ng-template>\n \n </div>\n <div style=\"margin-top: 1rem;\">\n <span *ngIf=\"data !== null && data?.length > 0; else NO_DATA\">\n State contains a Total of {{ data.length }} Records\n </span>\n <ng-template #NO_DATA>No Records</ng-template>\n <div style=\"display: flex; gap: .5rem; text-align: end; justify-content: flex-end;\">\n <button class=\"btn\" mat-stroked-button (click)=\"onClearRecords()\">Clear</button>\n <button class=\"btn\" mat-stroked-button (click)=\"onRefreshRecords()\">Refresh</button>\n </div>\n </div>\n </div>\n\n\n\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request ({{ dataType }})</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n <div>{{ (GET$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n <div>{{ (POST$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n <div>{{ (PUT$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n <div>{{ (DELETE$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n \n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n \n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n \n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">STREAMING POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM_AI$ | async) as data\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n</div>", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i9.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i10$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i11.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
2900
+ }
2901
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerStateDemoComponent, decorators: [{
2902
+ type: Component,
2903
+ args: [{ selector: 'app-request-manager-state-demo', template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request State Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>State Data Type</mat-label>\n <mat-select formControlName=\"datatype\">\n <mat-option value=\"ARRAY\">Array</mat-option>\n <mat-option value=\"OBJECT\">Object</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"mapper\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #DBState>Database Storage</mat-slide-toggle>\n <div *ngIf=\"DBState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem\" formGroupName=\"database\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Table Name</mat-label>\n <input matInput placeholder=\"table\" formControlName=\"table\" value=\"\">\n </mat-form-field>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>Expires In</mat-label>\n <mat-select formControlName=\"expiresIn\">\n <mat-option value=\"1m\">One Minute</mat-option>\n <mat-option value=\"1h\">One Hour</mat-option>\n <mat-option value=\"1d\">One Day</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n </div>\n <div style=\"margin-top: 1rem; display: flex;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onSetStateOptions()\" [disabled]=\"!hasChanged\">\n Set API Request Options\n </button>\n </div>\n <div>\n <mat-error *ngIf=\"(error$ | async) as error\">\n {{ error | json }}\n </mat-error>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\" \n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <div *ngIf=\"pollingState.checked\">\n <mat-progress-bar mode=\"determinate\" \n *ngIf=\"!(isPending$ | async) && (this.countdown$ | async) || -1 > 0\" \n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\" *ngIf=\"(GET$ | async) as data\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1;\">CURRENT STATE ({{ dataType }})</h2>\n </div>\n <div *ngIf=\"data.length > 1\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Records</mat-label>\n <mat-select [formControl]=\"selectedRecord\" [disabled]=\"data === null && data?.length === 0\">\n <mat-option [value]=\"\">None</mat-option>\n <mat-option *ngFor=\"let item of data\" [value]=\"item\">\n {{item.domain}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div *ngIf=\"(dataObservable$ | async) as dataRecord\">\n <div *ngIf=\"(selectedRecord$ | async) as record; else NO_RECORD\">\n {{ record | json }}\n </div>\n <ng-template #NO_RECORD>No Record Selected from State</ng-template>\n \n </div>\n <div style=\"margin-top: 1rem;\">\n <span *ngIf=\"data !== null && data?.length > 0; else NO_DATA\">\n State contains a Total of {{ data.length }} Records\n </span>\n <ng-template #NO_DATA>No Records</ng-template>\n <div style=\"display: flex; gap: .5rem; text-align: end; justify-content: flex-end;\">\n <button class=\"btn\" mat-stroked-button (click)=\"onClearRecords()\">Clear</button>\n <button class=\"btn\" mat-stroked-button (click)=\"onRefreshRecords()\">Refresh</button>\n </div>\n </div>\n </div>\n\n\n\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request ({{ dataType }})</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n <div>{{ (GET$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n <div>{{ (POST$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n <div>{{ (PUT$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n <div>{{ (DELETE$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n \n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n \n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n \n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">STREAMING POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM_AI$ | async) as data\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n</div>", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}\n"] }]
2904
+ }], ctorParameters: function () { return []; }, propDecorators: { failedState: [{
2905
+ type: ViewChild,
2906
+ args: ["failedState", { static: true }]
2907
+ }], pollingState: [{
2908
+ type: ViewChild,
2909
+ args: ["pollingState", { static: true }]
2910
+ }] } });
2911
+
2912
+ class HttpRequestManagerModule {
2913
+ static forRoot(config = ConfigOptions.adapt()) {
2914
+ return {
2915
+ ngModule: HttpRequestManagerModule,
2916
+ providers: [
2917
+ { provide: CONFIG_SETTINGS_TOKEN, useValue: ConfigOptions.adapt(config) },
2918
+ HTTPManagerService, LocalStorageManagerService //all services that need access to config
2919
+ ],
2920
+ };
2921
+ }
2922
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestManagerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2923
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestManagerModule, declarations: [HttpRequestServicesDemoComponent,
2924
+ RequestManagerStateDemoComponent,
2925
+ RequestManagerDemoComponent,
2926
+ LocalStorageDemoComponent
2927
+ // DatabaseDataDemoComponent,
2928
+ ], imports: [CommonModule,
2929
+ ToastMessageModule,
2930
+ FormsModule,
2931
+ ReactiveFormsModule,
2932
+ MatButtonModule,
2933
+ MatSelectModule,
2934
+ MatChipsModule,
2935
+ MatMenuModule,
2936
+ MatIconModule,
2937
+ MatTableModule,
2938
+ MatToolbarModule,
2939
+ MatButtonToggleModule,
2940
+ MatAutocompleteModule,
2941
+ MatProgressBarModule,
2942
+ MatSlideToggleModule,
2943
+ MatDividerModule,
2944
+ MatFormFieldModule,
2945
+ MatInputModule,
2946
+ MatSlideToggleModule, i1.TranslateModule, MatSidenavModule,
2947
+ FileDownloaderModule], exports: [HttpRequestServicesDemoComponent] }); }
2948
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestManagerModule, providers: [
2949
+ { provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
2950
+ { provide: HTTP_INTERCEPTORS, useClass: RequestHeadersInterceptor, multi: true },
2951
+ { provide: HTTP_INTERCEPTORS, useClass: ProxyDebuggerInterceptor, multi: true },
2952
+ { provide: CONFIG_SETTINGS_TOKEN, useValue: ConfigOptions.adapt() },
2953
+ HTTPManagerService, LocalStorageManagerService
2954
+ ], imports: [CommonModule,
2955
+ ToastMessageModule,
2956
+ FormsModule,
2957
+ ReactiveFormsModule,
2958
+ MatButtonModule,
2959
+ MatSelectModule,
2960
+ MatChipsModule,
2961
+ MatMenuModule,
2962
+ MatIconModule,
2963
+ MatTableModule,
2964
+ MatToolbarModule,
2965
+ MatButtonToggleModule,
2966
+ MatAutocompleteModule,
2967
+ MatProgressBarModule,
2968
+ MatSlideToggleModule,
2969
+ MatDividerModule,
2970
+ MatFormFieldModule,
2971
+ MatInputModule,
2972
+ MatSlideToggleModule,
2973
+ TranslateModule.forRoot(),
2974
+ MatSidenavModule,
2975
+ FileDownloaderModule] }); }
2976
+ }
2977
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestManagerModule, decorators: [{
2978
+ type: NgModule,
2979
+ args: [{
2980
+ imports: [
2981
+ CommonModule,
2982
+ ToastMessageModule,
2983
+ FormsModule,
2984
+ ReactiveFormsModule,
2985
+ MatButtonModule,
2986
+ MatSelectModule,
2987
+ MatChipsModule,
2988
+ MatMenuModule,
2989
+ MatIconModule,
2990
+ MatTableModule,
2991
+ MatToolbarModule,
2992
+ MatButtonToggleModule,
2993
+ MatAutocompleteModule,
2994
+ MatProgressBarModule,
2995
+ MatSlideToggleModule,
2996
+ MatDividerModule,
2997
+ MatFormFieldModule,
2998
+ MatInputModule,
2999
+ MatSlideToggleModule,
3000
+ TranslateModule.forRoot(),
3001
+ MatSidenavModule,
3002
+ FileDownloaderModule,
3003
+ ],
3004
+ declarations: [
3005
+ HttpRequestServicesDemoComponent,
3006
+ RequestManagerStateDemoComponent,
3007
+ RequestManagerDemoComponent,
3008
+ LocalStorageDemoComponent
3009
+ // DatabaseDataDemoComponent,
3010
+ ],
3011
+ exports: [
3012
+ HttpRequestServicesDemoComponent,
3013
+ ],
3014
+ providers: [
3015
+ { provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
3016
+ { provide: HTTP_INTERCEPTORS, useClass: RequestHeadersInterceptor, multi: true },
3017
+ { provide: HTTP_INTERCEPTORS, useClass: ProxyDebuggerInterceptor, multi: true },
3018
+ { provide: CONFIG_SETTINGS_TOKEN, useValue: ConfigOptions.adapt() },
3019
+ HTTPManagerService, LocalStorageManagerService
3020
+ ],
3021
+ }]
3022
+ }] });
3023
+
3024
+ class HttpRequestServicesDemoComponent {
3025
+ constructor(configOptions) {
3026
+ this.configOptions = configOptions;
3027
+ this.requestTypes = [
3028
+ { name: "Http Service", value: 'http_service' },
3029
+ { name: "Http State Service", value: 'http_state_service' },
3030
+ { name: "Database Service", value: 'database_service', divider: true, disabled: true },
3031
+ { name: "Local Storage Service", value: 'local_storage_service' },
3032
+ ];
3033
+ this.selectedService = this.requestTypes[0].value;
3034
+ }
3035
+ ngOnInit() {
3036
+ if (this.configOptions)
3037
+ this.injectionOptions = this.configOptions;
3038
+ }
3039
+ onSelected(type) {
3040
+ this.selectedService = this.requestTypes[type].value;
3041
+ }
3042
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestServicesDemoComponent, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
3043
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HttpRequestServicesDemoComponent, selector: "app-http-request-services-demo", ngImport: i0, template: "<mat-toolbar style=\"display:flex\">\n <div>Global Data</div>\n <div style=\"flex:1\"></div>\n <button mat-stroked-button [matMenuTriggerFor]=\"menu\">Services</button>\n <mat-menu #menu=\"matMenu\">\n <ng-container *ngFor=\"let type of requestTypes; index as i\">\n <div\n *ngIf=\"type?.divider\"\n style=\"margin-top: .5rem; margin-bottom: .5rem;\"\n >\n <mat-divider></mat-divider>\n </div>\n <button\n mat-menu-item\n (click)=\"onSelected(i)\"\n [disabled]=\"type.disabled\"\n >\n {{ type.name }}\n </button>\n </ng-container>\n\n </mat-menu>\n</mat-toolbar>\n\n<span [ngSwitch]=\"selectedService\">\n <p *ngSwitchCase=\"'http_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-demo></app-request-manager-demo>\n </p>\n <p *ngSwitchCase=\"'http_state_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-state-demo></app-request-manager-state-demo>\n </p>\n <p *ngSwitchCase=\"'database_service'\">\n <!-- <app-database-data-demo></app-database-data-demo> -->\n </p>\n <p *ngSwitchCase=\"'local_storage_service'\">\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-demo></app-local-storage-demo>\n </p>\n <p *ngSwitchDefault>\n Other\n </p>\n</span>\n\n<ng-template #HTTP_OPTIONS>\n <ng-container *ngIf=\"injectionOptions?.httpRequestOptions\">\n <div class=\"box\">\n <h3 style=\"font-weight: bold;\">Injection Token Detected - HTTP Options</h3>\n {{ injectionOptions?.httpRequestOptions| json }}\n </div>\n </ng-container>\n</ng-template>\n\n<ng-template #LOCAL_OPTIONS>\n <ng-container class=\"box\" *ngIf=\"injectionOptions?.LocalStorageOptions\">\n <div class=\"box\">\n <h3 style=\"font-weight: bold;\">Injection Token Detected - LocalStorage Options</h3>\n {{ injectionOptions?.LocalStorageOptions| json }}\n </div>\n </ng-container>\n</ng-template>\n\n\n", styles: [".box{padding:1rem;background-color:#f5f5f5;border:thin gray solid;margin-top:1rem}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$2.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "component", type: i4$1.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: i11.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: RequestManagerStateDemoComponent, selector: "app-request-manager-state-demo" }, { kind: "component", type: RequestManagerDemoComponent, selector: "app-request-manager-demo" }, { kind: "component", type: LocalStorageDemoComponent, selector: "app-local-storage-demo" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
3044
+ }
3045
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestServicesDemoComponent, decorators: [{
3046
+ type: Component,
3047
+ args: [{ selector: 'app-http-request-services-demo', template: "<mat-toolbar style=\"display:flex\">\n <div>Global Data</div>\n <div style=\"flex:1\"></div>\n <button mat-stroked-button [matMenuTriggerFor]=\"menu\">Services</button>\n <mat-menu #menu=\"matMenu\">\n <ng-container *ngFor=\"let type of requestTypes; index as i\">\n <div\n *ngIf=\"type?.divider\"\n style=\"margin-top: .5rem; margin-bottom: .5rem;\"\n >\n <mat-divider></mat-divider>\n </div>\n <button\n mat-menu-item\n (click)=\"onSelected(i)\"\n [disabled]=\"type.disabled\"\n >\n {{ type.name }}\n </button>\n </ng-container>\n\n </mat-menu>\n</mat-toolbar>\n\n<span [ngSwitch]=\"selectedService\">\n <p *ngSwitchCase=\"'http_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-demo></app-request-manager-demo>\n </p>\n <p *ngSwitchCase=\"'http_state_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-state-demo></app-request-manager-state-demo>\n </p>\n <p *ngSwitchCase=\"'database_service'\">\n <!-- <app-database-data-demo></app-database-data-demo> -->\n </p>\n <p *ngSwitchCase=\"'local_storage_service'\">\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-demo></app-local-storage-demo>\n </p>\n <p *ngSwitchDefault>\n Other\n </p>\n</span>\n\n<ng-template #HTTP_OPTIONS>\n <ng-container *ngIf=\"injectionOptions?.httpRequestOptions\">\n <div class=\"box\">\n <h3 style=\"font-weight: bold;\">Injection Token Detected - HTTP Options</h3>\n {{ injectionOptions?.httpRequestOptions| json }}\n </div>\n </ng-container>\n</ng-template>\n\n<ng-template #LOCAL_OPTIONS>\n <ng-container class=\"box\" *ngIf=\"injectionOptions?.LocalStorageOptions\">\n <div class=\"box\">\n <h3 style=\"font-weight: bold;\">Injection Token Detected - LocalStorage Options</h3>\n {{ injectionOptions?.LocalStorageOptions| json }}\n </div>\n </ng-container>\n</ng-template>\n\n\n", styles: [".box{padding:1rem;background-color:#f5f5f5;border:thin gray solid;margin-top:1rem}\n"] }]
3048
+ }], ctorParameters: function () { return [{ type: ConfigOptions, decorators: [{
3049
+ type: Inject,
3050
+ args: [CONFIG_SETTINGS_TOKEN]
3051
+ }] }]; } });
3052
+
3053
+ /*
3054
+ * Public API Surface of http-request-manager
3055
+ */
3056
+
3057
+ /**
3058
+ * Generated bundle index. Do not edit.
3059
+ */
3060
+
3061
+ export { ApiRequest, AppService, AsymmetricalEncryptionService, ConfigHTTPOptions, ConfigOptions, DataType, DatabaseStorage, ErrorDisplaySettings, GlobalStoreOptions, HTTPManagerService, HTTPManagerStateService, HeadersService, HttpRequestManagerModule, HttpRequestServicesDemoComponent, LocalStorageManagerService, LocalStorageOptions, PathQueryService, Random, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomSignature, RandomStr, RequestErrorInterceptor, RequestHeadersInterceptor, RequestOptions, RetryOptions, SettingOptions, StorageData, StorageOption, StorageType, SymmetricalEncryptionService, UUID, UtilsService, WithCredentialsInterceptor, countdown, delayedRetry, requestPolling, requestStreaming };
3062
+ //# sourceMappingURL=http-request-manager.mjs.map