@memberjunction/server 6.2.0-edge.4 → 6.2.0-edge.6
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 +47 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +91 -30
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +311 -81
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +17 -3
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +44 -10
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/apiRoot.d.ts +32 -0
- package/dist/apiRoot.d.ts.map +1 -0
- package/dist/apiRoot.js +67 -0
- package/dist/apiRoot.js.map +1 -0
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +27 -0
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/LoginScreenEngine.d.ts +22 -0
- package/dist/auth/LoginScreenEngine.d.ts.map +1 -0
- package/dist/auth/LoginScreenEngine.js +57 -0
- package/dist/auth/LoginScreenEngine.js.map +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +52 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +10 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +37 -1
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/localDevAuth.d.ts +79 -0
- package/dist/auth/localDevAuth.d.ts.map +1 -0
- package/dist/auth/localDevAuth.js +439 -0
- package/dist/auth/localDevAuth.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +2 -2
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +3 -2
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +12 -0
- package/dist/auth/magicLink/types.d.ts.map +1 -1
- package/dist/auth/sessionUserClone.d.ts +1 -1
- package/dist/auth/sessionUserClone.d.ts.map +1 -1
- package/dist/auth/sessionUserClone.js +3 -2
- package/dist/auth/sessionUserClone.js.map +1 -1
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts +292 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +442 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -0
- package/dist/broadcast/index.d.ts +6 -0
- package/dist/broadcast/index.d.ts.map +1 -0
- package/dist/broadcast/index.js +6 -0
- package/dist/broadcast/index.js.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts +43 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js +144 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts +46 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js +149 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts +49 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js +131 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts +24 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js +51 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js.map +1 -0
- package/dist/cache.d.ts +3 -2
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +632 -22
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +104 -4
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +3 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +29 -8
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts +29 -0
- package/dist/coreRoutes.d.ts.map +1 -0
- package/dist/coreRoutes.js +156 -0
- package/dist/coreRoutes.js.map +1 -0
- package/dist/generated/graphql-schemas/__mj.d.ts +1016 -29
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +5125 -434
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +85 -30
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +175 -60
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +2 -0
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/PubSubManager.d.ts +10 -0
- package/dist/generic/PubSubManager.d.ts.map +1 -1
- package/dist/generic/PubSubManager.js +44 -1
- package/dist/generic/PubSubManager.js.map +1 -1
- package/dist/generic/PushStatusResolver.d.ts +39 -6
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +94 -12
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +168 -69
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +464 -405
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +11 -3
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +91 -13
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/generic/actionOutputFieldSecurity.d.ts +26 -0
- package/dist/generic/actionOutputFieldSecurity.d.ts.map +1 -0
- package/dist/generic/actionOutputFieldSecurity.js +47 -0
- package/dist/generic/actionOutputFieldSecurity.js.map +1 -0
- package/dist/generic/fieldSecurityTransport.d.ts +30 -0
- package/dist/generic/fieldSecurityTransport.d.ts.map +1 -0
- package/dist/generic/fieldSecurityTransport.js +30 -0
- package/dist/generic/fieldSecurityTransport.js.map +1 -0
- package/dist/globalCors.d.ts +33 -0
- package/dist/globalCors.d.ts.map +1 -0
- package/dist/globalCors.js +58 -0
- package/dist/globalCors.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +230 -222
- package/dist/index.js.map +1 -1
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +6 -1
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.d.ts +12 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.js +50 -1
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
- package/dist/multiTenancy/index.d.ts.map +1 -1
- package/dist/multiTenancy/index.js +22 -2
- package/dist/multiTenancy/index.js.map +1 -1
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -1
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js +2 -1
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -1
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -1
- package/dist/realtimeSessions/RealtimeVerifyRouter.js +2 -1
- package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -1
- package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts +100 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts.map +1 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.js +173 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.js.map +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -1
- package/dist/realtimeSessions/SessionVerificationPortsBase.js +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -1
- package/dist/realtimeSessions/index.d.ts +2 -0
- package/dist/realtimeSessions/index.d.ts.map +1 -1
- package/dist/realtimeSessions/index.js +2 -0
- package/dist/realtimeSessions/index.js.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts +32 -0
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js +56 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
- package/dist/realtimeSessions/sessionAccess.d.ts +91 -8
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
- package/dist/realtimeSessions/sessionAccess.js +127 -20
- package/dist/realtimeSessions/sessionAccess.js.map +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.js +5 -2
- package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.d.ts +2 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.js +19 -3
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts +67 -7
- package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.js +201 -19
- package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
- package/dist/realtimeWidget/host-identity.d.ts +1 -1
- package/dist/realtimeWidget/host-identity.js +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +20 -1
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +17 -1
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +2 -1
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +19 -1
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +63 -12
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +1 -0
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.d.ts +18 -4
- package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.js +32 -8
- package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
- package/dist/resolvers/AgentSessionResolver.d.ts +10 -4
- package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/AgentSessionResolver.js +40 -17
- package/dist/resolvers/AgentSessionResolver.js.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts +5 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.js +9 -7
- package/dist/resolvers/ArtifactFileResolver.js.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.d.ts +8 -4
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.js +6 -6
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
- package/dist/resolvers/DatasetResolver.d.ts +24 -3
- package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
- package/dist/resolvers/DatasetResolver.js +57 -8
- package/dist/resolvers/DatasetResolver.js.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts +13 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.js +50 -14
- package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +3 -2
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +46 -3
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +211 -50
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +1 -0
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +87 -11
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +292 -105
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
- package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js +117 -38
- package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +6 -3
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +49 -9
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +8 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +31 -3
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.d.ts +6 -0
- package/dist/resolvers/PipelineProgressResolver.d.ts.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.js +5 -3
- package/dist/resolvers/PipelineProgressResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts +2 -0
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +33 -6
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +2 -0
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +15 -6
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RSUResolver.d.ts.map +1 -1
- package/dist/resolvers/RSUResolver.js +12 -0
- package/dist/resolvers/RSUResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +18 -10
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +92 -54
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +11 -9
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +56 -8
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +241 -67
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +4 -4
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTestResolver.js +3 -1
- package/dist/resolvers/RunTestResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts +12 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.js +15 -2
- package/dist/resolvers/SearchKnowledgeStreamResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +2 -3
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +4 -0
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts +2 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.js +28 -1
- package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.d.ts +24 -0
- package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.js +66 -13
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +34 -2
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +150 -27
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts +1 -1
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js +2 -1
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/resolvers/agent-run-data-guard.d.ts +31 -0
- package/dist/resolvers/agent-run-data-guard.d.ts.map +1 -0
- package/dist/resolvers/agent-run-data-guard.js +72 -0
- package/dist/resolvers/agent-run-data-guard.js.map +1 -0
- package/dist/rest/EntityCRUDHandler.d.ts +6 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +19 -5
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +8 -5
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.d.ts +49 -0
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -0
- package/dist/rest/RealtimeRecordingHandler.js +383 -0
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -0
- package/dist/rest/ViewOperationsHandler.d.ts +9 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +43 -17
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +6 -0
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +6 -0
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverExtensionReservedRoots.d.ts +12 -10
- package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
- package/dist/serverExtensionReservedRoots.js +14 -17
- package/dist/serverExtensionReservedRoots.js.map +1 -1
- package/dist/serverRoleConfigUnits.d.ts +29 -0
- package/dist/serverRoleConfigUnits.d.ts.map +1 -0
- package/dist/serverRoleConfigUnits.js +33 -0
- package/dist/serverRoleConfigUnits.js.map +1 -0
- package/dist/services/MJStorageBlobStore.d.ts +8 -1
- package/dist/services/MJStorageBlobStore.d.ts.map +1 -1
- package/dist/services/MJStorageBlobStore.js +25 -19
- package/dist/services/MJStorageBlobStore.js.map +1 -1
- package/dist/services/StartTaskGraphDispatcher.js +2 -2
- package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +5 -3
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +27 -5
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphAgentRunner.d.ts +14 -2
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +157 -9
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +59 -2
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +626 -16
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/sharedCache.d.ts.map +1 -1
- package/dist/sharedCache.js +3 -0
- package/dist/sharedCache.js.map +1 -1
- package/dist/types.d.ts +23 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +99 -98
- package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
- package/src/__tests__/AdhocQueryResolver.dialect.test.ts +137 -0
- package/src/__tests__/AgentRunStatusPublisher.test.ts +49 -0
- package/src/__tests__/AgentSessionResolver.ownership.test.ts +137 -0
- package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
- package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
- package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
- package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
- package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +369 -18
- package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
- package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
- package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
- package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
- package/src/__tests__/LoginScreenEngine.test.ts +86 -0
- package/src/__tests__/MJStorageBlobStore.storageGate.test.ts +63 -0
- package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
- package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
- package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +324 -46
- package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
- package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +98 -0
- package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
- package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
- package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +243 -7
- package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
- package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +176 -0
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +23 -1
- package/src/__tests__/ResolverBase.publishStatusUpdate.test.ts +68 -0
- package/src/__tests__/ResolverBase.userViewCacheAndDedup.test.ts +130 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +69 -13
- package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
- package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +20 -28
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +264 -0
- package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +4 -1
- package/src/__tests__/RunTemplateResolver.test.ts +35 -2
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
- package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
- package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
- package/src/__tests__/SessionJanitor.test.ts +365 -10
- package/src/__tests__/SessionManager.test.ts +122 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
- package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +468 -23
- package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
- package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
- package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
- package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
- package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
- package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
- package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
- package/src/__tests__/ViewOperationsHandler.test.ts +7 -2
- package/src/__tests__/WidgetSessionService.test.ts +583 -4
- package/src/__tests__/agent-run-data-guard.test.ts +130 -0
- package/src/__tests__/apiRootBoot.test.ts +202 -0
- package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
- package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +109 -0
- package/src/__tests__/conversationRunEvents.test.ts +56 -14
- package/src/__tests__/fieldSecurityFixtures.ts +91 -0
- package/src/__tests__/globalCors.test.ts +217 -0
- package/src/__tests__/localDevAuth.test.ts +196 -0
- package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
- package/src/__tests__/multiTenancy.security.test.ts +51 -0
- package/src/__tests__/multiTenancy.test.ts +1 -1
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
- package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +64 -1
- package/src/__tests__/realtimeRecordingHandler.test.ts +669 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +29 -1
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.anonymous.test.ts +31 -0
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.namedScoped.test.ts +37 -0
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +146 -7
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
- package/src/__tests__/resolverBase.cloudEventChangedFields.test.ts +157 -0
- package/src/__tests__/resolverBase.fieldSecurityTransport.test.ts +222 -0
- package/src/__tests__/resolverBase.fls.test.ts +146 -97
- package/src/__tests__/restTransport.fieldSecurity.test.ts +148 -0
- package/src/__tests__/runParamsTimeZone.test.ts +179 -0
- package/src/__tests__/runStreams.fieldSecurity.test.ts +100 -0
- package/src/__tests__/runViewProperties.test.ts +114 -0
- package/src/__tests__/scalabilityBenchmarks.test.ts +765 -0
- package/src/__tests__/scalabilityDatabaseIntegration.test.ts +207 -0
- package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
- package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -98
- package/src/__tests__/sessionUserClone.test.ts +5 -1
- package/src/__tests__/sharedCache.test.ts +5 -3
- package/src/__tests__/startupSweepOrder.test.ts +40 -0
- package/src/__tests__/unifiedAuth.test.ts +28 -0
- package/src/__tests__/widgetGuestElevation.test.ts +2 -0
- package/src/agentSessions/SessionJanitor.ts +369 -93
- package/src/agentSessions/SessionManager.ts +45 -10
- package/src/apiRoot.ts +78 -0
- package/src/auth/AuthProviderCatalogRouter.ts +29 -0
- package/src/auth/LoginScreenEngine.ts +50 -0
- package/src/auth/index.ts +57 -12
- package/src/auth/initializeProviders.ts +43 -1
- package/src/auth/localDevAuth.ts +528 -0
- package/src/auth/magicLink/MagicLinkKeys.ts +2 -2
- package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
- package/src/auth/magicLink/types.ts +10 -0
- package/src/auth/sessionUserClone.ts +3 -2
- package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +674 -0
- package/src/broadcast/index.ts +5 -0
- package/src/broadcast/providers/AWSIoTCoreBroadcastProvider.ts +180 -0
- package/src/broadcast/providers/AzureWebPubSubBroadcastProvider.ts +182 -0
- package/src/broadcast/providers/GCPPubSubBroadcastProvider.ts +169 -0
- package/src/broadcast/providers/SequencedRoleBucketBroadcastProvider.ts +57 -0
- package/src/cache.ts +2 -1
- package/src/config.ts +115 -5
- package/src/context.ts +32 -8
- package/src/coreRoutes.ts +181 -0
- package/src/generated/graphql-schemas/__mj.ts +3684 -284
- package/src/generic/CacheInvalidationResolver.ts +172 -60
- package/src/generic/OrphanedConversationDetailReconciler.ts +4 -2
- package/src/generic/PubSubManager.ts +54 -1
- package/src/generic/PushStatusResolver.ts +109 -12
- package/src/generic/ResolverBase.ts +540 -431
- package/src/generic/RunViewResolver.ts +97 -15
- package/src/generic/actionOutputFieldSecurity.ts +75 -0
- package/src/generic/fieldSecurityTransport.ts +62 -0
- package/src/globalCors.ts +71 -0
- package/src/index.ts +239 -238
- package/src/integration/CustomColumnPromoter.ts +6 -1
- package/src/logging/variablesLoggingMiddleware.ts +59 -3
- package/src/multiTenancy/index.ts +24 -2
- package/src/realtimeSessions/README.md +7 -3
- package/src/realtimeSessions/RealtimeSessionVerificationService.ts +2 -1
- package/src/realtimeSessions/RealtimeVerifyRouter.ts +2 -1
- package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
- package/src/realtimeSessions/index.ts +2 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +69 -0
- package/src/realtimeSessions/sessionAccess.ts +183 -23
- package/src/realtimeSessions/sessionConfigStamps.ts +1 -1
- package/src/realtimeSessions/subscriptionAuthorization.ts +4 -2
- package/src/realtimeSessions/verificationWorkflow.ts +3 -1
- package/src/realtimeWidget/WidgetRouter.ts +22 -4
- package/src/realtimeWidget/WidgetSessionService.ts +252 -17
- package/src/realtimeWidget/host-identity.ts +1 -1
- package/src/realtimeWidget/widgetCore.ts +30 -1
- package/src/realtimeWidget/widgetGuestElevation.ts +2 -1
- package/src/resolvers/ActionResolver.ts +78 -15
- package/src/resolvers/AdhocQueryResolver.ts +1 -0
- package/src/resolvers/AgentRunStatusPublisher.ts +36 -8
- package/src/resolvers/AgentSessionResolver.ts +46 -18
- package/src/resolvers/ArtifactFileResolver.ts +9 -8
- package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
- package/src/resolvers/DatasetResolver.ts +70 -10
- package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
- package/src/resolvers/EntityRecordNameResolver.ts +3 -2
- package/src/resolvers/FetchEntityVectorsResolver.ts +248 -55
- package/src/resolvers/FileCategoryResolver.ts +1 -0
- package/src/resolvers/FileResolver.ts +334 -109
- package/src/resolvers/GetDataContextDataResolver.ts +139 -41
- package/src/resolvers/GetDataResolver.ts +6 -3
- package/src/resolvers/IntegrationDiscoveryResolver.ts +53 -9
- package/src/resolvers/MergeRecordsResolver.ts +23 -2
- package/src/resolvers/PipelineProgressResolver.ts +12 -3
- package/src/resolvers/QueryResolver.ts +31 -6
- package/src/resolvers/QuerySystemUserResolver.ts +15 -6
- package/src/resolvers/RSUResolver.ts +12 -0
- package/src/resolvers/RealtimeClientSessionResolver.ts +114 -66
- package/src/resolvers/RemoteBrowserActionResolver.ts +15 -10
- package/src/resolvers/RunAIAgentResolver.ts +296 -85
- package/src/resolvers/RunTemplateResolver.ts +6 -4
- package/src/resolvers/RunTestResolver.ts +3 -1
- package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
- package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
- package/src/resolvers/SyncDataResolver.ts +4 -0
- package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
- package/src/resolvers/TestQuerySQLResolver.ts +69 -13
- package/src/resolvers/TransactionGroupResolver.ts +185 -30
- package/src/resolvers/UserViewResolver.ts +2 -1
- package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
- package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
- package/src/resolvers/agent-run-data-guard.ts +89 -0
- package/src/rest/EntityCRUDHandler.ts +22 -5
- package/src/rest/RESTEndpointHandler.ts +8 -5
- package/src/rest/RealtimeRecordingHandler.ts +467 -0
- package/src/rest/ViewOperationsHandler.ts +52 -18
- package/src/rest/setupRESTEndpoints.ts +6 -0
- package/src/serverExtensionReservedRoots.ts +14 -17
- package/src/serverRoleConfigUnits.ts +48 -0
- package/src/services/MJStorageBlobStore.ts +31 -30
- package/src/services/StartTaskGraphDispatcher.ts +2 -2
- package/src/services/TaskGraphActionRunner.ts +25 -5
- package/src/services/TaskGraphAgentRunner.ts +188 -11
- package/src/services/TaskGraphContinuationDeliverer.ts +738 -16
- package/src/sharedCache.ts +3 -0
- package/src/types.ts +23 -1
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { BaseSingleton, MJGlobal } from '@memberjunction/global';
|
|
3
|
+
import { EntityInfo, Metadata, UserInfo } from '@memberjunction/core';
|
|
4
|
+
import type {
|
|
5
|
+
CacheInvalidationNotification,
|
|
6
|
+
CacheInvalidationPayload,
|
|
7
|
+
ReadPermissionRow,
|
|
8
|
+
RoleHolder,
|
|
9
|
+
} from '../generic/CacheInvalidationResolver.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Supported cache invalidation broadcast topologies.
|
|
13
|
+
*/
|
|
14
|
+
export type CacheInvalidationBroadcastTopology =
|
|
15
|
+
| 'SequencedRoleBucket'
|
|
16
|
+
| 'AzureWebPubSub'
|
|
17
|
+
| 'AWSIoTCore'
|
|
18
|
+
| 'GCPPubSub';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Configuration options for the cache invalidation broadcast subsystem.
|
|
22
|
+
* Configured under `cacheSettings.broadcast` in `mj.config.cjs` or via `MJ_CACHE_BROADCAST_*` env vars.
|
|
23
|
+
*/
|
|
24
|
+
export interface CacheBroadcastProviderConfig {
|
|
25
|
+
/**
|
|
26
|
+
* Driver key registered with `@RegisterClass(BaseCacheInvalidationBroadcastProvider, key)`.
|
|
27
|
+
* Defaults to `'SequencedRoleBucket'`.
|
|
28
|
+
*/
|
|
29
|
+
provider?: CacheInvalidationBroadcastTopology | string;
|
|
30
|
+
/**
|
|
31
|
+
* Maximum number of sequenced invalidation events retained in the in-memory ring buffer
|
|
32
|
+
* for catch-up delta queries (`GetCacheInvalidationsSince`). Defaults to 5000.
|
|
33
|
+
*/
|
|
34
|
+
ringBufferSize?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Optional list of entity names whose cache invalidation broadcasts should be suppressed
|
|
37
|
+
* (e.g., high-churn telemetry/audit tables never cached on the client).
|
|
38
|
+
*/
|
|
39
|
+
excludedEntities?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* Azure Web PubSub configuration (used when `provider === 'AzureWebPubSub'`).
|
|
42
|
+
*/
|
|
43
|
+
azureWebPubSub?: {
|
|
44
|
+
endpoint?: string;
|
|
45
|
+
hubName?: string;
|
|
46
|
+
accessKey?: string;
|
|
47
|
+
tokenTtlMinutes?: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* AWS IoT Core MQTT over WebSockets configuration (used when `provider === 'AWSIoTCore'`).
|
|
51
|
+
*/
|
|
52
|
+
awsIoTCore?: {
|
|
53
|
+
endpoint?: string;
|
|
54
|
+
region?: string;
|
|
55
|
+
topicPrefix?: string;
|
|
56
|
+
accessKeyId?: string;
|
|
57
|
+
secretAccessKey?: string;
|
|
58
|
+
tokenTtlSeconds?: number;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Google Cloud Pub/Sub / Cloud Run WebSockets configuration (used when `provider === 'GCPPubSub'`).
|
|
62
|
+
*/
|
|
63
|
+
gcpPubSub?: {
|
|
64
|
+
projectId?: string;
|
|
65
|
+
topicPrefix?: string;
|
|
66
|
+
gatewayUrl?: string;
|
|
67
|
+
signingSecret?: string;
|
|
68
|
+
tokenTtlSeconds?: number;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Catch-up response returned by `GetChangesSince` when a client detects a sequence gap
|
|
74
|
+
* via `X-MJ-Cache-Seq` / `X-MJ-Server-ID` HTTP headers or WebSocket reconnection.
|
|
75
|
+
*/
|
|
76
|
+
export interface CacheInvalidationCatchUpResponse {
|
|
77
|
+
/**
|
|
78
|
+
* True when the requested `sinceSequence` has already been evicted from the ring buffer,
|
|
79
|
+
* belongs to a future sequence, or the server restarted. Instructs the client to evict
|
|
80
|
+
* its local dataset cache and re-fetch cleanly.
|
|
81
|
+
*/
|
|
82
|
+
RequiresFullRefresh: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Latest monotonic sequence number assigned by this server process.
|
|
85
|
+
*/
|
|
86
|
+
CurrentSequence: number;
|
|
87
|
+
/**
|
|
88
|
+
* Unique process identifier for this MJServer instance (`X-MJ-Server-ID`).
|
|
89
|
+
*/
|
|
90
|
+
ServerProcessID: string;
|
|
91
|
+
/**
|
|
92
|
+
* Ordered delta of permission-filtered, RLS-shaped invalidation events strictly after `sinceSequence`.
|
|
93
|
+
*/
|
|
94
|
+
Events: CacheInvalidationNotification[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Connection token and subscription metadata returned by `NegotiateClientConnection`
|
|
99
|
+
* for Topology 3 external cloud WebSocket multiplexers (or in-process GraphQL WS fallback).
|
|
100
|
+
*/
|
|
101
|
+
export interface CacheBroadcastNegotiationResult {
|
|
102
|
+
/**
|
|
103
|
+
* Active provider driver key (e.g. `'SequencedRoleBucket'`, `'AzureWebPubSub'`, `'AWSIoTCore'`, `'GCPPubSub'`).
|
|
104
|
+
*/
|
|
105
|
+
Provider: string;
|
|
106
|
+
/**
|
|
107
|
+
* WebSocket endpoint URL for the client to connect to.
|
|
108
|
+
*/
|
|
109
|
+
Url: string;
|
|
110
|
+
/**
|
|
111
|
+
* Signed token / credentials authorizing the client for its role-scoped broadcast groups.
|
|
112
|
+
*/
|
|
113
|
+
Token?: string;
|
|
114
|
+
/**
|
|
115
|
+
* Role-scoped group/topic names the client is authorized to subscribe to.
|
|
116
|
+
*/
|
|
117
|
+
Groups: string[];
|
|
118
|
+
/**
|
|
119
|
+
* ISO-8601 expiration timestamp for the negotiated token.
|
|
120
|
+
*/
|
|
121
|
+
ExpiresAt: string;
|
|
122
|
+
/**
|
|
123
|
+
* Current server process ID for sequence continuity tracking.
|
|
124
|
+
*/
|
|
125
|
+
ServerProcessID: string;
|
|
126
|
+
/**
|
|
127
|
+
* Current server invalidation sequence at the moment of negotiation.
|
|
128
|
+
*/
|
|
129
|
+
CurrentSequence: number;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Result of evaluating an invalidation event against a single role fingerprint bucket.
|
|
134
|
+
*/
|
|
135
|
+
export interface RoleBucketEvaluationResult {
|
|
136
|
+
Allow: boolean;
|
|
137
|
+
WithholdKey: boolean;
|
|
138
|
+
Shaped: CacheInvalidationNotification;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface RingBufferEntry {
|
|
142
|
+
Sequence: number;
|
|
143
|
+
Payload: CacheInvalidationPayload;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* High-churn system telemetry/logging entities that can optionally be excluded from browser
|
|
148
|
+
* invalidation fan-out because browsers do not maintain live dataset caches for them.
|
|
149
|
+
*/
|
|
150
|
+
export const DEFAULT_HIGH_CHURN_SYSTEM_ENTITIES: readonly string[] = [
|
|
151
|
+
'MJ: Audit Logs',
|
|
152
|
+
'MJ: Error Logs',
|
|
153
|
+
'MJ: AI Prompt Runs',
|
|
154
|
+
'MJ: AI Agent Runs',
|
|
155
|
+
'MJ: AI Agent Run Steps',
|
|
156
|
+
'MJ: Query Execution Histories',
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Abstract base class for MemberJunction's pluggable Cache Invalidation Broadcast Hierarchy.
|
|
161
|
+
*
|
|
162
|
+
* Provides the shared primitives used by all broadcast topologies:
|
|
163
|
+
* 1. **Monotonic Sequence Ring Buffer (Topology 1)**: Every invalidation event is stamped with a
|
|
164
|
+
* monotonically increasing `Sequence` integer and stored in a bounded circular buffer (`MaxRingBufferSize`),
|
|
165
|
+
* enabling HTTP `X-MJ-Cache-Seq` piggybacking and `GetCacheInvalidationsSince` delta catch-up.
|
|
166
|
+
* 2. **Role-Fingerprint $O(\text{Roles})$ Evaluation & Shaping Memoizer (Topology 2)**: Computes a canonical
|
|
167
|
+
* fingerprint of a user's sorted `RoleID`s (cached per `UserInfo` in a `WeakMap`) and memoizes
|
|
168
|
+
* entity read-permission checks (`CanRead`) and row-level security key-withholding (`ReadIsRowFiltered`)
|
|
169
|
+
* once per `(payload, entity, roleFingerprint)` tuple instead of once per connected WebSocket client.
|
|
170
|
+
* 3. **Cloud Multiplexer Extension Hooks (Topology 3)**: Subclasses (`AzureWebPubSubBroadcastProvider`,
|
|
171
|
+
* `AWSIoTCoreBroadcastProvider`, `GCPPubSubBroadcastProvider`) override `PublishInvalidation` and
|
|
172
|
+
* `NegotiateClientConnection` to offload WebSocket fan-out to managed cloud pub/sub infrastructure.
|
|
173
|
+
*/
|
|
174
|
+
export abstract class BaseCacheInvalidationBroadcastProvider {
|
|
175
|
+
private static readonly _serverProcessId: string = randomUUID();
|
|
176
|
+
|
|
177
|
+
private _currentSequence = 0;
|
|
178
|
+
private _maxRingBufferSize = 5000;
|
|
179
|
+
private _ringBuffer: Array<RingBufferEntry | undefined> = [];
|
|
180
|
+
private _ringHead = 0;
|
|
181
|
+
private _ringCount = 0;
|
|
182
|
+
private _excludedEntities: Set<string> = new Set<string>();
|
|
183
|
+
protected _config: CacheBroadcastProviderConfig = {};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Memoizes canonical role fingerprints per `RoleHolder` / `UserInfo` object reference.
|
|
187
|
+
*/
|
|
188
|
+
private readonly _roleFingerprintCache = new WeakMap<object, { roleCount: number; fingerprint: string }>();
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Memoizes `Metadata.EntityByName` lookup per `CacheInvalidationPayload` object reference
|
|
192
|
+
* so `CacheInvalidationFilter` and `CacheInvalidationResolver` only look up the entity once per event.
|
|
193
|
+
*/
|
|
194
|
+
private readonly _payloadEntityCache = new WeakMap<CacheInvalidationPayload, EntityInfo | null>();
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Memoizes entity-level read permission (`CanRead`) per `(payload, roleFingerprint)`.
|
|
198
|
+
*/
|
|
199
|
+
private readonly _payloadFilterMemo = new WeakMap<CacheInvalidationPayload, Map<string, boolean>>();
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Memoizes row-level security key-withholding and shaped `CacheInvalidationNotification`
|
|
203
|
+
* per `(payload, entity, roleFingerprint)`.
|
|
204
|
+
*/
|
|
205
|
+
private readonly _payloadShapeMemo = new WeakMap<
|
|
206
|
+
CacheInvalidationPayload,
|
|
207
|
+
WeakMap<object, Map<string, CacheInvalidationNotification>>
|
|
208
|
+
>();
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Unique identifier of the running MJServer process, emitted in `X-MJ-Server-ID`.
|
|
212
|
+
*/
|
|
213
|
+
public get ServerProcessID(): string {
|
|
214
|
+
return BaseCacheInvalidationBroadcastProvider._serverProcessId;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Identifier for the active broadcast topology.
|
|
219
|
+
*/
|
|
220
|
+
public abstract get Topology(): CacheInvalidationBroadcastTopology;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Latest monotonic sequence number assigned to a cache invalidation event in this process.
|
|
224
|
+
*/
|
|
225
|
+
public get CurrentSequence(): number {
|
|
226
|
+
return this._currentSequence;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Maximum number of invalidation events held in the circular ring buffer.
|
|
231
|
+
*/
|
|
232
|
+
public get MaxRingBufferSize(): number {
|
|
233
|
+
return this._maxRingBufferSize;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Number of invalidation events currently retained in the circular ring buffer.
|
|
238
|
+
*/
|
|
239
|
+
public get BufferedEventCount(): number {
|
|
240
|
+
return this._ringCount;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Configures the provider instance with buffer sizing, entity exclusions, and cloud settings.
|
|
245
|
+
*/
|
|
246
|
+
public Configure(config?: CacheBroadcastProviderConfig): void {
|
|
247
|
+
this._config = config ?? {};
|
|
248
|
+
const desiredSize = config?.ringBufferSize && config.ringBufferSize > 0 ? Math.floor(config.ringBufferSize) : 5000;
|
|
249
|
+
if (desiredSize !== this._maxRingBufferSize || this._ringBuffer.length === 0) {
|
|
250
|
+
this._maxRingBufferSize = desiredSize;
|
|
251
|
+
this._ringBuffer = new Array<RingBufferEntry | undefined>(this._maxRingBufferSize);
|
|
252
|
+
this._ringHead = 0;
|
|
253
|
+
this._ringCount = 0;
|
|
254
|
+
}
|
|
255
|
+
this._excludedEntities = new Set(
|
|
256
|
+
(config?.excludedEntities ?? [])
|
|
257
|
+
.map((name) => name.trim().toLowerCase())
|
|
258
|
+
.filter((name) => name.length > 0)
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Returns whether invalidation events for `entityName` should be broadcast to clients.
|
|
264
|
+
* Returns `false` for blank names or entities explicitly listed in `excludedEntities`.
|
|
265
|
+
*/
|
|
266
|
+
public ShouldBroadcastEntity(entityName: string | undefined | null): boolean {
|
|
267
|
+
if (!entityName) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
const normalized = entityName.trim().toLowerCase();
|
|
271
|
+
if (normalized.length === 0) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
return !this._excludedEntities.has(normalized);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Computes a canonical, order-independent role fingerprint for a user (`RoleHolder`).
|
|
279
|
+
* Memoized per user object in a `WeakMap` so repeated evaluations across thousands of events are $O(1)$.
|
|
280
|
+
*/
|
|
281
|
+
public GetRoleFingerprint(user: RoleHolder | undefined | null): string {
|
|
282
|
+
if (!user || typeof user !== 'object') {
|
|
283
|
+
return 'anonymous';
|
|
284
|
+
}
|
|
285
|
+
const roles = user.UserRoles;
|
|
286
|
+
if (!Array.isArray(roles)) {
|
|
287
|
+
return 'no-roles';
|
|
288
|
+
}
|
|
289
|
+
const cached = this._roleFingerprintCache.get(user);
|
|
290
|
+
if (cached && cached.roleCount === roles.length) {
|
|
291
|
+
return cached.fingerprint;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let fingerprint: string;
|
|
295
|
+
if (roles.length === 0) {
|
|
296
|
+
fingerprint = 'roles:empty';
|
|
297
|
+
} else if (roles.length === 1) {
|
|
298
|
+
fingerprint = `roles:${(roles[0]?.RoleID ?? '').trim().toLowerCase()}`;
|
|
299
|
+
} else {
|
|
300
|
+
const normalizedIds: string[] = new Array<string>(roles.length);
|
|
301
|
+
for (let i = 0; i < roles.length; i++) {
|
|
302
|
+
normalizedIds[i] = (roles[i]?.RoleID ?? '').trim().toLowerCase();
|
|
303
|
+
}
|
|
304
|
+
normalizedIds.sort();
|
|
305
|
+
fingerprint = `roles:${normalizedIds.join('|')}`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
this._roleFingerprintCache.set(user, { roleCount: roles.length, fingerprint });
|
|
309
|
+
return fingerprint;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Resolves and caches the `EntityInfo` for a `CacheInvalidationPayload` so that
|
|
314
|
+
* `CacheInvalidationFilter` and `CacheInvalidationResolver` do not repeat metadata lookups.
|
|
315
|
+
*/
|
|
316
|
+
public ResolveEntityForPayload(
|
|
317
|
+
payload: CacheInvalidationPayload,
|
|
318
|
+
entityLookup?: (entityName: string) => EntityInfo | undefined | null
|
|
319
|
+
): EntityInfo | null {
|
|
320
|
+
if (this._payloadEntityCache.has(payload)) {
|
|
321
|
+
return this._payloadEntityCache.get(payload) ?? null;
|
|
322
|
+
}
|
|
323
|
+
const entityName = payload?.entityName;
|
|
324
|
+
if (!entityName) {
|
|
325
|
+
this._payloadEntityCache.set(payload, null);
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
const entity = entityLookup
|
|
329
|
+
? (entityLookup(entityName) ?? null)
|
|
330
|
+
: (new Metadata().EntityByName(entityName) ?? null); // global-provider-ok: subscription broadcast provider resolves server-wide entity metadata once per event
|
|
331
|
+
this._payloadEntityCache.set(payload, entity);
|
|
332
|
+
return entity;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Evaluates whether `user` has entity-level read permission for `payload`, memoized by
|
|
337
|
+
* `(payload, entityName, roleFingerprint)` so $N$ subscribers sharing $R$ role combinations
|
|
338
|
+
* only run `GetUserPermisions` $R$ times per event.
|
|
339
|
+
*/
|
|
340
|
+
public EvaluateEntityReadAccess(
|
|
341
|
+
payload: CacheInvalidationPayload,
|
|
342
|
+
user: UserInfo | undefined,
|
|
343
|
+
entityLookup?: (entityName: string) => EntityInfo | undefined | null
|
|
344
|
+
): boolean {
|
|
345
|
+
if (!user) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
const entityName = payload?.entityName;
|
|
349
|
+
if (!this.ShouldBroadcastEntity(entityName)) {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const entity = this.ResolveEntityForPayload(payload, entityLookup);
|
|
354
|
+
if (!entity) {
|
|
355
|
+
// Unknown entity: deliver rather than leaving client cache silently stale
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Only coalesce across users when UserRoles is an array; mock users without UserRoles
|
|
360
|
+
// in isolated unit tests are evaluated directly.
|
|
361
|
+
if (!Array.isArray(user.UserRoles)) {
|
|
362
|
+
return entity.GetUserPermisions(user).CanRead;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
let bucketMap = this._payloadFilterMemo.get(payload);
|
|
366
|
+
if (!bucketMap) {
|
|
367
|
+
bucketMap = new Map<string, boolean>();
|
|
368
|
+
this._payloadFilterMemo.set(payload, bucketMap);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const bucketKey = `${entity.Name.toLowerCase()}::${this.GetRoleFingerprint(user)}`;
|
|
372
|
+
const cached = bucketMap.get(bucketKey);
|
|
373
|
+
if (cached !== undefined) {
|
|
374
|
+
return cached;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const canRead = entity.GetUserPermisions(user).CanRead;
|
|
378
|
+
bucketMap.set(bucketKey, canRead);
|
|
379
|
+
return canRead;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Evaluates whether every read permission the user holds on `entity` is gated by a
|
|
384
|
+
* Row-Level Security filter (`ReadRLSFilterID`).
|
|
385
|
+
*/
|
|
386
|
+
public ReadIsRowFiltered(
|
|
387
|
+
entity: { Permissions: ReadonlyArray<ReadPermissionRow> },
|
|
388
|
+
user: RoleHolder
|
|
389
|
+
): boolean {
|
|
390
|
+
const roles = new Set((user.UserRoles ?? []).map((role) => (role.RoleID ?? '').trim().toLowerCase()));
|
|
391
|
+
let filteredReads = 0;
|
|
392
|
+
for (const row of entity.Permissions) {
|
|
393
|
+
if (!row.CanRead) continue;
|
|
394
|
+
const isDeny = row.IsDeny ?? (row.Type ?? 'Allow').trim().toLowerCase() === 'deny';
|
|
395
|
+
if (isDeny) continue;
|
|
396
|
+
if (!roles.has((row.RoleID ?? '').trim().toLowerCase())) continue;
|
|
397
|
+
if (!row.ReadRLSFilterID) return false;
|
|
398
|
+
filteredReads += 1;
|
|
399
|
+
}
|
|
400
|
+
return filteredReads > 0;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Shapes a `CacheInvalidationPayload` into a `CacheInvalidationNotification` for `user` and `entity`.
|
|
405
|
+
* When `user` and `entity` are present and `user.UserRoles` is populated, the shaped object is
|
|
406
|
+
* memoized per `(payload, entity, roleFingerprint)` so $N$ subscribers sharing $R$ role buckets
|
|
407
|
+
* only allocate and evaluate `ReadIsRowFiltered` $R$ times per event.
|
|
408
|
+
*/
|
|
409
|
+
public ShapeEventForSubscriber(
|
|
410
|
+
payload: CacheInvalidationPayload,
|
|
411
|
+
user: RoleHolder | undefined,
|
|
412
|
+
entity: { Permissions: ReadonlyArray<ReadPermissionRow> } | null | undefined
|
|
413
|
+
): CacheInvalidationNotification {
|
|
414
|
+
if (!user || !entity || !Array.isArray(user.UserRoles)) {
|
|
415
|
+
const withholdKey = !!user && !!entity && this.ReadIsRowFiltered(entity, user);
|
|
416
|
+
return this.buildNotification(payload, withholdKey);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
let entityMap = this._payloadShapeMemo.get(payload);
|
|
420
|
+
if (!entityMap) {
|
|
421
|
+
entityMap = new WeakMap<object, Map<string, CacheInvalidationNotification>>();
|
|
422
|
+
this._payloadShapeMemo.set(payload, entityMap);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
let roleMap = entityMap.get(entity);
|
|
426
|
+
if (!roleMap) {
|
|
427
|
+
roleMap = new Map<string, CacheInvalidationNotification>();
|
|
428
|
+
entityMap.set(entity, roleMap);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const fingerprint = this.GetRoleFingerprint(user);
|
|
432
|
+
const existing = roleMap.get(fingerprint);
|
|
433
|
+
if (existing) {
|
|
434
|
+
return existing;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const withholdKey = this.ReadIsRowFiltered(entity, user);
|
|
438
|
+
const shaped = this.buildNotification(payload, withholdKey);
|
|
439
|
+
roleMap.set(fingerprint, shaped);
|
|
440
|
+
return shaped;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Assigns the next monotonic sequence number to `payload` (if not already stamped on this server),
|
|
445
|
+
* appends it to the bounded circular ring buffer, and invokes `OnInvalidationRecorded` for
|
|
446
|
+
* provider-specific fan-out.
|
|
447
|
+
*/
|
|
448
|
+
public RecordInvalidation(payload: CacheInvalidationPayload): CacheInvalidationPayload {
|
|
449
|
+
if (!this.ShouldBroadcastEntity(payload.entityName)) {
|
|
450
|
+
return payload;
|
|
451
|
+
}
|
|
452
|
+
if (this._ringBuffer.length === 0) {
|
|
453
|
+
this.Configure(this._config);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const seq = ++this._currentSequence;
|
|
457
|
+
payload.sequence = seq;
|
|
458
|
+
|
|
459
|
+
const writeIndex = (this._ringHead + this._ringCount) % this._maxRingBufferSize;
|
|
460
|
+
if (this._ringCount < this._maxRingBufferSize) {
|
|
461
|
+
this._ringBuffer[writeIndex] = { Sequence: seq, Payload: payload };
|
|
462
|
+
this._ringCount++;
|
|
463
|
+
} else {
|
|
464
|
+
// Buffer full: overwrite oldest at _ringHead and advance head
|
|
465
|
+
this._ringBuffer[this._ringHead] = { Sequence: seq, Payload: payload };
|
|
466
|
+
this._ringHead = (this._ringHead + 1) % this._maxRingBufferSize;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
void this.OnInvalidationRecorded(payload);
|
|
470
|
+
return payload;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Returns all permission-allowed, RLS-shaped invalidation events strictly after `sinceSequence`
|
|
475
|
+
* for `user`. If `sinceSequence` has already been evicted from the ring buffer (or lies in the
|
|
476
|
+
* future due to a server restart), sets `RequiresFullRefresh: true` and returns an empty `Events` list.
|
|
477
|
+
*/
|
|
478
|
+
public GetChangesSince(
|
|
479
|
+
sinceSequence: number,
|
|
480
|
+
user: UserInfo | undefined
|
|
481
|
+
): CacheInvalidationCatchUpResponse {
|
|
482
|
+
if (!user) {
|
|
483
|
+
return {
|
|
484
|
+
RequiresFullRefresh: true,
|
|
485
|
+
CurrentSequence: this._currentSequence,
|
|
486
|
+
ServerProcessID: this.ServerProcessID,
|
|
487
|
+
Events: [],
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (sinceSequence < 0 || sinceSequence > this._currentSequence) {
|
|
492
|
+
return {
|
|
493
|
+
RequiresFullRefresh: true,
|
|
494
|
+
CurrentSequence: this._currentSequence,
|
|
495
|
+
ServerProcessID: this.ServerProcessID,
|
|
496
|
+
Events: [],
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (sinceSequence === this._currentSequence) {
|
|
501
|
+
return {
|
|
502
|
+
RequiresFullRefresh: false,
|
|
503
|
+
CurrentSequence: this._currentSequence,
|
|
504
|
+
ServerProcessID: this.ServerProcessID,
|
|
505
|
+
Events: [],
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (this._ringCount === 0) {
|
|
510
|
+
return {
|
|
511
|
+
RequiresFullRefresh: true,
|
|
512
|
+
CurrentSequence: this._currentSequence,
|
|
513
|
+
ServerProcessID: this.ServerProcessID,
|
|
514
|
+
Events: [],
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const oldestEntry = this._ringBuffer[this._ringHead];
|
|
519
|
+
if (!oldestEntry || sinceSequence < oldestEntry.Sequence - 1) {
|
|
520
|
+
return {
|
|
521
|
+
RequiresFullRefresh: true,
|
|
522
|
+
CurrentSequence: this._currentSequence,
|
|
523
|
+
ServerProcessID: this.ServerProcessID,
|
|
524
|
+
Events: [],
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Coalesce duplicate entity+PK events within the catch-up window (latest event wins)
|
|
529
|
+
const coalescedPayloads = new Map<string, CacheInvalidationPayload>();
|
|
530
|
+
for (let i = 0; i < this._ringCount; i++) {
|
|
531
|
+
const idx = (this._ringHead + i) % this._maxRingBufferSize;
|
|
532
|
+
const entry = this._ringBuffer[idx];
|
|
533
|
+
if (!entry || entry.Sequence <= sinceSequence) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const payload = entry.Payload;
|
|
537
|
+
if (!this.EvaluateEntityReadAccess(payload, user)) {
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
const entity = this.ResolveEntityForPayload(payload);
|
|
541
|
+
const shaped = this.ShapeEventForSubscriber(payload, user, entity);
|
|
542
|
+
// If key is withheld (RLS-filtered), coalesce at whole-entity granularity; otherwise entity + PK
|
|
543
|
+
const dedupKey = shaped.PrimaryKeyValues
|
|
544
|
+
? `${shaped.EntityName.toLowerCase()}::pk::${shaped.PrimaryKeyValues}`
|
|
545
|
+
: `${shaped.EntityName.toLowerCase()}::all`;
|
|
546
|
+
coalescedPayloads.set(dedupKey, payload);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const events: CacheInvalidationNotification[] = [];
|
|
550
|
+
for (const payload of coalescedPayloads.values()) {
|
|
551
|
+
const entity = this.ResolveEntityForPayload(payload);
|
|
552
|
+
events.push(this.ShapeEventForSubscriber(payload, user, entity));
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return {
|
|
556
|
+
RequiresFullRefresh: false,
|
|
557
|
+
CurrentSequence: this._currentSequence,
|
|
558
|
+
ServerProcessID: this.ServerProcessID,
|
|
559
|
+
Events: events,
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Resets the sequence counter and ring buffer. Intended for unit tests.
|
|
565
|
+
*/
|
|
566
|
+
public ResetStateForTesting(): void {
|
|
567
|
+
this._currentSequence = 0;
|
|
568
|
+
this._ringHead = 0;
|
|
569
|
+
this._ringCount = 0;
|
|
570
|
+
this._ringBuffer = new Array<RingBufferEntry | undefined>(this._maxRingBufferSize);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Hook invoked after an invalidation event is sequenced and stored in the ring buffer.
|
|
575
|
+
* Cloud multiplexer providers override this to forward role-bucketed payloads to their
|
|
576
|
+
* external pub/sub infrastructure.
|
|
577
|
+
*/
|
|
578
|
+
protected abstract OnInvalidationRecorded(payload: CacheInvalidationPayload): Promise<void>;
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Negotiates a client broadcast connection (URL, token, and authorized role-bucket groups)
|
|
582
|
+
* for the given authenticated user.
|
|
583
|
+
*/
|
|
584
|
+
public abstract NegotiateClientConnection(
|
|
585
|
+
user: UserInfo,
|
|
586
|
+
defaultGraphQLWsUrl?: string
|
|
587
|
+
): Promise<CacheBroadcastNegotiationResult>;
|
|
588
|
+
|
|
589
|
+
private buildNotification(
|
|
590
|
+
payload: CacheInvalidationPayload,
|
|
591
|
+
withholdKey: boolean
|
|
592
|
+
): CacheInvalidationNotification {
|
|
593
|
+
const notification: CacheInvalidationNotification = {
|
|
594
|
+
EntityName: payload.entityName,
|
|
595
|
+
PrimaryKeyValues: withholdKey ? undefined : (payload.primaryKeyValues ?? undefined),
|
|
596
|
+
Action: payload.action,
|
|
597
|
+
SourceServerID: payload.sourceServerId,
|
|
598
|
+
Timestamp: payload.timestamp,
|
|
599
|
+
OriginSessionID: payload.originSessionId ?? undefined,
|
|
600
|
+
RecordData: withholdKey ? undefined : (payload.recordData ?? undefined),
|
|
601
|
+
};
|
|
602
|
+
if (payload.sequence !== undefined) {
|
|
603
|
+
notification.Sequence = payload.sequence;
|
|
604
|
+
}
|
|
605
|
+
return notification;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Process-wide singleton managing the active {@link BaseCacheInvalidationBroadcastProvider}.
|
|
611
|
+
*
|
|
612
|
+
* Uses `MJGlobal.Instance.ClassFactory` to instantiate the configured provider class
|
|
613
|
+
* (defaulting to `'SequencedRoleBucket'`).
|
|
614
|
+
*/
|
|
615
|
+
export class CacheInvalidationBroadcastManager extends BaseSingleton<CacheInvalidationBroadcastManager> {
|
|
616
|
+
private _provider: BaseCacheInvalidationBroadcastProvider | null = null;
|
|
617
|
+
private _fallbackFactory: (() => BaseCacheInvalidationBroadcastProvider) | null = null;
|
|
618
|
+
|
|
619
|
+
protected constructor() {
|
|
620
|
+
super();
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
public static get Instance(): CacheInvalidationBroadcastManager {
|
|
624
|
+
return super.getInstance<CacheInvalidationBroadcastManager>();
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Registers the default fallback provider factory so `Provider` is always available even
|
|
629
|
+
* before `Configure()` is explicitly called.
|
|
630
|
+
*/
|
|
631
|
+
public RegisterDefaultProviderFactory(factory: () => BaseCacheInvalidationBroadcastProvider): void {
|
|
632
|
+
this._fallbackFactory = factory;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Returns the active broadcast provider, lazily instantiating the default
|
|
637
|
+
* `SequencedRoleBucketBroadcastProvider` if not yet configured.
|
|
638
|
+
*/
|
|
639
|
+
public get Provider(): BaseCacheInvalidationBroadcastProvider {
|
|
640
|
+
if (!this._provider) {
|
|
641
|
+
this.Configure();
|
|
642
|
+
}
|
|
643
|
+
return this._provider!;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Configures and activates a broadcast provider via `MJGlobal.Instance.ClassFactory`.
|
|
648
|
+
*/
|
|
649
|
+
public Configure(config?: CacheBroadcastProviderConfig): BaseCacheInvalidationBroadcastProvider {
|
|
650
|
+
const driverKey = config?.provider?.trim() || 'SequencedRoleBucket';
|
|
651
|
+
let instance = MJGlobal.Instance.ClassFactory.CreateInstance<BaseCacheInvalidationBroadcastProvider>(
|
|
652
|
+
BaseCacheInvalidationBroadcastProvider,
|
|
653
|
+
driverKey
|
|
654
|
+
);
|
|
655
|
+
if (!instance && this._fallbackFactory) {
|
|
656
|
+
instance = this._fallbackFactory();
|
|
657
|
+
}
|
|
658
|
+
if (!instance) {
|
|
659
|
+
throw new Error(
|
|
660
|
+
`Failed to instantiate BaseCacheInvalidationBroadcastProvider for driver '${driverKey}'.`
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
instance.Configure(config);
|
|
664
|
+
this._provider = instance;
|
|
665
|
+
return instance;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Explicitly sets the active provider instance (useful for testing or custom programmatic wiring).
|
|
670
|
+
*/
|
|
671
|
+
public SetProvider(provider: BaseCacheInvalidationBroadcastProvider): void {
|
|
672
|
+
this._provider = provider;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './BaseCacheInvalidationBroadcastProvider.js';
|
|
2
|
+
export * from './providers/SequencedRoleBucketBroadcastProvider.js';
|
|
3
|
+
export * from './providers/AzureWebPubSubBroadcastProvider.js';
|
|
4
|
+
export * from './providers/AWSIoTCoreBroadcastProvider.js';
|
|
5
|
+
export * from './providers/GCPPubSubBroadcastProvider.js';
|