@brightchain/brightchain-api-lib 0.23.25 → 0.24.1
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/package.json +5 -5
- package/src/lib/__tests__/fixtures/mock-backend-brightchain-member.d.ts.map +1 -1
- package/src/lib/__tests__/fixtures/mock-backend-brightchain-member.js +11 -0
- package/src/lib/__tests__/fixtures/mock-backend-brightchain-member.js.map +1 -1
- package/src/lib/__tests__/fixtures/mocked-model.js +63 -60
- package/src/lib/__tests__/fixtures/mocked-model.js.map +1 -1
- package/src/lib/application.d.ts +1 -1
- package/src/lib/application.d.ts.map +1 -1
- package/src/lib/application.js +103 -34
- package/src/lib/application.js.map +1 -1
- package/src/lib/auth/aclEnforcedAvailability.js +4 -0
- package/src/lib/auth/aclEnforcedAvailability.js.map +1 -1
- package/src/lib/auth/aclEnforcedBlockStore.js +7 -0
- package/src/lib/auth/aclEnforcedBlockStore.js.map +1 -1
- package/src/lib/auth/ecdsaNodeAuthenticator.js +1 -0
- package/src/lib/auth/ecdsaNodeAuthenticator.js.map +1 -1
- package/src/lib/auth/poolAclBootstrap.js +2 -0
- package/src/lib/auth/poolAclBootstrap.js.map +1 -1
- package/src/lib/auth/poolAclStore.js +2 -1
- package/src/lib/auth/poolAclStore.js.map +1 -1
- package/src/lib/auth/poolAclUpdater.js +4 -0
- package/src/lib/auth/poolAclUpdater.js.map +1 -1
- package/src/lib/availability/availabilityMetrics.js +43 -45
- package/src/lib/availability/availabilityMetrics.js.map +1 -1
- package/src/lib/availability/availabilityService.js +26 -20
- package/src/lib/availability/availabilityService.js.map +1 -1
- package/src/lib/availability/blockRegistry.js +46 -25
- package/src/lib/availability/blockRegistry.js.map +1 -1
- package/src/lib/availability/discoveryProtocol.js +10 -8
- package/src/lib/availability/discoveryProtocol.js.map +1 -1
- package/src/lib/availability/gossipService.js +56 -45
- package/src/lib/availability/gossipService.js.map +1 -1
- package/src/lib/availability/heartbeatMonitor.js +22 -20
- package/src/lib/availability/heartbeatMonitor.js.map +1 -1
- package/src/lib/availability/poolDiscoveryService.js +7 -1
- package/src/lib/availability/poolDiscoveryService.js.map +1 -1
- package/src/lib/availability/quorumGossipHandler.js +13 -6
- package/src/lib/availability/quorumGossipHandler.js.map +1 -1
- package/src/lib/availability/reconciliationService.js +18 -12
- package/src/lib/availability/reconciliationService.js.map +1 -1
- package/src/lib/blockFetch/blockFetcher.js +14 -8
- package/src/lib/blockFetch/blockFetcher.js.map +1 -1
- package/src/lib/blockFetch/fetchQueue.js +9 -7
- package/src/lib/blockFetch/fetchQueue.js.map +1 -1
- package/src/lib/blockFetch/httpBlockFetchTransport.js +2 -0
- package/src/lib/blockFetch/httpBlockFetchTransport.js.map +1 -1
- package/src/lib/browserKeyring.js +5 -2
- package/src/lib/browserKeyring.js.map +1 -1
- package/src/lib/controllers/api/blocks.d.ts.map +1 -1
- package/src/lib/controllers/api/blocks.js +9 -3
- package/src/lib/controllers/api/blocks.js.map +1 -1
- package/src/lib/controllers/api/brighthub/connectionController.d.ts +80 -0
- package/src/lib/controllers/api/brighthub/connectionController.d.ts.map +1 -0
- package/src/lib/controllers/api/brighthub/connectionController.js +890 -0
- package/src/lib/controllers/api/brighthub/connectionController.js.map +1 -0
- package/src/lib/controllers/api/brighthub/index.d.ts +9 -0
- package/src/lib/controllers/api/brighthub/index.d.ts.map +1 -0
- package/src/lib/controllers/api/brighthub/index.js +12 -0
- package/src/lib/controllers/api/brighthub/index.js.map +1 -0
- package/src/lib/controllers/api/brighthub/messagingController.d.ts +84 -0
- package/src/lib/controllers/api/brighthub/messagingController.d.ts.map +1 -0
- package/src/lib/controllers/api/brighthub/messagingController.js +1077 -0
- package/src/lib/controllers/api/brighthub/messagingController.js.map +1 -0
- package/src/lib/controllers/api/brighthub/notificationController.d.ts +89 -0
- package/src/lib/controllers/api/brighthub/notificationController.d.ts.map +1 -0
- package/src/lib/controllers/api/brighthub/notificationController.js +444 -0
- package/src/lib/controllers/api/brighthub/notificationController.js.map +1 -0
- package/src/lib/controllers/api/brighthub/postController.d.ts +75 -0
- package/src/lib/controllers/api/brighthub/postController.d.ts.map +1 -0
- package/src/lib/controllers/api/brighthub/postController.js +388 -0
- package/src/lib/controllers/api/brighthub/postController.js.map +1 -0
- package/src/lib/controllers/api/brighthub/timelineController.d.ts +74 -0
- package/src/lib/controllers/api/brighthub/timelineController.d.ts.map +1 -0
- package/src/lib/controllers/api/brighthub/timelineController.js +418 -0
- package/src/lib/controllers/api/brighthub/timelineController.js.map +1 -0
- package/src/lib/controllers/api/brightpass.d.ts.map +1 -1
- package/src/lib/controllers/api/brightpass.js +46 -4
- package/src/lib/controllers/api/brightpass.js.map +1 -1
- package/src/lib/controllers/api/cbl.js +1 -0
- package/src/lib/controllers/api/cbl.js.map +1 -1
- package/src/lib/controllers/api/channels.js +2 -2
- package/src/lib/controllers/api/channels.js.map +1 -1
- package/src/lib/controllers/api/conversations.js +1 -1
- package/src/lib/controllers/api/conversations.js.map +1 -1
- package/src/lib/controllers/api/docs.js +2 -1
- package/src/lib/controllers/api/docs.js.map +1 -1
- package/src/lib/controllers/api/emails.d.ts.map +1 -1
- package/src/lib/controllers/api/emails.js +16 -2
- package/src/lib/controllers/api/emails.js.map +1 -1
- package/src/lib/controllers/api/explodingMessages.js +2 -4
- package/src/lib/controllers/api/explodingMessages.js.map +1 -1
- package/src/lib/controllers/api/groups.js +2 -2
- package/src/lib/controllers/api/groups.js.map +1 -1
- package/src/lib/controllers/api/health.d.ts +9 -2
- package/src/lib/controllers/api/health.d.ts.map +1 -1
- package/src/lib/controllers/api/health.js +48 -6
- package/src/lib/controllers/api/health.js.map +1 -1
- package/src/lib/controllers/api/index.d.ts +1 -0
- package/src/lib/controllers/api/index.d.ts.map +1 -1
- package/src/lib/controllers/api/index.js +1 -0
- package/src/lib/controllers/api/index.js.map +1 -1
- package/src/lib/controllers/api/introspection.js +2 -0
- package/src/lib/controllers/api/introspection.js.map +1 -1
- package/src/lib/controllers/api/messages.js +1 -1
- package/src/lib/controllers/api/messages.js.map +1 -1
- package/src/lib/controllers/api/nodes.js +6 -6
- package/src/lib/controllers/api/nodes.js.map +1 -1
- package/src/lib/controllers/api/quorum.d.ts +1 -1
- package/src/lib/controllers/api/quorum.d.ts.map +1 -1
- package/src/lib/controllers/api/quorum.js +3 -2
- package/src/lib/controllers/api/quorum.js.map +1 -1
- package/src/lib/controllers/api/scbl.js +3 -0
- package/src/lib/controllers/api/scbl.js.map +1 -1
- package/src/lib/controllers/api/sessions.d.ts +18 -2
- package/src/lib/controllers/api/sessions.d.ts.map +1 -1
- package/src/lib/controllers/api/sessions.js +60 -3
- package/src/lib/controllers/api/sessions.js.map +1 -1
- package/src/lib/controllers/api/sync.js +4 -4
- package/src/lib/controllers/api/sync.js.map +1 -1
- package/src/lib/controllers/api/user.d.ts +2 -0
- package/src/lib/controllers/api/user.d.ts.map +1 -1
- package/src/lib/controllers/api/user.js +95 -3
- package/src/lib/controllers/api/user.js.map +1 -1
- package/src/lib/controllers/identity/deviceController.js +2 -2
- package/src/lib/controllers/identity/deviceController.js.map +1 -1
- package/src/lib/controllers/identity/directoryController.js +1 -1
- package/src/lib/controllers/identity/directoryController.js.map +1 -1
- package/src/lib/controllers/identity/identityProofController.js +4 -6
- package/src/lib/controllers/identity/identityProofController.js.map +1 -1
- package/src/lib/databaseInit.d.ts +3 -3
- package/src/lib/databaseInit.js +5 -5
- package/src/lib/databaseInit.js.map +1 -1
- package/src/lib/datastore/block-document-store.d.ts.map +1 -1
- package/src/lib/datastore/block-document-store.js +18 -6
- package/src/lib/datastore/block-document-store.js.map +1 -1
- package/src/lib/datastore/document-store.d.ts.map +1 -1
- package/src/lib/datastore/memory-document-store.js +5 -2
- package/src/lib/datastore/memory-document-store.js.map +1 -1
- package/src/lib/encryption/encryptedMetadataService.js +2 -0
- package/src/lib/encryption/encryptedMetadataService.js.map +1 -1
- package/src/lib/encryption/encryptionAwareReplication.js +3 -0
- package/src/lib/encryption/encryptionAwareReplication.js.map +1 -1
- package/src/lib/encryption/errors.d.ts.map +1 -1
- package/src/lib/encryption/errors.js +8 -0
- package/src/lib/encryption/errors.js.map +1 -1
- package/src/lib/encryption/poolKeyManager.js +2 -0
- package/src/lib/encryption/poolKeyManager.js.map +1 -1
- package/src/lib/environment.js +10 -0
- package/src/lib/environment.js.map +1 -1
- package/src/lib/errors/express-validation.js +1 -0
- package/src/lib/errors/express-validation.js.map +1 -1
- package/src/lib/errors/invalid-backup-code-version.js +1 -0
- package/src/lib/errors/invalid-backup-code-version.js.map +1 -1
- package/src/lib/errors/memberIndexSchemaValidationError.js +1 -0
- package/src/lib/errors/memberIndexSchemaValidationError.js.map +1 -1
- package/src/lib/errors/missing-validated-data.js +2 -0
- package/src/lib/errors/missing-validated-data.js.map +1 -1
- package/src/lib/errors/token-not-found.js +1 -0
- package/src/lib/errors/token-not-found.js.map +1 -1
- package/src/lib/errors/typed-error-local.js +3 -0
- package/src/lib/errors/typed-error-local.js.map +1 -1
- package/src/lib/interfaces/brightpass/index.d.ts +1 -1
- package/src/lib/interfaces/brightpass/index.d.ts.map +1 -1
- package/src/lib/interfaces/environment.d.ts +1 -1
- package/src/lib/interfaces/environment.d.ts.map +1 -1
- package/src/lib/interfaces/member/memberProfileResponse.d.ts.map +1 -1
- package/src/lib/interfaces/member/operational.d.ts.map +1 -1
- package/src/lib/interfaces/member-init-config.d.ts +1 -1
- package/src/lib/interfaces/member-init-config.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-backup-codes-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-challenge-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-code-count-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-detailed-health-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-discover-block-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-express-validation-error.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-get-block-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-get-node-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-health-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-list-nodes-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-login-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-members-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-mnemonic-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-reconcile-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-register-node-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-registration-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-replicate-block-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-request-user-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-store-block-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-store-cbl-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/api-sync-request-response.d.ts.map +1 -1
- package/src/lib/interfaces/responses/brighthub/api-connection-response.d.ts +21 -0
- package/src/lib/interfaces/responses/brighthub/api-connection-response.d.ts.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-connection-response.js +3 -0
- package/src/lib/interfaces/responses/brighthub/api-connection-response.js.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-messaging-response.d.ts +39 -0
- package/src/lib/interfaces/responses/brighthub/api-messaging-response.d.ts.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-messaging-response.js +3 -0
- package/src/lib/interfaces/responses/brighthub/api-messaging-response.js.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-notification-response.d.ts +30 -0
- package/src/lib/interfaces/responses/brighthub/api-notification-response.d.ts.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-notification-response.js +3 -0
- package/src/lib/interfaces/responses/brighthub/api-notification-response.js.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-post-response.d.ts +21 -0
- package/src/lib/interfaces/responses/brighthub/api-post-response.d.ts.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-post-response.js +3 -0
- package/src/lib/interfaces/responses/brighthub/api-post-response.js.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-timeline-response.d.ts +14 -0
- package/src/lib/interfaces/responses/brighthub/api-timeline-response.d.ts.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-timeline-response.js +3 -0
- package/src/lib/interfaces/responses/brighthub/api-timeline-response.js.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-user-profile-response.d.ts +10 -0
- package/src/lib/interfaces/responses/brighthub/api-user-profile-response.d.ts.map +1 -0
- package/src/lib/interfaces/responses/brighthub/api-user-profile-response.js +3 -0
- package/src/lib/interfaces/responses/brighthub/api-user-profile-response.js.map +1 -0
- package/src/lib/interfaces/responses/brighthub/index.d.ts +13 -0
- package/src/lib/interfaces/responses/brighthub/index.d.ts.map +1 -0
- package/src/lib/interfaces/responses/brighthub/index.js +9 -0
- package/src/lib/interfaces/responses/brighthub/index.js.map +1 -0
- package/src/lib/interfaces/responses/index.d.ts +1 -0
- package/src/lib/interfaces/responses/index.d.ts.map +1 -1
- package/src/lib/interfaces/storage/storedDocumentTypes.d.ts +1 -1
- package/src/lib/interfaces/storage/storedDocumentTypes.js +1 -1
- package/src/lib/interfaces/storage/userRoleSchema.d.ts.map +1 -1
- package/src/lib/interfaces/storage/userRoleSchema.js +1 -3
- package/src/lib/interfaces/storage/userRoleSchema.js.map +1 -1
- package/src/lib/middlewares.js +31 -31
- package/src/lib/middlewares.js.map +1 -1
- package/src/lib/nodeKeyring.js +2 -0
- package/src/lib/nodeKeyring.js.map +1 -1
- package/src/lib/plugins/brightchain-database-plugin.d.ts +14 -14
- package/src/lib/plugins/brightchain-database-plugin.d.ts.map +1 -1
- package/src/lib/plugins/brightchain-database-plugin.js +36 -34
- package/src/lib/plugins/brightchain-database-plugin.js.map +1 -1
- package/src/lib/routers/api.d.ts +62 -1
- package/src/lib/routers/api.d.ts.map +1 -1
- package/src/lib/routers/api.js +123 -2
- package/src/lib/routers/api.js.map +1 -1
- package/src/lib/routers/app.d.ts.map +1 -1
- package/src/lib/routers/app.js +10 -1
- package/src/lib/routers/app.js.map +1 -1
- package/src/lib/routers/base.js +2 -0
- package/src/lib/routers/base.js.map +1 -1
- package/src/lib/secureEnclaveKeyring.js +4 -2
- package/src/lib/secureEnclaveKeyring.js.map +1 -1
- package/src/lib/services/auth.d.ts.map +1 -1
- package/src/lib/services/auth.js +11 -2
- package/src/lib/services/auth.js.map +1 -1
- package/src/lib/services/base.js +1 -0
- package/src/lib/services/base.js.map +1 -1
- package/src/lib/services/blockServiceFactory.js +2 -0
- package/src/lib/services/blockServiceFactory.js.map +1 -1
- package/src/lib/services/blockStore.js +3 -2
- package/src/lib/services/blockStore.js.map +1 -1
- package/src/lib/services/blocks.js +1 -0
- package/src/lib/services/blocks.js.map +1 -1
- package/src/lib/services/brightChainBackupCodeService.d.ts +114 -0
- package/src/lib/services/brightChainBackupCodeService.d.ts.map +1 -0
- package/src/lib/services/brightChainBackupCodeService.js +303 -0
- package/src/lib/services/brightChainBackupCodeService.js.map +1 -0
- package/src/lib/services/brightchain-authentication-provider.d.ts.map +1 -1
- package/src/lib/services/brightchain-authentication-provider.js +40 -9
- package/src/lib/services/brightchain-authentication-provider.js.map +1 -1
- package/src/lib/services/brightchain-member-init.service.d.ts +17 -17
- package/src/lib/services/brightchain-member-init.service.d.ts.map +1 -1
- package/src/lib/services/brightchain-member-init.service.js +12 -9
- package/src/lib/services/brightchain-member-init.service.js.map +1 -1
- package/src/lib/services/brighthub/connectionService.d.ts +286 -0
- package/src/lib/services/brighthub/connectionService.d.ts.map +1 -0
- package/src/lib/services/brighthub/connectionService.js +1887 -0
- package/src/lib/services/brighthub/connectionService.js.map +1 -0
- package/src/lib/services/brighthub/discoveryService.d.ts +110 -0
- package/src/lib/services/brighthub/discoveryService.d.ts.map +1 -0
- package/src/lib/services/brighthub/discoveryService.js +528 -0
- package/src/lib/services/brighthub/discoveryService.js.map +1 -0
- package/src/lib/services/brighthub/feedService.d.ts +141 -0
- package/src/lib/services/brighthub/feedService.d.ts.map +1 -0
- package/src/lib/services/brighthub/feedService.js +418 -0
- package/src/lib/services/brighthub/feedService.js.map +1 -0
- package/src/lib/services/brighthub/index.d.ts +11 -0
- package/src/lib/services/brighthub/index.d.ts.map +1 -0
- package/src/lib/services/brighthub/index.js +14 -0
- package/src/lib/services/brighthub/index.js.map +1 -0
- package/src/lib/services/brighthub/messagingService.d.ts +109 -0
- package/src/lib/services/brighthub/messagingService.d.ts.map +1 -0
- package/src/lib/services/brighthub/messagingService.js +947 -0
- package/src/lib/services/brighthub/messagingService.js.map +1 -0
- package/src/lib/services/brighthub/messagingService.test-helpers.d.ts +75 -0
- package/src/lib/services/brighthub/messagingService.test-helpers.d.ts.map +1 -0
- package/src/lib/services/brighthub/messagingService.test-helpers.js +237 -0
- package/src/lib/services/brighthub/messagingService.test-helpers.js.map +1 -0
- package/src/lib/services/brighthub/notificationService.d.ts +172 -0
- package/src/lib/services/brighthub/notificationService.d.ts.map +1 -0
- package/src/lib/services/brighthub/notificationService.js +768 -0
- package/src/lib/services/brighthub/notificationService.js.map +1 -0
- package/src/lib/services/brighthub/notificationService.test-helpers.d.ts +75 -0
- package/src/lib/services/brighthub/notificationService.test-helpers.d.ts.map +1 -0
- package/src/lib/services/brighthub/notificationService.test-helpers.js +230 -0
- package/src/lib/services/brighthub/notificationService.test-helpers.js.map +1 -0
- package/src/lib/services/brighthub/postService.d.ts +129 -0
- package/src/lib/services/brighthub/postService.d.ts.map +1 -0
- package/src/lib/services/brighthub/postService.js +470 -0
- package/src/lib/services/brighthub/postService.js.map +1 -0
- package/src/lib/services/brighthub/postService.test-helpers.d.ts +40 -0
- package/src/lib/services/brighthub/postService.test-helpers.d.ts.map +1 -0
- package/src/lib/services/brighthub/postService.test-helpers.js +84 -0
- package/src/lib/services/brighthub/postService.test-helpers.js.map +1 -0
- package/src/lib/services/brighthub/textFormatter.d.ts +64 -0
- package/src/lib/services/brighthub/textFormatter.d.ts.map +1 -0
- package/src/lib/services/brighthub/textFormatter.js +256 -0
- package/src/lib/services/brighthub/textFormatter.js.map +1 -0
- package/src/lib/services/brighthub/threadService.d.ts +79 -0
- package/src/lib/services/brighthub/threadService.d.ts.map +1 -0
- package/src/lib/services/brighthub/threadService.js +246 -0
- package/src/lib/services/brighthub/threadService.js.map +1 -0
- package/src/lib/services/brighthub/userProfileService.d.ts +203 -0
- package/src/lib/services/brighthub/userProfileService.d.ts.map +1 -0
- package/src/lib/services/brighthub/userProfileService.js +868 -0
- package/src/lib/services/brighthub/userProfileService.js.map +1 -0
- package/src/lib/services/brighthub/userProfileService.test-helpers.d.ts +86 -0
- package/src/lib/services/brighthub/userProfileService.test-helpers.d.ts.map +1 -0
- package/src/lib/services/brighthub/userProfileService.test-helpers.js +169 -0
- package/src/lib/services/brighthub/userProfileService.test-helpers.js.map +1 -0
- package/src/lib/services/brighthub/webSocketServer.d.ts +68 -0
- package/src/lib/services/brighthub/webSocketServer.d.ts.map +1 -0
- package/src/lib/services/brighthub/webSocketServer.js +194 -0
- package/src/lib/services/brighthub/webSocketServer.js.map +1 -0
- package/src/lib/services/brightpass/auditLogger.js +10 -5
- package/src/lib/services/brightpass/auditLogger.js.map +1 -1
- package/src/lib/services/brightpass/vaultEncryption.js +8 -8
- package/src/lib/services/brightpass/vaultEncryption.js.map +1 -1
- package/src/lib/services/brightpass.js +16 -8
- package/src/lib/services/brightpass.js.map +1 -1
- package/src/lib/services/cliOperatorPrompt.js +5 -2
- package/src/lib/services/cliOperatorPrompt.js.map +1 -1
- package/src/lib/services/clientWebSocketServer.d.ts +69 -4
- package/src/lib/services/clientWebSocketServer.d.ts.map +1 -1
- package/src/lib/services/clientWebSocketServer.js +188 -10
- package/src/lib/services/clientWebSocketServer.js.map +1 -1
- package/src/lib/services/contentAwareBlocksService.js +2 -0
- package/src/lib/services/contentAwareBlocksService.js.map +1 -1
- package/src/lib/services/contentIngestionService.d.ts.map +1 -1
- package/src/lib/services/contentIngestionService.js +2 -0
- package/src/lib/services/contentIngestionService.js.map +1 -1
- package/src/lib/services/diskQuorumService.js +3 -0
- package/src/lib/services/diskQuorumService.js.map +1 -1
- package/src/lib/services/email.js +5 -0
- package/src/lib/services/email.js.map +1 -1
- package/src/lib/services/eventNotificationSystem.d.ts +51 -10
- package/src/lib/services/eventNotificationSystem.d.ts.map +1 -1
- package/src/lib/services/eventNotificationSystem.js +76 -23
- package/src/lib/services/eventNotificationSystem.js.map +1 -1
- package/src/lib/services/expirationScheduler.js +6 -3
- package/src/lib/services/expirationScheduler.js.map +1 -1
- package/src/lib/services/fakeEmailService.js +3 -4
- package/src/lib/services/fakeEmailService.js.map +1 -1
- package/src/lib/services/fec.js +1 -3
- package/src/lib/services/fec.js.map +1 -1
- package/src/lib/services/fecServiceFactory.js +2 -2
- package/src/lib/services/fecServiceFactory.js.map +1 -1
- package/src/lib/services/fecUsageExample.js +1 -3
- package/src/lib/services/fecUsageExample.js.map +1 -1
- package/src/lib/services/identityExpirationScheduler.d.ts.map +1 -1
- package/src/lib/services/identityExpirationScheduler.js +7 -2
- package/src/lib/services/identityExpirationScheduler.js.map +1 -1
- package/src/lib/services/index.d.ts +3 -2
- package/src/lib/services/index.d.ts.map +1 -1
- package/src/lib/services/index.js +3 -2
- package/src/lib/services/index.js.map +1 -1
- package/src/lib/services/messageEventsWebSocketHandler.js +1 -0
- package/src/lib/services/messageEventsWebSocketHandler.js.map +1 -1
- package/src/lib/services/messagePassingService.js +5 -0
- package/src/lib/services/messagePassingService.js.map +1 -1
- package/src/lib/services/nativeRsFecService.js +3 -5
- package/src/lib/services/nativeRsFecService.js.map +1 -1
- package/src/lib/services/presenceService.js +5 -4
- package/src/lib/services/presenceService.js.map +1 -1
- package/src/lib/services/quorum.js +3 -2
- package/src/lib/services/quorum.js.map +1 -1
- package/src/lib/services/quorumDatabaseAdapter.d.ts +5 -5
- package/src/lib/services/quorumDatabaseAdapter.d.ts.map +1 -1
- package/src/lib/services/quorumDatabaseAdapter.js +5 -3
- package/src/lib/services/quorumDatabaseAdapter.js.map +1 -1
- package/src/lib/services/rbac-input-builder.js +5 -0
- package/src/lib/services/rbac-input-builder.js.map +1 -1
- package/src/lib/services/secureKeyStorage.js +3 -0
- package/src/lib/services/secureKeyStorage.js.map +1 -1
- package/src/lib/services/sessionAdapter.d.ts +4 -4
- package/src/lib/services/sessionAdapter.d.ts.map +1 -1
- package/src/lib/services/sessionAdapter.js +3 -2
- package/src/lib/services/sessionAdapter.js.map +1 -1
- package/src/lib/services/webSocketMessageServer.js +7 -4
- package/src/lib/services/webSocketMessageServer.js.map +1 -1
- package/src/lib/services/webSocketPeerProvider.js +2 -1
- package/src/lib/services/webSocketPeerProvider.js.map +1 -1
- package/src/lib/services/websocketHandler.js +9 -1
- package/src/lib/services/websocketHandler.js.map +1 -1
- package/src/lib/shared-types.d.ts +1 -2
- package/src/lib/shared-types.d.ts.map +1 -1
- package/src/lib/stores/__tests__/helpers/mockCloudBlockStore.d.ts +63 -0
- package/src/lib/stores/__tests__/helpers/mockCloudBlockStore.d.ts.map +1 -0
- package/src/lib/stores/__tests__/helpers/mockCloudBlockStore.js +160 -0
- package/src/lib/stores/__tests__/helpers/mockCloudBlockStore.js.map +1 -0
- package/src/lib/stores/availabilityAwareBlockStore.js +34 -5
- package/src/lib/stores/availabilityAwareBlockStore.js.map +1 -1
- package/src/lib/stores/cloudBlockStoreBase.d.ts +121 -0
- package/src/lib/stores/cloudBlockStoreBase.d.ts.map +1 -0
- package/src/lib/stores/cloudBlockStoreBase.js +1165 -0
- package/src/lib/stores/cloudBlockStoreBase.js.map +1 -0
- package/src/lib/stores/diskBlockAsyncStore.js +9 -5
- package/src/lib/stores/diskBlockAsyncStore.js.map +1 -1
- package/src/lib/stores/diskBlockMetadataStore.js +2 -0
- package/src/lib/stores/diskBlockMetadataStore.js.map +1 -1
- package/src/lib/stores/diskBlockStore.js +10 -8
- package/src/lib/stores/diskBlockStore.js.map +1 -1
- package/src/lib/stores/diskCBLStore.d.ts.map +1 -1
- package/src/lib/stores/diskCBLStore.js +8 -0
- package/src/lib/stores/diskCBLStore.js.map +1 -1
- package/src/lib/stores/index.d.ts +1 -0
- package/src/lib/stores/index.d.ts.map +1 -1
- package/src/lib/stores/index.js +1 -0
- package/src/lib/stores/index.js.map +1 -1
- package/src/lib/systemKeyring.d.ts.map +1 -1
- package/src/lib/systemKeyring.js +5 -4
- package/src/lib/systemKeyring.js.map +1 -1
- package/src/lib/transforms/checksumTransform.js +1 -0
- package/src/lib/transforms/checksumTransform.js.map +1 -1
- package/src/lib/transforms/memoryWritableStream.js +1 -0
- package/src/lib/transforms/memoryWritableStream.js.map +1 -1
- package/src/lib/transforms/xorMultipleTransform.js +3 -0
- package/src/lib/transforms/xorMultipleTransform.js.map +1 -1
- package/src/lib/utils/rehydration.d.ts +1 -1
- package/src/lib/utils/rehydration.js +1 -1
- package/src/lib/utils/serialization.d.ts +1 -1
- package/src/lib/utils/serialization.js +1 -1
- package/src/lib/services/backupCodeService.d.ts +0 -35
- package/src/lib/services/backupCodeService.d.ts.map +0 -1
- package/src/lib/services/backupCodeService.js +0 -109
- package/src/lib/services/backupCodeService.js.map +0 -1
|
@@ -0,0 +1,768 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NotificationService = void 0;
|
|
4
|
+
exports.createNotificationService = createNotificationService;
|
|
5
|
+
const brighthub_lib_1 = require("@brightchain/brighthub-lib");
|
|
6
|
+
const crypto_1 = require("crypto");
|
|
7
|
+
// ═══════════════════════════════════════════════════════
|
|
8
|
+
// Notification type → category mapping
|
|
9
|
+
// ═══════════════════════════════════════════════════════
|
|
10
|
+
/**
|
|
11
|
+
* Maps each NotificationType to its NotificationCategory.
|
|
12
|
+
*
|
|
13
|
+
* Req 55.2 – Social: likes, reposts, quotes, replies, mentions
|
|
14
|
+
* Req 55.3 – Messages: new messages, message requests, message reactions
|
|
15
|
+
* Req 55.4 – Connections: new followers, follow requests, reconnect reminders
|
|
16
|
+
* Req 55.5 – System: account alerts, security notifications, feature announcements
|
|
17
|
+
*/
|
|
18
|
+
const NOTIFICATION_TYPE_CATEGORY_MAP = {
|
|
19
|
+
// Social (Req 55.2)
|
|
20
|
+
[brighthub_lib_1.NotificationType.Like]: brighthub_lib_1.NotificationCategory.Social,
|
|
21
|
+
[brighthub_lib_1.NotificationType.Reply]: brighthub_lib_1.NotificationCategory.Social,
|
|
22
|
+
[brighthub_lib_1.NotificationType.Mention]: brighthub_lib_1.NotificationCategory.Social,
|
|
23
|
+
[brighthub_lib_1.NotificationType.Repost]: brighthub_lib_1.NotificationCategory.Social,
|
|
24
|
+
[brighthub_lib_1.NotificationType.Quote]: brighthub_lib_1.NotificationCategory.Social,
|
|
25
|
+
// Connections (Req 55.4)
|
|
26
|
+
[brighthub_lib_1.NotificationType.Follow]: brighthub_lib_1.NotificationCategory.Connections,
|
|
27
|
+
[brighthub_lib_1.NotificationType.FollowRequest]: brighthub_lib_1.NotificationCategory.Connections,
|
|
28
|
+
[brighthub_lib_1.NotificationType.ReconnectReminder]: brighthub_lib_1.NotificationCategory.Connections,
|
|
29
|
+
// Messages (Req 55.3)
|
|
30
|
+
[brighthub_lib_1.NotificationType.NewMessage]: brighthub_lib_1.NotificationCategory.Messages,
|
|
31
|
+
[brighthub_lib_1.NotificationType.MessageRequest]: brighthub_lib_1.NotificationCategory.Messages,
|
|
32
|
+
[brighthub_lib_1.NotificationType.MessageReaction]: brighthub_lib_1.NotificationCategory.Messages,
|
|
33
|
+
// System (Req 55.5)
|
|
34
|
+
[brighthub_lib_1.NotificationType.SystemAlert]: brighthub_lib_1.NotificationCategory.System,
|
|
35
|
+
[brighthub_lib_1.NotificationType.SecurityAlert]: brighthub_lib_1.NotificationCategory.System,
|
|
36
|
+
[brighthub_lib_1.NotificationType.FeatureAnnouncement]: brighthub_lib_1.NotificationCategory.System,
|
|
37
|
+
};
|
|
38
|
+
// ═══════════════════════════════════════════════════════
|
|
39
|
+
// NotificationService Implementation
|
|
40
|
+
// ═══════════════════════════════════════════════════════
|
|
41
|
+
/**
|
|
42
|
+
* Notification_Service implementation
|
|
43
|
+
* Handles notification CRUD, preferences, grouping, and real-time delivery
|
|
44
|
+
* @see Requirements: 9.1-9.7, 54.1-54.8
|
|
45
|
+
*/
|
|
46
|
+
class NotificationService {
|
|
47
|
+
notificationsCollection;
|
|
48
|
+
preferencesCollection;
|
|
49
|
+
groupsCollection;
|
|
50
|
+
listMembersCollection;
|
|
51
|
+
connectionMetadataCollection;
|
|
52
|
+
categoryAssignmentsCollection;
|
|
53
|
+
connectionInteractionsCollection;
|
|
54
|
+
constructor(application) {
|
|
55
|
+
this.notificationsCollection = application.getModel('brighthub_notifications');
|
|
56
|
+
this.preferencesCollection =
|
|
57
|
+
application.getModel('brighthub_notification_preferences');
|
|
58
|
+
this.groupsCollection = application.getModel('brighthub_notification_groups');
|
|
59
|
+
this.listMembersCollection =
|
|
60
|
+
application.getModel('brighthub_connection_list_members');
|
|
61
|
+
this.connectionMetadataCollection =
|
|
62
|
+
application.getModel('brighthub_connection_metadata');
|
|
63
|
+
this.categoryAssignmentsCollection =
|
|
64
|
+
application.getModel('brighthub_connection_category_assignments');
|
|
65
|
+
this.connectionInteractionsCollection =
|
|
66
|
+
application.getModel('brighthub_connection_interactions');
|
|
67
|
+
}
|
|
68
|
+
// ═══════════════════════════════════════════════════════
|
|
69
|
+
// Private helpers
|
|
70
|
+
// ═══════════════════════════════════════════════════════
|
|
71
|
+
clampLimit(limit) {
|
|
72
|
+
const l = limit ?? brighthub_lib_1.DEFAULT_NOTIFICATION_PAGE_LIMIT;
|
|
73
|
+
return Math.min(Math.max(1, l), brighthub_lib_1.MAX_NOTIFICATION_PAGE_LIMIT);
|
|
74
|
+
}
|
|
75
|
+
recordToNotification(record) {
|
|
76
|
+
return {
|
|
77
|
+
_id: record._id,
|
|
78
|
+
recipientId: record.recipientId,
|
|
79
|
+
type: record.type,
|
|
80
|
+
category: record.category,
|
|
81
|
+
actorId: record.actorId,
|
|
82
|
+
targetId: record.targetId,
|
|
83
|
+
content: record.content,
|
|
84
|
+
clickThroughUrl: record.clickThroughUrl,
|
|
85
|
+
groupId: record.groupId,
|
|
86
|
+
isRead: record.isRead,
|
|
87
|
+
createdAt: record.createdAt,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
getCategoryForType(type) {
|
|
91
|
+
return NOTIFICATION_TYPE_CATEGORY_MAP[type] ?? brighthub_lib_1.NotificationCategory.System;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Build default notification preferences for a user.
|
|
95
|
+
* All categories enabled, all channels enabled, no quiet hours, no DND, sound on.
|
|
96
|
+
*/
|
|
97
|
+
buildDefaultPreferences(userId) {
|
|
98
|
+
const defaultChannels = {
|
|
99
|
+
[brighthub_lib_1.NotificationChannel.InApp]: true,
|
|
100
|
+
[brighthub_lib_1.NotificationChannel.Email]: true,
|
|
101
|
+
[brighthub_lib_1.NotificationChannel.Push]: true,
|
|
102
|
+
};
|
|
103
|
+
const defaultCategorySettings = {
|
|
104
|
+
[brighthub_lib_1.NotificationCategory.Social]: {
|
|
105
|
+
enabled: true,
|
|
106
|
+
channels: { ...defaultChannels },
|
|
107
|
+
},
|
|
108
|
+
[brighthub_lib_1.NotificationCategory.Messages]: {
|
|
109
|
+
enabled: true,
|
|
110
|
+
channels: { ...defaultChannels },
|
|
111
|
+
},
|
|
112
|
+
[brighthub_lib_1.NotificationCategory.Connections]: {
|
|
113
|
+
enabled: true,
|
|
114
|
+
channels: { ...defaultChannels },
|
|
115
|
+
},
|
|
116
|
+
[brighthub_lib_1.NotificationCategory.System]: {
|
|
117
|
+
enabled: true,
|
|
118
|
+
channels: { ...defaultChannels },
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
userId,
|
|
123
|
+
categorySettings: defaultCategorySettings,
|
|
124
|
+
channelSettings: { ...defaultChannels },
|
|
125
|
+
soundEnabled: true,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get existing preferences from DB or create and persist defaults.
|
|
130
|
+
* Req 56.11: Store preferences in user profile and sync across devices.
|
|
131
|
+
*/
|
|
132
|
+
async getOrCreateDefaultPreferences(userId) {
|
|
133
|
+
const existing = await this.preferencesCollection
|
|
134
|
+
.findOne({ userId })
|
|
135
|
+
.exec();
|
|
136
|
+
if (existing) {
|
|
137
|
+
return this.recordToPreferences(existing);
|
|
138
|
+
}
|
|
139
|
+
// Create default preferences and persist
|
|
140
|
+
const defaults = this.buildDefaultPreferences(userId);
|
|
141
|
+
const now = new Date().toISOString();
|
|
142
|
+
const record = {
|
|
143
|
+
_id: (0, crypto_1.randomUUID)(),
|
|
144
|
+
userId,
|
|
145
|
+
categorySettings: defaults.categorySettings,
|
|
146
|
+
channelSettings: defaults.channelSettings,
|
|
147
|
+
soundEnabled: defaults.soundEnabled,
|
|
148
|
+
updatedAt: now,
|
|
149
|
+
};
|
|
150
|
+
await this.preferencesCollection.create(record);
|
|
151
|
+
return defaults;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Convert a DB record to IBaseNotificationPreferences<string>.
|
|
155
|
+
*/
|
|
156
|
+
recordToPreferences(record) {
|
|
157
|
+
const prefs = {
|
|
158
|
+
userId: record.userId,
|
|
159
|
+
categorySettings: record.categorySettings,
|
|
160
|
+
channelSettings: record.channelSettings,
|
|
161
|
+
soundEnabled: record.soundEnabled,
|
|
162
|
+
};
|
|
163
|
+
if (record.quietHours) {
|
|
164
|
+
prefs.quietHours = record.quietHours;
|
|
165
|
+
}
|
|
166
|
+
if (record.dndConfig) {
|
|
167
|
+
prefs.dndConfig = record.dndConfig;
|
|
168
|
+
}
|
|
169
|
+
return prefs;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Check if the current time falls within the quiet hours window.
|
|
173
|
+
* Req 56.5: Suppress in-app notifications during quiet hours.
|
|
174
|
+
* Req 56.6: Quiet hours with start/end times and timezone.
|
|
175
|
+
*/
|
|
176
|
+
isWithinQuietHours(config) {
|
|
177
|
+
if (!config.enabled) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
// Parse HH:mm times
|
|
181
|
+
const parseTime = (timeStr) => {
|
|
182
|
+
const match = /^(\d{2}):(\d{2})$/.exec(timeStr);
|
|
183
|
+
if (!match)
|
|
184
|
+
return null;
|
|
185
|
+
return { hours: parseInt(match[1], 10), minutes: parseInt(match[2], 10) };
|
|
186
|
+
};
|
|
187
|
+
const start = parseTime(config.startTime);
|
|
188
|
+
const end = parseTime(config.endTime);
|
|
189
|
+
if (!start || !end)
|
|
190
|
+
return false;
|
|
191
|
+
// Get current time in the specified timezone
|
|
192
|
+
let nowHours;
|
|
193
|
+
let nowMinutes;
|
|
194
|
+
try {
|
|
195
|
+
const nowInTz = new Date().toLocaleString('en-US', {
|
|
196
|
+
timeZone: config.timezone,
|
|
197
|
+
hour12: false,
|
|
198
|
+
hour: '2-digit',
|
|
199
|
+
minute: '2-digit',
|
|
200
|
+
});
|
|
201
|
+
// Format: "HH:MM"
|
|
202
|
+
const parts = nowInTz.split(':');
|
|
203
|
+
nowHours = parseInt(parts[0], 10);
|
|
204
|
+
nowMinutes = parseInt(parts[1], 10);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// Invalid timezone — treat as not within quiet hours
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
const nowTotal = nowHours * 60 + nowMinutes;
|
|
211
|
+
const startTotal = start.hours * 60 + start.minutes;
|
|
212
|
+
const endTotal = end.hours * 60 + end.minutes;
|
|
213
|
+
// Handle overnight quiet hours (e.g., 22:00 - 07:00)
|
|
214
|
+
if (startTotal <= endTotal) {
|
|
215
|
+
return nowTotal >= startTotal && nowTotal < endTotal;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
return nowTotal >= startTotal || nowTotal < endTotal;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Check if Do Not Disturb is currently active.
|
|
223
|
+
* Req 56.7: DND suppresses all non-critical notifications.
|
|
224
|
+
* Req 56.8: DND duration options.
|
|
225
|
+
*/
|
|
226
|
+
isDndActive(config) {
|
|
227
|
+
if (!config.enabled) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
// If there's an expiration, check if it has passed
|
|
231
|
+
if (config.expiresAt) {
|
|
232
|
+
const expiresAt = new Date(config.expiresAt);
|
|
233
|
+
if (new Date() >= expiresAt) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Enabled with no expiration (permanent) or not yet expired
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Check if a notification type is critical (should bypass DND/quiet hours).
|
|
242
|
+
* Req 56.9: Critical system notifications delivered even during DND.
|
|
243
|
+
*/
|
|
244
|
+
isCriticalNotificationType(type) {
|
|
245
|
+
return (type === brighthub_lib_1.NotificationType.SecurityAlert ||
|
|
246
|
+
type === brighthub_lib_1.NotificationType.SystemAlert);
|
|
247
|
+
}
|
|
248
|
+
// ═══════════════════════════════════════════════════════
|
|
249
|
+
// Notification CRUD (Req 9.1-9.7, 54.1-54.8)
|
|
250
|
+
// ═══════════════════════════════════════════════════════
|
|
251
|
+
async createNotification(recipientId, type, actorId, options) {
|
|
252
|
+
if (!recipientId || !actorId) {
|
|
253
|
+
throw new brighthub_lib_1.NotificationServiceError(brighthub_lib_1.NotificationErrorCode.InvalidInput, 'recipientId and actorId are required');
|
|
254
|
+
}
|
|
255
|
+
// Req 9.10: Suppress notifications from quiet-mode connections
|
|
256
|
+
const isQuiet = await this.isQuietModeConnection(recipientId, actorId);
|
|
257
|
+
if (isQuiet) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
const category = this.getCategoryForType(type);
|
|
261
|
+
const isCritical = this.isCriticalNotificationType(type);
|
|
262
|
+
// Req 56.4: Respect user preferences when creating notifications
|
|
263
|
+
if (!isCritical) {
|
|
264
|
+
const prefs = await this.getOrCreateDefaultPreferences(recipientId);
|
|
265
|
+
// Check if the category is disabled (Req 56.1-56.3)
|
|
266
|
+
const catSettings = prefs.categorySettings[category];
|
|
267
|
+
if (catSettings && !catSettings.enabled) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
// Req 56.5-56.6: Check quiet hours
|
|
271
|
+
if (prefs.quietHours && this.isWithinQuietHours(prefs.quietHours)) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
// Req 56.7-56.8: Check DND
|
|
275
|
+
if (prefs.dndConfig && this.isDndActive(prefs.dndConfig)) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const now = new Date().toISOString();
|
|
280
|
+
const record = {
|
|
281
|
+
_id: (0, crypto_1.randomUUID)(),
|
|
282
|
+
recipientId,
|
|
283
|
+
type,
|
|
284
|
+
category,
|
|
285
|
+
actorId,
|
|
286
|
+
targetId: options?.targetId,
|
|
287
|
+
content: options?.content ?? '',
|
|
288
|
+
clickThroughUrl: options?.clickThroughUrl ?? '',
|
|
289
|
+
isRead: false,
|
|
290
|
+
createdAt: now,
|
|
291
|
+
};
|
|
292
|
+
await this.notificationsCollection.create(record);
|
|
293
|
+
return this.recordToNotification(record);
|
|
294
|
+
}
|
|
295
|
+
async getNotifications(userId, options) {
|
|
296
|
+
const limit = this.clampLimit(options?.limit);
|
|
297
|
+
// Build filter
|
|
298
|
+
const filter = { recipientId: userId };
|
|
299
|
+
if (options?.category) {
|
|
300
|
+
filter.category = options.category;
|
|
301
|
+
}
|
|
302
|
+
if (options?.isRead !== undefined) {
|
|
303
|
+
filter.isRead = options.isRead;
|
|
304
|
+
}
|
|
305
|
+
// Query with reverse chronological order
|
|
306
|
+
let query = this.notificationsCollection.find(filter);
|
|
307
|
+
if (query.sort) {
|
|
308
|
+
query = query.sort({ createdAt: -1 });
|
|
309
|
+
}
|
|
310
|
+
// Cursor-based pagination: skip past cursor
|
|
311
|
+
if (options?.cursor && query.skip) {
|
|
312
|
+
const cursorIndex = parseInt(options.cursor, 10);
|
|
313
|
+
if (!isNaN(cursorIndex) && cursorIndex > 0) {
|
|
314
|
+
query = query.skip(cursorIndex);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Fetch limit + 1 to determine hasMore
|
|
318
|
+
if (query.limit) {
|
|
319
|
+
query = query.limit(limit + 1);
|
|
320
|
+
}
|
|
321
|
+
const records = await query.exec();
|
|
322
|
+
const hasMore = records.length > limit;
|
|
323
|
+
const items = records
|
|
324
|
+
.slice(0, limit)
|
|
325
|
+
.map((r) => this.recordToNotification(r));
|
|
326
|
+
// Calculate next cursor
|
|
327
|
+
const currentOffset = options?.cursor
|
|
328
|
+
? parseInt(options.cursor, 10) || 0
|
|
329
|
+
: 0;
|
|
330
|
+
const nextCursor = hasMore ? String(currentOffset + limit) : undefined;
|
|
331
|
+
return {
|
|
332
|
+
items,
|
|
333
|
+
cursor: nextCursor,
|
|
334
|
+
hasMore,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
async getUnreadCount(userId) {
|
|
338
|
+
const filter = {
|
|
339
|
+
recipientId: userId,
|
|
340
|
+
isRead: false,
|
|
341
|
+
};
|
|
342
|
+
if (this.notificationsCollection.countDocuments) {
|
|
343
|
+
return this.notificationsCollection.countDocuments(filter).exec();
|
|
344
|
+
}
|
|
345
|
+
// Fallback: count via find
|
|
346
|
+
const records = await this.notificationsCollection.find(filter).exec();
|
|
347
|
+
return records.length;
|
|
348
|
+
}
|
|
349
|
+
async markAsRead(notificationId, userId) {
|
|
350
|
+
const record = await this.notificationsCollection
|
|
351
|
+
.findOne({ _id: notificationId })
|
|
352
|
+
.exec();
|
|
353
|
+
if (!record) {
|
|
354
|
+
throw new brighthub_lib_1.NotificationServiceError(brighthub_lib_1.NotificationErrorCode.NotificationNotFound, `Notification ${notificationId} not found`);
|
|
355
|
+
}
|
|
356
|
+
if (record.recipientId !== userId) {
|
|
357
|
+
throw new brighthub_lib_1.NotificationServiceError(brighthub_lib_1.NotificationErrorCode.Unauthorized, "Cannot mark another user's notification as read");
|
|
358
|
+
}
|
|
359
|
+
await this.notificationsCollection
|
|
360
|
+
.updateOne({ _id: notificationId }, { isRead: true })
|
|
361
|
+
.exec();
|
|
362
|
+
}
|
|
363
|
+
async markAllAsRead(userId) {
|
|
364
|
+
// Find all unread notifications for the user and mark them as read
|
|
365
|
+
const unread = await this.notificationsCollection
|
|
366
|
+
.find({
|
|
367
|
+
recipientId: userId,
|
|
368
|
+
isRead: false,
|
|
369
|
+
})
|
|
370
|
+
.exec();
|
|
371
|
+
for (const record of unread) {
|
|
372
|
+
await this.notificationsCollection
|
|
373
|
+
.updateOne({ _id: record._id }, { isRead: true })
|
|
374
|
+
.exec();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
async deleteNotification(notificationId, userId) {
|
|
378
|
+
const record = await this.notificationsCollection
|
|
379
|
+
.findOne({ _id: notificationId })
|
|
380
|
+
.exec();
|
|
381
|
+
if (!record) {
|
|
382
|
+
throw new brighthub_lib_1.NotificationServiceError(brighthub_lib_1.NotificationErrorCode.NotificationNotFound, `Notification ${notificationId} not found`);
|
|
383
|
+
}
|
|
384
|
+
if (record.recipientId !== userId) {
|
|
385
|
+
throw new brighthub_lib_1.NotificationServiceError(brighthub_lib_1.NotificationErrorCode.Unauthorized, "Cannot delete another user's notification");
|
|
386
|
+
}
|
|
387
|
+
await this.notificationsCollection
|
|
388
|
+
.deleteOne({ _id: notificationId })
|
|
389
|
+
.exec();
|
|
390
|
+
}
|
|
391
|
+
async deleteAllNotifications(userId) {
|
|
392
|
+
if (this.notificationsCollection.deleteMany) {
|
|
393
|
+
await this.notificationsCollection
|
|
394
|
+
.deleteMany({ recipientId: userId })
|
|
395
|
+
.exec();
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
// Fallback: delete one by one
|
|
399
|
+
const records = await this.notificationsCollection
|
|
400
|
+
.find({ recipientId: userId })
|
|
401
|
+
.exec();
|
|
402
|
+
for (const record of records) {
|
|
403
|
+
await this.notificationsCollection
|
|
404
|
+
.deleteOne({ _id: record._id })
|
|
405
|
+
.exec();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
// ═══════════════════════════════════════════════════════
|
|
409
|
+
// Filtering (Req 9.8-9.12)
|
|
410
|
+
// ═══════════════════════════════════════════════════════
|
|
411
|
+
/**
|
|
412
|
+
* Req 9.8: Get notifications filtered by connection list members.
|
|
413
|
+
* Returns only notifications where the actorId is a member of the given list.
|
|
414
|
+
*/
|
|
415
|
+
async getNotificationsByList(userId, listId, options) {
|
|
416
|
+
// Get all member userIds from the list
|
|
417
|
+
const memberRecords = await this.listMembersCollection
|
|
418
|
+
.find({ listId })
|
|
419
|
+
.exec();
|
|
420
|
+
const memberIds = new Set(memberRecords.map((m) => m.userId));
|
|
421
|
+
// Get all notifications for the user, then filter by actor membership
|
|
422
|
+
const allResult = await this.getNotifications(userId, options);
|
|
423
|
+
const filtered = allResult.items.filter((n) => memberIds.has(n.actorId));
|
|
424
|
+
return {
|
|
425
|
+
items: filtered,
|
|
426
|
+
cursor: allResult.cursor,
|
|
427
|
+
hasMore: allResult.hasMore,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Req 9.9: Get notifications filtered by connection category.
|
|
432
|
+
* Returns only notifications where the actorId is in the given category.
|
|
433
|
+
*/
|
|
434
|
+
async getNotificationsByConnectionCategory(userId, categoryId, options) {
|
|
435
|
+
// Get all connections assigned to this category for this user
|
|
436
|
+
const assignments = await this.categoryAssignmentsCollection
|
|
437
|
+
.find({
|
|
438
|
+
ownerId: userId,
|
|
439
|
+
categoryId,
|
|
440
|
+
})
|
|
441
|
+
.exec();
|
|
442
|
+
const connectionIds = new Set(assignments.map((a) => a.connectionId));
|
|
443
|
+
// Get all notifications for the user, then filter by actor in category
|
|
444
|
+
const allResult = await this.getNotifications(userId, options);
|
|
445
|
+
const filtered = allResult.items.filter((n) => connectionIds.has(n.actorId));
|
|
446
|
+
return {
|
|
447
|
+
items: filtered,
|
|
448
|
+
cursor: allResult.cursor,
|
|
449
|
+
hasMore: allResult.hasMore,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Req 9.10: Check if a connection has quiet mode enabled.
|
|
454
|
+
*/
|
|
455
|
+
async isQuietModeConnection(userId, connectionId) {
|
|
456
|
+
const metadata = await this.connectionMetadataCollection
|
|
457
|
+
.findOne({
|
|
458
|
+
userId,
|
|
459
|
+
connectionId,
|
|
460
|
+
})
|
|
461
|
+
.exec();
|
|
462
|
+
return metadata?.isQuiet === true;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Req 9.12: Create a reconnect reminder for a 30-day inactive connection.
|
|
466
|
+
* Checks that the connection hasn't interacted in RECONNECT_REMINDER_DAYS days,
|
|
467
|
+
* then creates a notification with type ReconnectReminder and category Connections.
|
|
468
|
+
*/
|
|
469
|
+
async createReconnectReminder(userId, connectionId) {
|
|
470
|
+
// Look up the interaction record
|
|
471
|
+
const interaction = await this.connectionInteractionsCollection
|
|
472
|
+
.findOne({
|
|
473
|
+
userId,
|
|
474
|
+
connectionId,
|
|
475
|
+
})
|
|
476
|
+
.exec();
|
|
477
|
+
const cutoffDate = new Date();
|
|
478
|
+
cutoffDate.setDate(cutoffDate.getDate() - brighthub_lib_1.RECONNECT_REMINDER_DAYS);
|
|
479
|
+
// If there's a recent interaction, don't create a reminder
|
|
480
|
+
if (interaction?.lastInteractionAt) {
|
|
481
|
+
const lastInteraction = new Date(interaction.lastInteractionAt);
|
|
482
|
+
if (lastInteraction > cutoffDate) {
|
|
483
|
+
throw new brighthub_lib_1.NotificationServiceError(brighthub_lib_1.NotificationErrorCode.InvalidInput, `Connection ${connectionId} has interacted within the last ${brighthub_lib_1.RECONNECT_REMINDER_DAYS} days`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
// Create the reconnect reminder notification directly (bypass quiet mode check
|
|
487
|
+
// since this is a system-initiated reminder, not an actor-initiated notification)
|
|
488
|
+
const now = new Date().toISOString();
|
|
489
|
+
const record = {
|
|
490
|
+
_id: (0, crypto_1.randomUUID)(),
|
|
491
|
+
recipientId: userId,
|
|
492
|
+
type: brighthub_lib_1.NotificationType.ReconnectReminder,
|
|
493
|
+
category: brighthub_lib_1.NotificationCategory.Connections,
|
|
494
|
+
actorId: connectionId,
|
|
495
|
+
content: `You haven't interacted with this connection in ${brighthub_lib_1.RECONNECT_REMINDER_DAYS} days. Consider reconnecting!`,
|
|
496
|
+
clickThroughUrl: `/users/${connectionId}`,
|
|
497
|
+
isRead: false,
|
|
498
|
+
createdAt: now,
|
|
499
|
+
};
|
|
500
|
+
await this.notificationsCollection.create(record);
|
|
501
|
+
return this.recordToNotification(record);
|
|
502
|
+
}
|
|
503
|
+
// ═══════════════════════════════════════════════════════
|
|
504
|
+
// Preferences (Req 56.1-56.12)
|
|
505
|
+
// ═══════════════════════════════════════════════════════
|
|
506
|
+
/**
|
|
507
|
+
* Get notification preferences for a user.
|
|
508
|
+
* Returns existing preferences or creates defaults if none exist.
|
|
509
|
+
* Req 56.11: Store preferences in user profile and sync across devices.
|
|
510
|
+
*/
|
|
511
|
+
async getPreferences(userId) {
|
|
512
|
+
return this.getOrCreateDefaultPreferences(userId);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Update notification preferences for a user.
|
|
516
|
+
* Merges partial updates into existing preferences.
|
|
517
|
+
* Req 56.1-56.3: Per-category enable/disable and per-channel settings.
|
|
518
|
+
* Req 56.10: Sound preferences.
|
|
519
|
+
* Req 56.12: Preferences update reflected immediately.
|
|
520
|
+
*/
|
|
521
|
+
async updatePreferences(userId, preferences) {
|
|
522
|
+
const existing = await this.getOrCreateDefaultPreferences(userId);
|
|
523
|
+
// Merge category settings
|
|
524
|
+
if (preferences.categorySettings) {
|
|
525
|
+
for (const cat of Object.values(brighthub_lib_1.NotificationCategory)) {
|
|
526
|
+
if (preferences.categorySettings[cat]) {
|
|
527
|
+
existing.categorySettings[cat] = {
|
|
528
|
+
...existing.categorySettings[cat],
|
|
529
|
+
...preferences.categorySettings[cat],
|
|
530
|
+
channels: {
|
|
531
|
+
...existing.categorySettings[cat].channels,
|
|
532
|
+
...(preferences.categorySettings[cat].channels ?? {}),
|
|
533
|
+
},
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
// Merge channel settings
|
|
539
|
+
if (preferences.channelSettings) {
|
|
540
|
+
existing.channelSettings = {
|
|
541
|
+
...existing.channelSettings,
|
|
542
|
+
...preferences.channelSettings,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
// Merge optional fields
|
|
546
|
+
if (preferences.quietHours !== undefined) {
|
|
547
|
+
existing.quietHours = preferences.quietHours;
|
|
548
|
+
}
|
|
549
|
+
if (preferences.dndConfig !== undefined) {
|
|
550
|
+
existing.dndConfig = preferences.dndConfig;
|
|
551
|
+
}
|
|
552
|
+
if (preferences.soundEnabled !== undefined) {
|
|
553
|
+
existing.soundEnabled = preferences.soundEnabled;
|
|
554
|
+
}
|
|
555
|
+
// Save to database
|
|
556
|
+
const now = new Date().toISOString();
|
|
557
|
+
await this.preferencesCollection
|
|
558
|
+
.updateOne({ userId }, {
|
|
559
|
+
categorySettings: existing.categorySettings,
|
|
560
|
+
channelSettings: existing.channelSettings,
|
|
561
|
+
quietHours: existing.quietHours,
|
|
562
|
+
dndConfig: existing.dndConfig,
|
|
563
|
+
soundEnabled: existing.soundEnabled,
|
|
564
|
+
updatedAt: now,
|
|
565
|
+
})
|
|
566
|
+
.exec();
|
|
567
|
+
return existing;
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Set quiet hours configuration.
|
|
571
|
+
* Req 56.5: Suppress in-app notifications during quiet hours.
|
|
572
|
+
* Req 56.6: Start/end times with timezone support.
|
|
573
|
+
*/
|
|
574
|
+
async setQuietHours(userId, config) {
|
|
575
|
+
// Validate HH:mm format
|
|
576
|
+
const timeRegex = /^\d{2}:\d{2}$/;
|
|
577
|
+
if (!timeRegex.test(config.startTime) || !timeRegex.test(config.endTime)) {
|
|
578
|
+
throw new brighthub_lib_1.NotificationServiceError(brighthub_lib_1.NotificationErrorCode.InvalidQuietHoursConfig, 'startTime and endTime must be in HH:mm format');
|
|
579
|
+
}
|
|
580
|
+
// Validate timezone is non-empty
|
|
581
|
+
if (!config.timezone || config.timezone.trim().length === 0) {
|
|
582
|
+
throw new brighthub_lib_1.NotificationServiceError(brighthub_lib_1.NotificationErrorCode.InvalidQuietHoursConfig, 'timezone is required');
|
|
583
|
+
}
|
|
584
|
+
// Get or create preferences, then update quiet hours
|
|
585
|
+
await this.getOrCreateDefaultPreferences(userId);
|
|
586
|
+
const now = new Date().toISOString();
|
|
587
|
+
await this.preferencesCollection
|
|
588
|
+
.updateOne({ userId }, {
|
|
589
|
+
quietHours: config,
|
|
590
|
+
updatedAt: now,
|
|
591
|
+
})
|
|
592
|
+
.exec();
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Set Do Not Disturb configuration.
|
|
596
|
+
* Req 56.7: DND suppresses all non-critical notifications.
|
|
597
|
+
* Req 56.8: Duration options (1h, 8h, 24h, until manually disabled).
|
|
598
|
+
* Req 56.9: Critical system notifications still delivered during DND.
|
|
599
|
+
*/
|
|
600
|
+
async setDoNotDisturb(userId, config) {
|
|
601
|
+
// Calculate expiresAt from duration if provided
|
|
602
|
+
const resolvedConfig = { ...config };
|
|
603
|
+
if (config.enabled && config.duration && !config.expiresAt) {
|
|
604
|
+
const now = new Date();
|
|
605
|
+
const durationMs = this.parseDurationToMs(config.duration);
|
|
606
|
+
if (durationMs > 0) {
|
|
607
|
+
resolvedConfig.expiresAt = new Date(now.getTime() + durationMs).toISOString();
|
|
608
|
+
}
|
|
609
|
+
// Permanent duration: no expiresAt
|
|
610
|
+
}
|
|
611
|
+
// Get or create preferences, then update DND config
|
|
612
|
+
await this.getOrCreateDefaultPreferences(userId);
|
|
613
|
+
const now = new Date().toISOString();
|
|
614
|
+
await this.preferencesCollection
|
|
615
|
+
.updateOne({ userId }, {
|
|
616
|
+
dndConfig: resolvedConfig,
|
|
617
|
+
updatedAt: now,
|
|
618
|
+
})
|
|
619
|
+
.exec();
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Convert a MuteDuration to milliseconds.
|
|
623
|
+
* Returns 0 for Permanent (no expiration).
|
|
624
|
+
*/
|
|
625
|
+
parseDurationToMs(duration) {
|
|
626
|
+
switch (duration) {
|
|
627
|
+
case brighthub_lib_1.MuteDuration.OneHour:
|
|
628
|
+
return 60 * 60 * 1000;
|
|
629
|
+
case brighthub_lib_1.MuteDuration.EightHours:
|
|
630
|
+
return 8 * 60 * 60 * 1000;
|
|
631
|
+
case brighthub_lib_1.MuteDuration.TwentyFourHours:
|
|
632
|
+
return 24 * 60 * 60 * 1000;
|
|
633
|
+
case brighthub_lib_1.MuteDuration.SevenDays:
|
|
634
|
+
return 7 * 24 * 60 * 60 * 1000;
|
|
635
|
+
case brighthub_lib_1.MuteDuration.ThirtyDays:
|
|
636
|
+
return 30 * 24 * 60 * 60 * 1000;
|
|
637
|
+
case brighthub_lib_1.MuteDuration.Permanent:
|
|
638
|
+
return 0;
|
|
639
|
+
default:
|
|
640
|
+
return 0;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
// ═══════════════════════════════════════════════════════
|
|
644
|
+
// Grouping (Req 55.6-55.9)
|
|
645
|
+
// ═══════════════════════════════════════════════════════
|
|
646
|
+
/**
|
|
647
|
+
* Group notifications by type and target within the grouping window (1 hour).
|
|
648
|
+
*
|
|
649
|
+
* Req 55.6: Same action on same content within 1 hour → single grouped notification
|
|
650
|
+
* Req 55.7: Grouped notification displays count and list of actors
|
|
651
|
+
* Req 55.8: Individual actors with timestamps available via notificationIds
|
|
652
|
+
* Req 55.9: Supports ungrouping via skipGrouping flag (preference-driven)
|
|
653
|
+
*
|
|
654
|
+
* @param notifications - Array of notifications to group
|
|
655
|
+
* @param skipGrouping - When true, each notification becomes its own group (Req 55.9)
|
|
656
|
+
* @returns Array of notification groups
|
|
657
|
+
*/
|
|
658
|
+
async groupNotifications(notifications, skipGrouping) {
|
|
659
|
+
if (notifications.length === 0) {
|
|
660
|
+
return [];
|
|
661
|
+
}
|
|
662
|
+
// Req 55.9: If ungrouping is preferred, return each notification as its own group
|
|
663
|
+
if (skipGrouping) {
|
|
664
|
+
return notifications.map((n) => ({
|
|
665
|
+
_id: (0, crypto_1.randomUUID)(),
|
|
666
|
+
groupKey: `${n.type}:${n.targetId ?? n._id}`,
|
|
667
|
+
notificationIds: [n._id],
|
|
668
|
+
actorIds: [n.actorId],
|
|
669
|
+
count: 1,
|
|
670
|
+
latestAt: n.createdAt,
|
|
671
|
+
}));
|
|
672
|
+
}
|
|
673
|
+
// Sort notifications by createdAt ascending so we process oldest first
|
|
674
|
+
const sorted = [...notifications].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
675
|
+
// Build groups keyed by type:targetId.
|
|
676
|
+
// Within each key, we may have multiple time-window clusters.
|
|
677
|
+
const groupClusters = new Map();
|
|
678
|
+
for (const notification of sorted) {
|
|
679
|
+
const groupKey = `${notification.type}:${notification.targetId ?? notification._id}`;
|
|
680
|
+
const createdAtMs = new Date(notification.createdAt).getTime();
|
|
681
|
+
if (!groupClusters.has(groupKey)) {
|
|
682
|
+
groupClusters.set(groupKey, []);
|
|
683
|
+
}
|
|
684
|
+
const clusters = groupClusters.get(groupKey);
|
|
685
|
+
// Try to find an existing cluster where this notification fits
|
|
686
|
+
// (within NOTIFICATION_GROUPING_WINDOW_MS of the cluster's earliest notification)
|
|
687
|
+
let addedToCluster = false;
|
|
688
|
+
for (const cluster of clusters) {
|
|
689
|
+
if (createdAtMs - cluster.earliestAt <
|
|
690
|
+
brighthub_lib_1.NOTIFICATION_GROUPING_WINDOW_MS) {
|
|
691
|
+
cluster.notificationIds.push(notification._id);
|
|
692
|
+
cluster.actorIds.add(notification.actorId);
|
|
693
|
+
if (createdAtMs > cluster.latestAt) {
|
|
694
|
+
cluster.latestAt = createdAtMs;
|
|
695
|
+
}
|
|
696
|
+
addedToCluster = true;
|
|
697
|
+
break;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
// No matching cluster found — start a new one
|
|
701
|
+
if (!addedToCluster) {
|
|
702
|
+
clusters.push({
|
|
703
|
+
notificationIds: [notification._id],
|
|
704
|
+
actorIds: new Set([notification.actorId]),
|
|
705
|
+
earliestAt: createdAtMs,
|
|
706
|
+
latestAt: createdAtMs,
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
// Convert clusters to IBaseNotificationGroup<string>
|
|
711
|
+
const groups = [];
|
|
712
|
+
for (const [groupKey, clusters] of groupClusters) {
|
|
713
|
+
for (const cluster of clusters) {
|
|
714
|
+
groups.push({
|
|
715
|
+
_id: (0, crypto_1.randomUUID)(),
|
|
716
|
+
groupKey,
|
|
717
|
+
notificationIds: cluster.notificationIds,
|
|
718
|
+
actorIds: Array.from(cluster.actorIds),
|
|
719
|
+
count: cluster.notificationIds.length,
|
|
720
|
+
latestAt: new Date(cluster.latestAt).toISOString(),
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
// Sort groups by latestAt descending (most recent first)
|
|
725
|
+
groups.sort((a, b) => new Date(b.latestAt).getTime() - new Date(a.latestAt).getTime());
|
|
726
|
+
return groups;
|
|
727
|
+
}
|
|
728
|
+
// ═══════════════════════════════════════════════════════
|
|
729
|
+
// Real-time (Req 52.4, 52.5) — Task 20
|
|
730
|
+
// ═══════════════════════════════════════════════════════
|
|
731
|
+
wsHandler = null;
|
|
732
|
+
/**
|
|
733
|
+
* Late-bind the WebSocket handler for real-time notification delivery.
|
|
734
|
+
* Called after both NotificationService and BrightHubWebSocketHandler are created.
|
|
735
|
+
*/
|
|
736
|
+
setWebSocketHandler(handler) {
|
|
737
|
+
this.wsHandler = handler;
|
|
738
|
+
}
|
|
739
|
+
subscribeToNotifications(_userId, _callback) {
|
|
740
|
+
// Real-time subscriptions are handled by BrightHubWebSocketHandler
|
|
741
|
+
// via room-based pub/sub on ClientWebSocketServer.
|
|
742
|
+
// This method is kept for interface compatibility.
|
|
743
|
+
return () => {
|
|
744
|
+
/* unsubscribe is handled by WebSocket disconnect */
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
async broadcastNotification(notification) {
|
|
748
|
+
if (this.wsHandler) {
|
|
749
|
+
this.wsHandler.broadcastNotification(notification);
|
|
750
|
+
// Also send updated unread count
|
|
751
|
+
const count = await this.getUnreadCount(notification.recipientId);
|
|
752
|
+
this.wsHandler.broadcastNotificationCount(notification.recipientId, count);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
exports.NotificationService = NotificationService;
|
|
757
|
+
// ═══════════════════════════════════════════════════════
|
|
758
|
+
// Factory function
|
|
759
|
+
// ═══════════════════════════════════════════════════════
|
|
760
|
+
/**
|
|
761
|
+
* Create a new NotificationService instance
|
|
762
|
+
* @param application Application with database collections
|
|
763
|
+
* @returns NotificationService instance
|
|
764
|
+
*/
|
|
765
|
+
function createNotificationService(application) {
|
|
766
|
+
return new NotificationService(application);
|
|
767
|
+
}
|
|
768
|
+
//# sourceMappingURL=notificationService.js.map
|