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,246 @@
1
+ import { inject, Injectable } from '@angular/core';
2
+ import { firstValueFrom } from 'rxjs';
3
+ import { Table } from 'dexie';
4
+ import { DatabaseManagerService } from '../database-manager-service/database.manager.service';
5
+ import { SqlValidationError } from './models/sql-errors.model';
6
+ import { ExecutionPlan, ExecutionPlanType, PlanStep } from './models/execution-plan.model';
7
+
8
+ @Injectable({ providedIn: 'root' })
9
+ export class DexieQueryExecutor {
10
+ private readonly _dbManager = inject(DatabaseManagerService);
11
+
12
+ async execute(plan: ExecutionPlan): Promise<any[]> {
13
+ switch (plan.type) {
14
+ case ExecutionPlanType.SIMPLE: return this._executeSimple(plan);
15
+ case ExecutionPlanType.AND_BOUNDED: return this._executeAndBounded(plan);
16
+ case ExecutionPlanType.AND_COMPOUND: return this._executeAndCompound(plan);
17
+ case ExecutionPlanType.OR_MERGE: return this._executeOrMerge(plan);
18
+ case ExecutionPlanType.JOIN_HASH: return this._executeJoinHash(plan);
19
+ default:
20
+ throw new SqlValidationError(`Unknown plan type`);
21
+ }
22
+ }
23
+
24
+ // ─── SIMPLE ───────────────────────────────────────────────────────────────
25
+
26
+ private async _executeSimple(plan: ExecutionPlan): Promise<any[]> {
27
+ const table = await this._getTable(plan.table);
28
+ let rows: any[];
29
+
30
+ if (!plan.primaryStep) {
31
+ rows = await table.toArray();
32
+ } else {
33
+ rows = await this._applyDexieStep(table, plan.primaryStep);
34
+ }
35
+
36
+ return this._postProcess(rows, plan);
37
+ }
38
+
39
+ // ─── AND_BOUNDED ──────────────────────────────────────────────────────────
40
+
41
+ private async _executeAndBounded(plan: ExecutionPlan): Promise<any[]> {
42
+ const table = await this._getTable(plan.table);
43
+
44
+ if (plan.compoundWarnCols?.length) {
45
+ console.warn(
46
+ `[DexieSqlService] Consider adding a compound index [${plan.compoundWarnCols.join('+')}] ` +
47
+ `to table "${plan.table}" for full index coverage on AND conditions.`,
48
+ );
49
+ }
50
+
51
+ let rows = plan.primaryStep
52
+ ? await this._applyDexieStep(table, plan.primaryStep)
53
+ : await table.toArray();
54
+
55
+ // Apply remaining AND conditions as JS filter
56
+ for (const f of plan.boundedFilters) {
57
+ rows = rows.filter(row => this._matchStep(row, f));
58
+ }
59
+
60
+ return this._postProcess(rows, plan);
61
+ }
62
+
63
+ // ─── AND_COMPOUND ─────────────────────────────────────────────────────────
64
+
65
+ private async _executeAndCompound(plan: ExecutionPlan): Promise<any[]> {
66
+ const table = await this._getTable(plan.table);
67
+ const rows = await (table.where(plan.compoundIndex!) as any).equals(plan.compoundValues!).toArray();
68
+ return this._postProcess(rows, plan);
69
+ }
70
+
71
+ // ─── OR_MERGE ─────────────────────────────────────────────────────────────
72
+
73
+ private async _executeOrMerge(plan: ExecutionPlan): Promise<any[]> {
74
+ const table = await this._getTable(plan.table);
75
+ const branches = plan.orBranches ?? [];
76
+
77
+ const results = await Promise.all(
78
+ branches.map(branch => this._applyDexieStep(table, branch)),
79
+ );
80
+
81
+ // Deduplicate by primary key
82
+ const pk = plan.dedupeKey ?? 'id';
83
+ const seen = new Map<any, any>();
84
+ for (const batch of results) {
85
+ for (const row of batch) {
86
+ seen.set(row[pk], row);
87
+ }
88
+ }
89
+
90
+ return this._postProcess(Array.from(seen.values()), plan);
91
+ }
92
+
93
+ // ─── JOIN_HASH ────────────────────────────────────────────────────────────
94
+
95
+ private async _executeJoinHash(plan: ExecutionPlan): Promise<any[]> {
96
+ const join = plan.joinInfo!;
97
+
98
+ const leftTable = await this._getTable(join.leftTable);
99
+ const rightTable = await this._getTable(join.rightTable);
100
+
101
+ // Fetch left rows (full scan; bounded WHERE filters applied post-join)
102
+ const leftRows = await leftTable.toArray();
103
+
104
+ // Extract FK values for right-side lookup
105
+ const fkValues = [...new Set(leftRows.map(r => r[join.leftKey]).filter(v => v != null))];
106
+
107
+ // Fetch right rows indexed by join key
108
+ const rightRows: any[] = fkValues.length > 0
109
+ ? await (rightTable.where(join.rightKey) as any).anyOf(fkValues).toArray()
110
+ : [];
111
+
112
+ // Build lookup map from rightKey → array of right rows
113
+ const rightMap = new Map<any, any[]>();
114
+ for (const rr of rightRows) {
115
+ const k = rr[join.rightKey];
116
+ if (!rightMap.has(k)) rightMap.set(k, []);
117
+ rightMap.get(k)!.push(rr);
118
+ }
119
+
120
+ // Hash join
121
+ const joined: any[] = [];
122
+ for (const lr of leftRows) {
123
+ const matches = rightMap.get(lr[join.leftKey]);
124
+ if (matches?.length) {
125
+ for (const rr of matches) {
126
+ joined.push({ ...lr, ...rr });
127
+ }
128
+ } else if (join.joinType === 'left') {
129
+ joined.push({ ...lr });
130
+ }
131
+ }
132
+
133
+ // Apply post-join bounded filters (any WHERE conditions from the query)
134
+ let result = joined;
135
+ for (const f of plan.boundedFilters) {
136
+ result = result.filter(row => this._matchStep(row, f));
137
+ }
138
+
139
+ return this._postProcess(result, plan);
140
+ }
141
+
142
+ // ─── Post-processing ──────────────────────────────────────────────────────
143
+
144
+ private _postProcess(rows: any[], plan: ExecutionPlan): any[] {
145
+ let result = rows;
146
+
147
+ // ORDER BY
148
+ if (plan.orderBy) {
149
+ const { col, dir } = plan.orderBy;
150
+ result = [...result].sort((a, b) => {
151
+ const av = a[col];
152
+ const bv = b[col];
153
+ if (av == null && bv == null) return 0;
154
+ if (av == null) return 1;
155
+ if (bv == null) return -1;
156
+ const cmp = av < bv ? -1 : av > bv ? 1 : 0;
157
+ return dir === 'desc' ? -cmp : cmp;
158
+ });
159
+ }
160
+
161
+ // LIMIT / OFFSET
162
+ const offset = plan.offset ?? 0;
163
+ const limit = plan.limit ?? null;
164
+ if (offset > 0 || limit != null) {
165
+ result = result.slice(offset, limit != null ? offset + limit : undefined);
166
+ }
167
+
168
+ // Projection
169
+ if (plan.projection && plan.projection.length > 0) {
170
+ const cols = plan.projection;
171
+ result = result.map(row => {
172
+ const projected: Record<string, any> = {};
173
+ for (const c of cols) projected[c] = row[c];
174
+ return projected;
175
+ });
176
+ }
177
+
178
+ // DISTINCT
179
+ if (plan.distinct) {
180
+ const seen = new Set<string>();
181
+ result = result.filter(row => {
182
+ const key = JSON.stringify(row);
183
+ if (seen.has(key)) return false;
184
+ seen.add(key);
185
+ return true;
186
+ });
187
+ }
188
+
189
+ // COUNT(*)
190
+ if (plan.aggregate === 'count') {
191
+ return [{ count: result.length }];
192
+ }
193
+
194
+ return result;
195
+ }
196
+
197
+ // ─── Dexie step dispatch ──────────────────────────────────────────────────
198
+
199
+ private _applyDexieStep(table: Table<any, any>, step: PlanStep): Promise<any[]> {
200
+ const col = step.col;
201
+ const val = step.val;
202
+
203
+ switch (step.op) {
204
+ case 'equals': return table.where(col).equals(val).toArray();
205
+ case 'notEqual': return table.where(col).notEqual(val).toArray();
206
+ case 'above': return table.where(col).above(val).toArray();
207
+ case 'aboveOrEqual': return table.where(col).aboveOrEqual(val).toArray();
208
+ case 'below': return table.where(col).below(val).toArray();
209
+ case 'belowOrEqual': return table.where(col).belowOrEqual(val).toArray();
210
+ case 'between': return table.where(col).between(val[0], val[1], true, true).toArray();
211
+ case 'anyOf': return table.where(col).anyOf(val).toArray();
212
+ case 'noneOf': return table.where(col).noneOf(val).toArray();
213
+ case 'startsWith': return table.where(col).startsWith(val).toArray();
214
+ default:
215
+ throw new SqlValidationError(`Unsupported Dexie op: "${step.op}"`);
216
+ }
217
+ }
218
+
219
+ // ─── JS row predicate ─────────────────────────────────────────────────────
220
+
221
+ private _matchStep(row: any, step: PlanStep): boolean {
222
+ const rv = row[step.col];
223
+ const v = step.val;
224
+ switch (step.op) {
225
+ case 'equals': return rv === v;
226
+ case 'notEqual': return rv !== v;
227
+ case 'above': return rv > v;
228
+ case 'aboveOrEqual': return rv >= v;
229
+ case 'below': return rv < v;
230
+ case 'belowOrEqual': return rv <= v;
231
+ case 'between': return rv >= v[0] && rv <= v[1];
232
+ case 'anyOf': return (v as any[]).includes(rv);
233
+ case 'noneOf': return !(v as any[]).includes(rv);
234
+ case 'startsWith': return typeof rv === 'string' && rv.startsWith(v);
235
+ default: return true;
236
+ }
237
+ }
238
+
239
+ // ─── Table accessor ───────────────────────────────────────────────────────
240
+
241
+ private async _getTable(tableName: string): Promise<Table<any, any>> {
242
+ const t = await firstValueFrom(this._dbManager.getDatabaseTable(tableName));
243
+ if (!t) throw new SqlValidationError(`Table "${tableName}" not found or not accessible`);
244
+ return t;
245
+ }
246
+ }
@@ -0,0 +1,31 @@
1
+ import { inject, Injectable } from '@angular/core';
2
+ import { from, Observable } from 'rxjs';
3
+ import { DexieSqlOptions } from './models/sql-options.model';
4
+ import { SqlParser } from './sql-parser';
5
+ import { SchemaValidator } from './schema-validator';
6
+ import { QueryPlanner } from './query-planner';
7
+ import { DexieQueryExecutor } from './dexie-query-executor';
8
+
9
+ @Injectable({ providedIn: 'root' })
10
+ export class DexieSqlService {
11
+ private readonly _parser = new SqlParser();
12
+ private readonly _validator = inject(SchemaValidator);
13
+ private readonly _planner = new QueryPlanner();
14
+ private readonly _executor = inject(DexieQueryExecutor);
15
+
16
+ /**
17
+ * Execute a MySQL-syntax SQL SELECT string against the DexieJS IndexedDB database.
18
+ * Returns an Observable that emits the result array and completes, or errors with
19
+ * SqlParseError / SqlValidationError if the query is invalid.
20
+ */
21
+ query(sql: string, options: DexieSqlOptions = {}): Observable<any[]> {
22
+ return from(this._run(sql, options));
23
+ }
24
+
25
+ private async _run(sql: string, options: DexieSqlOptions): Promise<any[]> {
26
+ const parsed = this._parser.parse(sql);
27
+ const validated = await this._validator.validate(parsed, options);
28
+ const plan = this._planner.plan(validated, options);
29
+ return this._executor.execute(plan);
30
+ }
31
+ }
@@ -0,0 +1,4 @@
1
+ export * from './dexie-sql.service';
2
+ export * from './models/index';
3
+ export { ParseResult } from './sql-parser';
4
+ export { TableSchemaInfo, ValidatedQuery } from './schema-validator';
@@ -0,0 +1,52 @@
1
+ export enum ExecutionPlanType {
2
+ SIMPLE = 'SIMPLE',
3
+ AND_BOUNDED = 'AND_BOUNDED',
4
+ AND_COMPOUND = 'AND_COMPOUND',
5
+ OR_MERGE = 'OR_MERGE',
6
+ JOIN_HASH = 'JOIN_HASH',
7
+ }
8
+
9
+ export type DexieOp =
10
+ | 'equals'
11
+ | 'notEqual'
12
+ | 'above'
13
+ | 'aboveOrEqual'
14
+ | 'below'
15
+ | 'belowOrEqual'
16
+ | 'between'
17
+ | 'anyOf'
18
+ | 'noneOf'
19
+ | 'startsWith';
20
+
21
+ export interface PlanStep {
22
+ col: string;
23
+ op: DexieOp;
24
+ val: any;
25
+ }
26
+
27
+ export interface JoinInfo {
28
+ leftTable: string;
29
+ rightTable: string;
30
+ leftKey: string;
31
+ rightKey: string;
32
+ joinType: 'inner' | 'left';
33
+ }
34
+
35
+ export interface ExecutionPlan {
36
+ type: ExecutionPlanType;
37
+ table: string;
38
+ primaryStep: PlanStep | null;
39
+ boundedFilters: PlanStep[];
40
+ compoundIndex?: string;
41
+ compoundValues?: any[];
42
+ compoundWarnCols?: string[];
43
+ orBranches?: PlanStep[];
44
+ joinInfo?: JoinInfo;
45
+ orderBy?: { col: string; dir: 'asc' | 'desc' } | null;
46
+ limit?: number | null;
47
+ offset?: number | null;
48
+ projection?: string[] | null;
49
+ aggregate?: 'count' | null;
50
+ distinct?: boolean;
51
+ dedupeKey?: string;
52
+ }
@@ -0,0 +1,3 @@
1
+ export * from './sql-errors.model';
2
+ export * from './sql-options.model';
3
+ export * from './execution-plan.model';
@@ -0,0 +1,13 @@
1
+ export class SqlParseError extends Error {
2
+ override name = 'SqlParseError';
3
+ constructor(message: string) {
4
+ super(message);
5
+ }
6
+ }
7
+
8
+ export class SqlValidationError extends Error {
9
+ override name = 'SqlValidationError';
10
+ constructor(message: string) {
11
+ super(message);
12
+ }
13
+ }
@@ -0,0 +1,3 @@
1
+ export interface DexieSqlOptions {
2
+ strict?: boolean;
3
+ }
@@ -0,0 +1,284 @@
1
+ import { SqlValidationError } from './models/sql-errors.model';
2
+ import { DexieSqlOptions } from './models/sql-options.model';
3
+ import {
4
+ ExecutionPlan,
5
+ ExecutionPlanType,
6
+ DexieOp,
7
+ PlanStep,
8
+ JoinInfo,
9
+ } from './models/execution-plan.model';
10
+ import { ValidatedQuery, TableSchemaInfo } from './schema-validator';
11
+
12
+ export class QueryPlanner {
13
+
14
+ plan(validated: ValidatedQuery, options: DexieSqlOptions = {}): ExecutionPlan {
15
+ const { ast, schemas, aliases } = validated;
16
+ const fromItems: any[] = (ast as any).from ?? [];
17
+ const mainTable = fromItems[0]?.table ?? '';
18
+ const dedupeKey = schemas[mainTable]?.pk ?? 'id';
19
+ const basePlan = this._buildBasePlanExtras(ast, mainTable, dedupeKey);
20
+
21
+ // ── JOIN ────────────────────────────────────────────────────────────────
22
+ const joinItem = fromItems.find((f: any) => f.join);
23
+ if (joinItem) {
24
+ return this._buildJoinPlan(ast, fromItems, joinItem, schemas, aliases, mainTable, basePlan);
25
+ }
26
+
27
+ const where = (ast as any).where;
28
+
29
+ // ── No WHERE ─────────────────────────────────────────────────────────────
30
+ if (!where) {
31
+ return { ...basePlan, type: ExecutionPlanType.SIMPLE, primaryStep: null, boundedFilters: [] };
32
+ }
33
+
34
+ // ── OR ──────────────────────────────────────────────────────────────────
35
+ if (where.operator === 'OR') {
36
+ return this._buildOrPlan(where, basePlan, aliases, mainTable);
37
+ }
38
+
39
+ // ── AND ──────────────────────────────────────────────────────────────────
40
+ if (where.operator === 'AND') {
41
+ return this._buildAndPlan(where, basePlan, schemas, aliases, mainTable, options);
42
+ }
43
+
44
+ // ── Single condition ────────────────────────────────────────────────────
45
+ const step = this._nodeToStep(where, aliases, mainTable);
46
+ return { ...basePlan, type: ExecutionPlanType.SIMPLE, primaryStep: step, boundedFilters: [] };
47
+ }
48
+
49
+ // ─── AND ──────────────────────────────────────────────────────────────────
50
+
51
+ private _buildAndPlan(
52
+ where: any,
53
+ basePlan: Partial<ExecutionPlan> & { table: string },
54
+ schemas: Record<string, TableSchemaInfo>,
55
+ aliases: Record<string, string>,
56
+ mainTable: string,
57
+ _options: DexieSqlOptions,
58
+ ): ExecutionPlan {
59
+ const conditions = this._flattenAnd(where);
60
+ const cols = conditions.map((c: any) => c.left?.column as string).filter(Boolean);
61
+ const schema = schemas[mainTable];
62
+
63
+ // Check for matching compound index
64
+ const matchedCompound = schema?.compoundIndexes.find(
65
+ ci => ci.length === cols.length && cols.every(c => ci.includes(c)),
66
+ );
67
+
68
+ if (matchedCompound) {
69
+ const orderedValues = matchedCompound.map(ciCol => {
70
+ const cond = conditions.find((c: any) => c.left?.column === ciCol);
71
+ return this._extractValue(cond.right, cond.operator);
72
+ });
73
+ return {
74
+ ...basePlan,
75
+ type: ExecutionPlanType.AND_COMPOUND,
76
+ primaryStep: null,
77
+ boundedFilters: [],
78
+ compoundIndex: `[${matchedCompound.join('+')}]`,
79
+ compoundValues: orderedValues,
80
+ } as ExecutionPlan;
81
+ }
82
+
83
+ // Pragmatic: first condition → Dexie, rest → JS filter
84
+ const primaryStep = this._nodeToStep(conditions[0], aliases, mainTable);
85
+ const boundedFilters = conditions.slice(1).map((c: any) => this._nodeToStep(c, aliases, mainTable));
86
+
87
+ return {
88
+ ...basePlan,
89
+ type: ExecutionPlanType.AND_BOUNDED,
90
+ primaryStep,
91
+ boundedFilters,
92
+ compoundWarnCols: cols,
93
+ } as ExecutionPlan;
94
+ }
95
+
96
+ // ─── OR ───────────────────────────────────────────────────────────────────
97
+
98
+ private _buildOrPlan(
99
+ where: any,
100
+ basePlan: Partial<ExecutionPlan> & { table: string },
101
+ aliases: Record<string, string>,
102
+ mainTable: string,
103
+ ): ExecutionPlan {
104
+ const branches = this._flattenOr(where);
105
+ const orBranches = branches.map((b: any) => this._nodeToStep(b, aliases, mainTable));
106
+ return {
107
+ ...basePlan,
108
+ type: ExecutionPlanType.OR_MERGE,
109
+ primaryStep: null,
110
+ boundedFilters: [],
111
+ orBranches,
112
+ } as ExecutionPlan;
113
+ }
114
+
115
+ // ─── JOIN ─────────────────────────────────────────────────────────────────
116
+
117
+ private _buildJoinPlan(
118
+ ast: any,
119
+ fromItems: any[],
120
+ joinItem: any,
121
+ schemas: Record<string, TableSchemaInfo>,
122
+ aliases: Record<string, string>,
123
+ mainTable: string,
124
+ basePlan: Partial<ExecutionPlan> & { table: string },
125
+ ): ExecutionPlan {
126
+ const rightTable = joinItem.table as string;
127
+ const onNode = joinItem.on;
128
+ const joinType = (joinItem.join as string).toLowerCase().includes('left') ? 'left' : 'inner';
129
+
130
+ // Resolve join keys from ON clause
131
+ const l = onNode?.left;
132
+ const r = onNode?.right;
133
+
134
+ const lTableResolved = aliases[l?.table ?? ''] ?? l?.table ?? mainTable;
135
+ const rTableResolved = aliases[r?.table ?? ''] ?? r?.table ?? rightTable;
136
+
137
+ let leftKey: string, rightKey: string;
138
+ if (lTableResolved === mainTable) {
139
+ leftKey = l?.column ?? '';
140
+ rightKey = r?.column ?? '';
141
+ } else {
142
+ leftKey = r?.column ?? '';
143
+ rightKey = l?.column ?? '';
144
+ }
145
+
146
+ const joinInfo: JoinInfo = { leftTable: mainTable, rightTable, leftKey, rightKey, joinType };
147
+
148
+ // WHERE conditions become post-join bounded filters
149
+ const where = (ast as any).where;
150
+ const boundedFilters: PlanStep[] = [];
151
+ if (where) {
152
+ this._flattenAnd(where.operator === 'AND' ? where : { operator: 'AND', left: where, right: null })
153
+ .filter(Boolean)
154
+ .forEach((c: any) => boundedFilters.push(this._nodeToStep(c, aliases, mainTable)));
155
+ }
156
+
157
+ return {
158
+ ...basePlan,
159
+ type: ExecutionPlanType.JOIN_HASH,
160
+ primaryStep: null,
161
+ boundedFilters: where ? (where.operator === 'AND' ? boundedFilters : [this._nodeToStep(where, aliases, mainTable)]) : [],
162
+ joinInfo,
163
+ } as ExecutionPlan;
164
+ }
165
+
166
+ // ─── Base plan extras (ORDER BY, LIMIT, OFFSET, projection, etc.) ─────────
167
+
168
+ private _buildBasePlanExtras(ast: any, mainTable: string, dedupeKey: string): Partial<ExecutionPlan> & { table: string } {
169
+ const plan: Partial<ExecutionPlan> & { table: string } = { table: mainTable, dedupeKey };
170
+
171
+ // ORDER BY
172
+ const orderby: any[] = ast.orderby ?? [];
173
+ if (orderby.length > 0) {
174
+ const ob = orderby[0];
175
+ plan.orderBy = {
176
+ col: ob.expr?.column ?? '',
177
+ dir: ob.type?.toUpperCase() === 'DESC' ? 'desc' : 'asc',
178
+ };
179
+ }
180
+
181
+ // LIMIT / OFFSET
182
+ if (ast.limit) {
183
+ const vals: any[] = ast.limit.value ?? [];
184
+ if (ast.limit.seperator === 'offset' && vals.length === 2) {
185
+ plan.limit = vals[0].value;
186
+ plan.offset = vals[1].value;
187
+ } else if (vals.length === 1) {
188
+ plan.limit = vals[0].value;
189
+ }
190
+ }
191
+
192
+ // Projection
193
+ const columns: any[] = ast.columns;
194
+ if (columns && columns !== '*' as any) {
195
+ // COUNT(*)
196
+ const countCol = columns.find((c: any) => c.expr?.type === 'aggr_func' && c.expr?.name === 'COUNT');
197
+ if (countCol) {
198
+ plan.aggregate = 'count';
199
+ plan.projection = null;
200
+ } else {
201
+ const projected = columns
202
+ .filter((c: any) => c.expr?.type === 'column_ref')
203
+ .map((c: any) => c.expr.column as string);
204
+ plan.projection = projected.length > 0 ? projected : null;
205
+ }
206
+ } else {
207
+ plan.projection = null;
208
+ }
209
+
210
+ // DISTINCT
211
+ plan.distinct = ast.distinct === 'DISTINCT';
212
+
213
+ return plan;
214
+ }
215
+
216
+ // ─── Node → PlanStep ──────────────────────────────────────────────────────
217
+
218
+ private _nodeToStep(node: any, aliases: Record<string, string>, defaultTable: string): PlanStep {
219
+ if (!node || node.type !== 'binary_expr' || node.left?.type !== 'column_ref') {
220
+ throw new SqlValidationError(`Unsupported WHERE condition structure`);
221
+ }
222
+
223
+ const col = node.left.column as string;
224
+ const { op, val } = this._mapOperator(node.operator, node.right);
225
+ return { col, op, val };
226
+ }
227
+
228
+ private _mapOperator(astOp: string, rightNode: any): { op: DexieOp; val: any } {
229
+ switch (astOp) {
230
+ case '=': return { op: 'equals', val: this._extractValue(rightNode, astOp) };
231
+ case '!=':
232
+ case '<>': return { op: 'notEqual', val: this._extractValue(rightNode, astOp) };
233
+ case '>': return { op: 'above', val: this._extractValue(rightNode, astOp) };
234
+ case '>=': return { op: 'aboveOrEqual', val: this._extractValue(rightNode, astOp) };
235
+ case '<': return { op: 'below', val: this._extractValue(rightNode, astOp) };
236
+ case '<=': return { op: 'belowOrEqual', val: this._extractValue(rightNode, astOp) };
237
+ case 'BETWEEN': {
238
+ const vals: any[] = rightNode?.value ?? [];
239
+ return { op: 'between', val: [vals[0]?.value, vals[1]?.value] };
240
+ }
241
+ case 'IN': return { op: 'anyOf', val: (rightNode?.value ?? []).map((v: any) => v.value) };
242
+ case 'NOT IN': return { op: 'noneOf', val: (rightNode?.value ?? []).map((v: any) => v.value) };
243
+ case 'LIKE': {
244
+ const raw = String(rightNode?.value ?? '');
245
+ if (raw.startsWith('%')) {
246
+ throw new SqlValidationError('LIKE with leading wildcard is not supported');
247
+ }
248
+ if (raw.includes('%')) {
249
+ const pctIdx = raw.indexOf('%');
250
+ if (pctIdx !== raw.length - 1) {
251
+ throw new SqlValidationError('LIKE with leading wildcard is not supported');
252
+ }
253
+ return { op: 'startsWith', val: raw.slice(0, -1) };
254
+ }
255
+ // No wildcard — treat as equals
256
+ return { op: 'equals', val: raw };
257
+ }
258
+ default:
259
+ throw new SqlValidationError(`Unsupported SQL operator: "${astOp}"`);
260
+ }
261
+ }
262
+
263
+ private _extractValue(node: any, _op: string): any {
264
+ return node?.value ?? null;
265
+ }
266
+
267
+ // ─── WHERE tree helpers ───────────────────────────────────────────────────
268
+
269
+ private _flattenAnd(node: any): any[] {
270
+ if (!node) return [];
271
+ if (node.type === 'binary_expr' && node.operator === 'AND') {
272
+ return [...this._flattenAnd(node.left), ...this._flattenAnd(node.right)];
273
+ }
274
+ return [node];
275
+ }
276
+
277
+ private _flattenOr(node: any): any[] {
278
+ if (!node) return [];
279
+ if (node.type === 'binary_expr' && node.operator === 'OR') {
280
+ return [...this._flattenOr(node.left), ...this._flattenOr(node.right)];
281
+ }
282
+ return [node];
283
+ }
284
+ }