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,1604 @@
1
+ # Utils Service
2
+
3
+ Comprehensive utility services for common tasks including encryption, headers, path/query building, object merging, and general utilities.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [UtilsService - General Utilities](#utilsservice---general-utilities)
8
+ 2. [Encryption Services](#encryption-services)
9
+ 3. [HeadersService](#headersservice)
10
+ 4. [PathQueryService](#pathqueryservice)
11
+ 5. [ObjectMergerService](#objectmergerservice)
12
+
13
+ ---
14
+
15
+ ## UtilsService - General Utilities
16
+
17
+ The `UtilsService` provides a collection of utility functions for common tasks.
18
+
19
+ ### Overview
20
+
21
+ **Features:**
22
+ - ✅ JSON Handling - Safe JSON parsing and stringification
23
+ - ✅ Type Checking - Runtime type validation
24
+ - ✅ Expiration Management - Duration strings to epoch timestamps
25
+ - ✅ Conversions - Base32, binary, and data format conversions
26
+ - ✅ Object Operations - Deep comparison and property access
27
+ - ✅ Time Utilities - Date/time calculations
28
+
29
+ ### JSON Operations
30
+
31
+ ```typescript
32
+ import { UtilsService } from 'http-request-manager';
33
+
34
+ const utils = inject(UtilsService);
35
+
36
+ // Safe JSON parsing
37
+ const parsed = utils.stringToJSON('{"name": "John", "age": 30}');
38
+ // Returns: { name: 'John', age: 30 }
39
+
40
+ // Safe JSON stringification
41
+ const stringified = utils.JSONToString({ name: 'John', age: 30 });
42
+ // Returns: '{"name":"John","age":30}'
43
+
44
+ // Handle invalid JSON gracefully
45
+ const invalid = utils.stringToJSON('invalid json');
46
+ // Returns: null (no exception thrown)
47
+ ```
48
+
49
+ ### Type Checking
50
+
51
+ ```typescript
52
+ // Check if value is string
53
+ utils.isString('hello'); // true
54
+ utils.isString(123); // false
55
+
56
+ // Check if value is object
57
+ utils.isObject({}); // true
58
+ utils.isObject([]); // false
59
+ utils.isObject(null); // false
60
+
61
+ // Check if value is JSON
62
+ utils.isJson('{"valid": true}'); // true
63
+ utils.isJson('invalid'); // false
64
+
65
+ // Check if object is empty
66
+ utils.isEmpty({}); // true
67
+ utils.isEmpty({ name: 'John' }); // false
68
+ ```
69
+
70
+ ### Expiration Management
71
+
72
+ ```typescript
73
+ // Parse duration strings to milliseconds
74
+ utils.parseExpiration('1h'); // 3600000
75
+ utils.parseExpiration('7d'); // 604800000
76
+ utils.parseExpiration('30m'); // 1800000
77
+ utils.parseExpiration('1y'); // 31536000000
78
+
79
+ // Convert to epoch timestamp
80
+ const expires = utils.calculateExpiresIn('7d');
81
+ // Returns: epoch timestamp 7 days from now
82
+
83
+ // Check if expired
84
+ const isExpired = utils.isExpired(expires);
85
+ // Returns: true/false
86
+
87
+ // Get time remaining
88
+ const remaining = utils.getTimeRemaining(expires);
89
+ // Returns: milliseconds until expiration
90
+ ```
91
+
92
+ **Duration Formats:**
93
+ - `'30s'` - 30 seconds
94
+ - `'5m'` - 5 minutes
95
+ - `'1h'` - 1 hour
96
+ - `'1d'` - 1 day
97
+ - `'7d'` - 7 days
98
+ - `'30d'` - 30 days
99
+ - `'1y'` - 1 year
100
+
101
+ ### Conversions
102
+
103
+ ```typescript
104
+ // Base32 to Hex
105
+ const hex = utils.base32ToHex('JBSWY3DPEHPK3PXP');
106
+
107
+ // Binary to Hex
108
+ const hex = utils.binaryToHex('01001000');
109
+
110
+ // String to Base64
111
+ const base64 = utils.stringToBase64('Hello World');
112
+
113
+ // Base64 to String
114
+ const str = utils.base64ToString('SGVsbG8gV29ybGQ=');
115
+ ```
116
+
117
+ ### Object Operations
118
+
119
+ ```typescript
120
+ // Deep compare objects
121
+ const areEqual = utils.isObjectEqual(obj1, obj2);
122
+
123
+ // Get nested property safely
124
+ const value = utils.getProperty(obj, 'user.address.city');
125
+ // Returns: undefined instead of throwing error
126
+
127
+ // Set nested property
128
+ utils.setProperty(obj, 'user.address.city', 'New York');
129
+ ```
130
+
131
+ ### Time Utilities
132
+
133
+ ```typescript
134
+ // Get current epoch time
135
+ const now = utils.getCurrentEpoch();
136
+
137
+ // Format date
138
+ const formatted = utils.formatDate(new Date(), 'YYYY-MM-DD');
139
+
140
+ // Calculate date difference
141
+ const diff = utils.getDateDifference(date1, date2, 'days');
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Encryption Services
147
+
148
+ ### SymmetricalEncryptionService
149
+
150
+ AES symmetric encryption for fast data encryption.
151
+
152
+ **Features:**
153
+ - 🔐 AES-256 encryption
154
+ - 🔑 Automatic key generation
155
+ - 📦 Ideal for data at rest
156
+ - ⚡ Fast encryption/decryption
157
+
158
+ **Usage:**
159
+
160
+ ```typescript
161
+ import { SymmetricalEncryptionService } from 'http-request-manager';
162
+
163
+ const encryption = inject(SymmetricalEncryptionService);
164
+
165
+ // Encrypt data
166
+ const encrypted = encryption.encrypt('Sensitive data');
167
+ console.log('Encrypted:', encrypted);
168
+
169
+ // Decrypt data
170
+ const decrypted = encryption.decrypt(encrypted);
171
+ console.log('Decrypted:', decrypted);
172
+
173
+ // Generate encryption key
174
+ const key = encryption.generateKey();
175
+ ```
176
+
177
+ **Methods:**
178
+ ```typescript
179
+ encrypt(data: string): string
180
+ decrypt(encryptedData: string): string
181
+ generateKey(): string
182
+ ```
183
+
184
+ ### AsymmetricalEncryptionService
185
+
186
+ RSA asymmetric encryption with public/private key pairs.
187
+
188
+ **Features:**
189
+ - 🔑 Public/private key encryption
190
+ - ✍️ Digital signatures
191
+ - 🔒 Enhanced security
192
+ - 📜 Key pair generation
193
+
194
+ **Usage:**
195
+
196
+ ```typescript
197
+ import { AsymmetricalEncryptionService } from 'http-request-manager';
198
+
199
+ const encryption = inject(AsymmetricalEncryptionService);
200
+
201
+ // Generate key pair
202
+ const keyPair = encryption.generateKeyPair();
203
+ console.log('Public Key:', keyPair.publicKey);
204
+ console.log('Private Key:', keyPair.privateKey);
205
+
206
+ // Encrypt with public key
207
+ const encrypted = encryption.encryptWithPublicKey(
208
+ 'Secret message',
209
+ keyPair.publicKey
210
+ );
211
+
212
+ // Decrypt with private key
213
+ const decrypted = encryption.decryptWithPrivateKey(
214
+ encrypted,
215
+ keyPair.privateKey
216
+ );
217
+
218
+ // Sign data
219
+ const signature = encryption.sign('Data to sign', keyPair.privateKey);
220
+
221
+ // Verify signature
222
+ const isValid = encryption.verify(
223
+ signature,
224
+ 'Data to sign',
225
+ keyPair.publicKey
226
+ );
227
+ ```
228
+
229
+ **Methods:**
230
+ ```typescript
231
+ generateKeyPair(): { publicKey: string, privateKey: string }
232
+ encryptWithPublicKey(data: string, publicKey: string): string
233
+ decryptWithPrivateKey(encryptedData: string, privateKey: string): string
234
+ sign(data: string, privateKey: string): string
235
+ verify(signature: string, data: string, publicKey: string): boolean
236
+ ```
237
+
238
+ ### Random Utility
239
+
240
+ Cryptographically secure random value generation.
241
+
242
+ **Usage:**
243
+
244
+ ```typescript
245
+ import { Random } from 'http-request-manager';
246
+
247
+ // Generate random string
248
+ const randomString = Random.generate(16);
249
+ // Example: 'a3f8b2c1d4e5f6g7'
250
+
251
+ // Generate random number
252
+ const randomNumber = Random.number(1, 100);
253
+ // Example: 42
254
+
255
+ // Generate random color
256
+ const randomColor = Random.color();
257
+ // Example: '#a3f129'
258
+
259
+ // Generate UUID
260
+ const uuid = Random.uuid();
261
+ // Example: '550e8400-e29b-41d4-a716-446655440000'
262
+ ```
263
+
264
+ **Methods:**
265
+ ```typescript
266
+ generate(length: number): string
267
+ number(min: number, max: number): number
268
+ color(): string
269
+ uuid(): string
270
+ ```
271
+
272
+ ---
273
+
274
+ ## HeadersService
275
+
276
+ Dynamic HTTP header management.
277
+
278
+ **Features:**
279
+ - 📝 Content-Type management
280
+ - 🌐 Accept-Language with locale
281
+ - 📅 Current-Date header
282
+ - 🔄 Dynamic updates
283
+
284
+ **Usage:**
285
+
286
+ ```typescript
287
+ import { HeadersService } from 'http-request-manager';
288
+
289
+ const headersService = inject(HeadersService);
290
+
291
+ // Get default headers
292
+ const headers = headersService.getDefaultHeaders();
293
+ // {
294
+ // 'Content-Type': 'application/json',
295
+ // 'Accept-Language': 'en-CA',
296
+ // 'Current-Date': '2026-03-28'
297
+ // }
298
+
299
+ // Get specific header
300
+ const contentType = headersService.getHeader('Content-Type');
301
+
302
+ // Set custom header
303
+ headersService.setHeader('Authorization', 'Bearer token');
304
+
305
+ // Remove header
306
+ headersService.removeHeader('Current-Date');
307
+
308
+ // Get all headers
309
+ const allHeaders = headersService.getAllHeaders();
310
+ ```
311
+
312
+ **Methods:**
313
+ ```typescript
314
+ getDefaultHeaders(): { [key: string]: string }
315
+ getHeader(name: string): string | undefined
316
+ setHeader(name: string, value: string): void
317
+ removeHeader(name: string): void
318
+ getAllHeaders(): { [key: string]: string }
319
+ getLanguageHeader(): string
320
+ getDateHeader(): string
321
+ ```
322
+
323
+ **Automatic Language Detection:**
324
+
325
+ The service automatically detects the current language from `@ngx-translate/core`:
326
+
327
+ ```typescript
328
+ // If current language is 'en'
329
+ headersService.getLanguageHeader();
330
+ // Returns: 'en-CA'
331
+
332
+ // If current language is 'fr'
333
+ headersService.getLanguageHeader();
334
+ // Returns: 'fr-CA'
335
+ ```
336
+
337
+ ---
338
+
339
+ ## PathQueryService
340
+
341
+ URL path and query parameter building.
342
+
343
+ **Features:**
344
+ - 🔗 Path segment joining
345
+ - ❓ Query parameter building
346
+ - 🔍 Query string parsing
347
+ - 📝 URL normalization
348
+
349
+ **Usage:**
350
+
351
+ ```typescript
352
+ import { PathQueryService } from 'http-request-manager';
353
+
354
+ const pathQuery = inject(PathQueryService);
355
+
356
+ // Build path from segments
357
+ const path = pathQuery.buildPath(['api', 'users', 123]);
358
+ // Returns: 'api/users/123'
359
+
360
+ // Build query string
361
+ const queryString = pathQuery.buildQuery({
362
+ page: 1,
363
+ limit: 10,
364
+ filter: 'active'
365
+ });
366
+ // Returns: '?page=1&limit=10&filter=active'
367
+
368
+ // Parse query string
369
+ const params = pathQuery.parseQuery('?page=1&limit=10');
370
+ // Returns: { page: 1, limit: 10 }
371
+
372
+ // Join path with query
373
+ const fullUrl = pathQuery.buildUrl('api/users', { page: 1 });
374
+ // Returns: 'api/users?page=1'
375
+
376
+ // Normalize path
377
+ const normalized = pathQuery.normalizePath('api//users///123');
378
+ // Returns: 'api/users/123'
379
+ ```
380
+
381
+ **Methods:**
382
+ ```typescript
383
+ buildPath(segments: any[]): string
384
+ buildQuery(params: { [key: string]: any }): string
385
+ parseQuery(queryString: string): { [key: string]: any }
386
+ buildUrl(path: string, params?: { [key: string]: any }): string
387
+ normalizePath(path: string): string
388
+ ```
389
+
390
+ ---
391
+
392
+ ## ObjectMergerService
393
+
394
+ Deep object merging with advanced options.
395
+
396
+ **Features:**
397
+ - 🔀 Deep merge objects
398
+ - 📦 Array merging options
399
+ - 🎯 Custom merge strategies
400
+ - 🛡️ Clone protection
401
+
402
+ **Usage:**
403
+
404
+ ```typescript
405
+ import { ObjectMergerService } from 'http-request-manager';
406
+
407
+ const merger = inject(ObjectMergerService);
408
+
409
+ // Basic deep merge
410
+ const merged = merger.deepMerge(obj1, obj2);
411
+
412
+ // Merge with options
413
+ const mergedWithOptions = merger.deepMerge(obj1, obj2, {
414
+ clone: true, // Don't mutate original objects
415
+ mergeArrays: false // Replace arrays instead of merging
416
+ });
417
+
418
+ // Custom merge strategy
419
+ const customMerged = merger.deepMerge(obj1, obj2, {
420
+ customMerge: (key, targetValue, sourceValue) => {
421
+ if (key === 'price') {
422
+ return Math.max(targetValue, sourceValue);
423
+ }
424
+ return undefined; // Use default merge
425
+ }
426
+ });
427
+ ```
428
+
429
+ **MergeOptions:**
430
+ ```typescript
431
+ interface MergeOptions {
432
+ clone?: boolean; // Clone source objects
433
+ mergeArrays?: boolean; // Merge arrays vs replace
434
+ customMerge?: (key: string, target: any, source: any) => any;
435
+ }
436
+ ```
437
+
438
+ **Example:**
439
+
440
+ ```typescript
441
+ const user1 = {
442
+ id: 1,
443
+ name: 'John',
444
+ preferences: {
445
+ theme: 'light',
446
+ notifications: true
447
+ },
448
+ tags: ['admin', 'user']
449
+ };
450
+
451
+ const user2 = {
452
+ name: 'John Doe',
453
+ preferences: {
454
+ language: 'en'
455
+ },
456
+ tags: ['moderator']
457
+ };
458
+
459
+ // Deep merge
460
+ const merged = merger.deepMerge(user1, user2);
461
+ // {
462
+ // id: 1,
463
+ // name: 'John Doe',
464
+ // preferences: {
465
+ // theme: 'light',
466
+ // notifications: true,
467
+ // language: 'en'
468
+ // },
469
+ // tags: ['admin', 'user', 'moderator']
470
+ // }
471
+ ```
472
+
473
+ **Methods:**
474
+ ```typescript
475
+ deepMerge<T>(target: T, source: Partial<T>, options?: MergeOptions): T
476
+ shallowMerge<T>(target: T, source: Partial<T>): T
477
+ mergeArray<T>(target: T[], source: T[]): T[]
478
+ ```
479
+
480
+ ---
481
+
482
+ ## AppService
483
+
484
+ Application-level utilities.
485
+
486
+ **Features:**
487
+ - 📱 App ID management
488
+ - 🔍 Environment detection
489
+ - 📊 Logging utilities
490
+
491
+ **Usage:**
492
+
493
+ ```typescript
494
+ import { AppService } from 'http-request-manager';
495
+
496
+ const appService = inject(AppService);
497
+
498
+ // Get app ID
499
+ const appId = appService.getAppId();
500
+
501
+ // Check environment
502
+ const isProduction = appService.isProduction();
503
+ const isDevelopment = appService.isDevelopment();
504
+
505
+ // Log with app context
506
+ appService.log('Info message', { data: 'value' });
507
+ appService.warn('Warning message');
508
+ appService.error('Error message');
509
+ ```
510
+
511
+ ---
512
+
513
+ ## Related Documentation
514
+
515
+ - [`Encryption Guide`](ENCRYPTION_README.md) - Detailed encryption documentation
516
+ - [`Models Guide`](MODELS_README.md) - Configuration models
517
+ - [`LocalStorage`](LOCAL_STORAGE_README.md) - Encrypted storage usage
518
+ - [`Interceptors`](INTERCEPTOR_README.md) - Header interceptor details
519
+ }
520
+
521
+ checkTypes() {
522
+ this.typeResult = {
523
+ isString: this.utils.isString(this.testValue),
524
+ isObject: this.utils.isObject(this.testValue),
525
+ isJson: this.utils.isJSON(this.testValue)
526
+ };
527
+ }
528
+
529
+ testExpiration() {
530
+ const oneDayFromNow = this.utils.expires('1d');
531
+ const currentTime = Math.floor(Date.now() / 1000);
532
+
533
+ this.expiryResult = {
534
+ oneDay: oneDayFromNow ? new Date(oneDayFromNow * 1000) : null,
535
+ current: new Date(currentTime * 1000),
536
+ hasExpired: this.utils.hasExpired(oneDayFromNow || 0),
537
+ timeRemaining: this.utils.expiresIn(oneDayFromNow || 0)
538
+ };
539
+ }
540
+
541
+ testConversions() {
542
+ this.conversionResult = {
543
+ base32ToHex: this.utils.base32ToHex('JBSWY3DPEHPK3PXP'),
544
+ binaryToHex: this.utils.binaryToHex('11000011100011110000')
545
+ };
546
+ }
547
+ }
548
+ ```
549
+
550
+ ## API Reference
551
+
552
+ ### JSON Operations
553
+
554
+ #### JSONToString(value: any): string
555
+
556
+ Safely convert value to JSON string:
557
+
558
+ ```typescript
559
+ const obj = { name: 'John', age: 30 };
560
+ const jsonString = this.utils.JSONToString(obj);
561
+ // Returns: '{"name":"John","age":30}'
562
+
563
+ const number = 42;
564
+ const stringValue = this.utils.JSONToString(number);
565
+ // Returns: '42'
566
+ ```
567
+
568
+ #### stringToJSON(value: string): any
569
+
570
+ Safely parse JSON string:
571
+
572
+ ```typescript
573
+ const jsonString = '{"name":"John","age":30}';
574
+ const obj = this.utils.stringToJSON(jsonString);
575
+ // Returns: { name: 'John', age: 30 }
576
+
577
+ const invalidJson = '{invalid json}';
578
+ const result = this.utils.stringToJSON(invalidJson);
579
+ // Returns: '{invalid json}' (unchanged)
580
+ ```
581
+
582
+ ### Type Checking
583
+
584
+ #### isString(value: any): boolean
585
+
586
+ Check if value is a string:
587
+
588
+ ```typescript
589
+ this.utils.isString('hello'); // true
590
+ this.utils.isString(123); // false
591
+ this.utils.isString(null); // false
592
+ this.utils.isString(undefined); // false
593
+ ```
594
+
595
+ #### isObject(value: any): boolean
596
+
597
+ Check if value is an object:
598
+
599
+ ```typescript
600
+ this.utils.isObject({}); // true
601
+ this.utils.isObject({ name: 'John' }); // true
602
+ this.utils.isObject(null); // false
603
+ this.utils.isObject([]); // true (arrays are objects)
604
+ this.utils.isObject('string'); // false
605
+ ```
606
+
607
+ #### isJSON(value: any): boolean
608
+
609
+ Check if value is valid JSON:
610
+
611
+ ```typescript
612
+ this.utils.isJSON('{"name":"John"}'); // true
613
+ this.utils.isJSON('not json'); // false
614
+ this.utils.isJSON(123); // false
615
+ this.utils.isJSON(null); // false
616
+ ```
617
+
618
+ ### Property Access
619
+
620
+ #### getValueByProp(obj: any, prop: string): any
621
+
622
+ Get property value by string path:
623
+
624
+ ```typescript
625
+ const obj = { user: { name: 'John', settings: { theme: 'dark' } } };
626
+
627
+ this.utils.getValueByProp(obj, 'user.name'); // undefined (doesn't support nesting)
628
+ this.utils.getValueByProp(obj.user, 'name'); // 'John'
629
+ this.utils.getValueByProp(obj.user.settings, 'theme'); // 'dark'
630
+ this.utils.getValueByProp(obj, 'nonexistent'); // false
631
+ ```
632
+
633
+ ### Object Comparison
634
+
635
+ #### objectsEqual(x: any, y: any): boolean
636
+
637
+ Deep comparison of two objects:
638
+
639
+ ```typescript
640
+ const obj1 = { name: 'John', age: 30, active: true };
641
+ const obj2 = { name: 'John', age: 30, active: true };
642
+ const obj3 = { name: 'John', age: 31, active: true };
643
+
644
+ this.utils.objectsEqual(obj1, obj2); // true
645
+ this.utils.objectsEqual(obj1, obj3); // false
646
+
647
+ // Nested objects
648
+ const nested1 = { user: { name: 'John', settings: { theme: 'dark' } } };
649
+ const nested2 = { user: { name: 'John', settings: { theme: 'dark' } } };
650
+ this.utils.objectsEqual(nested1, nested2); // true
651
+ ```
652
+
653
+ ### HTTP Operations
654
+
655
+ #### getJSON(file: string): Observable<any>
656
+
657
+ Get JSON file from assets:
658
+
659
+ ```typescript
660
+ this.utils.getJSON('data/config.json').subscribe(config => {
661
+ console.log('Config loaded:', config);
662
+ });
663
+ ```
664
+
665
+ ### Time Properties
666
+
667
+ #### today: number
668
+
669
+ Get current time in milliseconds:
670
+
671
+ ```typescript
672
+ const currentTime = this.utils.today;
673
+ console.log('Current time (ms):', currentTime);
674
+ ```
675
+
676
+ ### Expiration Management
677
+
678
+ #### expires(str?: string): number | undefined
679
+
680
+ Convert duration string to epoch timestamp:
681
+
682
+ ```typescript
683
+ // Time units: y=years, m=months, w=weeks, d=days, hr=hours, mn=minutes, s=seconds
684
+
685
+ this.utils.expires('1d'); // Current time + 1 day
686
+ this.utils.expires('2h'); // Current time + 2 hours
687
+ this.utils.expires('30m'); // Current time + 30 minutes
688
+ this.utils.expires('1w'); // Current time + 1 week
689
+ this.utils.expires('1y'); // Current time + 1 year
690
+
691
+ this.utils.expires(); // undefined (no duration provided)
692
+ ```
693
+
694
+ #### hasExpired(expiryDate: number): boolean
695
+
696
+ Check if timestamp has expired:
697
+
698
+ ```typescript
699
+ const futureTime = this.utils.expires('1d');
700
+ const pastTime = Math.floor(Date.now() / 1000) - 3600; // 1 hour ago
701
+
702
+ this.utils.hasExpired(futureTime); // false
703
+ this.utils.hasExpired(pastTime); // true
704
+ ```
705
+
706
+ #### hasExpiry(setting: any): boolean
707
+
708
+ Check if setting has expiration:
709
+
710
+ ```typescript
711
+ const setting1 = { expires: 1234567890 };
712
+ const setting2 = { encrypted: true };
713
+
714
+ this.utils.hasExpiry(setting1); // true
715
+ this.utils.hasExpiry(setting2); // false
716
+ ```
717
+
718
+ #### expiresIn(expiryDate: number): string | undefined
719
+
720
+ Get human-readable time remaining:
721
+
722
+ ```typescript
723
+ const oneDayFromNow = this.utils.expires('1d');
724
+ const oneHourFromNow = this.utils.expires('1h');
725
+
726
+ console.log(this.utils.expiresIn(oneDayFromNow)); // "1d"
727
+ console.log(this.utils.expiresIn(oneHourFromNow)); // "1h"
728
+
729
+ // For expired dates
730
+ const pastTime = Math.floor(Date.now() / 1000) - 3600;
731
+ console.log(this.utils.expiresIn(pastTime)); // "Expired"
732
+ ```
733
+
734
+ ### Conversions
735
+
736
+ #### base32ToHex(base32: string): string
737
+
738
+ Convert Base32 string to hexadecimal:
739
+
740
+ ```typescript
741
+ this.utils.base32ToHex('JBSWY3DPEHPK3PXP'); // '48656C6C6F20576F726C64'
742
+ this.utils.base32ToHex('MY'); // '66'
743
+ this.utils.base32ToHex('MZXQ6==='); // '6C'
744
+ ```
745
+
746
+ #### binaryToHex(binary: string): string
747
+
748
+ Convert binary string to hexadecimal:
749
+
750
+ ```typescript
751
+ this.utils.binaryToHex('11000011100011110000'); // 'C78F0'
752
+ this.utils.binaryToHex('10101010'); // 'AA000000'
753
+ this.utils.binaryToHex('1111'); // 'F000'
754
+ ```
755
+
756
+ ### String Utilities
757
+
758
+ #### lc(str: string): string
759
+
760
+ Convert string to lowercase with special character replacement:
761
+
762
+ ```typescript
763
+ this.utils.lc('Hello World!'); // 'helloworld'
764
+ this.utils.lc('Test-Case_String'); // 'testcasestring'
765
+ this.utils.lc('UPPER CASE'); // 'uppercase'
766
+ ```
767
+
768
+ ## Advanced Examples
769
+
770
+ ### Data Validation Service
771
+
772
+ ```typescript
773
+ import { Injectable } from '@angular/core';
774
+ import { UtilsService } from 'http-request-manager';
775
+
776
+ interface ValidationResult {
777
+ isValid: boolean;
778
+ errors: string[];
779
+ sanitizedData?: any;
780
+ }
781
+
782
+ @Injectable({
783
+ providedIn: 'root'
784
+ })
785
+ export class DataValidationService {
786
+ constructor(private utils: UtilsService) {}
787
+
788
+ validateAndSanitize<T>(data: any, schema: any): ValidationResult {
789
+ const errors: string[] = [];
790
+ let sanitizedData: any = {};
791
+
792
+ try {
793
+ // Check if data is object
794
+ if (!this.utils.isObject(data)) {
795
+ errors.push('Data must be an object');
796
+ return { isValid: false, errors };
797
+ }
798
+
799
+ // Sanitize each field according to schema
800
+ for (const [field, rules] of Object.entries(schema)) {
801
+ const value = data[field];
802
+ const sanitizedValue = this.sanitizeField(field, value, rules as any);
803
+
804
+ if (sanitizedValue !== undefined) {
805
+ sanitizedData[field] = sanitizedValue;
806
+ }
807
+ }
808
+
809
+ return {
810
+ isValid: errors.length === 0,
811
+ errors,
812
+ sanitizedData
813
+ };
814
+ } catch (error) {
815
+ errors.push(`Validation error: ${error}`);
816
+ return { isValid: false, errors };
817
+ }
818
+ }
819
+
820
+ private sanitizeField(field: string, value: any, rules: any): any {
821
+ // Handle required fields
822
+ if (rules.required && (value === undefined || value === null)) {
823
+ throw new Error(`Field '${field}' is required`);
824
+ }
825
+
826
+ if (value === undefined || value === null) {
827
+ return rules.default;
828
+ }
829
+
830
+ // Type validation
831
+ switch (rules.type) {
832
+ case 'string':
833
+ if (typeof value !== 'string') {
834
+ throw new Error(`Field '${field}' must be a string`);
835
+ }
836
+ break;
837
+
838
+ case 'number':
839
+ if (typeof value !== 'number' && isNaN(Number(value))) {
840
+ throw new Error(`Field '${field}' must be a number`);
841
+ }
842
+ value = Number(value);
843
+ break;
844
+
845
+ case 'boolean':
846
+ if (typeof value !== 'boolean') {
847
+ throw new Error(`Field '${field}' must be a boolean`);
848
+ }
849
+ break;
850
+
851
+ case 'object':
852
+ if (!this.utils.isObject(value)) {
853
+ throw new Error(`Field '${field}' must be an object`);
854
+ }
855
+ break;
856
+
857
+ case 'json':
858
+ if (!this.utils.isJSON(value)) {
859
+ throw new Error(`Field '${field}' must be valid JSON`);
860
+ }
861
+ value = this.utils.stringToJSON(value);
862
+ break;
863
+ }
864
+
865
+ // String-specific rules
866
+ if (rules.type === 'string') {
867
+ // Min/max length
868
+ if (rules.minLength && value.length < rules.minLength) {
869
+ throw new Error(`Field '${field}' must be at least ${rules.minLength} characters`);
870
+ }
871
+ if (rules.maxLength && value.length > rules.maxLength) {
872
+ throw new Error(`Field '${field}' must be no more than ${rules.maxLength} characters`);
873
+ }
874
+
875
+ // Pattern matching
876
+ if (rules.pattern && !rules.pattern.test(value)) {
877
+ throw new Error(`Field '${field}' does not match required pattern`);
878
+ }
879
+
880
+ // Sanitization
881
+ if (rules.lowercase) {
882
+ value = value.toLowerCase();
883
+ }
884
+ if (rules.trim) {
885
+ value = value.trim();
886
+ }
887
+ }
888
+
889
+ // Number-specific rules
890
+ if (rules.type === 'number') {
891
+ if (rules.min !== undefined && value < rules.min) {
892
+ throw new Error(`Field '${field}' must be at least ${rules.min}`);
893
+ }
894
+ if (rules.max !== undefined && value > rules.max) {
895
+ throw new Error(`Field '${field}' must be no more than ${rules.max}`);
896
+ }
897
+ }
898
+
899
+ // Array-specific rules
900
+ if (rules.type === 'array') {
901
+ if (!Array.isArray(value)) {
902
+ throw new Error(`Field '${field}' must be an array`);
903
+ }
904
+ if (rules.minItems && value.length < rules.minItems) {
905
+ throw new Error(`Field '${field}' must have at least ${rules.minItems} items`);
906
+ }
907
+ if (rules.maxItems && value.length > rules.maxItems) {
908
+ throw new Error(`Field '${field}' must have no more than ${rules.maxItems} items`);
909
+ }
910
+ }
911
+
912
+ return value;
913
+ }
914
+
915
+ // Predefined schemas
916
+ getUserSchema() {
917
+ return {
918
+ name: {
919
+ type: 'string',
920
+ required: true,
921
+ minLength: 2,
922
+ maxLength: 50,
923
+ pattern: /^[a-zA-Z\s]+$/,
924
+ trim: true
925
+ },
926
+ email: {
927
+ type: 'string',
928
+ required: true,
929
+ pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
930
+ lowercase: true,
931
+ trim: true
932
+ },
933
+ age: {
934
+ type: 'number',
935
+ min: 0,
936
+ max: 150
937
+ },
938
+ preferences: {
939
+ type: 'object',
940
+ default: {}
941
+ }
942
+ };
943
+ }
944
+
945
+ getProductSchema() {
946
+ return {
947
+ name: {
948
+ type: 'string',
949
+ required: true,
950
+ minLength: 1,
951
+ maxLength: 100
952
+ },
953
+ price: {
954
+ type: 'number',
955
+ required: true,
956
+ min: 0
957
+ },
958
+ description: {
959
+ type: 'string',
960
+ maxLength: 500,
961
+ trim: true
962
+ },
963
+ tags: {
964
+ type: 'array',
965
+ maxItems: 10,
966
+ default: []
967
+ }
968
+ };
969
+ }
970
+ }
971
+ ```
972
+
973
+ ### Cache Management Service
974
+
975
+ ```typescript
976
+ @Injectable()
977
+ export class CacheManagerService {
978
+ constructor(private utils: UtilsService) {}
979
+
980
+ createCache<T>(key: string, ttl: string, maxSize?: number) {
981
+ return {
982
+ key,
983
+ ttl: this.utils.expires(ttl),
984
+ maxSize,
985
+ data: new Map<string, { value: T; timestamp: number }>(),
986
+
987
+ set(itemKey: string, value: T): void {
988
+ // Clean up expired items
989
+ this.cleanup();
990
+
991
+ // Check size limit
992
+ if (this.maxSize && this.data.size >= this.maxSize) {
993
+ // Remove oldest item
994
+ const oldestKey = this.data.keys().next().value;
995
+ this.data.delete(oldestKey);
996
+ }
997
+
998
+ this.data.set(itemKey, {
999
+ value,
1000
+ timestamp: Date.now()
1001
+ });
1002
+ },
1003
+
1004
+ get(itemKey: string): T | null {
1005
+ this.cleanup();
1006
+
1007
+ const item = this.data.get(itemKey);
1008
+ if (item) {
1009
+ return item.value;
1010
+ }
1011
+
1012
+ return null;
1013
+ },
1014
+
1015
+ has(itemKey: string): boolean {
1016
+ this.cleanup();
1017
+ return this.data.has(itemKey);
1018
+ },
1019
+
1020
+ delete(itemKey: string): boolean {
1021
+ return this.data.delete(itemKey);
1022
+ },
1023
+
1024
+ clear(): void {
1025
+ this.data.clear();
1026
+ },
1027
+
1028
+ size(): number {
1029
+ this.cleanup();
1030
+ return this.data.size;
1031
+ },
1032
+
1033
+ cleanup(): void {
1034
+ const now = Date.now();
1035
+ const expiredKeys: string[] = [];
1036
+
1037
+ this.data.forEach((item, key) => {
1038
+ if (item.timestamp < this.ttl * 1000) {
1039
+ expiredKeys.push(key);
1040
+ }
1041
+ });
1042
+
1043
+ expiredKeys.forEach(key => this.data.delete(key));
1044
+ },
1045
+
1046
+ export(): Array<{ key: string; value: T; timestamp: number }> {
1047
+ this.cleanup();
1048
+ return Array.from(this.data.entries()).map(([key, item]) => ({
1049
+ key,
1050
+ value: item.value,
1051
+ timestamp: item.timestamp
1052
+ }));
1053
+ },
1054
+
1055
+ import(items: Array<{ key: string; value: T; timestamp: number }>): void {
1056
+ items.forEach(item => {
1057
+ if (item.timestamp > this.ttl * 1000) {
1058
+ this.data.set(item.key, {
1059
+ value: item.value,
1060
+ timestamp: item.timestamp
1061
+ });
1062
+ }
1063
+ });
1064
+ }
1065
+ };
1066
+ }
1067
+
1068
+ // Global cache instance
1069
+ private globalCache = this.createCache('global-cache', '1h', 100);
1070
+
1071
+ cacheResult<T>(key: string, fn: () => T, ttl: string = '1h'): T {
1072
+ const cached = this.globalCache.get(key);
1073
+ if (cached !== null) {
1074
+ return cached;
1075
+ }
1076
+
1077
+ const result = fn();
1078
+ this.globalCache.set(key, result);
1079
+ return result;
1080
+ }
1081
+
1082
+ invalidateCache(key: string): void {
1083
+ this.globalCache.delete(key);
1084
+ }
1085
+
1086
+ clearCache(): void {
1087
+ this.globalCache.clear();
1088
+ }
1089
+ }
1090
+ ```
1091
+
1092
+ ### Configuration Manager
1093
+
1094
+ ```typescript
1095
+ @Injectable()
1096
+ export class ConfigurationManagerService {
1097
+ private configs = new Map<string, any>();
1098
+
1099
+ constructor(private utils: UtilsService) {}
1100
+
1101
+ loadConfig<T>(configKey: string, defaultValue: T, expiration?: string): T {
1102
+ const cached = this.configs.get(configKey);
1103
+
1104
+ if (cached && !this.isExpired(cached.timestamp, expiration)) {
1105
+ return cached.value;
1106
+ }
1107
+
1108
+ // Load from storage or API
1109
+ const value = this.loadConfigValue<T>(configKey, defaultValue);
1110
+
1111
+ this.configs.set(configKey, {
1112
+ value,
1113
+ timestamp: Date.now(),
1114
+ expiresAt: expiration ? this.utils.expires(expiration) : undefined
1115
+ });
1116
+
1117
+ return value;
1118
+ }
1119
+
1120
+ updateConfig<T>(configKey: string, value: T, expiration?: string): void {
1121
+ this.configs.set(configKey, {
1122
+ value,
1123
+ timestamp: Date.now(),
1124
+ expiresAt: expiration ? this.utils.expires(expiration) : undefined
1125
+ });
1126
+
1127
+ this.saveConfigValue(configKey, value);
1128
+ }
1129
+
1130
+ getConfig<T>(configKey: string): T | null {
1131
+ const cached = this.configs.get(configKey);
1132
+ if (cached && !this.isExpired(cached.timestamp, undefined)) {
1133
+ return cached.value;
1134
+ }
1135
+ return null;
1136
+ }
1137
+
1138
+ invalidateConfig(configKey: string): void {
1139
+ this.configs.delete(configKey);
1140
+ }
1141
+
1142
+ clearConfigs(): void {
1143
+ this.configs.clear();
1144
+ }
1145
+
1146
+ private isExpired(timestamp: number, expiration?: string): boolean {
1147
+ if (!expiration) return false;
1148
+
1149
+ const expiryTime = this.utils.expires(expiration);
1150
+ return this.utils.hasExpired(expiryTime || 0);
1151
+ }
1152
+
1153
+ private loadConfigValue<T>(configKey: string, defaultValue: T): T {
1154
+ try {
1155
+ const stored = localStorage.getItem(`config:${configKey}`);
1156
+ if (stored) {
1157
+ const parsed = JSON.parse(stored);
1158
+ return parsed.value || defaultValue;
1159
+ }
1160
+ } catch (error) {
1161
+ console.warn(`Failed to load config ${configKey}:`, error);
1162
+ }
1163
+
1164
+ return defaultValue;
1165
+ }
1166
+
1167
+ private saveConfigValue(configKey: string, value: any): void {
1168
+ try {
1169
+ localStorage.setItem(`config:${configKey}`, JSON.stringify({
1170
+ value,
1171
+ savedAt: new Date().toISOString()
1172
+ }));
1173
+ } catch (error) {
1174
+ console.warn(`Failed to save config ${configKey}:`, error);
1175
+ }
1176
+ }
1177
+
1178
+ // Predefined configurations
1179
+ getAppConfig() {
1180
+ return this.loadConfig('app-config', {
1181
+ version: '1.0.0',
1182
+ apiUrl: 'http://localhost:3000',
1183
+ features: {
1184
+ enableAnalytics: true,
1185
+ enableNotifications: true,
1186
+ enableOffline: false
1187
+ },
1188
+ limits: {
1189
+ maxFileSize: 10485760, // 10MB
1190
+ maxRequestsPerMinute: 100
1191
+ }
1192
+ }, '1h');
1193
+ }
1194
+
1195
+ getUserPreferences() {
1196
+ return this.loadConfig('user-preferences', {
1197
+ theme: 'light',
1198
+ language: 'en',
1199
+ notifications: {
1200
+ email: true,
1201
+ push: true,
1202
+ sms: false
1203
+ },
1204
+ privacy: {
1205
+ analytics: true,
1206
+ marketing: false
1207
+ }
1208
+ }, '30d');
1209
+ }
1210
+
1211
+ getFeatureFlags() {
1212
+ return this.loadConfig('feature-flags', {
1213
+ newDashboard: false,
1214
+ darkMode: true,
1215
+ betaFeatures: false,
1216
+ experimentalUI: false
1217
+ }, '1d');
1218
+ }
1219
+ }
1220
+ ```
1221
+
1222
+ ### URL Parameter Parser
1223
+
1224
+ ```typescript
1225
+ @Injectable()
1226
+ export class URLParserService {
1227
+ constructor(private utils: UtilsService) {}
1228
+
1229
+ parseQueryParams(url: string): Record<string, string> {
1230
+ const params: Record<string, string> = {};
1231
+ const queryString = url.split('?')[1];
1232
+
1233
+ if (!queryString) return params;
1234
+
1235
+ queryString.split('&').forEach(pair => {
1236
+ const [key, value] = pair.split('=');
1237
+ if (key && value) {
1238
+ params[decodeURIComponent(key)] = decodeURIComponent(value);
1239
+ }
1240
+ });
1241
+
1242
+ return params;
1243
+ }
1244
+
1245
+ buildQueryString(params: Record<string, any>): string {
1246
+ const searchParams = new URLSearchParams();
1247
+
1248
+ Object.entries(params).forEach(([key, value]) => {
1249
+ if (value !== null && value !== undefined) {
1250
+ if (Array.isArray(value)) {
1251
+ value.forEach(item => searchParams.append(key, String(item)));
1252
+ } else {
1253
+ searchParams.set(key, String(value));
1254
+ }
1255
+ }
1256
+ });
1257
+
1258
+ return searchParams.toString();
1259
+ }
1260
+
1261
+ extractUrlParams(template: string, actualUrl: string): Record<string, string> {
1262
+ const templateParts = template.split('/');
1263
+ const actualParts = actualUrl.split('/');
1264
+ const params: Record<string, string> = {};
1265
+
1266
+ if (templateParts.length !== actualParts.length) {
1267
+ return params;
1268
+ }
1269
+
1270
+ templateParts.forEach((part, index) => {
1271
+ if (part.startsWith(':')) {
1272
+ const paramName = part.substring(1);
1273
+ params[paramName] = actualParts[index];
1274
+ }
1275
+ });
1276
+
1277
+ return params;
1278
+ }
1279
+
1280
+ buildUrl(template: string, params: Record<string, string>): string {
1281
+ let url = template;
1282
+
1283
+ Object.entries(params).forEach(([key, value]) => {
1284
+ url = url.replace(`:${key}`, encodeURIComponent(value));
1285
+ });
1286
+
1287
+ return url;
1288
+ }
1289
+
1290
+ // URL validation
1291
+ isValidUrl(url: string): boolean {
1292
+ try {
1293
+ new URL(url);
1294
+ return true;
1295
+ } catch {
1296
+ return false;
1297
+ }
1298
+ }
1299
+
1300
+ isValidEmail(email: string): boolean {
1301
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1302
+ return emailRegex.test(email);
1303
+ }
1304
+
1305
+ sanitizeUrl(url: string): string {
1306
+ // Remove potentially dangerous protocols
1307
+ const dangerousProtocols = ['javascript:', 'data:', 'vbscript:'];
1308
+
1309
+ dangerousProtocols.forEach(protocol => {
1310
+ if (url.toLowerCase().startsWith(protocol)) {
1311
+ throw new Error(`Dangerous protocol detected: ${protocol}`);
1312
+ }
1313
+ });
1314
+
1315
+ return url;
1316
+ }
1317
+ }
1318
+ ```
1319
+
1320
+ ## Integration with Other Services
1321
+
1322
+ ### With HTTP State Service
1323
+
1324
+ ```typescript
1325
+ @Injectable()
1326
+ export class SmartCacheService extends HTTPManagerStateService<any> {
1327
+ private utils = inject(UtilsService);
1328
+ private cache = new Map<string, { data: any; expiresAt: number }>();
1329
+
1330
+ constructor() {
1331
+ super(
1332
+ ApiRequest.adapt({ path: ['data'] }),
1333
+ DataType.OBJECT
1334
+ );
1335
+ }
1336
+
1337
+ fetchWithCache(key: string, fetchFn: () => any, ttl: string = '1h') {
1338
+ // Check cache first
1339
+ const cached = this.cache.get(key);
1340
+ if (cached && !this.utils.hasExpired(cached.expiresAt)) {
1341
+ return of(cached.data);
1342
+ }
1343
+
1344
+ // Fetch and cache
1345
+ return fetchFn().pipe(
1346
+ tap(data => {
1347
+ const expiresAt = this.utils.expires(ttl);
1348
+ this.cache.set(key, {
1349
+ data,
1350
+ expiresAt: expiresAt || 0
1351
+ });
1352
+ })
1353
+ );
1354
+ }
1355
+
1356
+ invalidateCache(key: string): void {
1357
+ this.cache.delete(key);
1358
+ }
1359
+
1360
+ clearExpiredCache(): void {
1361
+ const now = Date.now() / 1000;
1362
+ const expiredKeys: string[] = [];
1363
+
1364
+ this.cache.forEach((item, key) => {
1365
+ if (item.expiresAt < now) {
1366
+ expiredKeys.push(key);
1367
+ }
1368
+ });
1369
+
1370
+ expiredKeys.forEach(key => this.cache.delete(key));
1371
+ }
1372
+ }
1373
+ ```
1374
+
1375
+ ### With Local Storage
1376
+
1377
+ ```typescript
1378
+ @Injectable()
1379
+ export class SmartStorageService {
1380
+ private utils = inject(UtilsService);
1381
+ private storage = inject(LocalStorageManagerService);
1382
+
1383
+ setWithExpiration(key: string, value: any, expiration: string): void {
1384
+ const expiresAt = this.utils.expires(expiration);
1385
+
1386
+ this.storage.setItem(key, {
1387
+ value,
1388
+ expiresAt,
1389
+ createdAt: Date.now()
1390
+ });
1391
+ }
1392
+
1393
+ getWithExpiration<T>(key: string): T | null {
1394
+ const stored = this.storage.getItem(key);
1395
+
1396
+ if (!stored) return null;
1397
+
1398
+ if (this.utils.hasExpired(stored.expiresAt)) {
1399
+ this.storage.removeItem(key);
1400
+ return null;
1401
+ }
1402
+
1403
+ return stored.value;
1404
+ }
1405
+
1406
+ setIfNewer(key: string, value: any, timestamp: number): boolean {
1407
+ const stored = this.storage.getItem(key);
1408
+
1409
+ if (stored && stored.timestamp > timestamp) {
1410
+ return false; // Stored version is newer
1411
+ }
1412
+
1413
+ this.storage.setItem(key, {
1414
+ value,
1415
+ timestamp,
1416
+ updatedAt: Date.now()
1417
+ });
1418
+
1419
+ return true;
1420
+ }
1421
+ }
1422
+ ```
1423
+
1424
+ ## Best Practices
1425
+
1426
+ ### 1. Type Safety
1427
+
1428
+ ```typescript
1429
+ // ✅ Good - Validate types before operations
1430
+ if (this.utils.isString(value)) {
1431
+ const result = this.utils.lc(value);
1432
+ // Safe to use result as string
1433
+ }
1434
+
1435
+ // ❌ Avoid - No type checking
1436
+ const result = this.utils.lc(value); // Could fail if value is not string
1437
+ ```
1438
+
1439
+ ### 2. Error Handling
1440
+
1441
+ ```typescript
1442
+ // ✅ Good - Handle potential errors
1443
+ try {
1444
+ const parsed = this.utils.stringToJSON(jsonString);
1445
+ // Process parsed data
1446
+ } catch (error) {
1447
+ console.error('Failed to parse JSON:', error);
1448
+ return defaultValue;
1449
+ }
1450
+
1451
+ // ❌ Avoid - No error handling
1452
+ const parsed = this.utils.stringToJSON(jsonString); // Could throw
1453
+ ```
1454
+
1455
+ ### 3. Performance Considerations
1456
+
1457
+ ```typescript
1458
+ // ✅ Good - Cache expensive operations
1459
+ private cachedBase32Conversion = new Map<string, string>();
1460
+
1461
+ convertBase32(value: string): string {
1462
+ if (!this.cachedBase32Conversion.has(value)) {
1463
+ this.cachedBase32Conversion.set(value, this.utils.base32ToHex(value));
1464
+ }
1465
+ return this.cachedBase32Conversion.get(value)!;
1466
+ }
1467
+
1468
+ // ❌ Avoid - Repeated expensive operations
1469
+ // Converting the same value multiple times without caching
1470
+ ```
1471
+
1472
+ ### 4. Validation Before Usage
1473
+
1474
+ ```typescript
1475
+ // ✅ Good - Validate input before processing
1476
+ validateAndProcess(data: any): any {
1477
+ if (!this.utils.isObject(data)) {
1478
+ throw new Error('Data must be an object');
1479
+ }
1480
+
1481
+ if (!this.utils.isJSON(JSON.stringify(data))) {
1482
+ throw new Error('Data contains invalid JSON');
1483
+ }
1484
+
1485
+ return this.processData(data);
1486
+ }
1487
+ ```
1488
+
1489
+ ## Performance Optimization
1490
+
1491
+ ### Batch Operations
1492
+
1493
+ ```typescript
1494
+ @Injectable()
1495
+ export class BatchUtilsService {
1496
+ private utils = inject(UtilsService);
1497
+
1498
+ batchConvertExpirations(durations: string[]): number[] {
1499
+ return durations.map(duration => this.utils.expires(duration) || 0);
1500
+ }
1501
+
1502
+ batchValidateTypes(values: any[]): Array<{value: any; isString: boolean; isObject: boolean}> {
1503
+ return values.map(value => ({
1504
+ value,
1505
+ isString: this.utils.isString(value),
1506
+ isObject: this.utils.isObject(value)
1507
+ }));
1508
+ }
1509
+
1510
+ batchCompareObjects(pairs: Array<{x: any; y: any}>): boolean[] {
1511
+ return pairs.map(pair => this.utils.objectsEqual(pair.x, pair.y));
1512
+ }
1513
+ }
1514
+ ```
1515
+
1516
+ ### Memoization
1517
+
1518
+ ```typescript
1519
+ @Injectable()
1520
+ export class MemoizedUtilsService {
1521
+ private utils = inject(UtilsService);
1522
+
1523
+ // Memoization cache
1524
+ private stringToJsonCache = new Map<string, any>();
1525
+ private objectComparisonCache = new Map<string, boolean>();
1526
+
1527
+ memoizedStringToJSON(value: string): any {
1528
+ if (this.stringToJsonCache.has(value)) {
1529
+ return this.stringToJsonCache.get(value);
1530
+ }
1531
+
1532
+ const result = this.utils.stringToJSON(value);
1533
+ this.stringToJsonCache.set(value, result);
1534
+ return result;
1535
+ }
1536
+
1537
+ memoizedObjectsEqual(x: any, y: any): boolean {
1538
+ const key = JSON.stringify([x, y]);
1539
+
1540
+ if (this.objectComparisonCache.has(key)) {
1541
+ return this.objectComparisonCache.get(key);
1542
+ }
1543
+
1544
+ const result = this.utils.objectsEqual(x, y);
1545
+ this.objectComparisonCache.set(key, result);
1546
+ return result;
1547
+ }
1548
+
1549
+ clearCache(): void {
1550
+ this.stringToJsonCache.clear();
1551
+ this.objectComparisonCache.clear();
1552
+ }
1553
+ }
1554
+ ```
1555
+
1556
+ ## Troubleshooting
1557
+
1558
+ ### Common Issues
1559
+
1560
+ #### 1. JSON Parsing Errors
1561
+ ```typescript
1562
+ // ✅ Good - Safe JSON parsing
1563
+ safeJsonParse(jsonString: string, fallback: any = null): any {
1564
+ try {
1565
+ return this.utils.stringToJSON(jsonString);
1566
+ } catch (error) {
1567
+ console.warn('Invalid JSON:', jsonString, error);
1568
+ return fallback;
1569
+ }
1570
+ }
1571
+
1572
+ // ❌ Avoid - Unsafe parsing
1573
+ const data = JSON.parse(jsonString); // Could throw
1574
+ ```
1575
+
1576
+ #### 2. Type Checking Edge Cases
1577
+ ```typescript
1578
+ // ✅ Good - Handle edge cases
1579
+ isValidString(value: any): boolean {
1580
+ return this.utils.isString(value) && value.trim().length > 0;
1581
+ }
1582
+
1583
+ // ❌ Avoid - Incomplete validation
1584
+ const isString = this.utils.isString(value); // Could be empty string
1585
+ ```
1586
+
1587
+ #### 3. Expiration Calculation
1588
+ ```typescript
1589
+ // ✅ Good - Handle invalid durations
1590
+ safeExpires(duration: string, fallback: number): number {
1591
+ const expires = this.utils.expires(duration);
1592
+ return expires || fallback;
1593
+ }
1594
+
1595
+ // ❌ Avoid - No fallback
1596
+ const expires = this.utils.expires(duration); // Could be undefined
1597
+ ```
1598
+
1599
+ ## Related Documentation
1600
+
1601
+ - [Local Storage Service](local-storage/README.md)
1602
+ - [HTTP State Service](http-state/README.md)
1603
+ - [Database Manager Service](database/README.md)
1604
+ - [Architecture Overview](../architecture/README.md)