http-request-manager 18.15.33 → 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 (300) hide show
  1. package/TEST_COVERAGE_SUMMARY.md +458 -0
  2. package/ng-package.json +8 -0
  3. package/package.json +4 -13
  4. package/src/docs/ADVANCED_WEBSOCKET.md +633 -0
  5. package/src/docs/ARCHITECTURE.md +633 -0
  6. package/src/docs/BATCH_REQUEST_README.md +467 -0
  7. package/src/docs/COMPLETE_API_REFERENCE.md +1037 -0
  8. package/src/docs/DATABASE_README.md +1195 -0
  9. package/src/docs/ENCRYPTION_README.md +403 -0
  10. package/src/docs/HTTP_MANAGER_README.md +628 -0
  11. package/src/docs/HTTP_SINGNALS_MANAGER_README.md +654 -0
  12. package/src/docs/HTTP_STATE_MANAGER_README.md +1391 -0
  13. package/src/docs/INTERCEPTOR_README.md +549 -0
  14. package/src/docs/LOCAL_STORAGE_README.md +1056 -0
  15. package/src/docs/LOCAL_STORAGE_SIGNALS_README.md +338 -0
  16. package/src/docs/LOGGER_README.md +310 -0
  17. package/src/docs/MESSAGE_TRACKER_README.md +518 -0
  18. package/src/docs/MESSAGE_TRACKER_SIGNALS_README.md +563 -0
  19. package/src/docs/MODELS_README.md +1264 -0
  20. package/src/docs/SIGNAL_SERVICES_README.md +238 -0
  21. package/src/docs/SQL_DIXIE_README.md +574 -0
  22. package/src/docs/STORE_STATE_MANAGER_README.md +556 -0
  23. package/src/docs/STORE_STATE_SIGNALS_README.md +600 -0
  24. package/src/docs/UPLOAD_REQUEST_README.md +324 -0
  25. package/src/docs/UTILS_README.md +1604 -0
  26. package/src/docs/WEBSOCKET_MESSAGE_SERVICE.md +799 -0
  27. package/src/docs/WEBSOCKET_SIGNALS_README.md +641 -0
  28. package/src/docs/WEBSOCKET_SINGLETON_REFACTORING.md +201 -0
  29. package/src/docs/WS_MANAGER_README.md +613 -0
  30. package/src/lib/http-request-manager.module.ts +147 -0
  31. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.html +116 -0
  32. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.scss +0 -0
  33. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.ts +255 -0
  34. package/src/lib/http-request-services-demo/http-request-services-demo.component.html +123 -0
  35. package/src/lib/http-request-services-demo/http-request-services-demo.component.scss +6 -0
  36. package/src/lib/http-request-services-demo/http-request-services-demo.component.ts +53 -0
  37. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.html +195 -0
  38. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.scss +17 -0
  39. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.ts +208 -0
  40. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.html +200 -0
  41. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.scss +17 -0
  42. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.ts +214 -0
  43. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.html +53 -0
  44. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.scss +60 -0
  45. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.ts +72 -0
  46. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-download.module.ts +28 -0
  47. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.html +10 -0
  48. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.scss +29 -0
  49. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.ts +100 -0
  50. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/models/download-labels-model.ts +22 -0
  51. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.html +8 -0
  52. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.scss +19 -0
  53. package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.ts +26 -0
  54. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/app-session.model.ts +30 -0
  55. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/app.model.ts +19 -0
  56. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/get-sample.model.ts +25 -0
  57. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-ai-prompt.ts +19 -0
  58. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client-details.ts +24 -0
  59. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client-info.ts +30 -0
  60. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client.model.ts +49 -0
  61. package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-mapper-client-info.ts +33 -0
  62. package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.html +279 -0
  63. package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.scss +24 -0
  64. package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.ts +461 -0
  65. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
  66. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
  67. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
  68. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.ts +28 -0
  69. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.html +10 -0
  70. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.scss +29 -0
  71. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.ts +100 -0
  72. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
  73. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
  74. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
  75. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
  76. package/src/lib/http-request-services-demo/request-manager-demo/models/app-session.model.ts +30 -0
  77. package/src/lib/http-request-services-demo/request-manager-demo/models/app.model.ts +19 -0
  78. package/src/lib/http-request-services-demo/request-manager-demo/models/get-sample.model.ts +25 -0
  79. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.ts +19 -0
  80. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-details.ts +24 -0
  81. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.ts +30 -0
  82. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client.model.ts +49 -0
  83. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.ts +33 -0
  84. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.html +622 -0
  85. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.scss +106 -0
  86. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.ts +687 -0
  87. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.html +418 -0
  88. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.scss +24 -0
  89. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.ts +576 -0
  90. package/src/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.ts +89 -0
  91. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/services/state-data-request.service.ts +119 -0
  92. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.css +0 -0
  93. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.html +3 -0
  94. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.ts +16 -0
  95. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.css +0 -0
  96. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.html +3 -0
  97. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.ts +16 -0
  98. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.css +31 -0
  99. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.html +94 -0
  100. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.scss +41 -0
  101. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.spec.ts +203 -0
  102. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.ts +144 -0
  103. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.css +11 -0
  104. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.html +102 -0
  105. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.spec.ts +40 -0
  106. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.ts +230 -0
  107. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.css +30 -0
  108. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.html +172 -0
  109. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.spec.ts +31 -0
  110. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.ts +239 -0
  111. package/src/lib/http-request-services-demo/request-manager-ws-demo/models/oidc-client.model.ts +31 -0
  112. package/src/lib/http-request-services-demo/request-manager-ws-demo/models/user-data.model.ts +32 -0
  113. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.css +0 -0
  114. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.html +84 -0
  115. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.ts +40 -0
  116. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/index.ts +3 -0
  117. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/jwt-token.service.ts +62 -0
  118. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/message-service-demo.service.ts +83 -0
  119. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/notification-service-demo.service.ts +147 -0
  120. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/state-service-demo.service.ts +168 -0
  121. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
  122. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
  123. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
  124. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-download.module.ts +28 -0
  125. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.html +10 -0
  126. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.scss +29 -0
  127. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.ts +100 -0
  128. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
  129. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
  130. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
  131. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
  132. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app-session.model.ts +30 -0
  133. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app.model.ts +19 -0
  134. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/get-sample.model.ts +25 -0
  135. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.ts +19 -0
  136. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-details.ts +24 -0
  137. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.ts +30 -0
  138. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client.model.ts +49 -0
  139. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.ts +33 -0
  140. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.html +380 -0
  141. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.scss +24 -0
  142. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.ts +410 -0
  143. package/src/lib/http-request-services-demo/store-state-manager-demo/models/settings.model.ts +28 -0
  144. package/src/lib/http-request-services-demo/store-state-manager-demo/services/settings-state.service.ts +49 -0
  145. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.css +0 -0
  146. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.html +23 -0
  147. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.ts +36 -0
  148. package/src/lib/http-request-services-demo/store-state-signals-demo/store-state-signals-demo.component.ts +161 -0
  149. package/src/lib/http-request-services-demo/upload-demo/models/index.ts +1 -0
  150. package/src/lib/http-request-services-demo/upload-demo/models/upload-state.model.ts +30 -0
  151. package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.html +89 -0
  152. package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.scss +160 -0
  153. package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.spec.ts +101 -0
  154. package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.ts +136 -0
  155. package/src/lib/index.ts +3 -0
  156. package/src/lib/interceptors/credentials.interceptor.ts +16 -0
  157. package/src/lib/interceptors/index.ts +6 -0
  158. package/src/lib/interceptors/models/error-settings.model.ts +22 -0
  159. package/src/lib/interceptors/models/index.ts +2 -0
  160. package/src/lib/interceptors/proxy-debugger.interceptor.ts +46 -0
  161. package/src/lib/interceptors/request-error.interceptor.ts +65 -0
  162. package/src/lib/interceptors/request-header.interceptor.ts +56 -0
  163. package/src/lib/message-display/README.md +509 -0
  164. package/src/lib/message-display/index.ts +4 -0
  165. package/src/lib/message-display/models/action.model.ts +27 -0
  166. package/src/lib/message-display/models/communication-message.model.ts +77 -0
  167. package/src/lib/message-display/models/display-config.model.ts +35 -0
  168. package/src/lib/message-display/models/display-rule.interface.ts +28 -0
  169. package/src/lib/message-display/models/display-strategy.interface.ts +8 -0
  170. package/src/lib/message-display/models/index.ts +6 -0
  171. package/src/lib/message-display/models/slide.model.ts +24 -0
  172. package/src/lib/message-display/rules/default-display-rules.ts +35 -0
  173. package/src/lib/message-display/services/message-display-router.service.ts +63 -0
  174. package/src/lib/message-display/strategies/snackbar.strategy.ts +46 -0
  175. package/src/lib/models/batch-options.model.ts +33 -0
  176. package/src/lib/models/batch-progress.model.ts +19 -0
  177. package/src/lib/models/batch-request-state.model.ts +40 -0
  178. package/src/lib/models/batch-result.model.ts +30 -0
  179. package/src/lib/models/config-http-options.model.ts +45 -0
  180. package/src/lib/models/config-local-storage-options.model.ts +27 -0
  181. package/src/lib/models/config-options.model.ts +27 -0
  182. package/src/lib/models/config-token.model.ts +9 -0
  183. package/src/lib/models/data-type.enum.ts +5 -0
  184. package/src/lib/models/database-storage.model.ts +24 -0
  185. package/src/lib/models/index.ts +16 -0
  186. package/src/lib/models/retry-options.model.ts +22 -0
  187. package/src/lib/models/upload-validation-error.model.ts +46 -0
  188. package/src/lib/services/SQL-DixieJS service/dexie-query-executor.ts +246 -0
  189. package/src/lib/services/SQL-DixieJS service/dexie-sql.service.ts +31 -0
  190. package/src/lib/services/SQL-DixieJS service/index.ts +4 -0
  191. package/src/lib/services/SQL-DixieJS service/models/execution-plan.model.ts +52 -0
  192. package/src/lib/services/SQL-DixieJS service/models/index.ts +3 -0
  193. package/src/lib/services/SQL-DixieJS service/models/sql-errors.model.ts +13 -0
  194. package/src/lib/services/SQL-DixieJS service/models/sql-options.model.ts +3 -0
  195. package/src/lib/services/SQL-DixieJS service/query-planner.ts +284 -0
  196. package/src/lib/services/SQL-DixieJS service/schema-validator.ts +217 -0
  197. package/src/lib/services/SQL-DixieJS service/sql-parser.ts +35 -0
  198. package/src/lib/services/database-manager-service/database.manager.service.ts +384 -0
  199. package/src/lib/services/database-manager-service/db.storage.service.ts +240 -0
  200. package/src/lib/services/database-manager-service/index.ts +4 -0
  201. package/src/lib/services/database-manager-service/models/index.ts +2 -0
  202. package/src/lib/services/database-manager-service/models/table-schema.ts +33 -0
  203. package/src/lib/services/index.ts +20 -0
  204. package/src/lib/services/local-storage-manager-service/index.ts +4 -0
  205. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.spec.ts +71 -0
  206. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.ts +567 -0
  207. package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.spec.ts +67 -0
  208. package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.ts +437 -0
  209. package/src/lib/services/local-storage-manager-service/models/global-store-options.model.ts +30 -0
  210. package/src/lib/services/local-storage-manager-service/models/index.ts +6 -0
  211. package/src/lib/services/local-storage-manager-service/models/setting-options.model.ts +35 -0
  212. package/src/lib/services/local-storage-manager-service/models/storage-data.model.ts +24 -0
  213. package/src/lib/services/local-storage-manager-service/models/storage-option.model.ts +32 -0
  214. package/src/lib/services/local-storage-manager-service/models/storage-type.enum.ts +5 -0
  215. package/src/lib/services/request-manager-services/README.md +282 -0
  216. package/src/lib/services/request-manager-services/http-manager-signals.service.ts +674 -0
  217. package/src/lib/services/request-manager-services/http-manager.service.spec.ts +353 -0
  218. package/src/lib/services/request-manager-services/http-manager.service.ts +727 -0
  219. package/src/lib/services/request-manager-services/index.ts +8 -0
  220. package/src/lib/services/request-manager-services/request-signals.service.ts +372 -0
  221. package/src/lib/services/request-manager-services/request.service.ts +435 -0
  222. package/src/lib/services/request-manager-services/rxjs-operators/countdown.ts +17 -0
  223. package/src/lib/services/request-manager-services/rxjs-operators/delay-retry.ts +16 -0
  224. package/src/lib/services/request-manager-services/rxjs-operators/index.ts +4 -0
  225. package/src/lib/services/request-manager-services/rxjs-operators/request-polling.ts +35 -0
  226. package/src/lib/services/request-manager-services/rxjs-operators/request-streaming.ts +468 -0
  227. package/src/lib/services/request-manager-state-service/http-manager-state.store.spec.ts +665 -0
  228. package/src/lib/services/request-manager-state-service/http-manager-state.store.ts +2395 -0
  229. package/src/lib/services/request-manager-state-service/index.ts +3 -0
  230. package/src/lib/services/request-manager-state-service/models/api-request.model.ts +86 -0
  231. package/src/lib/services/request-manager-state-service/models/index.ts +14 -0
  232. package/src/lib/services/request-manager-state-service/models/operation-result.model.ts +18 -0
  233. package/src/lib/services/request-manager-state-service/models/parsing-result.model.ts +21 -0
  234. package/src/lib/services/request-manager-state-service/models/request-options.model.ts +37 -0
  235. package/src/lib/services/request-manager-state-service/models/stream-config.model.ts +20 -0
  236. package/src/lib/services/request-manager-state-service/models/stream-event-metadata.model.ts +23 -0
  237. package/src/lib/services/request-manager-state-service/models/stream-event.model.ts +23 -0
  238. package/src/lib/services/request-manager-state-service/models/stream-output.model.ts +23 -0
  239. package/src/lib/services/request-manager-state-service/models/stream-progress.model.ts +24 -0
  240. package/src/lib/services/request-manager-state-service/models/stream-type.enum.ts +13 -0
  241. package/src/lib/services/request-manager-state-service/models/ws-options.model.ts +42 -0
  242. package/src/lib/services/store-state-manager-service/index.ts +4 -0
  243. package/src/lib/services/store-state-manager-service/models/index.ts +3 -0
  244. package/src/lib/services/store-state-manager-service/models/state-operation-result.model.ts +30 -0
  245. package/src/lib/services/store-state-manager-service/models/state-storage-options.model.ts +24 -0
  246. package/src/lib/services/store-state-manager-service/store-state-manager-signals.service.ts +169 -0
  247. package/src/lib/services/store-state-manager-service/store-state-manager.service.ts +153 -0
  248. package/src/lib/services/utils/app.service.spec.ts +25 -0
  249. package/src/lib/services/utils/app.service.ts +21 -0
  250. package/src/lib/services/utils/encryption/README.md +79 -0
  251. package/src/lib/services/utils/encryption/asymmetrical-encryption.service.ts +282 -0
  252. package/src/lib/services/utils/encryption/encryption-test.service.ts +39 -0
  253. package/src/lib/services/utils/encryption/index.ts +5 -0
  254. package/src/lib/services/utils/encryption/random.ts +81 -0
  255. package/src/lib/services/utils/encryption/symmetrical-encryption.service.ts +106 -0
  256. package/src/lib/services/utils/headers.service.spec.ts +80 -0
  257. package/src/lib/services/utils/headers.service.ts +18 -0
  258. package/src/lib/services/utils/index.ts +9 -0
  259. package/src/lib/services/utils/logger.service.ts +90 -0
  260. package/src/lib/services/utils/models/index.ts +4 -0
  261. package/src/lib/services/utils/models/normalized-request-options.model.ts +24 -0
  262. package/src/lib/services/utils/models/path-tracker-state.model.ts +20 -0
  263. package/src/lib/services/utils/models/query-params-tracker-options.model.ts +24 -0
  264. package/src/lib/services/utils/models/query-tracker-state.model.ts +23 -0
  265. package/src/lib/services/utils/object-merger.service.spec.ts +18 -0
  266. package/src/lib/services/utils/object-merger.service.ts +78 -0
  267. package/src/lib/services/utils/path-query.service.spec.ts +117 -0
  268. package/src/lib/services/utils/path-query.service.ts +69 -0
  269. package/src/lib/services/utils/query-params-tracker.service.ts +442 -0
  270. package/src/lib/services/utils/random-color.utils.ts +83 -0
  271. package/src/lib/services/utils/utils.service.spec.ts +165 -0
  272. package/src/lib/services/utils/utils.service.ts +192 -0
  273. package/src/lib/services/ws-manager-service/index.ts +13 -0
  274. package/src/lib/services/ws-manager-service/message-tracker-signals.service.ts +147 -0
  275. package/src/lib/services/ws-manager-service/message-tracker.service.ts +477 -0
  276. package/src/lib/services/ws-manager-service/models/channel-info.model.ts +29 -0
  277. package/src/lib/services/ws-manager-service/models/channel-message-data.model.ts +24 -0
  278. package/src/lib/services/ws-manager-service/models/channel-message.model.ts +36 -0
  279. package/src/lib/services/ws-manager-service/models/channel-type.enum.ts +6 -0
  280. package/src/lib/services/ws-manager-service/models/communication-type.enum.ts +5 -0
  281. package/src/lib/services/ws-manager-service/models/index.ts +10 -0
  282. package/src/lib/services/ws-manager-service/models/notification-message.model.ts +29 -0
  283. package/src/lib/services/ws-manager-service/models/public-message.model.ts +18 -0
  284. package/src/lib/services/ws-manager-service/models/state-message.model.ts +18 -0
  285. package/src/lib/services/ws-manager-service/models/ws-user.model.ts +38 -0
  286. package/src/lib/services/ws-manager-service/services/index.ts +4 -0
  287. package/src/lib/services/ws-manager-service/services/websocket-message.service.ts +129 -0
  288. package/src/lib/services/ws-manager-service/services/websocket.service.ts +434 -0
  289. package/src/lib/services/ws-manager-service/websocket-service/index.ts +1 -0
  290. package/src/lib/services/ws-manager-service/websocket-service/websocket-manager.service.ts +716 -0
  291. package/src/lib/services/ws-manager-service/websocket-services-complete.spec.ts +596 -0
  292. package/src/lib/services/ws-manager-service/websocket-signals-manager.service.ts +141 -0
  293. package/src/public-api.ts +19 -0
  294. package/tsconfig.lib.json +34 -0
  295. package/tsconfig.lib.prod.json +10 -0
  296. package/tsconfig.spec.json +14 -0
  297. package/fesm2022/http-request-manager.mjs +0 -13688
  298. package/fesm2022/http-request-manager.mjs.map +0 -1
  299. package/http-request-manager-18.15.33.tgz +0 -0
  300. package/types/http-request-manager.d.ts +0 -3968
