http-request-manager 18.15.32 → 18.15.34

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 (301) hide show
  1. package/README.md +2 -0
  2. package/TEST_COVERAGE_SUMMARY.md +458 -0
  3. package/ng-package.json +8 -0
  4. package/package.json +5 -13
  5. package/src/docs/ADVANCED_WEBSOCKET.md +633 -0
  6. package/src/docs/ARCHITECTURE.md +633 -0
  7. package/src/docs/BATCH_REQUEST_README.md +467 -0
  8. package/src/docs/COMPLETE_API_REFERENCE.md +1037 -0
  9. package/src/docs/DATABASE_README.md +1195 -0
  10. package/src/docs/ENCRYPTION_README.md +403 -0
  11. package/src/docs/HTTP_MANAGER_README.md +628 -0
  12. package/src/docs/HTTP_SINGNALS_MANAGER_README.md +654 -0
  13. package/src/docs/HTTP_STATE_MANAGER_README.md +1391 -0
  14. package/src/docs/INTERCEPTOR_README.md +549 -0
  15. package/src/docs/LOCAL_STORAGE_README.md +1056 -0
  16. package/src/docs/LOCAL_STORAGE_SIGNALS_README.md +338 -0
  17. package/src/docs/LOGGER_README.md +310 -0
  18. package/src/docs/MESSAGE_TRACKER_README.md +518 -0
  19. package/src/docs/MESSAGE_TRACKER_SIGNALS_README.md +563 -0
  20. package/src/docs/MODELS_README.md +1264 -0
  21. package/src/docs/SIGNAL_SERVICES_README.md +238 -0
  22. package/src/docs/SQL_DIXIE_README.md +574 -0
  23. package/src/docs/STORE_STATE_MANAGER_README.md +556 -0
  24. package/src/docs/STORE_STATE_SIGNALS_README.md +600 -0
  25. package/src/docs/UPLOAD_REQUEST_README.md +324 -0
  26. package/src/docs/UTILS_README.md +1604 -0
  27. package/src/docs/WEBSOCKET_MESSAGE_SERVICE.md +799 -0
  28. package/src/docs/WEBSOCKET_SIGNALS_README.md +641 -0
  29. package/src/docs/WEBSOCKET_SINGLETON_REFACTORING.md +201 -0
  30. package/src/docs/WS_MANAGER_README.md +613 -0
  31. package/src/lib/http-request-manager.module.ts +147 -0
  32. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.html +116 -0
  33. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.scss +0 -0
  34. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.ts +255 -0
  35. package/src/lib/http-request-services-demo/http-request-services-demo.component.html +123 -0
  36. package/src/lib/http-request-services-demo/http-request-services-demo.component.scss +6 -0
  37. package/src/lib/http-request-services-demo/http-request-services-demo.component.ts +53 -0
  38. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.html +195 -0
  39. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.scss +17 -0
  40. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.ts +208 -0
  41. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.html +200 -0
  42. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.scss +17 -0
  43. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.ts +214 -0
  44. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.html +53 -0
  45. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.scss +60 -0
  46. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.ts +72 -0
  47. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-download.module.ts +28 -0
  48. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.html +10 -0
  49. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.scss +29 -0
  50. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.ts +100 -0
  51. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/models/download-labels-model.ts +22 -0
  52. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.html +8 -0
  53. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.scss +19 -0
  54. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.ts +26 -0
  55. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/app-session.model.ts +30 -0
  56. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/app.model.ts +19 -0
  57. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/get-sample.model.ts +25 -0
  58. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-ai-prompt.ts +19 -0
  59. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client-details.ts +24 -0
  60. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client-info.ts +30 -0
  61. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client.model.ts +49 -0
  62. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-mapper-client-info.ts +33 -0
  63. package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.html +279 -0
  64. package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.scss +24 -0
  65. package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.ts +461 -0
  66. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
  67. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
  68. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
  69. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.ts +28 -0
  70. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.html +10 -0
  71. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.scss +29 -0
  72. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.ts +100 -0
  73. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
  74. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
  75. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
  76. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
  77. package/src/lib/http-request-services-demo/request-manager-demo/models/app-session.model.ts +30 -0
  78. package/src/lib/http-request-services-demo/request-manager-demo/models/app.model.ts +19 -0
  79. package/src/lib/http-request-services-demo/request-manager-demo/models/get-sample.model.ts +25 -0
  80. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.ts +19 -0
  81. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-details.ts +24 -0
  82. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.ts +30 -0
  83. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client.model.ts +49 -0
  84. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.ts +33 -0
  85. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.html +622 -0
  86. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.scss +106 -0
  87. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.ts +687 -0
  88. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.html +418 -0
  89. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.scss +24 -0
  90. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.ts +576 -0
  91. package/src/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.ts +89 -0
  92. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/services/state-data-request.service.ts +119 -0
  93. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.css +0 -0
  94. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.html +3 -0
  95. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.ts +16 -0
  96. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.css +0 -0
  97. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.html +3 -0
  98. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.ts +16 -0
  99. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.css +31 -0
  100. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.html +94 -0
  101. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.scss +41 -0
  102. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.spec.ts +203 -0
  103. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.ts +144 -0
  104. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.css +11 -0
  105. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.html +102 -0
  106. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.spec.ts +40 -0
  107. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.ts +230 -0
  108. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.css +30 -0
  109. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.html +172 -0
  110. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.spec.ts +31 -0
  111. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.ts +239 -0
  112. package/src/lib/http-request-services-demo/request-manager-ws-demo/models/oidc-client.model.ts +31 -0
  113. package/src/lib/http-request-services-demo/request-manager-ws-demo/models/user-data.model.ts +32 -0
  114. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.css +0 -0
  115. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.html +84 -0
  116. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.ts +40 -0
  117. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/index.ts +3 -0
  118. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/jwt-token.service.ts +62 -0
  119. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/message-service-demo.service.ts +83 -0
  120. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/notification-service-demo.service.ts +147 -0
  121. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/state-service-demo.service.ts +168 -0
  122. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
  123. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
  124. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
  125. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-download.module.ts +28 -0
  126. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.html +10 -0
  127. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.scss +29 -0
  128. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.ts +100 -0
  129. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
  130. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
  131. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
  132. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
  133. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app-session.model.ts +30 -0
  134. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app.model.ts +19 -0
  135. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/get-sample.model.ts +25 -0
  136. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.ts +19 -0
  137. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-details.ts +24 -0
  138. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.ts +30 -0
  139. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client.model.ts +49 -0
  140. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.ts +33 -0
  141. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.html +380 -0
  142. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.scss +24 -0
  143. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.ts +410 -0
  144. package/src/lib/http-request-services-demo/store-state-manager-demo/models/settings.model.ts +28 -0
  145. package/src/lib/http-request-services-demo/store-state-manager-demo/services/settings-state.service.ts +49 -0
  146. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.css +0 -0
  147. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.html +23 -0
  148. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.ts +36 -0
  149. package/src/lib/http-request-services-demo/store-state-signals-demo/store-state-signals-demo.component.ts +161 -0
  150. package/src/lib/http-request-services-demo/upload-demo/models/index.ts +1 -0
  151. package/src/lib/http-request-services-demo/upload-demo/models/upload-state.model.ts +30 -0
  152. package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.html +89 -0
  153. package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.scss +160 -0
  154. package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.spec.ts +101 -0
  155. package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.ts +136 -0
  156. package/src/lib/index.ts +3 -0
  157. package/src/lib/interceptors/credentials.interceptor.ts +16 -0
  158. package/src/lib/interceptors/index.ts +6 -0
  159. package/src/lib/interceptors/models/error-settings.model.ts +22 -0
  160. package/src/lib/interceptors/models/index.ts +2 -0
  161. package/src/lib/interceptors/proxy-debugger.interceptor.ts +46 -0
  162. package/src/lib/interceptors/request-error.interceptor.ts +65 -0
  163. package/src/lib/interceptors/request-header.interceptor.ts +56 -0
  164. package/src/lib/message-display/README.md +509 -0
  165. package/src/lib/message-display/index.ts +4 -0
  166. package/src/lib/message-display/models/action.model.ts +27 -0
  167. package/src/lib/message-display/models/communication-message.model.ts +77 -0
  168. package/src/lib/message-display/models/display-config.model.ts +35 -0
  169. package/src/lib/message-display/models/display-rule.interface.ts +28 -0
  170. package/src/lib/message-display/models/display-strategy.interface.ts +8 -0
  171. package/src/lib/message-display/models/index.ts +6 -0
  172. package/src/lib/message-display/models/slide.model.ts +24 -0
  173. package/src/lib/message-display/rules/default-display-rules.ts +35 -0
  174. package/src/lib/message-display/services/message-display-router.service.ts +63 -0
  175. package/src/lib/message-display/strategies/snackbar.strategy.ts +46 -0
  176. package/src/lib/models/batch-options.model.ts +33 -0
  177. package/src/lib/models/batch-progress.model.ts +19 -0
  178. package/src/lib/models/batch-request-state.model.ts +40 -0
  179. package/src/lib/models/batch-result.model.ts +30 -0
  180. package/src/lib/models/config-http-options.model.ts +45 -0
  181. package/src/lib/models/config-local-storage-options.model.ts +27 -0
  182. package/src/lib/models/config-options.model.ts +27 -0
  183. package/src/lib/models/config-token.model.ts +9 -0
  184. package/src/lib/models/data-type.enum.ts +5 -0
  185. package/src/lib/models/database-storage.model.ts +24 -0
  186. package/src/lib/models/index.ts +16 -0
  187. package/src/lib/models/retry-options.model.ts +22 -0
  188. package/src/lib/models/upload-validation-error.model.ts +46 -0
  189. package/src/lib/services/SQL-DixieJS service/dexie-query-executor.ts +246 -0
  190. package/src/lib/services/SQL-DixieJS service/dexie-sql.service.ts +31 -0
  191. package/src/lib/services/SQL-DixieJS service/index.ts +4 -0
  192. package/src/lib/services/SQL-DixieJS service/models/execution-plan.model.ts +52 -0
  193. package/src/lib/services/SQL-DixieJS service/models/index.ts +3 -0
  194. package/src/lib/services/SQL-DixieJS service/models/sql-errors.model.ts +13 -0
  195. package/src/lib/services/SQL-DixieJS service/models/sql-options.model.ts +3 -0
  196. package/src/lib/services/SQL-DixieJS service/query-planner.ts +284 -0
  197. package/src/lib/services/SQL-DixieJS service/schema-validator.ts +217 -0
  198. package/src/lib/services/SQL-DixieJS service/sql-parser.ts +35 -0
  199. package/src/lib/services/database-manager-service/database.manager.service.ts +384 -0
  200. package/src/lib/services/database-manager-service/db.storage.service.ts +240 -0
  201. package/src/lib/services/database-manager-service/index.ts +4 -0
  202. package/src/lib/services/database-manager-service/models/index.ts +2 -0
  203. package/src/lib/services/database-manager-service/models/table-schema.ts +33 -0
  204. package/src/lib/services/index.ts +20 -0
  205. package/src/lib/services/local-storage-manager-service/index.ts +4 -0
  206. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.spec.ts +71 -0
  207. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.ts +567 -0
  208. package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.spec.ts +67 -0
  209. package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.ts +437 -0
  210. package/src/lib/services/local-storage-manager-service/models/global-store-options.model.ts +30 -0
  211. package/src/lib/services/local-storage-manager-service/models/index.ts +6 -0
  212. package/src/lib/services/local-storage-manager-service/models/setting-options.model.ts +35 -0
  213. package/src/lib/services/local-storage-manager-service/models/storage-data.model.ts +24 -0
  214. package/src/lib/services/local-storage-manager-service/models/storage-option.model.ts +32 -0
  215. package/src/lib/services/local-storage-manager-service/models/storage-type.enum.ts +5 -0
  216. package/src/lib/services/request-manager-services/README.md +282 -0
  217. package/src/lib/services/request-manager-services/http-manager-signals.service.ts +674 -0
  218. package/src/lib/services/request-manager-services/http-manager.service.spec.ts +353 -0
  219. package/src/lib/services/request-manager-services/http-manager.service.ts +727 -0
  220. package/src/lib/services/request-manager-services/index.ts +8 -0
  221. package/src/lib/services/request-manager-services/request-signals.service.ts +372 -0
  222. package/src/lib/services/request-manager-services/request.service.ts +435 -0
  223. package/src/lib/services/request-manager-services/rxjs-operators/countdown.ts +17 -0
  224. package/src/lib/services/request-manager-services/rxjs-operators/delay-retry.ts +16 -0
  225. package/src/lib/services/request-manager-services/rxjs-operators/index.ts +4 -0
  226. package/src/lib/services/request-manager-services/rxjs-operators/request-polling.ts +35 -0
  227. package/src/lib/services/request-manager-services/rxjs-operators/request-streaming.ts +468 -0
  228. package/src/lib/services/request-manager-state-service/http-manager-state.store.spec.ts +665 -0
  229. package/src/lib/services/request-manager-state-service/http-manager-state.store.ts +2395 -0
  230. package/src/lib/services/request-manager-state-service/index.ts +3 -0
  231. package/src/lib/services/request-manager-state-service/models/api-request.model.ts +86 -0
  232. package/src/lib/services/request-manager-state-service/models/index.ts +14 -0
  233. package/src/lib/services/request-manager-state-service/models/operation-result.model.ts +18 -0
  234. package/src/lib/services/request-manager-state-service/models/parsing-result.model.ts +21 -0
  235. package/src/lib/services/request-manager-state-service/models/request-options.model.ts +37 -0
  236. package/src/lib/services/request-manager-state-service/models/stream-config.model.ts +20 -0
  237. package/src/lib/services/request-manager-state-service/models/stream-event-metadata.model.ts +23 -0
  238. package/src/lib/services/request-manager-state-service/models/stream-event.model.ts +23 -0
  239. package/src/lib/services/request-manager-state-service/models/stream-output.model.ts +23 -0
  240. package/src/lib/services/request-manager-state-service/models/stream-progress.model.ts +24 -0
  241. package/src/lib/services/request-manager-state-service/models/stream-type.enum.ts +13 -0
  242. package/src/lib/services/request-manager-state-service/models/ws-options.model.ts +42 -0
  243. package/src/lib/services/store-state-manager-service/index.ts +4 -0
  244. package/src/lib/services/store-state-manager-service/models/index.ts +3 -0
  245. package/src/lib/services/store-state-manager-service/models/state-operation-result.model.ts +30 -0
  246. package/src/lib/services/store-state-manager-service/models/state-storage-options.model.ts +24 -0
  247. package/src/lib/services/store-state-manager-service/store-state-manager-signals.service.ts +169 -0
  248. package/src/lib/services/store-state-manager-service/store-state-manager.service.ts +153 -0
  249. package/src/lib/services/utils/app.service.spec.ts +25 -0
  250. package/src/lib/services/utils/app.service.ts +21 -0
  251. package/src/lib/services/utils/encryption/README.md +79 -0
  252. package/src/lib/services/utils/encryption/asymmetrical-encryption.service.ts +282 -0
  253. package/src/lib/services/utils/encryption/encryption-test.service.ts +39 -0
  254. package/src/lib/services/utils/encryption/index.ts +5 -0
  255. package/src/lib/services/utils/encryption/random.ts +81 -0
  256. package/src/lib/services/utils/encryption/symmetrical-encryption.service.ts +106 -0
  257. package/src/lib/services/utils/headers.service.spec.ts +80 -0
  258. package/src/lib/services/utils/headers.service.ts +18 -0
  259. package/src/lib/services/utils/index.ts +9 -0
  260. package/src/lib/services/utils/logger.service.ts +90 -0
  261. package/src/lib/services/utils/models/index.ts +4 -0
  262. package/src/lib/services/utils/models/normalized-request-options.model.ts +24 -0
  263. package/src/lib/services/utils/models/path-tracker-state.model.ts +20 -0
  264. package/src/lib/services/utils/models/query-params-tracker-options.model.ts +24 -0
  265. package/src/lib/services/utils/models/query-tracker-state.model.ts +23 -0
  266. package/src/lib/services/utils/object-merger.service.spec.ts +18 -0
  267. package/src/lib/services/utils/object-merger.service.ts +78 -0
  268. package/src/lib/services/utils/path-query.service.spec.ts +117 -0
  269. package/src/lib/services/utils/path-query.service.ts +69 -0
  270. package/src/lib/services/utils/query-params-tracker.service.ts +442 -0
  271. package/src/lib/services/utils/random-color.utils.ts +83 -0
  272. package/src/lib/services/utils/utils.service.spec.ts +165 -0
  273. package/src/lib/services/utils/utils.service.ts +192 -0
  274. package/src/lib/services/ws-manager-service/index.ts +13 -0
  275. package/src/lib/services/ws-manager-service/message-tracker-signals.service.ts +147 -0
  276. package/src/lib/services/ws-manager-service/message-tracker.service.ts +477 -0
  277. package/src/lib/services/ws-manager-service/models/channel-info.model.ts +29 -0
  278. package/src/lib/services/ws-manager-service/models/channel-message-data.model.ts +24 -0
  279. package/src/lib/services/ws-manager-service/models/channel-message.model.ts +36 -0
  280. package/src/lib/services/ws-manager-service/models/channel-type.enum.ts +6 -0
  281. package/src/lib/services/ws-manager-service/models/communication-type.enum.ts +5 -0
  282. package/src/lib/services/ws-manager-service/models/index.ts +10 -0
  283. package/src/lib/services/ws-manager-service/models/notification-message.model.ts +29 -0
  284. package/src/lib/services/ws-manager-service/models/public-message.model.ts +18 -0
  285. package/src/lib/services/ws-manager-service/models/state-message.model.ts +18 -0
  286. package/src/lib/services/ws-manager-service/models/ws-user.model.ts +38 -0
  287. package/src/lib/services/ws-manager-service/services/index.ts +4 -0
  288. package/src/lib/services/ws-manager-service/services/websocket-message.service.ts +129 -0
  289. package/src/lib/services/ws-manager-service/services/websocket.service.ts +434 -0
  290. package/src/lib/services/ws-manager-service/websocket-service/index.ts +1 -0
  291. package/src/lib/services/ws-manager-service/websocket-service/websocket-manager.service.ts +716 -0
  292. package/src/lib/services/ws-manager-service/websocket-services-complete.spec.ts +596 -0
  293. package/src/lib/services/ws-manager-service/websocket-signals-manager.service.ts +141 -0
  294. package/src/public-api.ts +19 -0
  295. package/tsconfig.lib.json +34 -0
  296. package/tsconfig.lib.prod.json +10 -0
  297. package/tsconfig.spec.json +14 -0
  298. package/fesm2022/http-request-manager.mjs +0 -13297
  299. package/fesm2022/http-request-manager.mjs.map +0 -1
  300. package/http-request-manager-18.15.32.tgz +0 -0
  301. package/types/http-request-manager.d.ts +0 -3875
