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.
- package/README.md +2 -0
- package/TEST_COVERAGE_SUMMARY.md +458 -0
- package/ng-package.json +8 -0
- package/package.json +5 -13
- package/src/docs/ADVANCED_WEBSOCKET.md +633 -0
- package/src/docs/ARCHITECTURE.md +633 -0
- package/src/docs/BATCH_REQUEST_README.md +467 -0
- package/src/docs/COMPLETE_API_REFERENCE.md +1037 -0
- package/src/docs/DATABASE_README.md +1195 -0
- package/src/docs/ENCRYPTION_README.md +403 -0
- package/src/docs/HTTP_MANAGER_README.md +628 -0
- package/src/docs/HTTP_SINGNALS_MANAGER_README.md +654 -0
- package/src/docs/HTTP_STATE_MANAGER_README.md +1391 -0
- package/src/docs/INTERCEPTOR_README.md +549 -0
- package/src/docs/LOCAL_STORAGE_README.md +1056 -0
- package/src/docs/LOCAL_STORAGE_SIGNALS_README.md +338 -0
- package/src/docs/LOGGER_README.md +310 -0
- package/src/docs/MESSAGE_TRACKER_README.md +518 -0
- package/src/docs/MESSAGE_TRACKER_SIGNALS_README.md +563 -0
- package/src/docs/MODELS_README.md +1264 -0
- package/src/docs/SIGNAL_SERVICES_README.md +238 -0
- package/src/docs/SQL_DIXIE_README.md +574 -0
- package/src/docs/STORE_STATE_MANAGER_README.md +556 -0
- package/src/docs/STORE_STATE_SIGNALS_README.md +600 -0
- package/src/docs/UPLOAD_REQUEST_README.md +324 -0
- package/src/docs/UTILS_README.md +1604 -0
- package/src/docs/WEBSOCKET_MESSAGE_SERVICE.md +799 -0
- package/src/docs/WEBSOCKET_SIGNALS_README.md +641 -0
- package/src/docs/WEBSOCKET_SINGLETON_REFACTORING.md +201 -0
- package/src/docs/WS_MANAGER_README.md +613 -0
- package/src/lib/http-request-manager.module.ts +147 -0
- package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.html +116 -0
- package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.scss +0 -0
- package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.ts +255 -0
- package/src/lib/http-request-services-demo/http-request-services-demo.component.html +123 -0
- package/src/lib/http-request-services-demo/http-request-services-demo.component.scss +6 -0
- package/src/lib/http-request-services-demo/http-request-services-demo.component.ts +53 -0
- package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.html +195 -0
- package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.scss +17 -0
- package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.ts +208 -0
- package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.html +200 -0
- package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.scss +17 -0
- package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.ts +214 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.html +53 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.scss +60 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.ts +72 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-download.module.ts +28 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.html +10 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.scss +29 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.ts +100 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/models/download-labels-model.ts +22 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.html +8 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.scss +19 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.ts +26 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/app-session.model.ts +30 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/app.model.ts +19 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/get-sample.model.ts +25 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-ai-prompt.ts +19 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client-details.ts +24 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client-info.ts +30 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client.model.ts +49 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-mapper-client-info.ts +33 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.html +279 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.scss +24 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.ts +461 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.ts +28 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.html +10 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.scss +29 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.ts +100 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/app-session.model.ts +30 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/app.model.ts +19 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/get-sample.model.ts +25 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.ts +19 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-details.ts +24 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.ts +30 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client.model.ts +49 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.ts +33 -0
- package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.html +622 -0
- package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.scss +106 -0
- package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.ts +687 -0
- package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.html +418 -0
- package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.scss +24 -0
- package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.ts +576 -0
- package/src/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.ts +89 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/services/state-data-request.service.ts +119 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.css +0 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.html +3 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.ts +16 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.css +0 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.html +3 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.ts +16 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.css +31 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.html +94 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.scss +41 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.spec.ts +203 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.ts +144 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.css +11 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.html +102 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.spec.ts +40 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.ts +230 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.css +30 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.html +172 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.spec.ts +31 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.ts +239 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/models/oidc-client.model.ts +31 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/models/user-data.model.ts +32 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.css +0 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.html +84 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.ts +40 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/index.ts +3 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/jwt-token.service.ts +62 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/message-service-demo.service.ts +83 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/notification-service-demo.service.ts +147 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/state-service-demo.service.ts +168 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-download.module.ts +28 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.html +10 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.scss +29 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.ts +100 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app-session.model.ts +30 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app.model.ts +19 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/get-sample.model.ts +25 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.ts +19 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-details.ts +24 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.ts +30 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client.model.ts +49 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.ts +33 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.html +380 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.scss +24 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.ts +410 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/models/settings.model.ts +28 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/services/settings-state.service.ts +49 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.css +0 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.html +23 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.ts +36 -0
- package/src/lib/http-request-services-demo/store-state-signals-demo/store-state-signals-demo.component.ts +161 -0
- package/src/lib/http-request-services-demo/upload-demo/models/index.ts +1 -0
- package/src/lib/http-request-services-demo/upload-demo/models/upload-state.model.ts +30 -0
- package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.html +89 -0
- package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.scss +160 -0
- package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.spec.ts +101 -0
- package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.ts +136 -0
- package/src/lib/index.ts +3 -0
- package/src/lib/interceptors/credentials.interceptor.ts +16 -0
- package/src/lib/interceptors/index.ts +6 -0
- package/src/lib/interceptors/models/error-settings.model.ts +22 -0
- package/src/lib/interceptors/models/index.ts +2 -0
- package/src/lib/interceptors/proxy-debugger.interceptor.ts +46 -0
- package/src/lib/interceptors/request-error.interceptor.ts +65 -0
- package/src/lib/interceptors/request-header.interceptor.ts +56 -0
- package/src/lib/message-display/README.md +509 -0
- package/src/lib/message-display/index.ts +4 -0
- package/src/lib/message-display/models/action.model.ts +27 -0
- package/src/lib/message-display/models/communication-message.model.ts +77 -0
- package/src/lib/message-display/models/display-config.model.ts +35 -0
- package/src/lib/message-display/models/display-rule.interface.ts +28 -0
- package/src/lib/message-display/models/display-strategy.interface.ts +8 -0
- package/src/lib/message-display/models/index.ts +6 -0
- package/src/lib/message-display/models/slide.model.ts +24 -0
- package/src/lib/message-display/rules/default-display-rules.ts +35 -0
- package/src/lib/message-display/services/message-display-router.service.ts +63 -0
- package/src/lib/message-display/strategies/snackbar.strategy.ts +46 -0
- package/src/lib/models/batch-options.model.ts +33 -0
- package/src/lib/models/batch-progress.model.ts +19 -0
- package/src/lib/models/batch-request-state.model.ts +40 -0
- package/src/lib/models/batch-result.model.ts +30 -0
- package/src/lib/models/config-http-options.model.ts +45 -0
- package/src/lib/models/config-local-storage-options.model.ts +27 -0
- package/src/lib/models/config-options.model.ts +27 -0
- package/src/lib/models/config-token.model.ts +9 -0
- package/src/lib/models/data-type.enum.ts +5 -0
- package/src/lib/models/database-storage.model.ts +24 -0
- package/src/lib/models/index.ts +16 -0
- package/src/lib/models/retry-options.model.ts +22 -0
- package/src/lib/models/upload-validation-error.model.ts +46 -0
- package/src/lib/services/SQL-DixieJS service/dexie-query-executor.ts +246 -0
- package/src/lib/services/SQL-DixieJS service/dexie-sql.service.ts +31 -0
- package/src/lib/services/SQL-DixieJS service/index.ts +4 -0
- package/src/lib/services/SQL-DixieJS service/models/execution-plan.model.ts +52 -0
- package/src/lib/services/SQL-DixieJS service/models/index.ts +3 -0
- package/src/lib/services/SQL-DixieJS service/models/sql-errors.model.ts +13 -0
- package/src/lib/services/SQL-DixieJS service/models/sql-options.model.ts +3 -0
- package/src/lib/services/SQL-DixieJS service/query-planner.ts +284 -0
- package/src/lib/services/SQL-DixieJS service/schema-validator.ts +217 -0
- package/src/lib/services/SQL-DixieJS service/sql-parser.ts +35 -0
- package/src/lib/services/database-manager-service/database.manager.service.ts +384 -0
- package/src/lib/services/database-manager-service/db.storage.service.ts +240 -0
- package/src/lib/services/database-manager-service/index.ts +4 -0
- package/src/lib/services/database-manager-service/models/index.ts +2 -0
- package/src/lib/services/database-manager-service/models/table-schema.ts +33 -0
- package/src/lib/services/index.ts +20 -0
- package/src/lib/services/local-storage-manager-service/index.ts +4 -0
- package/src/lib/services/local-storage-manager-service/local-storage-manager.service.spec.ts +71 -0
- package/src/lib/services/local-storage-manager-service/local-storage-manager.service.ts +567 -0
- package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.spec.ts +67 -0
- package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.ts +437 -0
- package/src/lib/services/local-storage-manager-service/models/global-store-options.model.ts +30 -0
- package/src/lib/services/local-storage-manager-service/models/index.ts +6 -0
- package/src/lib/services/local-storage-manager-service/models/setting-options.model.ts +35 -0
- package/src/lib/services/local-storage-manager-service/models/storage-data.model.ts +24 -0
- package/src/lib/services/local-storage-manager-service/models/storage-option.model.ts +32 -0
- package/src/lib/services/local-storage-manager-service/models/storage-type.enum.ts +5 -0
- package/src/lib/services/request-manager-services/README.md +282 -0
- package/src/lib/services/request-manager-services/http-manager-signals.service.ts +674 -0
- package/src/lib/services/request-manager-services/http-manager.service.spec.ts +353 -0
- package/src/lib/services/request-manager-services/http-manager.service.ts +727 -0
- package/src/lib/services/request-manager-services/index.ts +8 -0
- package/src/lib/services/request-manager-services/request-signals.service.ts +372 -0
- package/src/lib/services/request-manager-services/request.service.ts +435 -0
- package/src/lib/services/request-manager-services/rxjs-operators/countdown.ts +17 -0
- package/src/lib/services/request-manager-services/rxjs-operators/delay-retry.ts +16 -0
- package/src/lib/services/request-manager-services/rxjs-operators/index.ts +4 -0
- package/src/lib/services/request-manager-services/rxjs-operators/request-polling.ts +35 -0
- package/src/lib/services/request-manager-services/rxjs-operators/request-streaming.ts +468 -0
- package/src/lib/services/request-manager-state-service/http-manager-state.store.spec.ts +665 -0
- package/src/lib/services/request-manager-state-service/http-manager-state.store.ts +2395 -0
- package/src/lib/services/request-manager-state-service/index.ts +3 -0
- package/src/lib/services/request-manager-state-service/models/api-request.model.ts +86 -0
- package/src/lib/services/request-manager-state-service/models/index.ts +14 -0
- package/src/lib/services/request-manager-state-service/models/operation-result.model.ts +18 -0
- package/src/lib/services/request-manager-state-service/models/parsing-result.model.ts +21 -0
- package/src/lib/services/request-manager-state-service/models/request-options.model.ts +37 -0
- package/src/lib/services/request-manager-state-service/models/stream-config.model.ts +20 -0
- package/src/lib/services/request-manager-state-service/models/stream-event-metadata.model.ts +23 -0
- package/src/lib/services/request-manager-state-service/models/stream-event.model.ts +23 -0
- package/src/lib/services/request-manager-state-service/models/stream-output.model.ts +23 -0
- package/src/lib/services/request-manager-state-service/models/stream-progress.model.ts +24 -0
- package/src/lib/services/request-manager-state-service/models/stream-type.enum.ts +13 -0
- package/src/lib/services/request-manager-state-service/models/ws-options.model.ts +42 -0
- package/src/lib/services/store-state-manager-service/index.ts +4 -0
- package/src/lib/services/store-state-manager-service/models/index.ts +3 -0
- package/src/lib/services/store-state-manager-service/models/state-operation-result.model.ts +30 -0
- package/src/lib/services/store-state-manager-service/models/state-storage-options.model.ts +24 -0
- package/src/lib/services/store-state-manager-service/store-state-manager-signals.service.ts +169 -0
- package/src/lib/services/store-state-manager-service/store-state-manager.service.ts +153 -0
- package/src/lib/services/utils/app.service.spec.ts +25 -0
- package/src/lib/services/utils/app.service.ts +21 -0
- package/src/lib/services/utils/encryption/README.md +79 -0
- package/src/lib/services/utils/encryption/asymmetrical-encryption.service.ts +282 -0
- package/src/lib/services/utils/encryption/encryption-test.service.ts +39 -0
- package/src/lib/services/utils/encryption/index.ts +5 -0
- package/src/lib/services/utils/encryption/random.ts +81 -0
- package/src/lib/services/utils/encryption/symmetrical-encryption.service.ts +106 -0
- package/src/lib/services/utils/headers.service.spec.ts +80 -0
- package/src/lib/services/utils/headers.service.ts +18 -0
- package/src/lib/services/utils/index.ts +9 -0
- package/src/lib/services/utils/logger.service.ts +90 -0
- package/src/lib/services/utils/models/index.ts +4 -0
- package/src/lib/services/utils/models/normalized-request-options.model.ts +24 -0
- package/src/lib/services/utils/models/path-tracker-state.model.ts +20 -0
- package/src/lib/services/utils/models/query-params-tracker-options.model.ts +24 -0
- package/src/lib/services/utils/models/query-tracker-state.model.ts +23 -0
- package/src/lib/services/utils/object-merger.service.spec.ts +18 -0
- package/src/lib/services/utils/object-merger.service.ts +78 -0
- package/src/lib/services/utils/path-query.service.spec.ts +117 -0
- package/src/lib/services/utils/path-query.service.ts +69 -0
- package/src/lib/services/utils/query-params-tracker.service.ts +442 -0
- package/src/lib/services/utils/random-color.utils.ts +83 -0
- package/src/lib/services/utils/utils.service.spec.ts +165 -0
- package/src/lib/services/utils/utils.service.ts +192 -0
- package/src/lib/services/ws-manager-service/index.ts +13 -0
- package/src/lib/services/ws-manager-service/message-tracker-signals.service.ts +147 -0
- package/src/lib/services/ws-manager-service/message-tracker.service.ts +477 -0
- package/src/lib/services/ws-manager-service/models/channel-info.model.ts +29 -0
- package/src/lib/services/ws-manager-service/models/channel-message-data.model.ts +24 -0
- package/src/lib/services/ws-manager-service/models/channel-message.model.ts +36 -0
- package/src/lib/services/ws-manager-service/models/channel-type.enum.ts +6 -0
- package/src/lib/services/ws-manager-service/models/communication-type.enum.ts +5 -0
- package/src/lib/services/ws-manager-service/models/index.ts +10 -0
- package/src/lib/services/ws-manager-service/models/notification-message.model.ts +29 -0
- package/src/lib/services/ws-manager-service/models/public-message.model.ts +18 -0
- package/src/lib/services/ws-manager-service/models/state-message.model.ts +18 -0
- package/src/lib/services/ws-manager-service/models/ws-user.model.ts +38 -0
- package/src/lib/services/ws-manager-service/services/index.ts +4 -0
- package/src/lib/services/ws-manager-service/services/websocket-message.service.ts +129 -0
- package/src/lib/services/ws-manager-service/services/websocket.service.ts +434 -0
- package/src/lib/services/ws-manager-service/websocket-service/index.ts +1 -0
- package/src/lib/services/ws-manager-service/websocket-service/websocket-manager.service.ts +716 -0
- package/src/lib/services/ws-manager-service/websocket-services-complete.spec.ts +596 -0
- package/src/lib/services/ws-manager-service/websocket-signals-manager.service.ts +141 -0
- package/src/public-api.ts +19 -0
- package/tsconfig.lib.json +34 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +14 -0
- package/fesm2022/http-request-manager.mjs +0 -13297
- package/fesm2022/http-request-manager.mjs.map +0 -1
- package/http-request-manager-18.15.32.tgz +0 -0
- package/types/http-request-manager.d.ts +0 -3875
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject, Observable, Subscription, timer } from 'rxjs';
|
|
3
|
+
import { take } from 'rxjs/operators';
|
|
4
|
+
import { WSOptions } from '../../request-manager-state-service';
|
|
5
|
+
import { UUID_STR } from '../../utils/encryption/random';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* WebSocketManagerService - Singleton WebSocket connection manager
|
|
9
|
+
*
|
|
10
|
+
* This service ensures only ONE WebSocket connection exists across ALL instances
|
|
11
|
+
* of HTTPManagerStateService. It uses static properties to track connection state
|
|
12
|
+
* globally, preventing duplicate connections when multiple state services are created.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* - Inject into HTTPManagerService (or directly into state services)
|
|
16
|
+
* - Call connect() with WSOptions - only the first call establishes connection
|
|
17
|
+
* - Subsequent calls detect existing connection and skip reconnection
|
|
18
|
+
* - All instances share the same connectionStatus$ and messages$ observables
|
|
19
|
+
*/
|
|
20
|
+
@Injectable({
|
|
21
|
+
providedIn: 'root',
|
|
22
|
+
})
|
|
23
|
+
export class WebSocketManagerService {
|
|
24
|
+
|
|
25
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
26
|
+
// STATIC SINGLETON STATE (Shared across ALL instances)
|
|
27
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
28
|
+
|
|
29
|
+
private static socket: WebSocket | null = null;
|
|
30
|
+
private static isConnecting = false;
|
|
31
|
+
private static connectionInitialized = false;
|
|
32
|
+
|
|
33
|
+
// Store last options for reconnection
|
|
34
|
+
private static lastOptions: WSOptions | null = null;
|
|
35
|
+
private static lastJwtToken: string = '';
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
// Retry configuration
|
|
39
|
+
private static retryCount = 0;
|
|
40
|
+
private static retryDelay = 5000;
|
|
41
|
+
private static retrySubscription: Subscription | null = null;
|
|
42
|
+
private static maxRetries = 10;
|
|
43
|
+
private static connectionReadyNotified = false;
|
|
44
|
+
private static retryCountSubject = new BehaviorSubject<number>(0);
|
|
45
|
+
public retryCount$ = WebSocketManagerService.retryCountSubject.asObservable();
|
|
46
|
+
private static maxRetriesSubject = new BehaviorSubject<number>(10);
|
|
47
|
+
public maxRetries$ = WebSocketManagerService.maxRetriesSubject.asObservable();
|
|
48
|
+
|
|
49
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
50
|
+
// INSTANCE OBSERVABLES (Shared across ALL instances via static BehaviorSubjects)
|
|
51
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
52
|
+
|
|
53
|
+
private static messages = new BehaviorSubject<any>(null);
|
|
54
|
+
public messages$: Observable<any> = WebSocketManagerService.messages.asObservable();
|
|
55
|
+
|
|
56
|
+
private static connectionStatus = new BehaviorSubject<boolean>(false);
|
|
57
|
+
public connectionStatus$: Observable<boolean> = WebSocketManagerService.connectionStatus.asObservable();
|
|
58
|
+
|
|
59
|
+
private static isSubscribed: boolean = false;
|
|
60
|
+
|
|
61
|
+
// Track currently subscribed channels
|
|
62
|
+
private static subscribedChannels = new BehaviorSubject<Set<string>>(new Set());
|
|
63
|
+
public subscribedChannels$: Observable<Set<string>> = WebSocketManagerService.subscribedChannels.asObservable();
|
|
64
|
+
|
|
65
|
+
// Public method to get current subscribed channels
|
|
66
|
+
public static getSubscribedChannels(): Set<string> {
|
|
67
|
+
return WebSocketManagerService.subscribedChannels.getValue();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Public method to add a channel to subscribed channels
|
|
71
|
+
public static addSubscribedChannel(channelName: string): void {
|
|
72
|
+
const current = new Set(WebSocketManagerService.subscribedChannels.value);
|
|
73
|
+
current.add(channelName);
|
|
74
|
+
WebSocketManagerService.subscribedChannels.next(current);
|
|
75
|
+
console.log(`📝 Added ${channelName} to subscribedChannels (now has ${current.size} channels)`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Reconnect event (emitted when connection is established/re-established)
|
|
79
|
+
private static onReconnect = new BehaviorSubject<void>(undefined);
|
|
80
|
+
public onReconnect$: Observable<void> = WebSocketManagerService.onReconnect.asObservable();
|
|
81
|
+
|
|
82
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
83
|
+
// SESSION MANAGEMENT
|
|
84
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
85
|
+
|
|
86
|
+
private getSessionId(): string {
|
|
87
|
+
return sessionStorage.getItem('WSID') ?? (() => {
|
|
88
|
+
const uuid = UUID_STR()
|
|
89
|
+
sessionStorage.setItem('WSID', uuid)
|
|
90
|
+
return uuid
|
|
91
|
+
})()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
95
|
+
// CONNECTION MANAGEMENT
|
|
96
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Connect to WebSocket server
|
|
100
|
+
*
|
|
101
|
+
* IMPORTANT: Only the first call across ALL instances will establish a connection.
|
|
102
|
+
* Subsequent calls will detect the existing connection and return immediately.
|
|
103
|
+
*
|
|
104
|
+
* @param options - WebSocket configuration options
|
|
105
|
+
* @param jwtToken - Optional JWT token for authentication
|
|
106
|
+
*/
|
|
107
|
+
connect(options: WSOptions, jwtToken: string): void {
|
|
108
|
+
// Cancel any pending retry timer before attempting a new connection
|
|
109
|
+
WebSocketManagerService.retrySubscription?.unsubscribe();
|
|
110
|
+
WebSocketManagerService.retrySubscription = null;
|
|
111
|
+
|
|
112
|
+
// Check if connection already exists and is open
|
|
113
|
+
if (WebSocketManagerService.socket) {
|
|
114
|
+
if (WebSocketManagerService.socket.readyState === WebSocket.OPEN) {
|
|
115
|
+
console.log('✓ WebSocket connection already OPEN (singleton).');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (WebSocketManagerService.socket.readyState === WebSocket.CONNECTING) {
|
|
120
|
+
console.log('⏳ WebSocket is already CONNECTING (singleton). Waiting for handshake.');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Clean up stale connection
|
|
125
|
+
if (WebSocketManagerService.socket.readyState === WebSocket.CLOSING ||
|
|
126
|
+
WebSocketManagerService.socket.readyState === WebSocket.CLOSED) {
|
|
127
|
+
console.log(`🧹 Cleaning up stale socket (State: ${WebSocketManagerService.socket.readyState}).`);
|
|
128
|
+
WebSocketManagerService.socket.close();
|
|
129
|
+
WebSocketManagerService.socket = null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Prevent duplicate connection attempts
|
|
134
|
+
if (WebSocketManagerService.isConnecting) {
|
|
135
|
+
console.log('⏳ Connection already in progress...');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Store jwt token for retry
|
|
140
|
+
WebSocketManagerService.lastJwtToken = jwtToken;
|
|
141
|
+
WebSocketManagerService.lastOptions = options;
|
|
142
|
+
|
|
143
|
+
// Always set maxRetries and delay from latest options
|
|
144
|
+
if (options?.retry?.times) {
|
|
145
|
+
WebSocketManagerService.maxRetries = options.retry.times;
|
|
146
|
+
WebSocketManagerService.maxRetriesSubject.next(options.retry.times);
|
|
147
|
+
} else {
|
|
148
|
+
WebSocketManagerService.maxRetries = 10;
|
|
149
|
+
WebSocketManagerService.maxRetriesSubject.next(10);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (options?.retry?.delay) {
|
|
153
|
+
WebSocketManagerService.retryDelay = options.retry.delay * 1000;
|
|
154
|
+
} else {
|
|
155
|
+
WebSocketManagerService.retryDelay = 5000;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Mark as connecting — connectionStatus true while connecting/retrying, false only when exhausted
|
|
159
|
+
WebSocketManagerService.isConnecting = true;
|
|
160
|
+
WebSocketManagerService.isSubscribed = false;
|
|
161
|
+
WebSocketManagerService.connectionReadyNotified = false;
|
|
162
|
+
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
163
|
+
WebSocketManagerService.connectionStatus.next(true);
|
|
164
|
+
|
|
165
|
+
const sessionId = this.getSessionId();
|
|
166
|
+
const URL = (jwtToken) ? `${options.wsServer}?token=${jwtToken}&sessionId=${sessionId}` : `${options.wsServer}?sessionId=${sessionId}`;
|
|
167
|
+
|
|
168
|
+
console.log(`🔌 Initiating WebSocket connection to: ${options.wsServer}`);
|
|
169
|
+
|
|
170
|
+
// Create new WebSocket instance (static)
|
|
171
|
+
WebSocketManagerService.socket = new WebSocket(URL);
|
|
172
|
+
|
|
173
|
+
WebSocketManagerService.socket.onopen = () => {
|
|
174
|
+
console.log(`📡 WebSocket handshake complete — awaiting server confirmation`);
|
|
175
|
+
// Force clear subscribedChannels on new connection - server lost our subscriptions
|
|
176
|
+
console.log('🧹 Clearing subscribedChannels on connect (was:', WebSocketManagerService.subscribedChannels.value.size, 'channels)');
|
|
177
|
+
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
178
|
+
|
|
179
|
+
// Do NOT reset retryCount here — reset happens only on confirmed stable connection
|
|
180
|
+
// (onmessage first valid response). Resetting here would cause the counter to always
|
|
181
|
+
// show 1/N because onopen fires before onclose increments the counter.
|
|
182
|
+
WebSocketManagerService.isConnecting = false;
|
|
183
|
+
WebSocketManagerService.connectionInitialized = true;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
WebSocketManagerService.socket.onmessage = (event) => {
|
|
187
|
+
try {
|
|
188
|
+
const data = JSON.parse(event.data);
|
|
189
|
+
|
|
190
|
+
if (data.error) {
|
|
191
|
+
WebSocketManagerService.messages.next(data);
|
|
192
|
+
// Log the server error and close — onclose will drive the retry logic
|
|
193
|
+
if (data.error === 'JWT_INVALID' || data.error === 'AUTH_BLOCKED') {
|
|
194
|
+
console.error(`🚫 ${data.error}: ${data.message || 'Authentication error'} — will retry`);
|
|
195
|
+
} else {
|
|
196
|
+
console.error(`❌ Server error: ${data.error} — will retry`);
|
|
197
|
+
}
|
|
198
|
+
WebSocketManagerService.socket?.close();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// First valid (non-error) message confirms the server accepted auth.
|
|
203
|
+
// Notify readiness once per connection so pending intended subscriptions
|
|
204
|
+
// are replayed after the socket is actually usable.
|
|
205
|
+
if (!WebSocketManagerService.connectionReadyNotified) {
|
|
206
|
+
if (WebSocketManagerService.retryCount > 0) {
|
|
207
|
+
console.log(`✅ Server confirmed connection after ${WebSocketManagerService.retryCount} retries.`);
|
|
208
|
+
WebSocketManagerService.retryCount = 0;
|
|
209
|
+
WebSocketManagerService.retryCountSubject.next(0);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
WebSocketManagerService.connectionReadyNotified = true;
|
|
213
|
+
console.log(`🔄 Emitting reconnect event for MessageTrackerService`);
|
|
214
|
+
WebSocketManagerService.onReconnect.next();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
WebSocketManagerService.messages.next(data);
|
|
218
|
+
|
|
219
|
+
} catch (error) {
|
|
220
|
+
console.error('Error parsing WebSocket message:', event.data);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
WebSocketManagerService.socket.onclose = (event: CloseEvent) => {
|
|
225
|
+
console.log(`🔴 WebSocket closed (code: ${event.code})`);
|
|
226
|
+
WebSocketManagerService.isConnecting = false;
|
|
227
|
+
WebSocketManagerService.connectionReadyNotified = false;
|
|
228
|
+
WebSocketManagerService.socket = null;
|
|
229
|
+
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
230
|
+
|
|
231
|
+
const maxRetries = WebSocketManagerService.maxRetries;
|
|
232
|
+
const retryDelay = WebSocketManagerService.retryDelay;
|
|
233
|
+
|
|
234
|
+
if (WebSocketManagerService.lastOptions && WebSocketManagerService.retryCount < maxRetries) {
|
|
235
|
+
WebSocketManagerService.retryCount++;
|
|
236
|
+
WebSocketManagerService.retryCountSubject.next(WebSocketManagerService.retryCount);
|
|
237
|
+
console.log(`🔄 Reconnect attempt ${WebSocketManagerService.retryCount}/${maxRetries}...`);
|
|
238
|
+
// connectionStatus stays true — still actively retrying
|
|
239
|
+
WebSocketManagerService.retrySubscription = timer(retryDelay).pipe(take(1)).subscribe(() => this.connect(WebSocketManagerService.lastOptions!, WebSocketManagerService.lastJwtToken));
|
|
240
|
+
} else {
|
|
241
|
+
console.error(`❌ WebSocket failed after ${maxRetries} retries. Giving up.`);
|
|
242
|
+
WebSocketManagerService.connectionStatus.next(false);
|
|
243
|
+
WebSocketManagerService.retryCount = maxRetries;
|
|
244
|
+
WebSocketManagerService.retryCountSubject.next(maxRetries);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
WebSocketManagerService.socket.onerror = (error) => {
|
|
249
|
+
console.error('❌ WebSocket error:', error);
|
|
250
|
+
WebSocketManagerService.isConnecting = false;
|
|
251
|
+
// onclose will fire after onerror and drive retry/give-up logic
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Disconnect from WebSocket server
|
|
257
|
+
*/
|
|
258
|
+
disconnect(): void {
|
|
259
|
+
WebSocketManagerService.retrySubscription?.unsubscribe();
|
|
260
|
+
WebSocketManagerService.retrySubscription = null;
|
|
261
|
+
if (WebSocketManagerService.socket) {
|
|
262
|
+
console.log('🔌 Disconnecting WebSocket...');
|
|
263
|
+
WebSocketManagerService.socket.close();
|
|
264
|
+
WebSocketManagerService.socket = null;
|
|
265
|
+
WebSocketManagerService.connectionStatus.next(false);
|
|
266
|
+
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
271
|
+
// SUBSCRIPTION MANAGEMENT
|
|
272
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
273
|
+
|
|
274
|
+
private sendSubscribe(channelName: string, user: any): void {
|
|
275
|
+
const alreadySubscribed = WebSocketManagerService.subscribedChannels.value.has(channelName);
|
|
276
|
+
|
|
277
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN && !alreadySubscribed) {
|
|
278
|
+
const message = {
|
|
279
|
+
type: 'subscribe',
|
|
280
|
+
subscribedChannel: channelName,
|
|
281
|
+
content: {
|
|
282
|
+
id: this.getSessionId(),
|
|
283
|
+
...user
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
WebSocketManagerService.socket.send(JSON.stringify(message));
|
|
287
|
+
|
|
288
|
+
// Track this channel as subscribed
|
|
289
|
+
const current = new Set(WebSocketManagerService.subscribedChannels.value);
|
|
290
|
+
current.add(channelName);
|
|
291
|
+
WebSocketManagerService.subscribedChannels.next(current);
|
|
292
|
+
|
|
293
|
+
WebSocketManagerService.isSubscribed = true;
|
|
294
|
+
console.log(`[CLIENT] Sent initial subscription to: ${channelName}`);
|
|
295
|
+
} else {
|
|
296
|
+
console.warn(`[CLIENT] Subscription prevented. Open: ${WebSocketManagerService.socket?.readyState === WebSocket.OPEN}, Already subscribed to ${channelName}: ${alreadySubscribed}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Send subscribe with lastSeenId for message sync support
|
|
302
|
+
* @param channelName - Channel name to subscribe to
|
|
303
|
+
* @param user - User data
|
|
304
|
+
* @param lastSeenId - Last message ID seen (for replay)
|
|
305
|
+
*/
|
|
306
|
+
sendSubscribeWithLastSeen(channelName: string, user: any, lastSeenId: number): void {
|
|
307
|
+
const alreadySubscribed = WebSocketManagerService.subscribedChannels.value.has(channelName);
|
|
308
|
+
const isOpen = WebSocketManagerService.socket?.readyState === WebSocket.OPEN;
|
|
309
|
+
|
|
310
|
+
console.log(`🔍 Subscription check for "${channelName}": isOpen=${isOpen}, alreadySubscribed=${alreadySubscribed}`);
|
|
311
|
+
|
|
312
|
+
if (isOpen && !alreadySubscribed && WebSocketManagerService.socket) {
|
|
313
|
+
const message = {
|
|
314
|
+
type: 'subscribe',
|
|
315
|
+
subscribedChannel: channelName,
|
|
316
|
+
lastSeenId, // NEW: For message replay
|
|
317
|
+
content: {
|
|
318
|
+
id: this.getSessionId(),
|
|
319
|
+
...user
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
WebSocketManagerService.socket.send(JSON.stringify(message));
|
|
323
|
+
|
|
324
|
+
// DON'T track as subscribed yet - wait for server confirmation ('subscribed' message)
|
|
325
|
+
// This prevents race conditions where we think we're subscribed but server doesn't
|
|
326
|
+
|
|
327
|
+
WebSocketManagerService.isSubscribed = true;
|
|
328
|
+
console.log(`[CLIENT] Sent subscription with lastSeenId=${lastSeenId} to: ${channelName}`);
|
|
329
|
+
} else {
|
|
330
|
+
console.warn(`[CLIENT] Subscription prevented. Open: ${isOpen}, Already subscribed to ${channelName}: ${alreadySubscribed}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Subscribe to a channel
|
|
336
|
+
* @param channelName - Channel name to subscribe to
|
|
337
|
+
*/
|
|
338
|
+
subscribeToChannel(channelName: string): void {
|
|
339
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
340
|
+
try {
|
|
341
|
+
const message = {
|
|
342
|
+
type: 'subscribe',
|
|
343
|
+
subscribedChannel: channelName,
|
|
344
|
+
content: {}
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
WebSocketManagerService.socket.send(JSON.stringify(message));
|
|
348
|
+
|
|
349
|
+
// Track locally - create new Set to trigger change detection
|
|
350
|
+
const current = new Set(WebSocketManagerService.subscribedChannels.value);
|
|
351
|
+
current.add(channelName);
|
|
352
|
+
WebSocketManagerService.subscribedChannels.next(current);
|
|
353
|
+
console.log(`📝 Subscribed to channel: ${channelName}`);
|
|
354
|
+
} catch (error) {
|
|
355
|
+
console.error(`❌ Failed to subscribe to channel "${channelName}":`, error);
|
|
356
|
+
}
|
|
357
|
+
} else {
|
|
358
|
+
console.warn(`Cannot subscribe to channel "${channelName}": WebSocket not yet open.`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Subscribe to multiple channels
|
|
364
|
+
* @param channelNames - Array of channel names to subscribe to
|
|
365
|
+
*/
|
|
366
|
+
subscribeToChannels(channelNames: string[]): void {
|
|
367
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
368
|
+
channelNames.forEach(channel => this.subscribeToChannel(channel));
|
|
369
|
+
} else {
|
|
370
|
+
console.warn('Cannot subscribe: WebSocket not yet open.');
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Unsubscribe from a channel
|
|
376
|
+
* @param channel - Channel name to unsubscribe from
|
|
377
|
+
*/
|
|
378
|
+
unsubscribeFromChannel(channel: string): void {
|
|
379
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
380
|
+
WebSocketManagerService.socket.send(JSON.stringify({ type: 'unsubscribe', subscribedChannel: channel }));
|
|
381
|
+
|
|
382
|
+
// Remove from local tracking - create new Set to trigger change detection
|
|
383
|
+
const current = new Set(WebSocketManagerService.subscribedChannels.value);
|
|
384
|
+
current.delete(channel);
|
|
385
|
+
WebSocketManagerService.subscribedChannels.next(current);
|
|
386
|
+
console.log(`💬 Unsubscribed from channel: ${channel}`);
|
|
387
|
+
} else {
|
|
388
|
+
console.error('WebSocket is not open. Cannot unsubscribe from channel.');
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Get currently subscribed channels
|
|
394
|
+
* @returns Set of subscribed channel names
|
|
395
|
+
*/
|
|
396
|
+
getSubscribedChannels(): Set<string> {
|
|
397
|
+
return WebSocketManagerService.subscribedChannels.value;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
401
|
+
// MESSAGE SENDING
|
|
402
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Generic send method for message tracking (acks, gap requests, etc.)
|
|
406
|
+
* @param message - Message object to send
|
|
407
|
+
*/
|
|
408
|
+
send(message: any): void {
|
|
409
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
410
|
+
WebSocketManagerService.socket.send(JSON.stringify(message));
|
|
411
|
+
} else {
|
|
412
|
+
console.warn('⚠️ Cannot send message: WebSocket not open', message);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Send broadcast message
|
|
418
|
+
* @param content - Message content to broadcast
|
|
419
|
+
*/
|
|
420
|
+
sendBroadcast(content: any): void {
|
|
421
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
422
|
+
WebSocketManagerService.socket.send(JSON.stringify({ type: 'broadcast', content }));
|
|
423
|
+
console.log(`📢 Send broadcast: ${content}`);
|
|
424
|
+
} else {
|
|
425
|
+
console.error('WebSocket is not open. Cannot send broadcast.');
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Send message in channel (state manager message)
|
|
431
|
+
* @param channel - Channel name
|
|
432
|
+
* @param content - Message content
|
|
433
|
+
*/
|
|
434
|
+
sendMessageInChannel(channel: string, content: any): void {
|
|
435
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
436
|
+
const message = {
|
|
437
|
+
type: 'statemanagerMessage',
|
|
438
|
+
subscribedChannel: channel,
|
|
439
|
+
content
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
// DEBUG: Log the exact message being sent
|
|
443
|
+
// console.log('🔍 [DEBUG] sendMessageInChannel:', {
|
|
444
|
+
// channel,
|
|
445
|
+
// channelType: typeof channel,
|
|
446
|
+
// channelEmpty: channel === '' || channel === null || channel === undefined,
|
|
447
|
+
// content,
|
|
448
|
+
// fullMessage: message,
|
|
449
|
+
// jsonString: JSON.stringify(message)
|
|
450
|
+
// });
|
|
451
|
+
|
|
452
|
+
WebSocketManagerService.socket.send(JSON.stringify(message));
|
|
453
|
+
console.log(`💬 Send message:`, content);
|
|
454
|
+
} else {
|
|
455
|
+
console.error('WebSocket is not open. Cannot send message.');
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Send channel message (broadcasts to all subscribers in the channel)
|
|
461
|
+
* @param channel - Channel name
|
|
462
|
+
* @param content - Message content
|
|
463
|
+
*/
|
|
464
|
+
sendChannelMessage(channel: string, content: any): void {
|
|
465
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
466
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
467
|
+
type: 'message',
|
|
468
|
+
subscribedChannel: channel,
|
|
469
|
+
content
|
|
470
|
+
}));
|
|
471
|
+
console.log(`💬 Send channel message to [${channel}]:`, content);
|
|
472
|
+
} else {
|
|
473
|
+
console.error('WebSocket is not open. Cannot send channel message.');
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Send message to multiple channels at once (batch)
|
|
479
|
+
* @param channels - Array of channel names
|
|
480
|
+
* @param content - Message content
|
|
481
|
+
*/
|
|
482
|
+
sendChannelMessageToChannels(channels: string[], content: any): void {
|
|
483
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
484
|
+
try {
|
|
485
|
+
// New batch format
|
|
486
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
487
|
+
type: 'channelMessage',
|
|
488
|
+
channels: channels,
|
|
489
|
+
data: content
|
|
490
|
+
}));
|
|
491
|
+
console.log(`💬 Send channel message to channels [${channels.join(', ')}]:`, content);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
console.error('❌ Failed to send channelMessage batch:', error);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Legacy fallback - send individual messages to each channel
|
|
497
|
+
try {
|
|
498
|
+
channels.forEach(channel => {
|
|
499
|
+
WebSocketManagerService.socket?.send(JSON.stringify({
|
|
500
|
+
type: 'message',
|
|
501
|
+
subscribedChannel: channel,
|
|
502
|
+
content
|
|
503
|
+
}));
|
|
504
|
+
});
|
|
505
|
+
} catch (err) {
|
|
506
|
+
console.warn('⚠️ Legacy fallback failed sending individual messages', err);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
} else {
|
|
510
|
+
console.error('WebSocket is not open. Cannot send message to channels.');
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Send message to specific user
|
|
516
|
+
* @param user - User identifier
|
|
517
|
+
* @param content - Message content
|
|
518
|
+
*/
|
|
519
|
+
sendMessageToUser(user: string, content: any): void {
|
|
520
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
521
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
522
|
+
type: 'userMessage',
|
|
523
|
+
subscribedChannel: user,
|
|
524
|
+
content
|
|
525
|
+
}));
|
|
526
|
+
console.log(`💬 Send message:`, content);
|
|
527
|
+
} else {
|
|
528
|
+
console.error('WebSocket is not open. Cannot send message.');
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
533
|
+
// CHANNEL MANAGEMENT
|
|
534
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Request list of all channels from server
|
|
538
|
+
*/
|
|
539
|
+
getAllChannels(): void {
|
|
540
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
541
|
+
WebSocketManagerService.socket.send(JSON.stringify({ type: 'getChannels' }));
|
|
542
|
+
console.log('🗂️ List of all channels');
|
|
543
|
+
} else {
|
|
544
|
+
console.error('WebSocket is not open. Cannot request channels.');
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Create a new channel on server
|
|
550
|
+
* @param channel - Channel name to create
|
|
551
|
+
*/
|
|
552
|
+
createChannel(channel: string): void {
|
|
553
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
554
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
555
|
+
type: 'createChannel',
|
|
556
|
+
content: channel
|
|
557
|
+
}));
|
|
558
|
+
console.log('🗂️ Created channel:', channel);
|
|
559
|
+
} else {
|
|
560
|
+
console.error('WebSocket is not open. Cannot request channels.');
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Delete a channel from server
|
|
566
|
+
* @param channel - Channel name to delete
|
|
567
|
+
*/
|
|
568
|
+
deleteChannel(channel: string): void {
|
|
569
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
570
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
571
|
+
type: 'deleteChannel',
|
|
572
|
+
content: channel
|
|
573
|
+
}));
|
|
574
|
+
console.log('🗂️ Delete channel:', channel);
|
|
575
|
+
} else {
|
|
576
|
+
console.error('WebSocket is not open. Cannot request channels.');
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Get users in a specific channel
|
|
582
|
+
* @param channel - Channel name
|
|
583
|
+
*/
|
|
584
|
+
getUsersInChannel(channel: string): void {
|
|
585
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
586
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
587
|
+
type: 'getUsers',
|
|
588
|
+
subscribedChannel: channel
|
|
589
|
+
}));
|
|
590
|
+
console.log(`👥 List all users in channel: ${channel}`);
|
|
591
|
+
} else {
|
|
592
|
+
console.error('WebSocket is not open. Cannot request users.');
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
597
|
+
// NOTIFICATION CHANNELS (MES- prefix)
|
|
598
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Create a notification channel
|
|
602
|
+
* @param channel - Channel name (should include MES- prefix)
|
|
603
|
+
*/
|
|
604
|
+
createNotificationChannel(channel: string): void {
|
|
605
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
606
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
607
|
+
type: 'createNotificationChannel',
|
|
608
|
+
content: channel
|
|
609
|
+
}));
|
|
610
|
+
console.log('📢 Created notification channel:', channel);
|
|
611
|
+
} else {
|
|
612
|
+
console.error('WebSocket is not open. Cannot create notification channel.');
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Get all notification channels (in-memory)
|
|
618
|
+
*/
|
|
619
|
+
getNotificationChannels(): void {
|
|
620
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
621
|
+
WebSocketManagerService.socket.send(JSON.stringify({ type: 'getNotificationChannels' }));
|
|
622
|
+
console.log('📢 Requested notification channels list');
|
|
623
|
+
} else {
|
|
624
|
+
console.error('WebSocket is not open. Cannot request notification channels.');
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Get today's notification channels from database
|
|
630
|
+
*/
|
|
631
|
+
getTodaysNotificationChannels(): void {
|
|
632
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
633
|
+
WebSocketManagerService.socket.send(JSON.stringify({ type: 'getTodaysNotificationChannels' }));
|
|
634
|
+
console.log('📢 Requested today\'s notification channels from DB');
|
|
635
|
+
} else {
|
|
636
|
+
console.error('WebSocket is not open. Cannot request today\'s notification channels.');
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Subscribe to a notification channel with optional date filters
|
|
642
|
+
* @param channel - Channel name
|
|
643
|
+
* @param options - Optional start/end epoch filters
|
|
644
|
+
* @param user - User information
|
|
645
|
+
*/
|
|
646
|
+
subscribeToNotificationChannel(channel: string, options?: { startEpoch?: number; endEpoch?: number }, user?: any): void {
|
|
647
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
648
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
649
|
+
type: 'subscribeNotifications',
|
|
650
|
+
subscribedChannel: channel,
|
|
651
|
+
content: {
|
|
652
|
+
...options,
|
|
653
|
+
user: user
|
|
654
|
+
}
|
|
655
|
+
}));
|
|
656
|
+
console.log(`📢 Subscribed to notification channel: ${channel}`);
|
|
657
|
+
} else {
|
|
658
|
+
console.error('WebSocket is not open. Cannot subscribe to notification channel.');
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Unsubscribe from a notification channel
|
|
664
|
+
* @param channel - Channel name
|
|
665
|
+
*/
|
|
666
|
+
unsubscribeFromNotificationChannel(channel: string): void {
|
|
667
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
668
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
669
|
+
type: 'unsubscribeNotifications',
|
|
670
|
+
subscribedChannel: channel
|
|
671
|
+
}));
|
|
672
|
+
console.log(`📢 Unsubscribed from notification channel: ${channel}`);
|
|
673
|
+
} else {
|
|
674
|
+
console.error('WebSocket is not open. Cannot unsubscribe from notification channel.');
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Send notification to channel
|
|
680
|
+
* @param channel - Channel name (should include MES- prefix)
|
|
681
|
+
* @param content - Notification content
|
|
682
|
+
*/
|
|
683
|
+
sendNotification(channel: string, content: any): void {
|
|
684
|
+
if (WebSocketManagerService.socket?.readyState === WebSocket.OPEN) {
|
|
685
|
+
WebSocketManagerService.socket.send(JSON.stringify({
|
|
686
|
+
type: 'notification',
|
|
687
|
+
subscribedChannel: channel,
|
|
688
|
+
content
|
|
689
|
+
}));
|
|
690
|
+
console.log(`📢 Sent notification to channel: ${channel}`, content);
|
|
691
|
+
} else {
|
|
692
|
+
console.error('WebSocket is not open. Cannot send notification.');
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
697
|
+
// CONNECTION STATUS (Static getter for direct access)
|
|
698
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Check if WebSocket connection is currently open
|
|
702
|
+
* @returns true if connected, false otherwise
|
|
703
|
+
*/
|
|
704
|
+
static isConnected(): boolean {
|
|
705
|
+
return WebSocketManagerService.socket?.readyState === WebSocket.OPEN;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Check if connection has been initialized (attempted at least once)
|
|
710
|
+
* @returns true if connection was initialized, false otherwise
|
|
711
|
+
*/
|
|
712
|
+
static isInitialized(): boolean {
|
|
713
|
+
return WebSocketManagerService.connectionInitialized;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
}
|