@@ -0,0 +1,567 @@
1
+ import { Inject, Injectable, OnDestroy, Optional, inject } from '@angular/core';
2
+ import { ComponentStore } from '@ngrx/component-store';
3
+ import { withLatestFrom, map, tap } from 'rxjs/operators';
4
+
5
+ import { UtilsService } from '../utils/utils.service';
6
+ import { SymmetricalEncryptionService } from '../utils/encryption/symmetrical-encryption.service';
7
+
8
+ import { StorageOption, StorageType } from './models';
9
+ import { SettingOptions } from './models/setting-options.model';
10
+ import { StorageData } from './models/storage-data.model';
11
+ import { EncryptionTestService } from '../utils/encryption/encryption-test.service';
12
+ import { interval } from 'rxjs';
13
+ import { AppService } from '../utils/app.service';
14
+ import { CONFIG_SETTINGS_TOKEN } from '../../models/config-token.model';
15
+ import { ConfigOptions } from '../request-manager-services';
16
+ import { ObjectMergerService } from '../utils/object-merger.service';
17
+
18
+ export interface State {
19
+ localStores: StorageData[]
20
+ sessionStores: StorageData[]
21
+ settings: StorageOption[]
22
+ }
23
+
24
+ const storage: State = {
25
+ localStores: [],
26
+ sessionStores: [],
27
+ settings: [],
28
+ };
29
+
30
+ @Injectable({ providedIn: 'root' })
31
+ export class LocalStorageManagerService extends ComponentStore<State> implements OnDestroy {
32
+
33
+ storageName = 'storage'
34
+ storageSettingsName = 'global-storage'
35
+ defaultOptions = SettingOptions.adapt()
36
+
37
+ stateRetrieved = false
38
+ encrypted = false
39
+
40
+ app = inject(AppService)
41
+ utils = inject(UtilsService)
42
+ objectMergerService = inject(ObjectMergerService)
43
+ encryption = inject(SymmetricalEncryptionService)
44
+ encryptionTest = inject(EncryptionTestService)
45
+
46
+ // SELECTORS
47
+
48
+ private readonly data$ = this.select((state) => state)
49
+
50
+ readonly stores$ = this.select((state) => state.settings)
51
+
52
+ readonly storeExists$ = (store: string) => this.select(
53
+ this.data$,
54
+ (data) => data.settings.find(item => item.name === store) ? true : false
55
+ )
56
+
57
+ readonly store$ = (store: string) => this.select(
58
+ this.data$,
59
+ (data) => {
60
+ store = store.toLowerCase()
61
+ const foundStore = [...data.settings].reverse().find(item => item.name === store)
62
+
63
+ if(foundStore) {
64
+
65
+ const options = SettingOptions.adapt(foundStore.options)
66
+
67
+ const found = foundStore.options?.storage === StorageType.GLOBAL
68
+ ? [...data.localStores].reverse().find(item => item.id === foundStore.id) as StorageData
69
+ : [...data.sessionStores].reverse().find(item => item.id === foundStore.id) as StorageData
70
+
71
+ if(!found) {
72
+ // console.warn('[CacheDebug] store$: settings entry found but no data entry in localStores/sessionStores', { store, foundStoreId: foundStore.id, storageType: foundStore.options?.storage })
73
+ this.deleteStore({ name: store })
74
+ return
75
+ }
76
+
77
+ let storageData = found.data;
78
+ if (options.encrypted) {
79
+ if(!this.app?.appID) {
80
+ console.warn('No App ID found - AppId not Provided, cannot decrypt encrypted store')
81
+ return
82
+ }
83
+
84
+ if (this.isString(found.data) && !this.encryptionTest.isEncrypted(found.data)) {
85
+ storageData = found.data;
86
+ } else {
87
+ const decryptedData = this.encryption.decrypt(found.data, this.app.appID);
88
+ if (decryptedData !== null) {
89
+ storageData = decryptedData;
90
+ } else {
91
+ console.warn(`Failed to decrypt data for store: ${store}`);
92
+ storageData = found.data;
93
+ }
94
+ }
95
+ }
96
+
97
+ try {
98
+ return (this.isString(storageData)) ? JSON.parse(storageData) : storageData;
99
+ } catch (error) {
100
+ console.warn(`Failed to parse storage data for store: ${store}`, error);
101
+ return storageData; // Return raw data if parsing fails
102
+ }
103
+
104
+ } else {
105
+ return null
106
+ }
107
+
108
+ }
109
+ )
110
+
111
+ readonly settings$ = this.select(state => (state) ? state.settings : storage.settings)
112
+
113
+ readonly setting$ = (store: string) => this.select(
114
+ this.data$,
115
+ (state) => {
116
+ const foundSetting = [...state.settings].reverse().find(item => item.name === store)
117
+ return (foundSetting) ? foundSetting : null
118
+ }
119
+ )
120
+
121
+ persistence$ = this.data$
122
+ .subscribe(data => {
123
+ if(this.stateRetrieved) this.persistState(data)
124
+ })
125
+
126
+ startTimer() {
127
+ const timer$ = interval(1000 * 3).pipe(
128
+ withLatestFrom(this.data$),
129
+ map(([_, state]) => state),
130
+ tap((state) => {
131
+
132
+ const expired: StorageOption[] = this.expired(state) ? this.expired(state) : []
133
+
134
+ if (expired.length > 0) {
135
+
136
+ const ids = expired.map((item) => item.id)
137
+
138
+ const updatedState: State = {
139
+ ...state,
140
+ localStores: state.localStores.filter((item) => !ids.includes(item.id)),
141
+ sessionStores: state.sessionStores.filter((item) => !ids.includes(item.id)),
142
+ settings: state.settings.filter((item) => !ids.includes(item.id)),
143
+ };
144
+
145
+ this.persistState(updatedState)
146
+ this.updateState(updatedState)
147
+
148
+ }
149
+ })
150
+ );
151
+
152
+ timer$.subscribe()
153
+ }
154
+
155
+ private updateState = this.updater((state, updatedState: State) => ({
156
+ ...updatedState,
157
+ }))
158
+
159
+
160
+ constructor(@Optional() @Inject(CONFIG_SETTINGS_TOKEN) private configOptions?: ConfigOptions) {
161
+
162
+ super(storage)
163
+
164
+ this.storageName = configOptions?.LocalStorageOptions?.storageName || this.storageName
165
+ this.storageSettingsName = configOptions?.LocalStorageOptions?.storageSettingsName || this.storageSettingsName
166
+ this.defaultOptions = configOptions?.LocalStorageOptions?.options || this.defaultOptions
167
+
168
+ this.retrieveState()
169
+ this.startTimer()
170
+ }
171
+
172
+ readonly setStore = this.updater((state: State, store: { id: string, name: string, data: any, options: SettingOptions }): any => {
173
+
174
+ const settings = StorageOption.adapt(store)
175
+ store.name = store.name.toLowerCase()
176
+ settings.options = this.objectMergerService.mergeStorageOptions(settings.options)
177
+
178
+ const type = store.options.storage
179
+ const hasStore = this.hasGlobalStorage(type, store.id)
180
+
181
+ store.name = this.validStoreName(store.name)
182
+
183
+ if(!hasStore) {
184
+ // console.warn(`No such Store: ${store.name}`)
185
+ return state
186
+ } else {
187
+
188
+ const str = this.encryptionTest.isEncrypted(store.data) ? store.data : JSON.stringify(store.data)
189
+ const dataStr = (this.isObjectOrArray(str)) ? (store.options.encrypted) ? this.encryption.encrypt(str, this.app.appID) : store.data : store.data
190
+
191
+ const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : []
192
+ const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : []
193
+ const localStores = state.localStores.filter(item => item.id !== settings.id)
194
+ const sessionStores = state.sessionStores.filter(item => item.id !== settings.id)
195
+ const stateSettings = state.settings.filter(item => item.id !== settings.id)
196
+
197
+ return {
198
+ ...state,
199
+ localStores: [...localStores, ...localData],
200
+ sessionStores: [...sessionStores, ...sessionData],
201
+ settings: [...stateSettings, ...[settings]],
202
+ }
203
+
204
+ }
205
+
206
+ })
207
+
208
+ readonly createStore = this.updater((state: State, store: { id?: string, name: string, data: any, options: SettingOptions }): any => {
209
+
210
+ store.name = store.name.toLowerCase()
211
+ store.options = this.objectMergerService.mergeStorageOptions(store.options)
212
+ const settings = StorageOption.adapt(store)
213
+ settings.options = this.objectMergerService.mergeStorageOptions(settings.options)
214
+ const foundStore = state?.settings.some(item => item.name === store.name)
215
+
216
+ const expires = (settings.options?.expiresIn) ? this.utils.expires(settings.options?.expiresIn) : 0
217
+ if(settings.options) settings.options.expires = expires
218
+
219
+ store.name = this.validStoreName(store.name)
220
+
221
+ if(foundStore) {
222
+ return state
223
+ } else {
224
+ if(!this.isObjectOrArray(store.data)) {
225
+ console.warn('Data must ba an Object or Array')
226
+ return
227
+ }
228
+
229
+ store.data = (this.isString(store.data)) ? JSON.parse(store.data) : store.data
230
+ const dataStr = (store.options.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data
231
+
232
+ const localData = (settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : []
233
+ const sessionData = (settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : []
234
+
235
+ return {
236
+ ...state,
237
+ localStores: [...state.localStores, ...localData],
238
+ sessionStores: [...state.sessionStores, ...sessionData],
239
+ settings: [...state.settings, ...[settings]],
240
+ }
241
+
242
+ }
243
+
244
+ })
245
+
246
+ readonly updateStore = this.updater((state: State, store: { name: string, data: any }): any => {
247
+
248
+ store.name = store.name.toLowerCase()
249
+ store.name = this.validStoreName(store.name)
250
+
251
+ const settings = [...state.settings].reverse().find(item => item.name === store.name)
252
+
253
+ if(settings) {
254
+
255
+ const dataStr = (settings.options?.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data
256
+
257
+ const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : []
258
+ const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : []
259
+
260
+ return {
261
+ ...state,
262
+ localStores: [...state.localStores.filter(item => item.id !== settings.id), ...localData],
263
+ sessionStores: [...state.sessionStores.filter(item => item.id !== settings.id), ...sessionData],
264
+ }
265
+ }
266
+
267
+ return state
268
+
269
+ })
270
+
271
+ readonly deleteStore = this.updater((state: State, store: { name: string }): any => {
272
+
273
+ store.name = store.name.toLowerCase()
274
+ store.name = this.validStoreName(store.name)
275
+
276
+ const id = state.settings.find(item => item.name === store.name)?.id
277
+
278
+ if(id) {
279
+
280
+ const settings = state.settings.filter(item => item.id !== id)
281
+ const localData = state.localStores.filter(item => item.id !== id)
282
+ const sessionData = state.sessionStores.filter(item => item.id !== id)
283
+
284
+ return {
285
+ ...state,
286
+ localStores: [...localData],
287
+ sessionStores: [...sessionData],
288
+ settings: [...settings],
289
+ }
290
+
291
+ } else {
292
+ // console.warn(`No such Store: ${store.name}`)
293
+ return state
294
+ }
295
+
296
+ })
297
+
298
+ resetStore() {
299
+
300
+ const newState = {
301
+ localStores: [],
302
+ sessionStores: [],
303
+ settings: [],
304
+ }
305
+
306
+ this.updateState(newState)
307
+ this.persistState(newState)
308
+
309
+ }
310
+
311
+ private persistState(state: State|null) {
312
+
313
+ if(!state) return
314
+
315
+ const strLocal = JSON.stringify(state.localStores)
316
+ localStorage.setItem(this.storageName, strLocal)
317
+
318
+ const strSession = JSON.stringify(state.sessionStores)
319
+ sessionStorage.setItem(this.storageName, strSession)
320
+
321
+ const settingsStr = this.encryption.encrypt(state.settings, this.app.appID)
322
+ localStorage.setItem(this.storageSettingsName, settingsStr || '')
323
+
324
+ }
325
+
326
+ private expired(state: State|null) {
327
+
328
+ if(!state) return []
329
+ return state.settings?.filter(item => (item.options?.expires || 0) > 0 && this.utils.hasExpired(item.options?.expires || 0))
330
+
331
+ }
332
+
333
+ retrieveState() {
334
+
335
+ const str = localStorage.getItem(this.storageSettingsName)
336
+
337
+ const localStr = localStorage.getItem(this.storageName)
338
+ const sessionStr = sessionStorage.getItem(this.storageName)
339
+
340
+ let localData: StorageData[] = [];
341
+ let sessionData: StorageData[] = [];
342
+ let settings: StorageOption[] = [];
343
+
344
+ try {
345
+ localData = (localStr) ? JSON.parse(localStr) : [];
346
+ } catch (error) {
347
+ console.warn('Failed to parse local storage data:', error);
348
+ localData = [];
349
+ }
350
+
351
+ try {
352
+ sessionData = (sessionStr) ? JSON.parse(sessionStr) : [];
353
+ } catch (error) {
354
+ console.warn('Failed to parse session storage data:', error);
355
+ sessionData = [];
356
+ }
357
+
358
+ if (str) {
359
+ const plainSettings = this.tryParseSettingsArray(str);
360
+ if (plainSettings) {
361
+ settings = plainSettings;
362
+ const migratedSettings = this.encryption.encrypt(settings, this.app.appID);
363
+ if (migratedSettings) {
364
+ localStorage.setItem(this.storageSettingsName, migratedSettings);
365
+ }
366
+ console.warn('Recovered settings from plaintext storage and migrated to encrypted format');
367
+ } else {
368
+ const decryptedStr = this.encryption.decrypt(str, this.app.appID);
369
+ if (decryptedStr) {
370
+ const decryptedSettings = this.tryParseSettingsArray(decryptedStr);
371
+ if (decryptedSettings) {
372
+ settings = decryptedSettings;
373
+ } else {
374
+ console.warn('Failed to parse decrypted settings data. Resetting corrupted settings store.');
375
+ localStorage.removeItem(this.storageSettingsName);
376
+ settings = [];
377
+ }
378
+ } else {
379
+ console.warn('Failed to decrypt settings data. Resetting corrupted settings store.');
380
+ localStorage.removeItem(this.storageSettingsName);
381
+ settings = [];
382
+ }
383
+ }
384
+ }
385
+
386
+ settings.forEach(store => {
387
+
388
+ const expired = (store.options?.expires || 0) > 0 && this.utils.hasExpired(store.options?.expires || 0)
389
+
390
+ if(!expired) {
391
+
392
+ const hasStorage = this.hasGlobalStorage(store.options?.storage, store.id || '')
393
+
394
+ if(!hasStorage) {
395
+ this.createStore({ id: store.id, name: store.name, data: [], options: SettingOptions.adapt(store.options)})
396
+ } else {
397
+ const storeData = (store.options?.storage === StorageType.GLOBAL) ? localData.find(item => item.id === store.id) : sessionData.find(item => item.id === store.id)
398
+ this.setStore({ id: store.id || '', name: store.name, data: storeData?.data, options: SettingOptions.adapt(store.options) })
399
+ }
400
+
401
+ }
402
+
403
+ })
404
+
405
+ this.stateRetrieved = true
406
+
407
+ }
408
+
409
+ private isObjectOrArray = (obj: any) => {
410
+
411
+ let parsed;
412
+
413
+ try {
414
+ parsed = (typeof obj === 'object') ? obj : JSON.parse(obj)
415
+ } catch (e) {
416
+ return false;
417
+ }
418
+
419
+ if (Array.isArray(parsed)) {
420
+ const allStringsOrObjectsOrNumbers = parsed.every(item =>
421
+ typeof item === 'string' ||
422
+ typeof item === 'object' && item !== null ||
423
+ typeof item === 'number'
424
+ );
425
+ return allStringsOrObjectsOrNumbers;
426
+ }
427
+
428
+ return typeof parsed === 'object' && parsed !== null;
429
+
430
+ }
431
+
432
+ private isString (obj: any) {
433
+ return (Object.prototype.toString.call(obj) === '[object String]')
434
+ }
435
+
436
+ private fixAndParseJSON(jsonString: string): any {
437
+ const fixedString = jsonString
438
+ .replace(/'/g, '"')
439
+ .replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":')
440
+ .replace(/,\s*(\}|\])/g, '$1');
441
+
442
+ try {
443
+ return JSON.parse(fixedString);
444
+ } catch (error: any) {
445
+ throw new Error('Failed to parse JSON: ' + error.message);
446
+ }
447
+ }
448
+
449
+ private validStoreName(str: string) {
450
+ return str
451
+ .toLowerCase() // Convert to lowercase
452
+ .replace(/\s+/g, '_') // Replace spaces with underscores
453
+ .replace(/[^ -~]/g, ''); // Remove non-ASCII characters
454
+ }
455
+
456
+ private hasGlobalStorage(type: StorageType = StorageType.GLOBAL, id: string) {
457
+
458
+ const strData: StorageOption[] = []
459
+
460
+ if(type === StorageType.GLOBAL) {
461
+ const str = localStorage.getItem(this.storageName)
462
+ strData.push(...(str ? JSON.parse(str) : []))
463
+ } else {
464
+ const str = sessionStorage.getItem(this.storageName)
465
+ strData.push(...(str ? JSON.parse(str) : []))
466
+ }
467
+
468
+ const found = strData.find(store => store.id === id)
469
+ return (found) ? true : false
470
+
471
+ }
472
+
473
+ override ngOnDestroy() {
474
+ this.persistence$.unsubscribe()
475
+ }
476
+
477
+ /**
478
+ * Clears all stored data from localStorage and sessionStorage
479
+ * Use this method to recover from corrupted data errors
480
+ */
481
+ clearAllStoredData(): void {
482
+ try {
483
+ // Use resetStore() instead of directly removing raw localStorage keys.
484
+ // clearAllStoredData previously only removed the raw localStorage entries, leaving
485
+ // the ComponentStore's in-memory BehaviorSubject untouched. Any subsequent call to
486
+ // store$(name) would read from the in-memory state and return the old (stale) data,
487
+ // because store$ is a ComponentStore selector — it reads from in-memory state, not
488
+ // from raw localStorage. This caused stale requestCache / queryParams to persist
489
+ // after a deleteDatabase() call, blocking all subsequent API requests.
490
+ // resetStore() correctly updates both the in-memory state AND persists to localStorage.
491
+ this.resetStore();
492
+ console.log('Cleared all stored data');
493
+ } catch (error) {
494
+ console.error('Failed to clear stored data:', error);
495
+ }
496
+ }
497
+
498
+ /**
499
+ * Checks if stored data appears to be corrupted
500
+ * Returns true if data appears corrupted
501
+ */
502
+ checkForCorruptedData(): boolean {
503
+ try {
504
+ const str = localStorage.getItem(this.storageSettingsName);
505
+ if (str) {
506
+ const plainSettings = this.tryParseSettingsArray(str);
507
+ if (plainSettings) {
508
+ return false;
509
+ }
510
+
511
+ const decryptedStr = this.encryption.decrypt(str, this.app.appID);
512
+ if (decryptedStr !== null && decryptedStr !== undefined) {
513
+ const decryptedSettings = this.tryParseSettingsArray(decryptedStr);
514
+ return !decryptedSettings;
515
+ }
516
+
517
+ return true;
518
+ }
519
+ return false;
520
+ } catch (error) {
521
+ // Parsing failed, data is corrupted
522
+ return true;
523
+ }
524
+ }
525
+
526
+ private tryParseSettingsArray(raw: any): StorageOption[] | null {
527
+ if (!raw) {
528
+ return null;
529
+ }
530
+
531
+ if (Array.isArray(raw)) {
532
+ return raw;
533
+ }
534
+
535
+ if (!this.isString(raw)) {
536
+ return null;
537
+ }
538
+
539
+ try {
540
+ const parsed = JSON.parse(raw);
541
+ if (Array.isArray(parsed)) {
542
+ return parsed;
543
+ }
544
+
545
+ if (this.isString(parsed)) {
546
+ const nestedParsed = JSON.parse(parsed);
547
+ if (Array.isArray(nestedParsed)) {
548
+ return nestedParsed;
549
+ }
550
+ }
551
+ } catch {
552
+ // Continue to fallback parser
553
+ }
554
+
555
+ try {
556
+ const fallbackParsed = this.fixAndParseJSON(raw);
557
+ if (Array.isArray(fallbackParsed)) {
558
+ return fallbackParsed;
559
+ }
560
+ } catch {
561
+ return null;
562
+ }
563
+
564
+ return null;
565
+ }
566
+
567
+ }
@@ -0,0 +1,67 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { LocalStorageSignalsManagerService } from './local-storage-signals-manager.service';
3
+ import { UtilsService } from '../utils/utils.service';
4
+ import { SymmetricalEncryptionService } from '../utils/encryption/symmetrical-encryption.service';
5
+ import { EncryptionTestService } from '../utils/encryption/encryption-test.service';
6
+ import { AppService } from '../utils/app.service';
7
+ import { ObjectMergerService } from '../utils/object-merger.service';
8
+
9
+ describe('LocalStorageSignalsManagerService (signals)', () => {
10
+ let service: LocalStorageSignalsManagerService;
11
+ let utilsService: jasmine.SpyObj<UtilsService>;
12
+ let encryptionService: jasmine.SpyObj<SymmetricalEncryptionService>;
13
+ let encryptionTestService: jasmine.SpyObj<EncryptionTestService>;
14
+ let appService: jasmine.SpyObj<AppService>;
15
+ let objectMergerService: jasmine.SpyObj<ObjectMergerService>;
16
+
17
+ beforeEach(() => {
18
+ localStorage.clear();
19
+ sessionStorage.clear();
20
+
21
+ const utilsSpy = jasmine.createSpyObj('UtilsService', ['expires', 'hasExpired', 'generateUUID']);
22
+ const encryptionSpy = jasmine.createSpyObj('SymmetricalEncryptionService', ['encrypt', 'decrypt']);
23
+ const encryptionTestSpy = jasmine.createSpyObj('EncryptionTestService', ['isEncrypted']);
24
+ const appServiceSpy = jasmine.createSpyObj('AppService', [], { appID: 'test-app-id' });
25
+ const objectMergerSpy = jasmine.createSpyObj('ObjectMergerService', ['mergeStorageOptions']);
26
+
27
+ utilsSpy.generateUUID.and.returnValue('test-uuid');
28
+
29
+ TestBed.configureTestingModule({
30
+ providers: [
31
+ LocalStorageSignalsManagerService,
32
+ { provide: UtilsService, useValue: utilsSpy },
33
+ { provide: SymmetricalEncryptionService, useValue: encryptionSpy },
34
+ { provide: EncryptionTestService, useValue: encryptionTestSpy },
35
+ { provide: AppService, useValue: appServiceSpy },
36
+ { provide: ObjectMergerService, useValue: objectMergerSpy }
37
+ ]
38
+ });
39
+
40
+ service = TestBed.inject(LocalStorageSignalsManagerService);
41
+ utilsService = TestBed.inject(UtilsService) as jasmine.SpyObj<UtilsService>;
42
+ encryptionService = TestBed.inject(SymmetricalEncryptionService) as jasmine.SpyObj<SymmetricalEncryptionService>;
43
+ encryptionTestService = TestBed.inject(EncryptionTestService) as jasmine.SpyObj<EncryptionTestService>;
44
+ appService = TestBed.inject(AppService) as jasmine.SpyObj<AppService>;
45
+ objectMergerService = TestBed.inject(ObjectMergerService) as jasmine.SpyObj<ObjectMergerService>;
46
+
47
+ // Setup default spy behaviors
48
+ utilsService.hasExpired.and.returnValue(false);
49
+ utilsService.expires.and.returnValue(0);
50
+ encryptionTestService.isEncrypted.and.returnValue(false);
51
+ encryptionService.encrypt.and.returnValue('encrypted');
52
+ encryptionService.decrypt.and.returnValue('{}');
53
+
54
+ // Ensure empty initial state via the public API
55
+ service.resetStore();
56
+ });
57
+
58
+ afterEach(() => {
59
+ localStorage.clear();
60
+ sessionStorage.clear();
61
+ });
62
+
63
+ it('should be created', () => {
64
+ expect(service).toBeTruthy();
65
+ });
66
+
67
+ });