@@ -0,0 +1,665 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { BehaviorSubject, of } from 'rxjs';
3
+
4
+ import { DataType } from '../../models/data-type.enum';
5
+ import { DatabaseStorage } from '../../models/database-storage.model';
6
+ import { DatabaseManagerService } from '../database-manager-service';
7
+ import { HTTPManagerService } from '../request-manager-services';
8
+ import { LocalStorageManagerService } from '../local-storage-manager-service';
9
+ import { LoggerService } from '../../services/utils/logger.service';
10
+ import { UtilsService } from '../..';
11
+ import { HTTPManagerStateService } from './http-manager-state.store';
12
+ import { ApiRequest, RequestOptions } from './models';
13
+
14
+ class MockLocalStorageManagerService {
15
+ private stores: Record<string, any> = {};
16
+
17
+ private normalizeStoreName(name: string): string {
18
+ return String(name).trim().toLowerCase().replace(/\s+/g, '_');
19
+ }
20
+
21
+ createStore(store: { name: string; data: any }): void {
22
+ this.stores[this.normalizeStoreName(store.name)] = store.data;
23
+ }
24
+
25
+ updateStore(store: { name: string; data: any }): void {
26
+ const key = this.normalizeStoreName(store.name);
27
+ this.stores[key] = { ...(this.stores[key] || {}), ...store.data };
28
+ }
29
+
30
+ store$(name: string) {
31
+ const value = this.stores[this.normalizeStoreName(name)];
32
+ return of(typeof value === 'undefined' ? null : value);
33
+ }
34
+ }
35
+
36
+ class MockLocalStorageManagerWithTracker {
37
+ stores: Record<string, any> = {};
38
+
39
+ private normalizeStoreName(name: string): string {
40
+ return String(name).trim().toLowerCase().replace(/\s+/g, '_');
41
+ }
42
+
43
+ createStore(store: { name: string; data: any; options?: any }): void {
44
+ const key = this.normalizeStoreName(store.name);
45
+ if (key in this.stores) return; // no-op if already exists — mirrors real LocalStorageManagerService behaviour
46
+ this.stores[key] = store.data;
47
+ }
48
+
49
+ updateStore(store: { name: string; data: any }): void {
50
+ const key = this.normalizeStoreName(store.name);
51
+ this.stores[key] = { ...(this.stores[key] || {}), ...store.data };
52
+ }
53
+
54
+ store$(name: string) {
55
+ const value = this.stores[this.normalizeStoreName(name)];
56
+ return of(typeof value === 'undefined' ? null : value);
57
+ }
58
+
59
+ storeExists$(name: string) {
60
+ const key = this.normalizeStoreName(name);
61
+ return of(key in this.stores);
62
+ }
63
+
64
+ deleteStore(store: { name: string }): void {
65
+ const key = this.normalizeStoreName(store.name);
66
+ delete this.stores[key];
67
+ }
68
+ }
69
+
70
+ describe('HTTPManagerStateService requestCache.queryParams DB gating', () => {
71
+ let service: HTTPManagerStateService<any>;
72
+ let httpManagerService: jasmine.SpyObj<HTTPManagerService<any>>;
73
+ let dbManagerService: jasmine.SpyObj<DatabaseManagerService>;
74
+
75
+ beforeEach(() => {
76
+ httpManagerService = jasmine.createSpyObj<HTTPManagerService<any>>(
77
+ 'HTTPManagerService',
78
+ [
79
+ 'getRequest',
80
+ 'connect',
81
+ 'subscribeToChannel',
82
+ 'sendMessageInChannel',
83
+ ],
84
+ {
85
+ error$: of(false),
86
+ isPending$: of(false),
87
+ isPending: new BehaviorSubject<boolean>(false),
88
+ connectionStatus$: of(false),
89
+ messages$: of(null),
90
+ subscribedChannels$: of(new Set<string>()),
91
+ }
92
+ );
93
+
94
+ dbManagerService = jasmine.createSpyObj<DatabaseManagerService>('DatabaseManagerService', [
95
+ 'createDatabaseTable',
96
+ 'databaseExists',
97
+ 'hasDatabaseTable',
98
+ 'getTableRecords',
99
+ 'clearTable',
100
+ 'createTableRecords',
101
+ ]);
102
+
103
+ httpManagerService.getRequest.and.returnValue(of([{ id: 99, name: 'api' }]));
104
+
105
+ dbManagerService.createDatabaseTable.and.returnValue(of(true));
106
+ dbManagerService.databaseExists.and.returnValue(of(true));
107
+ dbManagerService.hasDatabaseTable.and.returnValue(of(true));
108
+ dbManagerService.getTableRecords.and.returnValue(of([{ id: 1, name: 'db' }]));
109
+ dbManagerService.clearTable.and.returnValue(of([]) as any);
110
+ dbManagerService.createTableRecords.and.returnValue(of([]) as any);
111
+
112
+ TestBed.configureTestingModule({
113
+ providers: [
114
+ { provide: HTTPManagerService, useValue: httpManagerService },
115
+ { provide: DatabaseManagerService, useValue: dbManagerService },
116
+ { provide: LocalStorageManagerService, useClass: MockLocalStorageManagerService },
117
+ {
118
+ provide: UtilsService,
119
+ useValue: {
120
+ expires: () => Math.floor(Date.now() / 1000) + 3600,
121
+ hasExpired: () => false,
122
+ }
123
+ },
124
+ {
125
+ provide: LoggerService,
126
+ useValue: {
127
+ debug: () => undefined,
128
+ info: () => undefined,
129
+ warn: () => undefined,
130
+ error: () => undefined,
131
+ }
132
+ },
133
+ {
134
+ provide: HTTPManagerStateService,
135
+ useFactory: () => new HTTPManagerStateService(
136
+ ApiRequest.adapt({ server: 'http://localhost', path: ['oidc', 'api'] }),
137
+ DataType.ARRAY,
138
+ DatabaseStorage.adapt({ table: 'state_table', expiresIn: '1d' })
139
+ ),
140
+ },
141
+ ]
142
+ });
143
+
144
+ service = TestBed.inject(HTTPManagerStateService);
145
+ });
146
+
147
+ it('should preserve existing store properties (e.g. schema signature) after updateStore call', () => {
148
+ const localStorageMock = TestBed.inject(LocalStorageManagerService) as any;
149
+ const tableName = 'state_table';
150
+ const key = tableName.trim().toLowerCase().replace(/\s+/g, '_');
151
+
152
+ localStorageMock['stores'][key] = { schemaSignature: 'abc123', someOtherProp: 'preserved' };
153
+
154
+ service.fetchRecords(RequestOptions.adapt({ path: [{ page: 1, size: 10 }] }));
155
+
156
+ const stored = localStorageMock['stores'][key];
157
+ expect(stored['schemaSignature']).toBeDefined();
158
+ expect(stored['someOtherProp']).toBe('preserved');
159
+ });
160
+
161
+ it('should skip API for GET when requestCache.GET.queryParams already has the param value', () => {
162
+ const localStorageMock = TestBed.inject(LocalStorageManagerService) as any;
163
+ const key = 'state_table';
164
+ localStorageMock['stores'][key] = {
165
+ requestCache: {
166
+ GET: {
167
+ signature: 'sig',
168
+ savedAt: Date.now(),
169
+ path: [{ page: 1, size: 35 }],
170
+ headers: {},
171
+ queryParams: { page: ['1'], size: ['35'] },
172
+ queryParamsExpires: null,
173
+ }
174
+ }
175
+ };
176
+
177
+ service.fetchRecords(RequestOptions.adapt({ path: [{ page: 1, size: 35 }] }));
178
+
179
+ expect(httpManagerService.getRequest).not.toHaveBeenCalled();
180
+ });
181
+
182
+ it('should call API for GET when requestCache.GET.queryParams has no entry for the path query', () => {
183
+ service.fetchRecords(RequestOptions.adapt({ path: [{ page: 2, size: 35 }] }));
184
+
185
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
186
+ });
187
+
188
+ it('should skip API for STREAM when requestCache.STREAM.queryParams already has the param value', () => {
189
+ const localStorageMock = TestBed.inject(LocalStorageManagerService) as any;
190
+ const key = 'state_table';
191
+ localStorageMock['stores'][key] = {
192
+ requestCache: {
193
+ STREAM: {
194
+ signature: 'sig',
195
+ savedAt: Date.now(),
196
+ path: [{ page: 1 }],
197
+ headers: {},
198
+ queryParams: { page: ['1'] },
199
+ queryParamsExpires: null,
200
+ }
201
+ }
202
+ };
203
+
204
+ service.fetchStream(RequestOptions.adapt({ path: [{ page: 1 }] }));
205
+
206
+ expect(httpManagerService.getRequest).not.toHaveBeenCalled();
207
+ });
208
+
209
+ it('should call API for STREAM when requestCache.STREAM.queryParams has no entry for the path query', () => {
210
+ service.fetchStream(RequestOptions.adapt({ path: [{ page: 2 }] }));
211
+
212
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
213
+ });
214
+
215
+ it('should call API for GET without database configured regardless of query params', () => {
216
+ httpManagerService.getRequest.calls.reset();
217
+
218
+ const noDbService = TestBed.runInInjectionContext(() => new HTTPManagerStateService(
219
+ ApiRequest.adapt({ server: 'http://localhost', path: ['ai', 'pagination'] }),
220
+ DataType.ARRAY,
221
+ undefined
222
+ ));
223
+
224
+ noDbService.fetchRecords(RequestOptions.adapt({
225
+ path: ['ai/pagination?page=0&size=25'],
226
+ }));
227
+
228
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
229
+ });
230
+
231
+ it('should call API for STREAM without database configured regardless of query params', () => {
232
+ httpManagerService.getRequest.calls.reset();
233
+
234
+ const noDbService = TestBed.runInInjectionContext(() => new HTTPManagerStateService(
235
+ ApiRequest.adapt({ server: 'http://localhost', path: ['ai', 'pagination'] }),
236
+ DataType.ARRAY,
237
+ undefined
238
+ ));
239
+
240
+ noDbService.fetchStream(RequestOptions.adapt({
241
+ path: ['ai/pagination?page=0&size=25'],
242
+ }));
243
+
244
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
245
+ });
246
+ });
247
+
248
+ describe('HTTPManagerStateService tracker refresh race condition', () => {
249
+ let service: HTTPManagerStateService<any>;
250
+ let httpManagerService: jasmine.SpyObj<HTTPManagerService<any>>;
251
+ let dbManagerService: jasmine.SpyObj<DatabaseManagerService>;
252
+ let localStorageManager: MockLocalStorageManagerWithTracker;
253
+
254
+ beforeEach(() => {
255
+ httpManagerService = jasmine.createSpyObj<HTTPManagerService<any>>(
256
+ 'HTTPManagerService',
257
+ [
258
+ 'getRequest',
259
+ 'connect',
260
+ 'subscribeToChannel',
261
+ 'sendMessageInChannel',
262
+ ],
263
+ {
264
+ error$: of(false),
265
+ isPending$: of(false),
266
+ isPending: new BehaviorSubject<boolean>(false),
267
+ connectionStatus$: of(false),
268
+ messages$: of(null),
269
+ subscribedChannels$: of(new Set<string>()),
270
+ }
271
+ );
272
+
273
+ dbManagerService = jasmine.createSpyObj<DatabaseManagerService>('DatabaseManagerService', [
274
+ 'createDatabaseTable',
275
+ 'databaseExists',
276
+ 'hasDatabaseTable',
277
+ 'getTableRecords',
278
+ 'clearTable',
279
+ 'createTableRecords',
280
+ ]);
281
+
282
+ httpManagerService.getRequest.and.returnValue(of([{ id: 99, name: 'api' }]));
283
+
284
+ dbManagerService.createDatabaseTable.and.returnValue(of(true));
285
+ dbManagerService.databaseExists.and.returnValue(of(true));
286
+ dbManagerService.hasDatabaseTable.and.returnValue(of(true));
287
+ dbManagerService.getTableRecords.and.returnValue(of([{ id: 1, name: 'db' }]));
288
+ dbManagerService.clearTable.and.returnValue(of([]) as any);
289
+ dbManagerService.createTableRecords.and.returnValue(of([]) as any);
290
+
291
+ localStorageManager = new MockLocalStorageManagerWithTracker();
292
+
293
+ TestBed.configureTestingModule({
294
+ providers: [
295
+ { provide: HTTPManagerService, useValue: httpManagerService },
296
+ { provide: DatabaseManagerService, useValue: dbManagerService },
297
+ { provide: LocalStorageManagerService, useValue: localStorageManager },
298
+ {
299
+ provide: UtilsService,
300
+ useValue: {
301
+ expires: () => Math.floor(Date.now() / 1000) + 3600,
302
+ hasExpired: () => false,
303
+ }
304
+ },
305
+ {
306
+ provide: LoggerService,
307
+ useValue: {
308
+ debug: () => undefined,
309
+ info: () => undefined,
310
+ warn: () => undefined,
311
+ error: () => undefined,
312
+ }
313
+ },
314
+ ]
315
+ });
316
+ });
317
+
318
+ it('should block duplicate API call on refresh when requestCache.GET.queryParams already has the consumed value', (done: DoneFn) => {
319
+ // Pre-populate store with requestCache.GET.queryParams already containing active=true
320
+ localStorageManager.createStore({
321
+ name: 'new-contacts-cache',
322
+ data: {
323
+ table: 'new-contacts-cache',
324
+ expiresIn: '1d',
325
+ expires: Math.floor(Date.now() / 1000) + 86400,
326
+ schemaSignature: '["++id","active","name_first","name_last"]',
327
+ requestCache: {
328
+ GET: {
329
+ signature: '{"headers":{},"method":"GET","path":["contacts","location",5,"stream_flattened",{"active":true}],"server":"rest/","stream":true,"streamType":"ai_streaming"}',
330
+ savedAt: Date.now(),
331
+ path: ['contacts', 'location', 5, 'stream_flattened', { active: true }],
332
+ headers: {},
333
+ queryParams: { active: ['true'] },
334
+ queryParamsExpires: null,
335
+ }
336
+ }
337
+ }
338
+ });
339
+
340
+ // Create service matching the user's setup:
341
+ // server: 'rest/', path: ['contacts', 'location'], table: 'new-contacts-cache'
342
+ const contactsService = TestBed.runInInjectionContext(() => new HTTPManagerStateService(
343
+ ApiRequest.adapt({ server: 'rest/', path: ['contacts', 'location'] }),
344
+ DataType.ARRAY,
345
+ DatabaseStorage.adapt({ table: 'new-contacts-cache', expiresIn: '1d' })
346
+ ));
347
+
348
+ // Simulate the user's call: loadContactsByLocation(5, true)
349
+ // which calls: fetchRecords(RequestOptions.adapt({ path: [5, 'stream_flattened', { active: true }] }))
350
+ httpManagerService.getRequest.calls.reset();
351
+
352
+ contactsService.fetchRecords(RequestOptions.adapt({
353
+ path: [5, 'stream_flattened', { active: true }]
354
+ }));
355
+
356
+ // The tracker should recognize that 'active=true' has already been consumed
357
+ // and block the API call, returning DB data instead
358
+ setTimeout(() => {
359
+ expect(httpManagerService.getRequest).not.toHaveBeenCalled();
360
+ done();
361
+ }, 500);
362
+ });
363
+
364
+ it('should allow API call when requestCache.GET has no prior queryParams for the path+query', (done: DoneFn) => {
365
+ // No queryParams in localStorage - fresh page load with no prior visits
366
+ localStorageManager.createStore({
367
+ name: 'new-contacts-cache',
368
+ data: {
369
+ table: 'new-contacts-cache',
370
+ expiresIn: '1d',
371
+ expires: Math.floor(Date.now() / 1000) + 86400,
372
+ }
373
+ });
374
+
375
+ const contactsService = TestBed.runInInjectionContext(() => new HTTPManagerStateService(
376
+ ApiRequest.adapt({ server: 'rest/', path: ['contacts', 'location'] }),
377
+ DataType.ARRAY,
378
+ DatabaseStorage.adapt({ table: 'new-contacts-cache', expiresIn: '1d' })
379
+ ));
380
+
381
+ httpManagerService.getRequest.calls.reset();
382
+
383
+ contactsService.fetchRecords(RequestOptions.adapt({
384
+ path: [5, 'stream_flattened', { active: true }]
385
+ }));
386
+
387
+ // First call - tracker should allow the request since active=true is new
388
+ setTimeout(() => {
389
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
390
+ done();
391
+ }, 500);
392
+ });
393
+
394
+ it('should block API call when same query param value is already in queryParams but allow a new value', (done: DoneFn) => {
395
+ // requestCache.GET.queryParams already has active=true consumed, but not active=false
396
+ localStorageManager.createStore({
397
+ name: 'new-contacts-cache',
398
+ data: {
399
+ table: 'new-contacts-cache',
400
+ expiresIn: '1d',
401
+ expires: Math.floor(Date.now() / 1000) + 86400,
402
+ requestCache: {
403
+ GET: {
404
+ signature: '{"headers":{},"method":"GET","path":["contacts","location",5,"stream_flattened",{"active":true}],"server":"rest/"}',
405
+ savedAt: Date.now(),
406
+ path: ['contacts', 'location', 5, 'stream_flattened', { active: true }],
407
+ headers: {},
408
+ queryParams: { active: ['true'] },
409
+ queryParamsExpires: null,
410
+ }
411
+ }
412
+ }
413
+ });
414
+
415
+ const contactsService = TestBed.runInInjectionContext(() => new HTTPManagerStateService(
416
+ ApiRequest.adapt({ server: 'rest/', path: ['contacts', 'location'] }),
417
+ DataType.ARRAY,
418
+ DatabaseStorage.adapt({ table: 'new-contacts-cache', expiresIn: '1d' })
419
+ ));
420
+
421
+ // First call with active=true - should be BLOCKED (already consumed)
422
+ httpManagerService.getRequest.calls.reset();
423
+
424
+ contactsService.fetchRecords(RequestOptions.adapt({
425
+ path: [5, 'stream_flattened', { active: true }]
426
+ }));
427
+
428
+ setTimeout(() => {
429
+ expect(httpManagerService.getRequest).not.toHaveBeenCalled();
430
+
431
+ // Second call with active=false - should be ALLOWED (new value)
432
+ httpManagerService.getRequest.calls.reset();
433
+
434
+ contactsService.fetchRecords(RequestOptions.adapt({
435
+ path: [5, 'stream_flattened', { active: false }]
436
+ }));
437
+
438
+ setTimeout(() => {
439
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
440
+ done();
441
+ }, 500);
442
+ }, 500);
443
+ });
444
+ });
445
+
446
+ describe('HTTPManagerStateService requestCache.queryParams – unit coverage', () => {
447
+ let httpManagerService: jasmine.SpyObj<HTTPManagerService<any>>;
448
+ let dbManagerService: jasmine.SpyObj<DatabaseManagerService>;
449
+ let localStorageManager: MockLocalStorageManagerWithTracker;
450
+
451
+ function buildService(table = 'test-table') {
452
+ return TestBed.runInInjectionContext(() => new HTTPManagerStateService(
453
+ ApiRequest.adapt({ server: 'http://localhost', path: ['api'] }),
454
+ DataType.ARRAY,
455
+ DatabaseStorage.adapt({ table, expiresIn: '1d' })
456
+ ));
457
+ }
458
+
459
+ beforeEach(() => {
460
+ httpManagerService = jasmine.createSpyObj<HTTPManagerService<any>>(
461
+ 'HTTPManagerService',
462
+ ['getRequest', 'connect', 'subscribeToChannel', 'sendMessageInChannel'],
463
+ {
464
+ error$: of(false),
465
+ isPending$: of(false),
466
+ isPending: new BehaviorSubject<boolean>(false),
467
+ connectionStatus$: of(false),
468
+ messages$: of(null),
469
+ subscribedChannels$: of(new Set<string>()),
470
+ }
471
+ );
472
+
473
+ dbManagerService = jasmine.createSpyObj<DatabaseManagerService>('DatabaseManagerService', [
474
+ 'createDatabaseTable', 'databaseExists', 'hasDatabaseTable',
475
+ 'getTableRecords', 'clearTable', 'createTableRecords',
476
+ ]);
477
+
478
+ httpManagerService.getRequest.and.returnValue(of([{ id: 99 }]));
479
+ dbManagerService.createDatabaseTable.and.returnValue(of(true));
480
+ dbManagerService.databaseExists.and.returnValue(of(true));
481
+ dbManagerService.hasDatabaseTable.and.returnValue(of(true));
482
+ dbManagerService.getTableRecords.and.returnValue(of([{ id: 1 }]));
483
+ dbManagerService.clearTable.and.returnValue(of([]) as any);
484
+ dbManagerService.createTableRecords.and.returnValue(of([]) as any);
485
+
486
+ localStorageManager = new MockLocalStorageManagerWithTracker();
487
+
488
+ TestBed.configureTestingModule({
489
+ providers: [
490
+ { provide: HTTPManagerService, useValue: httpManagerService },
491
+ { provide: DatabaseManagerService, useValue: dbManagerService },
492
+ { provide: LocalStorageManagerService, useValue: localStorageManager },
493
+ {
494
+ provide: UtilsService,
495
+ useValue: { expires: () => Math.floor(Date.now() / 1000) + 3600, hasExpired: () => false }
496
+ },
497
+ {
498
+ provide: LoggerService,
499
+ useValue: { debug: () => undefined, info: () => undefined, warn: () => undefined, error: () => undefined }
500
+ },
501
+ ]
502
+ });
503
+ });
504
+
505
+ // 5.1 — first call with a new query param value is allowed; queryParams is populated
506
+ it('should allow first call with new query param value and populate requestCache.GET.queryParams', (done: DoneFn) => {
507
+ const svc = buildService();
508
+ httpManagerService.getRequest.calls.reset();
509
+
510
+ svc.fetchRecords(RequestOptions.adapt({ path: [{ page: 1 }] }));
511
+
512
+ setTimeout(() => {
513
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
514
+ const store = localStorageManager['stores']['test-table'];
515
+ expect(store?.requestCache?.GET?.queryParams?.page).toContain('1');
516
+ done();
517
+ }, 100);
518
+ });
519
+
520
+ // 5.2 — repeat call with same param value is blocked
521
+ it('should block repeat call when same query param value is already in requestCache.GET.queryParams', (done: DoneFn) => {
522
+ localStorageManager.createStore({
523
+ name: 'test-table',
524
+ data: {
525
+ expires: Math.floor(Date.now() / 1000) + 86400,
526
+ requestCache: {
527
+ GET: { signature: 'sig', savedAt: Date.now(), path: [{ page: 1 }], headers: {},
528
+ queryParams: { page: ['1'] }, queryParamsExpires: null }
529
+ }
530
+ }
531
+ });
532
+ const svc = buildService();
533
+ httpManagerService.getRequest.calls.reset();
534
+
535
+ svc.fetchRecords(RequestOptions.adapt({ path: [{ page: 1 }] }));
536
+
537
+ setTimeout(() => {
538
+ expect(httpManagerService.getRequest).not.toHaveBeenCalled();
539
+ done();
540
+ }, 100);
541
+ });
542
+
543
+ // 5.3 — call with a new param value is allowed and appended to queryParams
544
+ it('should allow call with new param value and append it to requestCache.GET.queryParams', (done: DoneFn) => {
545
+ localStorageManager.createStore({
546
+ name: 'test-table',
547
+ data: {
548
+ expires: Math.floor(Date.now() / 1000) + 86400,
549
+ requestCache: {
550
+ GET: { signature: 'sig', savedAt: Date.now(), path: [{ page: 1 }], headers: {},
551
+ queryParams: { page: ['1'] }, queryParamsExpires: null }
552
+ }
553
+ }
554
+ });
555
+ const svc = buildService();
556
+ httpManagerService.getRequest.calls.reset();
557
+
558
+ svc.fetchRecords(RequestOptions.adapt({ path: [{ page: 2 }] }));
559
+
560
+ setTimeout(() => {
561
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
562
+ const store = localStorageManager['stores']['test-table'];
563
+ expect(store?.requestCache?.GET?.queryParams?.page).toContain('1');
564
+ expect(store?.requestCache?.GET?.queryParams?.page).toContain('2');
565
+ done();
566
+ }, 100);
567
+ });
568
+
569
+ // 5.4 — queryParams survives saveRequestCacheMetadata (T4 write does not wipe T2 write)
570
+ it('should preserve queryParams in requestCache.GET after saveRequestCacheMetadata runs at T4', (done: DoneFn) => {
571
+ const svc = buildService();
572
+ httpManagerService.getRequest.calls.reset();
573
+
574
+ svc.fetchRecords(RequestOptions.adapt({ path: [{ page: 1 }] }));
575
+
576
+ setTimeout(() => {
577
+ const store = localStorageManager['stores']['test-table'];
578
+ // queryParams written at T2 (checkTrackerAllowsRequest) must survive T4 (saveRequestCacheMetadata)
579
+ expect(store?.requestCache?.GET?.queryParams).toBeDefined();
580
+ expect(store?.requestCache?.GET?.queryParams?.page).toContain('1');
581
+ // T4 signature field also present, proving both writes coexist
582
+ expect(store?.requestCache?.GET?.signature).toBeDefined();
583
+ done();
584
+ }, 100);
585
+ });
586
+
587
+ // 5.5 — expired queryParamsExpires resets queryParams and allows the call
588
+ it('should reset queryParams when queryParamsExpires is in the past and allow the call', (done: DoneFn) => {
589
+ const pastEpoch = Math.floor(Date.now() / 1000) - 1;
590
+ localStorageManager.createStore({
591
+ name: 'test-table',
592
+ data: {
593
+ expires: Math.floor(Date.now() / 1000) + 86400,
594
+ requestCache: {
595
+ GET: { signature: 'sig', savedAt: Date.now(), path: [{ page: 1 }], headers: {},
596
+ queryParams: { page: ['1'] }, queryParamsExpires: pastEpoch }
597
+ }
598
+ }
599
+ });
600
+ const svc = buildService();
601
+ httpManagerService.getRequest.calls.reset();
602
+
603
+ // Same value that was "consumed" — allowed because expiry reset cleared queryParams
604
+ svc.fetchRecords(RequestOptions.adapt({ path: [{ page: 1 }] }));
605
+
606
+ setTimeout(() => {
607
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
608
+ done();
609
+ }, 100);
610
+ });
611
+
612
+ // 5.6 — ignoreQueryParams excludes listed keys from queryParams and the allow/block decision
613
+ it('should exclude ignoreQueryParams keys from queryParams and the block decision', (done: DoneFn) => {
614
+ localStorageManager.createStore({
615
+ name: 'test-table',
616
+ data: {
617
+ expires: Math.floor(Date.now() / 1000) + 86400,
618
+ requestCache: {
619
+ GET: { signature: 'sig', savedAt: Date.now(), path: [{ page: 1 }], headers: {},
620
+ queryParams: { page: ['1'] }, queryParamsExpires: null }
621
+ }
622
+ }
623
+ });
624
+ const svc = buildService();
625
+ httpManagerService.getRequest.calls.reset();
626
+
627
+ // page=1 is consumed, but status is ignored — only page is evaluated → blocked
628
+ svc.fetchRecords(RequestOptions.adapt({
629
+ path: [{ page: 1, status: 'active' }],
630
+ ignoreQueryParams: ['status'],
631
+ }));
632
+
633
+ setTimeout(() => {
634
+ expect(httpManagerService.getRequest).not.toHaveBeenCalled();
635
+ const store = localStorageManager['stores']['test-table'];
636
+ // status must NOT appear in queryParams
637
+ expect(store?.requestCache?.GET?.queryParams?.status).toBeUndefined();
638
+ done();
639
+ }, 100);
640
+ });
641
+
642
+ // 5.7 — STREAM path populates and checks requestCache.STREAM.queryParams
643
+ it('should populate and check requestCache.STREAM.queryParams for stream requests', (done: DoneFn) => {
644
+ const svc = buildService();
645
+ httpManagerService.getRequest.calls.reset();
646
+
647
+ // First STREAM call — should be allowed and populate STREAM.queryParams
648
+ svc.fetchStream(RequestOptions.adapt({ path: [{ page: 1 }] }));
649
+
650
+ setTimeout(() => {
651
+ expect(httpManagerService.getRequest).toHaveBeenCalled();
652
+ const store = localStorageManager['stores']['test-table'];
653
+ expect(store?.requestCache?.STREAM?.queryParams?.page).toContain('1');
654
+
655
+ // Second STREAM call with same value — should be blocked
656
+ httpManagerService.getRequest.calls.reset();
657
+ svc.fetchStream(RequestOptions.adapt({ path: [{ page: 1 }] }));
658
+
659
+ setTimeout(() => {
660
+ expect(httpManagerService.getRequest).not.toHaveBeenCalled();
661
+ done();
662
+ }, 100);
663
+ }, 100);
664
+ });
665
+ });