http-request-manager 18.7.20 → 18.7.21

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 (197) hide show
  1. package/ARCHITECTURE.md +483 -0
  2. package/DATABASE_README.md +1176 -0
  3. package/HTTP_MANAGER_README.md +579 -0
  4. package/HTTP_SINGNALS_MANAGER_README.md +654 -0
  5. package/HTTP_STATE_MANAGER_README.md +948 -0
  6. package/INTERCEPTOR_README.md +549 -0
  7. package/LOCAL_STORAGE_README.md +1056 -0
  8. package/STORE_STATE_MANAGER_README.md +1322 -0
  9. package/UTILS_README.md +1186 -0
  10. package/WS_MANAGER_README.md +613 -0
  11. package/ng-package.json +8 -0
  12. package/package.json +1 -12
  13. package/src/lib/http-request-manager.module.ts +132 -0
  14. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.html +65 -0
  15. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.scss +0 -0
  16. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.ts +224 -0
  17. package/src/lib/http-request-services-demo/http-request-services-demo.component.html +114 -0
  18. package/src/lib/http-request-services-demo/http-request-services-demo.component.scss +6 -0
  19. package/src/lib/http-request-services-demo/http-request-services-demo.component.ts +52 -0
  20. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.html +195 -0
  21. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.scss +17 -0
  22. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.ts +206 -0
  23. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.html +200 -0
  24. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.scss +17 -0
  25. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.ts +212 -0
  26. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
  27. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
  28. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
  29. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.ts +28 -0
  30. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.html +10 -0
  31. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.scss +29 -0
  32. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.ts +100 -0
  33. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
  34. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
  35. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
  36. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
  37. package/src/lib/http-request-services-demo/request-manager-demo/models/app-session.model.ts +30 -0
  38. package/src/lib/http-request-services-demo/request-manager-demo/models/app.model.ts +19 -0
  39. package/src/lib/http-request-services-demo/request-manager-demo/models/get-sample.model.ts +25 -0
  40. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.ts +19 -0
  41. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-details.ts +24 -0
  42. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.ts +30 -0
  43. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client.model.ts +49 -0
  44. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.ts +33 -0
  45. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.html +392 -0
  46. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.scss +24 -0
  47. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.ts +461 -0
  48. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.html +393 -0
  49. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.scss +24 -0
  50. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.ts +421 -0
  51. package/src/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.ts +87 -0
  52. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/services/state-data-request.service.ts +120 -0
  53. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.css +0 -0
  54. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.html +3 -0
  55. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.ts +16 -0
  56. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.css +0 -0
  57. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.html +3 -0
  58. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.ts +16 -0
  59. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.css +31 -0
  60. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.html +72 -0
  61. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.scss +41 -0
  62. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.spec.ts +205 -0
  63. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.ts +77 -0
  64. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.css +11 -0
  65. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.html +96 -0
  66. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.spec.ts +31 -0
  67. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.ts +229 -0
  68. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.css +30 -0
  69. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.html +172 -0
  70. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.spec.ts +31 -0
  71. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.ts +239 -0
  72. package/src/lib/http-request-services-demo/request-manager-ws-demo/models/oidc-client.model.ts +31 -0
  73. package/src/lib/http-request-services-demo/request-manager-ws-demo/models/user-data.model.ts +32 -0
  74. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.css +0 -0
  75. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.html +84 -0
  76. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.ts +41 -0
  77. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/index.ts +3 -0
  78. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/message-service-demo.service.ts +83 -0
  79. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/notification-service-demo.service.ts +147 -0
  80. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/state-service-demo.service.ts +158 -0
  81. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
  82. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
  83. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
  84. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-download.module.ts +28 -0
  85. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.html +10 -0
  86. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.scss +29 -0
  87. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.ts +100 -0
  88. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
  89. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
  90. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
  91. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
  92. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app-session.model.ts +30 -0
  93. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app.model.ts +19 -0
  94. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/get-sample.model.ts +25 -0
  95. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.ts +19 -0
  96. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-details.ts +24 -0
  97. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.ts +30 -0
  98. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client.model.ts +49 -0
  99. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.ts +33 -0
  100. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.html +380 -0
  101. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.scss +24 -0
  102. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.ts +410 -0
  103. package/src/lib/http-request-services-demo/store-state-manager-demo/models/settings.model.ts +28 -0
  104. package/src/lib/http-request-services-demo/store-state-manager-demo/services/settings-state.service.ts +48 -0
  105. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.css +0 -0
  106. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.html +23 -0
  107. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.ts +36 -0
  108. package/src/lib/index.ts +3 -0
  109. package/src/lib/interceptors/credentials.interceptor.ts +16 -0
  110. package/src/lib/interceptors/index.ts +6 -0
  111. package/src/lib/interceptors/models/error-settings.model.ts +22 -0
  112. package/src/lib/interceptors/models/index.ts +2 -0
  113. package/src/lib/interceptors/proxy-debugger.interceptor.ts +46 -0
  114. package/src/lib/interceptors/request-error.interceptor.ts +65 -0
  115. package/src/lib/interceptors/request-header.interceptor.ts +53 -0
  116. package/src/lib/models/config-http-options.model.ts +42 -0
  117. package/src/lib/models/config-local-storage-options.model.ts +27 -0
  118. package/src/lib/models/config-options.model.ts +27 -0
  119. package/src/lib/models/config-token.model.ts +9 -0
  120. package/src/lib/models/data-type.enum.ts +5 -0
  121. package/src/lib/models/database-storage.model.ts +24 -0
  122. package/src/lib/models/index.ts +12 -0
  123. package/src/lib/models/retry-options.model.ts +22 -0
  124. package/src/lib/services/database-manager-service/database.manager.service.ts +262 -0
  125. package/src/lib/services/database-manager-service/db.storage.service.ts +207 -0
  126. package/src/lib/services/database-manager-service/index.ts +4 -0
  127. package/src/lib/services/database-manager-service/models/index.ts +2 -0
  128. package/src/lib/services/database-manager-service/models/table-schema.ts +33 -0
  129. package/src/lib/services/index.ts +12 -0
  130. package/src/lib/services/local-storage-manager-service/index.ts +4 -0
  131. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.spec.ts +71 -0
  132. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.ts +426 -0
  133. package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.spec.ts +67 -0
  134. package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.ts +345 -0
  135. package/src/lib/services/local-storage-manager-service/models/global-store-options.model.ts +30 -0
  136. package/src/lib/services/local-storage-manager-service/models/index.ts +6 -0
  137. package/src/lib/services/local-storage-manager-service/models/setting-options.model.ts +35 -0
  138. package/src/lib/services/local-storage-manager-service/models/storage-data.model.ts +24 -0
  139. package/src/lib/services/local-storage-manager-service/models/storage-option.model.ts +32 -0
  140. package/src/lib/services/local-storage-manager-service/models/storage-type.enum.ts +5 -0
  141. package/src/lib/services/request-manager-services/README.md +268 -0
  142. package/src/lib/services/request-manager-services/http-manager-signals.service.ts +246 -0
  143. package/src/lib/services/request-manager-services/http-manager.service.spec.ts +232 -0
  144. package/src/lib/services/request-manager-services/http-manager.service.ts +274 -0
  145. package/src/lib/services/request-manager-services/index.ts +8 -0
  146. package/src/lib/services/request-manager-services/request-signals.service.ts +214 -0
  147. package/src/lib/services/request-manager-services/request.service.ts +309 -0
  148. package/src/lib/services/request-manager-services/rxjs-operators/countdown.ts +17 -0
  149. package/src/lib/services/request-manager-services/rxjs-operators/delay-retry.ts +16 -0
  150. package/src/lib/services/request-manager-services/rxjs-operators/index.ts +4 -0
  151. package/src/lib/services/request-manager-services/rxjs-operators/request-polling.ts +35 -0
  152. package/src/lib/services/request-manager-services/rxjs-operators/request-streaming.ts +436 -0
  153. package/src/lib/services/request-manager-state-service/http-manager-state.store.ts +1321 -0
  154. package/src/lib/services/request-manager-state-service/index.ts +3 -0
  155. package/src/lib/services/request-manager-state-service/models/api-request.model.ts +61 -0
  156. package/src/lib/services/request-manager-state-service/models/index.ts +6 -0
  157. package/src/lib/services/request-manager-state-service/models/request-options.model.ts +22 -0
  158. package/src/lib/services/request-manager-state-service/models/stream-type.enum.ts +13 -0
  159. package/src/lib/services/request-manager-state-service/models/ws-options.model.ts +39 -0
  160. package/src/lib/services/store-state-manager-service/index.ts +3 -0
  161. package/src/lib/services/store-state-manager-service/models/index.ts +2 -0
  162. package/src/lib/services/store-state-manager-service/models/state-storage-options.model.ts +24 -0
  163. package/src/lib/services/store-state-manager-service/store-state-manager.service.ts +88 -0
  164. package/src/lib/services/utils/app.service.spec.ts +25 -0
  165. package/src/lib/services/utils/app.service.ts +21 -0
  166. package/src/lib/services/utils/encryption/README.md +79 -0
  167. package/src/lib/services/utils/encryption/asymmetrical-encryption.service.ts +282 -0
  168. package/src/lib/services/utils/encryption/encryption-test.service.ts +39 -0
  169. package/src/lib/services/utils/encryption/index.ts +5 -0
  170. package/src/lib/services/utils/encryption/random.ts +81 -0
  171. package/src/lib/services/utils/encryption/symmetrical-encryption.service.ts +93 -0
  172. package/src/lib/services/utils/headers.service.spec.ts +80 -0
  173. package/src/lib/services/utils/headers.service.ts +18 -0
  174. package/src/lib/services/utils/index.ts +7 -0
  175. package/src/lib/services/utils/object-merger.service.spec.ts +18 -0
  176. package/src/lib/services/utils/object-merger.service.ts +78 -0
  177. package/src/lib/services/utils/path-query.service.spec.ts +117 -0
  178. package/src/lib/services/utils/path-query.service.ts +69 -0
  179. package/src/lib/services/utils/random-color.utils.ts +83 -0
  180. package/src/lib/services/utils/utils.service.spec.ts +165 -0
  181. package/src/lib/services/utils/utils.service.ts +192 -0
  182. package/src/lib/services/ws-manager-service/index.ts +4 -0
  183. package/src/lib/services/ws-manager-service/models/channel-info.model.ts +24 -0
  184. package/src/lib/services/ws-manager-service/models/channel-message-data.model.ts +24 -0
  185. package/src/lib/services/ws-manager-service/models/channel-message.model.ts +24 -0
  186. package/src/lib/services/ws-manager-service/models/communication-type.enum.ts +5 -0
  187. package/src/lib/services/ws-manager-service/models/index.ts +5 -0
  188. package/src/lib/services/ws-manager-service/models/ws-user.model.ts +38 -0
  189. package/src/lib/services/ws-manager-service/services/index.ts +3 -0
  190. package/src/lib/services/ws-manager-service/services/websocket.service.ts +392 -0
  191. package/src/public-api.ts +14 -0
  192. package/tsconfig.lib.json +32 -0
  193. package/tsconfig.lib.prod.json +10 -0
  194. package/tsconfig.spec.json +14 -0
  195. package/fesm2022/http-request-manager.mjs +0 -7633
  196. package/fesm2022/http-request-manager.mjs.map +0 -1
  197. package/types/http-request-manager.d.ts +0 -2277
@@ -0,0 +1,214 @@
1
+ import { HttpClient, HttpEvent, HttpEventType, HttpHeaderResponse } from '@angular/common/http';
2
+ import { Injectable, inject, signal, computed } from '@angular/core';
3
+ import { Observable, throwError } from 'rxjs';
4
+ import { catchError, finalize, map } from 'rxjs/operators';
5
+
6
+ import { ApiRequest } from '../request-manager-state-service/models/api-request.model';
7
+ import { PathQueryService, HeadersService } from '../utils';
8
+ import { requestStreaming } from './rxjs-operators/request-streaming';
9
+
10
+ @Injectable({
11
+ providedIn: 'root'
12
+ })
13
+ export class RequestSignalsService {
14
+
15
+ private http = inject(HttpClient);
16
+ private pathQueryService = inject(PathQueryService);
17
+ private headersService = inject(HeadersService);
18
+
19
+ isPending = signal(false);
20
+ progress = signal(0);
21
+
22
+ isIdle = computed(() => !this.isPending());
23
+
24
+ getRecordRequest<T>(options: ApiRequest): Observable<T> {
25
+ const urlPath = this.buildUrlPath(options);
26
+ const headers = this.buildCombinedHeaders(options);
27
+
28
+ this.isPending.set(true);
29
+
30
+ return (options.stream)
31
+ ? this.http.get<any>(urlPath, headers).pipe(
32
+ requestStreaming(),
33
+ this.handleFinalize()
34
+ )
35
+ : this.http.get<T>(urlPath, headers).pipe(
36
+ this.request(options),
37
+ this.handleFinalize()
38
+ );
39
+ }
40
+
41
+ createRecordRequest<T>(options: ApiRequest, data: any): Observable<T> {
42
+ const urlPath = this.buildUrlPath(options);
43
+ const headers = this.buildCombinedHeaders(options);
44
+
45
+ this.isPending.set(true);
46
+
47
+ return (options.stream)
48
+ ? this.http.post<any>(urlPath, data, headers).pipe(
49
+ requestStreaming(),
50
+ this.handleFinalize()
51
+ )
52
+ : this.http.post<T>(urlPath, data, headers).pipe(
53
+ this.request(options),
54
+ this.handleFinalize()
55
+ );
56
+ }
57
+
58
+ updateRecordRequest<T>(options: ApiRequest, data: any): Observable<T> {
59
+ const urlPath = this.buildUrlPath(options);
60
+ const headers = this.buildHeaders(options);
61
+
62
+ this.isPending.set(true);
63
+
64
+ return this.http.put<any>(urlPath, data, headers).pipe(
65
+ this.request(options),
66
+ this.handleFinalize()
67
+ );
68
+ }
69
+
70
+ deleteRecordRequest<T>(options: ApiRequest): Observable<T> {
71
+ const urlPath = this.buildUrlPath(options);
72
+ const headers = this.buildHeaders(options);
73
+
74
+ this.isPending.set(true);
75
+
76
+ return this.http.delete<any>(urlPath, headers).pipe(
77
+ this.request(options),
78
+ this.handleFinalize()
79
+ );
80
+ }
81
+
82
+ private buildUrlPath(options: ApiRequest): string {
83
+ return this.pathQueryService.buildAPIPath(options.server, options.path);
84
+ }
85
+
86
+ private buildHeaders(options: ApiRequest): any {
87
+ return this.headersService.generateHeaders(options.headers);
88
+ }
89
+
90
+ private buildCombinedHeaders(options: ApiRequest): any {
91
+ const headers = this.headersService.generateHeaders(options.headers);
92
+ return this.combineHeaders(headers, options.stream || false);
93
+ }
94
+
95
+ private request<T>(options: ApiRequest): (source: Observable<any>) => Observable<T> {
96
+ return (source$: Observable<any>): Observable<T> => {
97
+ return source$.pipe(
98
+ map(data => {
99
+ if (options?.adapter) {
100
+ return Array.isArray(data)
101
+ ? data.map((item: any) => options.adapter(item))
102
+ : options.adapter(data);
103
+ }
104
+ return data;
105
+ })
106
+ );
107
+ };
108
+ }
109
+
110
+ downloadFileRequest(options: ApiRequest): Observable<any> {
111
+ this.isPending.set(true);
112
+
113
+ const urlPath = this.buildUrlPath(options);
114
+
115
+ return this.http.get(urlPath, { responseType: 'blob', observe: 'events', reportProgress: true })
116
+ .pipe(
117
+ map((event: HttpEvent<any>) => {
118
+ this.isPending.set(true);
119
+
120
+ if (event instanceof HttpHeaderResponse) {
121
+ if (event.status !== 200) {
122
+ this.isPending.set(false);
123
+ throw new Error('Download failed');
124
+ }
125
+ }
126
+
127
+ switch (event.type) {
128
+ case HttpEventType.DownloadProgress:
129
+ const status = (event.total) ? Math.round(event.loaded / (event.total || 1) * 100) : 100;
130
+ this.progress.set(status);
131
+ return status;
132
+
133
+ case HttpEventType.Response:
134
+ try {
135
+ const fileNamePath = (options?.saveAs) ? options.saveAs : (options.path) ? options.path[options.path.length - 1] : [];
136
+ const header_content = event.headers.get('Content-Disposition') || '';
137
+ const file = (header_content) ? header_content.split('=')[1].substring(0, header_content.split('=')[1].length) : '';
138
+
139
+ const fileName = (fileNamePath !== '') ? fileNamePath : file;
140
+
141
+ if (fileName === '') {
142
+ this.isPending.set(false);
143
+ throw new Error('Save File: (file name and extension) not found in Headers or Path');
144
+ }
145
+
146
+ this.downloadFile(fileName, event.body);
147
+ this.isPending.set(false);
148
+
149
+ return 100;
150
+
151
+ } catch (error) {
152
+ throw new Error('Download failed');
153
+ }
154
+
155
+ default:
156
+ this.isPending.set(false);
157
+ return 0;
158
+ }
159
+ }),
160
+ catchError(err => {
161
+ return throwError(() => err);
162
+ })
163
+ );
164
+ }
165
+
166
+ private handleFinalize(): (source: Observable<any>) => Observable<any> {
167
+ return finalize(() => this.isPending.set(false));
168
+ }
169
+
170
+ private downloadFile(file: string, fileData: any) {
171
+ const navigatorAny = window.navigator as any;
172
+ const extension = file.split('.')[1]?.toLowerCase();
173
+ const newBlob = new Blob([fileData], { type: this.createFileType(extension) });
174
+
175
+ if (navigatorAny.msSaveOrOpenBlob) {
176
+ navigatorAny.msSaveOrOpenBlob(newBlob, file);
177
+ } else {
178
+ const link = document.createElement('a');
179
+ const url = window.URL.createObjectURL(newBlob);
180
+ link.href = url;
181
+ link.download = file;
182
+ link.click();
183
+ window.URL.revokeObjectURL(url);
184
+ }
185
+ }
186
+
187
+ private createFileType(ext: string): string {
188
+ let fileType = "";
189
+
190
+ if (ext === 'pdf' || ext === 'csv') fileType = `application/${ext}`;
191
+ else if (ext === 'jpeg' || ext === 'jpg' || ext === 'png') fileType = `image/${ext}`;
192
+ else if (ext === 'txt') fileType = 'text/plain';
193
+ else if (ext === 'ppt' || ext === 'pot' || ext === 'pps' || ext === 'ppa') fileType = 'application/vnd.ms-powerpoint';
194
+ else if (ext === 'pptx') fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
195
+ else if (ext === 'doc' || ext === 'dot') fileType = 'application/msword';
196
+ else if (ext === 'docx') fileType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
197
+ else if (ext === 'xls' || ext === 'xlt' || ext === 'xla') fileType = 'application/vnd.ms-excel';
198
+ else if (ext === 'xlsx') fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
199
+
200
+ return fileType;
201
+ }
202
+
203
+ private combineHeaders(headers: any, isStreaming: boolean) {
204
+ return (isStreaming)
205
+ ? {
206
+ ...headers,
207
+ observe: 'events',
208
+ responseType: 'text',
209
+ reportProgress: true,
210
+ Accept: 'text/event-stream'
211
+ }
212
+ : headers;
213
+ }
214
+ }
@@ -0,0 +1,309 @@
1
+ import { HttpClient, HttpEvent, HttpEventType, HttpHeaderResponse } from '@angular/common/http';
2
+ import { Injectable, inject } from '@angular/core';
3
+ import { BehaviorSubject, Observable, throwError } from 'rxjs';
4
+ import { catchError, delay, finalize, map, tap } from 'rxjs/operators';
5
+
6
+ import { ApiRequest } from '../request-manager-state-service/models/api-request.model';
7
+ import { StreamType } from '../request-manager-state-service/models/stream-type.enum';
8
+ import { PathQueryService, HeadersService } from '../utils';
9
+ import { requestStreaming, StreamConfig } from './rxjs-operators/request-streaming';
10
+ import { WebsocketService } from '../ws-manager-service';
11
+
12
+
13
+ @Injectable({
14
+ providedIn: 'root'
15
+ })
16
+ export class RequestService extends WebsocketService {
17
+
18
+ private http = inject(HttpClient)
19
+
20
+ private pathQueryService = inject(PathQueryService)
21
+ private headersService = inject(HeadersService)
22
+
23
+ isPending = new BehaviorSubject<boolean>(false)
24
+ isPending$ = this.isPending.asObservable()
25
+
26
+ progress = new BehaviorSubject<number>(0)
27
+ progress$ = this.progress.asObservable()
28
+
29
+ getRecordRequest<T>(options: ApiRequest): Observable<T>;
30
+ // Overload for non-streaming requests
31
+ getRecordRequest<T>(options: ApiRequest): Observable<T>;
32
+ // Overload for streaming requests
33
+ getRecordRequest<T>(options: ApiRequest & { stream: true }): Observable<T[]>;
34
+ // Implementation
35
+ getRecordRequest<T>(options: ApiRequest): Observable<any> {
36
+ const urlPath = this.buildUrlPath(options);
37
+ const headers = this.buildCombinedHeaders(options);
38
+
39
+ this.isPending.next(true);
40
+
41
+ return (options.stream)
42
+ ? this.http.get<any>(urlPath, {
43
+ ...headers,
44
+ observe: 'events',
45
+ responseType: 'text',
46
+ reportProgress: true
47
+ }).pipe(
48
+ tap(data => console.log('STREAM DATA', data)),
49
+ requestStreaming({ streamType: options.streamType || StreamType.AI_STREAMING }),
50
+ this.requestStreaming(options),
51
+ this.handleFinalize()
52
+ )
53
+ : this.http.get<T>(urlPath, headers).pipe(
54
+ this.request(options),
55
+ )
56
+ }
57
+
58
+ createRecordRequest<T>(options: ApiRequest, data: any): Observable<T>;
59
+ createRecordRequest<T>(options: ApiRequest & { stream: true }, data: any): Observable<T[]>;
60
+ // Overload for non-streaming requests
61
+ createRecordRequest<T>(options: ApiRequest, data: any): Observable<T>;
62
+ // Overload for streaming requests
63
+ createRecordRequest<T>(options: ApiRequest & { stream: true }, data: any): Observable<T[]>;
64
+ // Implementation
65
+ createRecordRequest<T>(options: ApiRequest, data: any): Observable<any> {
66
+
67
+ const urlPath = this.buildUrlPath(options);
68
+ const headers = this.buildCombinedHeaders(options);
69
+
70
+ this.isPending.next(true);
71
+
72
+ return (options.stream)
73
+ ? this.http.post<any>(urlPath, data, {
74
+ ...headers,
75
+ observe: 'events',
76
+ responseType: 'text',
77
+ reportProgress: true
78
+ }).pipe(
79
+ requestStreaming({ streamType: options.streamType || StreamType.AI_STREAMING }),
80
+ this.requestStreaming(options),
81
+ this.handleFinalize()
82
+ )
83
+ : this.http.post<T>(urlPath, data, headers).pipe(
84
+ this.request(options),
85
+ )
86
+ }
87
+
88
+ updateRecordRequest<T>(options: ApiRequest, data: any): Observable<T> {
89
+ const urlPath = this.buildUrlPath(options);
90
+ const headers = this.buildHeaders(options);
91
+
92
+ this.isPending.next(true);
93
+
94
+ return this.http.put<any>(urlPath, data, headers).pipe(
95
+ this.request(options),
96
+ )
97
+ }
98
+
99
+ deleteRecordRequest<T>(options: ApiRequest): Observable<T> {
100
+
101
+ const urlPath = this.buildUrlPath(options);
102
+ const headers = this.buildHeaders(options);
103
+
104
+ this.isPending.next(true);
105
+
106
+ return this.http.delete<any>(urlPath, headers).pipe(
107
+ this.request(options),
108
+ )
109
+ }
110
+
111
+ // Helper functions
112
+ private buildUrlPath(options: ApiRequest): string {
113
+ return this.pathQueryService.buildAPIPath(options.server, options.path);
114
+ }
115
+
116
+ private buildHeaders(options: ApiRequest): any {
117
+ return this.headersService.generateHeaders(options.headers);
118
+ }
119
+
120
+ private buildCombinedHeaders(options: ApiRequest): any {
121
+ const headers = this.headersService.generateHeaders(options.headers)
122
+ return this.combineHeaders(headers, options.stream || false)
123
+ }
124
+
125
+ private request<T>(options: ApiRequest): (source: Observable<any>) => Observable<T> {
126
+ return (source$: Observable<any>): Observable<T> => {
127
+ return source$.pipe(
128
+ map(data => {
129
+ if (!data || (Array.isArray(data) && data.length === 0)) {
130
+ return data
131
+ }
132
+ if (options?.adapter) {
133
+ return Array.isArray(data)
134
+ ? data.map((item: any) => options.adapter(item))
135
+ : options.adapter(data)
136
+ }
137
+ return data
138
+ })
139
+ )
140
+ }
141
+ }
142
+
143
+ private requestStreaming<T>(options: ApiRequest): (source: Observable<T[]>) => Observable<T[]> {
144
+ return (source$: Observable<T[]>): Observable<T[]> => {
145
+ return source$.pipe(
146
+ map(data => {
147
+ if (!data || (Array.isArray(data) && data.length === 0)) {
148
+ return data
149
+ }
150
+ if (options?.adapter) {
151
+ return data.map((item: any) => options.adapter(item))
152
+ }
153
+ return data
154
+ })
155
+ )
156
+ }
157
+ }
158
+
159
+ downloadFileRequest(options: ApiRequest): Observable<any> {
160
+
161
+ this.isPending.next(true);
162
+
163
+ const urlPath = this.buildUrlPath(options);
164
+
165
+ return this.http.get(urlPath, { responseType: 'blob', observe: 'events', reportProgress: true })
166
+ .pipe(
167
+ map((event: HttpEvent<any>) => {
168
+
169
+ this.isPending.next(true)
170
+
171
+ if (event instanceof HttpHeaderResponse) {
172
+ if(event.status !== 200) {
173
+ this.isPending.next(false)
174
+ throw new Error('Download failed');
175
+ }
176
+ }
177
+
178
+ // 0 Sent Request has been sent.
179
+ // 1 UploadProgress Upload is in progress.
180
+ // 2 ResponseHeader Response headers received.
181
+ // 3 DownloadProgress Download is in progress.
182
+ // 4 Response Response is fully received.
183
+ // 5 User Custom user event.
184
+
185
+ switch (event.type) {
186
+
187
+ case HttpEventType.DownloadProgress:
188
+
189
+ const status = (event.total) ? Math.round(event.loaded / (event.total || 1) * 100) : 100
190
+ this.progress.next(status)
191
+ return status
192
+
193
+ case HttpEventType.Response:
194
+
195
+ try {
196
+
197
+ const fileNamePath = (options?.saveAs) ? options.saveAs : (options.path) ? options.path[options.path.length - 1] : []
198
+ const fileContentHeader = options.fileContentHeader || 'Content-Disposition'
199
+ const header_content = event.headers.get(fileContentHeader);
200
+
201
+ // checks if header_content is not empty and splits the header_content to get the file name
202
+ // otherwise, it will use the fileDownload - contains the file name and extension
203
+ const file = (header_content) ? header_content.split('=')[1].substring(0, header_content.split('=')[1].length) : ''
204
+
205
+ const fileName = (file) ? file : fileNamePath
206
+
207
+ if (fileName === '') {
208
+ this.isPending.next(false);
209
+ throw new Error('Save File: (file name and extension) not found in Headers or Path');
210
+ }
211
+
212
+ this.downloadFile(fileName, event.body)
213
+ this.isPending.next(false)
214
+
215
+ return 100
216
+
217
+ } catch (error) {
218
+ throw new Error('Download failed');
219
+ }
220
+
221
+ default:
222
+ this.isPending.next(false)
223
+ return 0
224
+ }
225
+
226
+ }),
227
+ catchError(err => {
228
+ return throwError(() => err)
229
+ })
230
+ )
231
+ }
232
+
233
+ private handleFinalize(): (source: Observable<any>) => Observable<any> {
234
+ return finalize(() => this.isPending.next(false));
235
+ }
236
+
237
+ private downloadFile(file:string, fileData: any) {
238
+
239
+ const navigatorAny = window.navigator as any
240
+
241
+ const extension = file.split('.')[1].toLowerCase()
242
+
243
+ var newBlob = new Blob([fileData], { type: this.createFileType(extension) })
244
+
245
+ if (navigatorAny.msSaveOrOpenBlob) {
246
+ navigatorAny.msSaveOrOpenBlob(newBlob, file)
247
+ } else {
248
+ const link = document.createElement('a')
249
+ const url = window.URL.createObjectURL(newBlob)
250
+ link.href = url
251
+ link.download = file
252
+ link.click()
253
+ window.URL.revokeObjectURL(url)
254
+ }
255
+
256
+ }
257
+
258
+ private createFileType(ext: any): string {
259
+
260
+ let fileType: string = ""
261
+
262
+ if (ext == 'pdf' || ext == 'csv') {
263
+ fileType = `application/${ext}`
264
+ }
265
+ else if (ext == 'jpeg' || ext == 'jpg' || ext == 'png') {
266
+ fileType = `image/${ext}`
267
+ }
268
+ else if (ext == 'txt') {
269
+ fileType = 'text/plain'
270
+ }
271
+
272
+ else if (ext == 'ppt' || ext == 'pot' || ext == 'pps' || ext == 'ppa') {
273
+ fileType = 'application/vnd.ms-powerpoint'
274
+ }
275
+ else if (ext == 'pptx') {
276
+ fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
277
+ }
278
+ else if (ext == 'doc' || ext == 'dot') {
279
+ fileType = 'application/msword'
280
+ }
281
+ else if (ext == 'docx') {
282
+ fileType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
283
+ }
284
+ else if (ext == 'xls' || ext == 'xlt' || ext == 'xla') {
285
+ fileType = 'application/vnd.ms-excel'
286
+ }
287
+ else if (ext == 'xlsx') {
288
+ fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
289
+ }
290
+
291
+ return fileType
292
+
293
+ }
294
+
295
+ private combineHeaders(headers: any, isStreaming: boolean) {
296
+
297
+ return (isStreaming) ?
298
+ {
299
+ ...headers,
300
+ observe: 'events',
301
+ responseType: 'text',
302
+ reportProgress: true,
303
+ Accept: 'text/event-stream'
304
+ }
305
+ : headers
306
+
307
+ }
308
+
309
+ }
@@ -0,0 +1,17 @@
1
+ import { Observable, defer, interval } from 'rxjs';
2
+ import { takeWhile, map, tap } from 'rxjs/operators';
3
+
4
+ export function countdown(duration: number): Observable<number> {
5
+
6
+ return defer(() => {
7
+
8
+ const currentCount = { current: duration }
9
+
10
+ return interval(1000).pipe(
11
+ map(() => --currentCount.current),
12
+ takeWhile(count => count >= 0)
13
+ )
14
+
15
+ })
16
+
17
+ }
@@ -0,0 +1,16 @@
1
+ import { Observable, timer } from 'rxjs';
2
+ import { retry } from 'rxjs/operators';
3
+
4
+ const DEFAULT_MAX_RETRIES = 3;
5
+
6
+ export function delayedRetry<T>(delayMs: number, maxRetry = DEFAULT_MAX_RETRIES) {
7
+ return (src: Observable<T>) =>
8
+ src.pipe(
9
+ retry({
10
+ count: maxRetry,
11
+ delay: () => timer(delayMs)
12
+ })
13
+ );
14
+ }
15
+
16
+
@@ -0,0 +1,4 @@
1
+ export * from "./countdown";
2
+ export * from "./delay-retry";
3
+ export * from "./request-polling";
4
+ export * from "./request-streaming";
@@ -0,0 +1,35 @@
1
+ import { Observable, interval } from 'rxjs';
2
+ import { mergeMap, startWith, takeUntil, tap } from 'rxjs/operators';
3
+
4
+ export function requestPolling<T>(pollInterval: number, stopCondition$: Observable<any>, isPending$: any) {
5
+ return (source: Observable<T>): Observable<T> => {
6
+ return interval(pollInterval * 1000)
7
+ .pipe(
8
+ startWith(0),
9
+ tap(() => {
10
+ try {
11
+ if (isPending$ && typeof isPending$.next === 'function') {
12
+ isPending$.next(true);
13
+ } else if (isPending$ && typeof isPending$.set === 'function') {
14
+ isPending$.set(true);
15
+ }
16
+ } catch (e) {
17
+ // no-op if setting fails
18
+ }
19
+ }),
20
+ mergeMap(() => source),
21
+ tap(() => {
22
+ try {
23
+ if (isPending$ && typeof isPending$.next === 'function') {
24
+ isPending$.next(false);
25
+ } else if (isPending$ && typeof isPending$.set === 'function') {
26
+ isPending$.set(false);
27
+ }
28
+ } catch (e) {
29
+ // no-op if setting fails
30
+ }
31
+ }),
32
+ takeUntil(stopCondition$),
33
+ );
34
+ };
35
+ }