@memberjunction/server 6.2.0-edge.5 → 6.2.0-edge.7
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 +96 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/BridgeHostInstance.d.ts +8 -3
- package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -1
- package/dist/agentSessions/BridgeHostInstance.js +14 -4
- package/dist/agentSessions/BridgeHostInstance.js.map +1 -1
- package/dist/agentSessions/HandoffOfferExpiry.d.ts +10 -0
- package/dist/agentSessions/HandoffOfferExpiry.d.ts.map +1 -0
- package/dist/agentSessions/HandoffOfferExpiry.js +18 -0
- package/dist/agentSessions/HandoffOfferExpiry.js.map +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +34 -11
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +88 -44
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +29 -9
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +62 -16
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/conversationBrowsers.d.ts +61 -0
- package/dist/agentSessions/conversationBrowsers.d.ts.map +1 -0
- package/dist/agentSessions/conversationBrowsers.js +118 -0
- package/dist/agentSessions/conversationBrowsers.js.map +1 -0
- package/dist/agentSessions/sessionDeadline.d.ts +43 -0
- package/dist/agentSessions/sessionDeadline.d.ts.map +1 -0
- package/dist/agentSessions/sessionDeadline.js +68 -0
- package/dist/agentSessions/sessionDeadline.js.map +1 -0
- package/dist/auth/APIKeyScopeAuth.d.ts.map +1 -1
- package/dist/auth/APIKeyScopeAuth.js +5 -4
- package/dist/auth/APIKeyScopeAuth.js.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +2 -0
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +51 -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/loginEmailResolution.d.ts +41 -0
- package/dist/auth/loginEmailResolution.d.ts.map +1 -0
- package/dist/auth/loginEmailResolution.js +47 -0
- package/dist/auth/loginEmailResolution.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +51 -3
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js +130 -13
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +3 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +23 -5
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts +39 -5
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +221 -9
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +1 -1
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +1 -1
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/redeemLanding.d.ts +2 -2
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
- package/dist/auth/magicLink/redeemLanding.js +7 -4
- package/dist/auth/magicLink/redeemLanding.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +39 -3
- package/dist/auth/magicLink/types.d.ts.map +1 -1
- package/dist/auth/magicLink/types.js +0 -4
- package/dist/auth/magicLink/types.js.map +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +1 -0
- package/dist/auth/newUsers.js.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/backgroundSweepConfigUnits.d.ts +231 -0
- package/dist/backgroundSweepConfigUnits.d.ts.map +1 -0
- package/dist/backgroundSweepConfigUnits.js +180 -0
- package/dist/backgroundSweepConfigUnits.js.map +1 -0
- 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 +1402 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +120 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +5 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +64 -12
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts +3 -1
- package/dist/coreRoutes.d.ts.map +1 -1
- package/dist/coreRoutes.js +20 -4
- package/dist/coreRoutes.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +863 -14
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +4167 -62
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +50 -30
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +154 -79
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts +11 -0
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +29 -1
- 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 +93 -11
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +114 -29
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +509 -220
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +15 -3
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +126 -20
- 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/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +262 -84
- package/dist/index.js.map +1 -1
- package/dist/integration/ConnectionPause.d.ts +121 -0
- package/dist/integration/ConnectionPause.d.ts.map +1 -0
- package/dist/integration/ConnectionPause.js +183 -0
- package/dist/integration/ConnectionPause.js.map +1 -0
- package/dist/integration/CustomColumnPromoter.d.ts +72 -6
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +93 -47
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/integration/EntityMapLifecycle.d.ts +78 -4
- package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
- package/dist/integration/EntityMapLifecycle.js +199 -5
- package/dist/integration/EntityMapLifecycle.js.map +1 -1
- package/dist/integration/InactiveRowWarnings.d.ts +31 -0
- package/dist/integration/InactiveRowWarnings.d.ts.map +1 -1
- package/dist/integration/InactiveRowWarnings.js +29 -0
- package/dist/integration/InactiveRowWarnings.js.map +1 -1
- package/dist/integration/ObjectNamesByID.d.ts +28 -0
- package/dist/integration/ObjectNamesByID.d.ts.map +1 -0
- package/dist/integration/ObjectNamesByID.js +87 -0
- package/dist/integration/ObjectNamesByID.js.map +1 -0
- package/dist/integration/PostRestartIntrospect.d.ts +26 -0
- package/dist/integration/PostRestartIntrospect.d.ts.map +1 -0
- package/dist/integration/PostRestartIntrospect.js +27 -0
- package/dist/integration/PostRestartIntrospect.js.map +1 -0
- package/dist/integration/RSUPostRestartProgress.d.ts +176 -0
- package/dist/integration/RSUPostRestartProgress.d.ts.map +1 -0
- package/dist/integration/RSUPostRestartProgress.js +323 -0
- package/dist/integration/RSUPostRestartProgress.js.map +1 -0
- package/dist/integration/RSUProgressBridge.d.ts +41 -2
- package/dist/integration/RSUProgressBridge.d.ts.map +1 -1
- package/dist/integration/RSUProgressBridge.js +84 -1
- package/dist/integration/RSUProgressBridge.js.map +1 -1
- package/dist/integration/RunArtifactAuthorization.d.ts +39 -0
- package/dist/integration/RunArtifactAuthorization.d.ts.map +1 -0
- package/dist/integration/RunArtifactAuthorization.js +45 -0
- package/dist/integration/RunArtifactAuthorization.js.map +1 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts +9 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -1
- package/dist/integration/SchemaRefreshLaunch.js +3 -2
- package/dist/integration/SchemaRefreshLaunch.js.map +1 -1
- package/dist/integration/ScopedFieldsForBuild.d.ts +46 -0
- package/dist/integration/ScopedFieldsForBuild.d.ts.map +1 -0
- package/dist/integration/ScopedFieldsForBuild.js +91 -0
- package/dist/integration/ScopedFieldsForBuild.js.map +1 -0
- package/dist/integration/TargetConfigGuard.d.ts +40 -0
- package/dist/integration/TargetConfigGuard.d.ts.map +1 -0
- package/dist/integration/TargetConfigGuard.js +40 -0
- package/dist/integration/TargetConfigGuard.js.map +1 -0
- 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/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/ownedRealtimeSession.d.ts +8 -6
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.js +14 -6
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
- package/dist/realtimeSessions/sessionAccess.d.ts +103 -11
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
- package/dist/realtimeSessions/sessionAccess.js +147 -22
- 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 +203 -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/visitorIdentity.d.ts.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.js +1 -0
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +20 -1
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +21 -8
- 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 +3 -1
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/requestOrigin.d.ts +22 -0
- package/dist/requestOrigin.d.ts.map +1 -0
- package/dist/requestOrigin.js +60 -0
- package/dist/requestOrigin.js.map +1 -0
- 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 +44 -17
- package/dist/resolvers/AgentSessionResolver.js.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.js +2 -1
- package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.js +2 -0
- package/dist/resolvers/ConversationRunEventsResolver.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/ExecuteRemoteOperationResolver.d.ts +6 -0
- package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts.map +1 -1
- package/dist/resolvers/ExecuteRemoteOperationResolver.js +30 -7
- package/dist/resolvers/ExecuteRemoteOperationResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +28 -0
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +117 -21
- 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 +5 -0
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +13 -4
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +34 -13
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +401 -11
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +2713 -1290
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +13 -2
- package/dist/resolvers/MCPResolver.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.map +1 -1
- package/dist/resolvers/QueryResolver.js +20 -6
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +38 -0
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +184 -88
- 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/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +1 -0
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +22 -2
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +118 -33
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +62 -10
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +224 -39
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +80 -16
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +388 -125
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +5 -3
- package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +19 -18
- package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +7 -5
- 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/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +4 -0
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.js +1 -0
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +17 -2
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +60 -15
- 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/meetingRecordingRegistration.d.ts.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.js +2 -0
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
- 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/MediaAccessKeys.d.ts.map +1 -1
- package/dist/rest/MediaAccessKeys.js +6 -2
- package/dist/rest/MediaAccessKeys.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +11 -5
- package/dist/rest/OAuthCallbackHandler.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 +3 -3
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.js +6 -8
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +6 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +24 -6
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +3 -1
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +11 -2
- package/dist/rest/setupRESTEndpoints.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/DurableEntityActionTaskSubmitter.d.ts.map +1 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js +6 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +2 -26
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphAgentRunner.d.ts +6 -0
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +38 -0
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +5 -0
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +43 -15
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/services/WorkQueueHostService.d.ts +2 -1
- package/dist/services/WorkQueueHostService.d.ts.map +1 -1
- package/dist/services/WorkQueueHostService.js +19 -4
- package/dist/services/WorkQueueHostService.js.map +1 -1
- package/dist/services/workQueueConfig.d.ts +2 -2
- package/dist/services/workQueueConfig.js +5 -5
- package/dist/services/workQueueConfig.js.map +1 -1
- package/dist/sharedCache.js +1 -1
- package/dist/sharedCache.js.map +1 -1
- package/dist/types.d.ts +40 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +98 -98
- package/src/__tests__/APIKeyScopeAuth.test.ts +4 -8
- package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
- package/src/__tests__/ActiveOperations.test.ts +68 -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 +150 -0
- package/src/__tests__/AssertTargetConfigs.test.ts +75 -0
- package/src/__tests__/BatchApplyParity.test.ts +109 -0
- package/src/__tests__/BridgeHostInstance.test.ts +42 -0
- package/src/__tests__/CollectInactiveRowWarnings.test.ts +115 -0
- package/src/__tests__/ConnectionPause.test.ts +192 -0
- package/src/__tests__/ConnectionPauseResolver.test.ts +166 -0
- package/src/__tests__/ConnectionPauseSave.test.ts +143 -0
- package/src/__tests__/CustomColumnPromoterCompletion.test.ts +142 -0
- package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
- package/src/__tests__/DeleteConnectionRemovesPerConnectionCatalog.test.ts +51 -0
- package/src/__tests__/DetachedDiscoveryStart.test.ts +65 -0
- package/src/__tests__/DurableEntityActionTaskSubmitter.test.ts +73 -0
- package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
- package/src/__tests__/EntityMapLifecycle.rekey.test.ts +252 -0
- package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
- package/src/__tests__/ExecuteRemoteOperationResolver.test.ts +213 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +206 -3
- package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
- package/src/__tests__/HandoffOfferExpiry.test.ts +40 -0
- package/src/__tests__/IntegrationRunArtifactAuthorization.test.ts +126 -0
- package/src/__tests__/MagicLinkKeys.test.ts +102 -0
- package/src/__tests__/MediaAccessKeys.test.ts +57 -10
- package/src/__tests__/NewArrivalsDefaultDisabled.test.ts +50 -0
- package/src/__tests__/ObjectNamesByID.test.ts +176 -0
- package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
- package/src/__tests__/PostRestartMapsInCatalogScope.test.ts +146 -0
- package/src/__tests__/QuerySystemUserResolver.childRows.test.ts +80 -0
- package/src/__tests__/QuerySystemUserResolver.collision.test.ts +200 -0
- package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
- package/src/__tests__/QuerySystemUserResolver.permissions.test.ts +132 -0
- package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
- package/src/__tests__/RSUPostRestartProgress.test.ts +343 -0
- package/src/__tests__/RSUProgressBridge.test.ts +188 -5
- package/src/__tests__/RSUStartupSweepWiring.test.ts +30 -0
- package/src/__tests__/ReactivateRefreshMessage.test.ts +10 -3
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +346 -46
- package/src/__tests__/{RefreshAdoptsNewColumns.test.ts → RefreshReportsNewColumns.test.ts} +25 -16
- package/src/__tests__/RemoteBrowserActionRecovery.test.ts +287 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +3 -0
- package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +100 -0
- package/src/__tests__/RemoteBrowserAudioStream.test.ts +3 -0
- package/src/__tests__/RemoteBrowserSnapshot.test.ts +3 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +344 -14
- package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
- package/src/__tests__/ResolverBase.encryptedApiZeroReencrypt.test.ts +307 -0
- package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +227 -0
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +83 -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 +72 -13
- package/src/__tests__/RunAIAgentResolver.consultPredecessor.test.ts +289 -0
- package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
- package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
- package/src/__tests__/RunAIAgentResolver.handoff.test.ts +649 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +19 -27
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +10 -2
- package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +91 -13
- package/src/__tests__/RunTemplateResolver.test.ts +35 -2
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
- package/src/__tests__/SchemaEvolutionCustomColumns.test.ts +119 -0
- package/src/__tests__/SchemaRefreshLaunch.test.ts +24 -2
- package/src/__tests__/ScopedFieldsForBuild.test.ts +192 -0
- package/src/__tests__/SessionJanitor.test.ts +195 -4
- package/src/__tests__/SessionManager.test.ts +164 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +2 -2
- package/src/__tests__/TaskGraphAgentRunner.test.ts +272 -16
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +114 -3
- package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
- package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
- package/src/__tests__/ViewOperationsHandler.test.ts +9 -7
- package/src/__tests__/WidgetSessionService.test.ts +583 -4
- package/src/__tests__/WorkQueueHostService.test.ts +25 -7
- package/src/__tests__/apiRootBoot.test.ts +1 -1
- package/src/__tests__/backgroundSweepConfigUnits.test.ts +153 -0
- package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
- package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +45 -0
- package/src/__tests__/contextRequestOrigin.test.ts +105 -0
- package/src/__tests__/conversationBrowsers.test.ts +62 -0
- package/src/__tests__/fieldSecurityFixtures.ts +91 -0
- package/src/__tests__/globalCors.test.ts +3 -3
- package/src/__tests__/localDevAuth.test.ts +196 -0
- package/src/__tests__/magicLinkExtensionCapabilities.test.ts +413 -0
- package/src/__tests__/orphanedConversationDetailReconciler.start.test.ts +82 -0
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
- package/src/__tests__/ownedRealtimeSession.test.ts +14 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +57 -1
- package/src/__tests__/realtimeRecordingHandler.test.ts +24 -2
- 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 +224 -7
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
- package/src/__tests__/requestOrigin.test.ts +104 -0
- 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__/securityHardeningPr6034.test.ts +120 -0
- package/src/__tests__/sessionDeadline.test.ts +51 -0
- package/src/__tests__/sessionUserClone.test.ts +5 -1
- package/src/__tests__/sharedCache.test.ts +11 -0
- package/src/__tests__/startupSweepOrder.test.ts +40 -0
- package/src/__tests__/unifiedAuth.test.ts +101 -1
- package/src/__tests__/widgetGuestElevation.test.ts +2 -0
- package/src/agentSessions/BridgeHostInstance.ts +20 -5
- package/src/agentSessions/HandoffOfferExpiry.ts +18 -0
- package/src/agentSessions/ReturningVisitorRecap.ts +1 -0
- package/src/agentSessions/SessionJanitor.ts +95 -45
- package/src/agentSessions/SessionManager.ts +73 -20
- package/src/agentSessions/conversationBrowsers.ts +143 -0
- package/src/agentSessions/sessionDeadline.ts +81 -0
- package/src/auth/APIKeyScopeAuth.ts +5 -4
- package/src/auth/AuthProviderCatalogRouter.ts +3 -0
- package/src/auth/__tests__/loginEmailResolution.test.ts +67 -0
- package/src/auth/index.ts +56 -12
- package/src/auth/initializeProviders.ts +43 -1
- package/src/auth/localDevAuth.ts +528 -0
- package/src/auth/loginEmailResolution.ts +67 -0
- package/src/auth/magicLink/MagicLinkKeys.ts +147 -15
- package/src/auth/magicLink/MagicLinkRouter.ts +33 -6
- package/src/auth/magicLink/MagicLinkService.ts +250 -10
- package/src/auth/magicLink/index.ts +1 -1
- package/src/auth/magicLink/redeemLanding.ts +7 -4
- package/src/auth/magicLink/types.ts +38 -3
- package/src/auth/newUsers.ts +1 -0
- package/src/auth/sessionUserClone.ts +3 -2
- package/src/backgroundSweepConfigUnits.ts +213 -0
- 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 +138 -0
- package/src/context.ts +71 -14
- package/src/coreRoutes.ts +29 -7
- package/src/generated/graphql-schemas/__mj.ts +4145 -1193
- package/src/generic/CacheInvalidationResolver.ts +135 -78
- package/src/generic/OrphanedConversationDetailReconciler.ts +36 -3
- package/src/generic/PubSubManager.ts +54 -1
- package/src/generic/PushStatusResolver.ts +108 -11
- package/src/generic/ResolverBase.ts +635 -234
- package/src/generic/RunViewResolver.ts +176 -64
- package/src/generic/actionOutputFieldSecurity.ts +75 -0
- package/src/generic/fieldSecurityTransport.ts +62 -0
- package/src/index.ts +310 -85
- package/src/integration/ConnectionPause.ts +222 -0
- package/src/integration/CustomColumnPromoter.ts +129 -54
- package/src/integration/EntityMapLifecycle.ts +229 -6
- package/src/integration/InactiveRowWarnings.ts +50 -0
- package/src/integration/ObjectNamesByID.ts +97 -0
- package/src/integration/PostRestartIntrospect.ts +49 -0
- package/src/integration/RSUPostRestartProgress.ts +359 -0
- package/src/integration/RSUProgressBridge.ts +85 -2
- package/src/integration/RunArtifactAuthorization.ts +65 -0
- package/src/integration/SchemaRefreshLaunch.ts +12 -2
- package/src/integration/ScopedFieldsForBuild.ts +113 -0
- package/src/integration/TargetConfigGuard.ts +71 -0
- package/src/logging/variablesLoggingMiddleware.ts +59 -3
- package/src/realtimeSessions/README.md +7 -3
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +16 -6
- package/src/realtimeSessions/sessionAccess.ts +211 -25
- 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 +254 -17
- package/src/realtimeWidget/host-identity.ts +1 -1
- package/src/realtimeWidget/visitorIdentity.ts +1 -0
- package/src/realtimeWidget/widgetCore.ts +34 -9
- package/src/realtimeWidget/widgetGuestElevation.ts +3 -1
- package/src/requestOrigin.ts +64 -0
- 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 +50 -18
- package/src/resolvers/AutotagPipelineResolver.ts +2 -1
- package/src/resolvers/ConversationRunEventsResolver.ts +2 -0
- package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
- package/src/resolvers/ExecuteRemoteOperationResolver.ts +41 -9
- package/src/resolvers/FetchEntityVectorsResolver.ts +132 -21
- package/src/resolvers/FileCategoryResolver.ts +1 -0
- package/src/resolvers/FileResolver.ts +14 -4
- package/src/resolvers/GetDataResolver.ts +35 -13
- package/src/resolvers/IntegrationDiscoveryResolver.ts +1570 -209
- package/src/resolvers/MCPResolver.ts +15 -2
- package/src/resolvers/MergeRecordsResolver.ts +23 -2
- package/src/resolvers/PipelineProgressResolver.ts +12 -3
- package/src/resolvers/QueryResolver.ts +20 -6
- package/src/resolvers/QuerySystemUserResolver.ts +207 -99
- package/src/resolvers/RSUResolver.ts +12 -0
- package/src/resolvers/RealtimeBridgeResolver.ts +1 -0
- package/src/resolvers/RealtimeClientSessionResolver.ts +144 -40
- package/src/resolvers/RemoteBrowserActionResolver.ts +252 -37
- package/src/resolvers/RunAIAgentResolver.ts +518 -163
- package/src/resolvers/RunAIPromptResolver.ts +18 -18
- package/src/resolvers/RunTemplateResolver.ts +9 -5
- package/src/resolvers/RunTestResolver.ts +3 -1
- package/src/resolvers/SyncDataResolver.ts +4 -0
- package/src/resolvers/TestQuerySQLResolver.ts +1 -0
- package/src/resolvers/TransactionGroupResolver.ts +66 -15
- package/src/resolvers/UserViewResolver.ts +2 -1
- package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +52 -0
- package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
- package/src/resolvers/meetingRecordingRegistration.ts +2 -0
- package/src/rest/EntityCRUDHandler.ts +22 -5
- package/src/rest/MediaAccessKeys.ts +6 -2
- package/src/rest/OAuthCallbackHandler.ts +13 -5
- package/src/rest/RESTEndpointHandler.ts +8 -5
- package/src/rest/RealtimeRecordingHandler.ts +9 -10
- package/src/rest/ViewOperationsHandler.ts +26 -7
- package/src/rest/setupRESTEndpoints.ts +11 -2
- package/src/serverRoleConfigUnits.ts +48 -0
- package/src/services/DurableEntityActionTaskSubmitter.ts +10 -2
- package/src/services/TaskGraphActionRunner.ts +2 -23
- package/src/services/TaskGraphAgentRunner.ts +43 -0
- package/src/services/TaskGraphContinuationDeliverer.ts +53 -20
- package/src/services/WorkQueueHostService.ts +26 -4
- package/src/services/workQueueConfig.ts +5 -5
- package/src/sharedCache.ts +1 -1
- package/src/types.ts +41 -1
- package/src/services/TaskOrchestration-Integration.md +0 -188
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { Arg, Ctx, Field, Int, ObjectType, Query, Resolver, Root, Subscription } from 'type-graphql';
|
|
3
|
+
import { EntityInfo, Metadata, RecordChangeFieldSecurityProjector, RecordChangesEntityName, UserInfo } from '@memberjunction/core';
|
|
4
|
+
import {
|
|
5
|
+
CacheInvalidationBroadcastManager,
|
|
6
|
+
} from '../broadcast/index.js';
|
|
3
7
|
|
|
4
8
|
export const CACHE_INVALIDATION_TOPIC = 'CACHE_INVALIDATION';
|
|
5
9
|
|
|
@@ -36,22 +40,55 @@ export function ConfigureRecordDataBroadcast(entities: readonly string[] | undef
|
|
|
36
40
|
*
|
|
37
41
|
* The subscription below is filtered only by ENTITY-level read permission, so anything included
|
|
38
42
|
* here is disclosed to every signed-in session that may read the entity at all — regardless of
|
|
39
|
-
* row-level security or any tenant scoping a consumer applies on the read
|
|
40
|
-
* this push traverses. The answer is therefore NO unless a deployment has
|
|
41
|
-
* entity in via `cacheSettings.recordDataBroadcastEntities
|
|
43
|
+
* row-level security, field-level security, or any tenant scoping a consumer applies on the read
|
|
44
|
+
* path, none of which this push traverses. The answer is therefore NO unless a deployment has
|
|
45
|
+
* explicitly opted the entity in via `cacheSettings.recordDataBroadcastEntities`, and always NO
|
|
46
|
+
* for an entity under field-level security (its own flag or an IS-A ancestor's), and for
|
|
47
|
+
* `MJ: Record Changes`, whatever the allowlist says: the row would carry columns (or, for Record
|
|
48
|
+
* Changes, other entities' values) some of those sessions may not read.
|
|
42
49
|
*
|
|
43
50
|
* Callers that get `false` simply omit `recordData`; the event still carries the entity name and
|
|
44
51
|
* primary key, so clients evict and re-fetch through the normal access-controlled read path.
|
|
45
52
|
*
|
|
46
53
|
* Matching is exact (trimmed, case-insensitive) rather than substring: a loose match would let an
|
|
47
54
|
* allowlisted name drag in every entity whose name contains it.
|
|
55
|
+
*
|
|
56
|
+
* @param entityInfo The entity's metadata, when the caller holds it. Otherwise it is looked up by
|
|
57
|
+
* name, so the field-security refusal applies either way.
|
|
48
58
|
*/
|
|
49
|
-
export function MayBroadcastRecordData(entityName: string): boolean {
|
|
59
|
+
export function MayBroadcastRecordData(entityName: string, entityInfo?: EntityInfo | null): boolean {
|
|
50
60
|
if (allowedRecordDataEntities.length === 0) return false;
|
|
61
|
+
if (fieldSecurityApplies(entityName, entityInfo)) return false;
|
|
62
|
+
if (isRecordChanges(entityName, entityInfo)) return false;
|
|
51
63
|
if (allowedRecordDataEntities.includes('*')) return true;
|
|
52
64
|
return allowedRecordDataEntities.includes(entityName.trim().toLowerCase());
|
|
53
65
|
}
|
|
54
66
|
|
|
67
|
+
/** Whether field-level security applies to the entity, resolving it by name when not supplied. */
|
|
68
|
+
function fieldSecurityApplies(entityName: string, entityInfo: EntityInfo | null | undefined): boolean {
|
|
69
|
+
const info = entityInfo ?? lookUpEntity(entityName);
|
|
70
|
+
return Boolean(info?.FieldLevelSecurityApplies);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Whether the entity is the Record Changes audit trail. Its rows carry other entities' values in
|
|
75
|
+
* `ChangesJSON` and `FullRecordJSON`, which are projected per reader, so a row is never broadcast
|
|
76
|
+
* even though field-level security is not switched on for the audit entity itself.
|
|
77
|
+
*/
|
|
78
|
+
function isRecordChanges(entityName: string, entityInfo: EntityInfo | null | undefined): boolean {
|
|
79
|
+
if (entityInfo) return RecordChangeFieldSecurityProjector.IsRecordChangesEntity(entityInfo);
|
|
80
|
+
return entityName.trim().toLowerCase() === RecordChangesEntityName.toLowerCase();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The entity by name from the process's metadata, or undefined when none is loaded. */
|
|
84
|
+
function lookUpEntity(entityName: string): EntityInfo | undefined {
|
|
85
|
+
try {
|
|
86
|
+
return new Metadata().EntityByName(entityName) ?? undefined; // global-provider-ok: metadata lookup for a process-wide broadcast gate
|
|
87
|
+
} catch {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
55
92
|
@ObjectType()
|
|
56
93
|
export class CacheInvalidationNotification {
|
|
57
94
|
@Field(() => String)
|
|
@@ -74,6 +111,48 @@ export class CacheInvalidationNotification {
|
|
|
74
111
|
|
|
75
112
|
@Field(() => String, { nullable: true })
|
|
76
113
|
RecordData?: string;
|
|
114
|
+
|
|
115
|
+
@Field(() => Int, { nullable: true })
|
|
116
|
+
Sequence?: number;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@ObjectType()
|
|
120
|
+
export class CacheInvalidationCatchUpResult {
|
|
121
|
+
@Field(() => Boolean)
|
|
122
|
+
RequiresFullRefresh!: boolean;
|
|
123
|
+
|
|
124
|
+
@Field(() => Int)
|
|
125
|
+
CurrentSequence!: number;
|
|
126
|
+
|
|
127
|
+
@Field(() => String)
|
|
128
|
+
ServerProcessID!: string;
|
|
129
|
+
|
|
130
|
+
@Field(() => [CacheInvalidationNotification])
|
|
131
|
+
Events!: CacheInvalidationNotification[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@ObjectType()
|
|
135
|
+
export class CacheBroadcastConnectionToken {
|
|
136
|
+
@Field(() => String)
|
|
137
|
+
Provider!: string;
|
|
138
|
+
|
|
139
|
+
@Field(() => String)
|
|
140
|
+
Url!: string;
|
|
141
|
+
|
|
142
|
+
@Field(() => String, { nullable: true })
|
|
143
|
+
Token?: string;
|
|
144
|
+
|
|
145
|
+
@Field(() => [String])
|
|
146
|
+
Groups!: string[];
|
|
147
|
+
|
|
148
|
+
@Field(() => String)
|
|
149
|
+
ExpiresAt!: string;
|
|
150
|
+
|
|
151
|
+
@Field(() => String)
|
|
152
|
+
ServerProcessID!: string;
|
|
153
|
+
|
|
154
|
+
@Field(() => Int)
|
|
155
|
+
CurrentSequence!: number;
|
|
77
156
|
}
|
|
78
157
|
|
|
79
158
|
/**
|
|
@@ -88,6 +167,7 @@ export interface CacheInvalidationPayload {
|
|
|
88
167
|
timestamp: Date;
|
|
89
168
|
originSessionId?: string;
|
|
90
169
|
recordData?: string;
|
|
170
|
+
sequence?: number;
|
|
91
171
|
}
|
|
92
172
|
|
|
93
173
|
/**
|
|
@@ -116,39 +196,23 @@ export interface CacheInvalidationFilterContext {
|
|
|
116
196
|
* see the class docblock below.
|
|
117
197
|
*
|
|
118
198
|
* `GetUserPermisions` is an in-memory match of the entity's permission rows against the user's
|
|
119
|
-
* roles,
|
|
120
|
-
*
|
|
199
|
+
* roles, memoized per `(payload, entityName, roleFingerprint)` by the active
|
|
200
|
+
* {@link BaseCacheInvalidationBroadcastProvider} so $N$ connected subscribers sharing $R$ role
|
|
201
|
+
* combinations only run `GetUserPermisions` $R$ times per event.
|
|
121
202
|
*/
|
|
122
203
|
export function CacheInvalidationFilter(data: {
|
|
123
204
|
payload: CacheInvalidationPayload;
|
|
124
205
|
context: CacheInvalidationFilterContext | undefined;
|
|
125
206
|
}): boolean {
|
|
126
207
|
const user = data.context?.userPayload?.userRecord as UserInfo | undefined;
|
|
127
|
-
// FAIL CLOSED on identity, matching `statusUpdatesFilter`. `onConnect` rejects a socket whose
|
|
128
|
-
// token does not validate, so a subscriber with no user record should not exist; if one does,
|
|
129
|
-
// it is the case least deserving of an unfiltered firehose.
|
|
130
208
|
if (!user) {
|
|
131
209
|
return false;
|
|
132
210
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// A pub/sub subscription filter has no per-request provider to thread: it runs on the server's
|
|
140
|
-
// own metadata, which is the one place the entity's permission rows can be answered from.
|
|
141
|
-
const entity = new Metadata().EntityByName(entityName); // global-provider-ok: subscription filter — server-wide metadata, no request-scoped provider exists here
|
|
142
|
-
// DELIVER when the entity is unknown here, deliberately — the opposite of the choice above.
|
|
143
|
-
// A name absent from metadata cannot be permission-checked, and withholding would silently
|
|
144
|
-
// stop invalidating a legitimately cacheable entity, which is a correctness bug rather than a
|
|
145
|
-
// disclosure one. All it discloses is the name and key of something this server cannot
|
|
146
|
-
// describe.
|
|
147
|
-
if (!entity) {
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return entity.GetUserPermisions(user).CanRead;
|
|
211
|
+
return CacheInvalidationBroadcastManager.Instance.Provider.EvaluateEntityReadAccess(
|
|
212
|
+
data.payload,
|
|
213
|
+
user,
|
|
214
|
+
(entityName) => new Metadata().EntityByName(entityName) // global-provider-ok: subscription filter — server-wide metadata, no request-scoped provider exists here
|
|
215
|
+
);
|
|
152
216
|
}
|
|
153
217
|
|
|
154
218
|
/** The part of a permission row and of a user this module reads, so the rule can be tested on plain objects. */
|
|
@@ -174,39 +238,23 @@ export interface RoleHolder {
|
|
|
174
238
|
* The same in-memory match `GetUserPermisions` does, with no I/O, so it can run per subscriber per event.
|
|
175
239
|
*/
|
|
176
240
|
export function ReadIsRowFiltered(entity: { Permissions: ReadonlyArray<ReadPermissionRow> }, user: RoleHolder): boolean {
|
|
177
|
-
|
|
178
|
-
let filteredReads = 0;
|
|
179
|
-
for (const row of entity.Permissions) {
|
|
180
|
-
if (!row.CanRead) continue;
|
|
181
|
-
const isDeny = row.IsDeny ?? (row.Type ?? 'Allow').trim().toLowerCase() === 'deny';
|
|
182
|
-
if (isDeny) continue;
|
|
183
|
-
if (!roles.has((row.RoleID ?? '').trim().toLowerCase())) continue;
|
|
184
|
-
if (!row.ReadRLSFilterID) return false;
|
|
185
|
-
filteredReads += 1;
|
|
186
|
-
}
|
|
187
|
-
return filteredReads > 0;
|
|
241
|
+
return CacheInvalidationBroadcastManager.Instance.Provider.ReadIsRowFiltered(entity, user);
|
|
188
242
|
}
|
|
189
243
|
|
|
190
244
|
/**
|
|
191
245
|
* The event as one subscriber may see it. A subscriber whose read of the entity is row-filtered gets the entity, the action and
|
|
192
246
|
* the time, and neither the key nor the row: "something in this entity changed", which the client already takes as a
|
|
193
247
|
* whole-entity invalidation (a null key on `remote-invalidate`). Everyone else gets the event as published.
|
|
248
|
+
*
|
|
249
|
+
* Memoized per `(payload, entity, roleFingerprint)` via the active broadcast provider so $N$ subscribers
|
|
250
|
+
* sharing $R$ role buckets only allocate and evaluate `ReadIsRowFiltered` $R$ times per event.
|
|
194
251
|
*/
|
|
195
252
|
export function ShapeCacheInvalidationEvent(
|
|
196
253
|
payload: CacheInvalidationPayload,
|
|
197
254
|
user: RoleHolder | undefined,
|
|
198
255
|
entity: { Permissions: ReadonlyArray<ReadPermissionRow> } | null | undefined,
|
|
199
256
|
): CacheInvalidationNotification {
|
|
200
|
-
|
|
201
|
-
return {
|
|
202
|
-
EntityName: payload.entityName,
|
|
203
|
-
PrimaryKeyValues: withholdKey ? undefined : (payload.primaryKeyValues ?? undefined),
|
|
204
|
-
Action: payload.action,
|
|
205
|
-
SourceServerID: payload.sourceServerId,
|
|
206
|
-
Timestamp: payload.timestamp,
|
|
207
|
-
OriginSessionID: payload.originSessionId ?? undefined,
|
|
208
|
-
RecordData: withholdKey ? undefined : (payload.recordData ?? undefined),
|
|
209
|
-
};
|
|
257
|
+
return CacheInvalidationBroadcastManager.Instance.Provider.ShapeEventForSubscriber(payload, user, entity);
|
|
210
258
|
}
|
|
211
259
|
|
|
212
260
|
/** @deprecated Use {@link CacheInvalidationFilter}. */
|
|
@@ -223,30 +271,8 @@ export class CacheInvalidationResolver {
|
|
|
223
271
|
* Subscription that broadcasts cache invalidation events to connected clients, so cross-server
|
|
224
272
|
* cache invalidation reaches browsers.
|
|
225
273
|
*
|
|
226
|
-
* Delivery is filtered
|
|
227
|
-
*
|
|
228
|
-
* other session and tenant.
|
|
229
|
-
*
|
|
230
|
-
* Because that narrowing stops well short of row level, `RecordData` is only populated for entities a
|
|
231
|
-
* deployment has opted in through `cacheSettings.recordDataBroadcastEntities` — see
|
|
232
|
-
* {@link MayBroadcastRecordData}, applied at both publish sites.
|
|
233
|
-
*
|
|
234
|
-
* `EntityName`, `PrimaryKeyValues`, `Action` and `Timestamp` ARE still broadcast to every
|
|
235
|
-
* session, and that is a disclosure, not a safe residue. An earlier version of this comment
|
|
236
|
-
* called them "safe to broadcast" on the grounds that reading the record still goes through
|
|
237
|
-
* the access-controlled path — true of the row's CONTENTS, and beside the point for the
|
|
238
|
-
* metadata itself. A session with no relationship to a record still learns that it exists,
|
|
239
|
-
* its stable key, and every time it changes; across entities it learns the cadence and volume
|
|
240
|
-
* of another tenant's activity.
|
|
241
|
-
*
|
|
242
|
-
* The key is kept for a subscriber who could read the row anyway, because consumers need it to
|
|
243
|
-
* re-read the record they were told about (see `ResolveEntityEventKey` in @memberjunction/core),
|
|
244
|
-
* and the coarse "something in this entity changed" forces whole-entity invalidation on the
|
|
245
|
-
* hottest write paths. It is withheld, with the row, from a subscriber whose every read of the
|
|
246
|
-
* entity goes through a row-level security filter ({@link ReadIsRowFiltered}): a filter the
|
|
247
|
-
* subscription cannot evaluate per event stands between them and the row, so they learn only
|
|
248
|
-
* that a row of the entity changed, and their caches refresh the entity as a whole. That is the
|
|
249
|
-
* same in-memory role match as the entity-level filter, once more per subscriber per event.
|
|
274
|
+
* Delivery is filtered by ENTITY-level read permission (see {@link CacheInvalidationFilter})
|
|
275
|
+
* and shaped per role-fingerprint bucket (see {@link ShapeCacheInvalidationEvent}).
|
|
250
276
|
*/
|
|
251
277
|
@Subscription(() => CacheInvalidationNotification, {
|
|
252
278
|
topics: CACHE_INVALIDATION_TOPIC,
|
|
@@ -258,8 +284,39 @@ export class CacheInvalidationResolver {
|
|
|
258
284
|
@Ctx() context: CacheInvalidationFilterContext | undefined
|
|
259
285
|
): CacheInvalidationNotification {
|
|
260
286
|
const user = context?.userPayload?.userRecord as UserInfo | undefined;
|
|
261
|
-
|
|
262
|
-
const entity = payload?.entityName ?
|
|
263
|
-
return
|
|
287
|
+
const provider = CacheInvalidationBroadcastManager.Instance.Provider;
|
|
288
|
+
const entity = payload?.entityName ? provider.ResolveEntityForPayload(payload) : null;
|
|
289
|
+
return provider.ShapeEventForSubscriber(payload, user, entity);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Returns all permission-allowed, RLS-shaped cache invalidation events strictly after
|
|
294
|
+
* `sinceSequence` from the server's bounded circular ring buffer.
|
|
295
|
+
*
|
|
296
|
+
* Invoked by `GraphQLDataProvider` when an HTTP response's `X-MJ-Cache-Seq` header or a
|
|
297
|
+
* WebSocket reconnect reveals missed invalidation sequence numbers.
|
|
298
|
+
*/
|
|
299
|
+
@Query(() => CacheInvalidationCatchUpResult)
|
|
300
|
+
GetCacheInvalidationsSince(
|
|
301
|
+
@Arg('sinceSequence', () => Int) sinceSequence: number,
|
|
302
|
+
@Ctx() context: CacheInvalidationFilterContext | undefined
|
|
303
|
+
): CacheInvalidationCatchUpResult {
|
|
304
|
+
const user = context?.userPayload?.userRecord as UserInfo | undefined;
|
|
305
|
+
return CacheInvalidationBroadcastManager.Instance.Provider.GetChangesSince(sinceSequence, user);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Negotiates a client broadcast connection (URL, signed token, and authorized role-bucket groups)
|
|
310
|
+
* for the active {@link BaseCacheInvalidationBroadcastProvider}.
|
|
311
|
+
*/
|
|
312
|
+
@Query(() => CacheBroadcastConnectionToken)
|
|
313
|
+
async NegotiateCacheBroadcastConnection(
|
|
314
|
+
@Ctx() context: CacheInvalidationFilterContext | undefined
|
|
315
|
+
): Promise<CacheBroadcastConnectionToken> {
|
|
316
|
+
const user = context?.userPayload?.userRecord as UserInfo | undefined;
|
|
317
|
+
if (!user) {
|
|
318
|
+
throw new Error('Authentication required to negotiate cache broadcast connection.');
|
|
319
|
+
}
|
|
320
|
+
return CacheInvalidationBroadcastManager.Instance.Provider.NegotiateClientConnection(user);
|
|
264
321
|
}
|
|
265
322
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { LogError, LogStatus, RunView } from '@memberjunction/core';
|
|
2
|
-
import { IndexByUUID } from '@memberjunction/global';
|
|
2
|
+
import { IndexByUUID, ShutdownRegistry } from '@memberjunction/global';
|
|
3
|
+
import { DEFAULT_CONVERSATION_DETAIL_RECONCILER_SETTINGS, type ConversationDetailReconcilerSettings } from '../backgroundSweepConfigUnits.js';
|
|
3
4
|
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
4
5
|
import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
5
|
-
import type { MJAIAgentRunEntity, MJConversationDetailEntity } from '@memberjunction/core-entities';
|
|
6
|
+
import type { MJAIAgentRunEntity, MJConversationDetailEntity, MJConversationDetailEntityExtended } from '@memberjunction/core-entities';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Grace period after a run reaches a terminal state before its conversation detail is considered
|
|
@@ -110,7 +111,9 @@ export async function ReconcileOrphanedConversationDetails(
|
|
|
110
111
|
LogError(`[OrphanDetailReconciler] No owner resolved for conversation ${detail.ConversationID}; leaving detail ${detail.ID}`);
|
|
111
112
|
continue;
|
|
112
113
|
}
|
|
113
|
-
const writable = await provider.GetEntityObject<
|
|
114
|
+
const writable = await provider.GetEntityObject<MJConversationDetailEntityExtended>('MJ: Conversation Details', owner);
|
|
115
|
+
// Closing an agent's reply is the server's write: unmarked, the gate refuses any change to what a reply says.
|
|
116
|
+
writable.MarkServerAuthoredReply();
|
|
114
117
|
if (!(await writable.Load(detail.ID))) {
|
|
115
118
|
LogError(`[OrphanDetailReconciler] Could not load detail ${detail.ID} for write`);
|
|
116
119
|
continue;
|
|
@@ -265,3 +268,33 @@ async function loadConversationOwners(
|
|
|
265
268
|
}
|
|
266
269
|
return owners;
|
|
267
270
|
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Runs {@link ReconcileOrphanedConversationDetails} once now (closes what a restart orphaned) and,
|
|
274
|
+
* when `settings.enabled`, again every `settings.sweepIntervalMs` (closes mid-life orphans),
|
|
275
|
+
* registering the timer for graceful shutdown. With `enabled` false only the startup pass runs, so an
|
|
276
|
+
* idle server sends no periodic queries for it (`conversationDetailReconciler`; see the Serverless
|
|
277
|
+
* Database Auto-Pause guide). A failed pass is logged, never thrown.
|
|
278
|
+
*
|
|
279
|
+
* @returns The repeat timer, or `null` when no repeat was scheduled.
|
|
280
|
+
*/
|
|
281
|
+
export function StartOrphanedConversationDetailReconciler(
|
|
282
|
+
provider: IMetadataProvider,
|
|
283
|
+
contextUser: UserInfo,
|
|
284
|
+
settings: ConversationDetailReconcilerSettings = DEFAULT_CONVERSATION_DETAIL_RECONCILER_SETTINGS
|
|
285
|
+
): ReturnType<typeof setInterval> | null {
|
|
286
|
+
const pass = (): void => {
|
|
287
|
+
void ReconcileOrphanedConversationDetails(provider, contextUser)
|
|
288
|
+
.catch(err => LogError(`[OrphanDetailReconciler] Pass failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
289
|
+
};
|
|
290
|
+
pass();
|
|
291
|
+
if (!settings.enabled) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const timer = setInterval(pass, settings.sweepIntervalMs);
|
|
295
|
+
ShutdownRegistry.Instance.Register({
|
|
296
|
+
ShutdownName: 'OrphanDetailReconciler',
|
|
297
|
+
Shutdown: () => { clearInterval(timer); },
|
|
298
|
+
});
|
|
299
|
+
return timer;
|
|
300
|
+
}
|
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
import { PubSubEngine } from 'type-graphql';
|
|
2
2
|
import { BaseSingleton } from '@memberjunction/global';
|
|
3
|
+
import {
|
|
4
|
+
CACHE_INVALIDATION_TOPIC,
|
|
5
|
+
type CacheInvalidationPayload,
|
|
6
|
+
} from './CacheInvalidationResolver.js';
|
|
7
|
+
import {
|
|
8
|
+
GetSessionStatusTopic,
|
|
9
|
+
PUSH_STATUS_UPDATES_TOPIC,
|
|
10
|
+
} from './PushStatusResolver.js';
|
|
11
|
+
import { CacheInvalidationBroadcastManager } from '../broadcast/index.js';
|
|
12
|
+
|
|
13
|
+
const _wrappedPubSubEngines = new WeakSet<PubSubEngine>();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Wraps a TypeGraphQL `PubSubEngine` so that publishes to {@link PUSH_STATUS_UPDATES_TOPIC}
|
|
17
|
+
* carrying a specific `sessionId` (`sessionId !== '*'`) are dynamically routed in $O(1)$ to
|
|
18
|
+
* `PUSH_STATUS_UPDATES:session:<sessionId>` instead of waking every connected browser tab.
|
|
19
|
+
* Wildcard (`sessionId === '*'`) updates continue to publish on {@link PUSH_STATUS_UPDATES_TOPIC}.
|
|
20
|
+
*/
|
|
21
|
+
export function CreateSessionRoutingPubSub(pubSub: PubSubEngine): PubSubEngine {
|
|
22
|
+
if (!pubSub || typeof pubSub.publish !== 'function' || _wrappedPubSubEngines.has(pubSub)) {
|
|
23
|
+
return pubSub;
|
|
24
|
+
}
|
|
25
|
+
const rawPublish = pubSub.publish.bind(pubSub);
|
|
26
|
+
pubSub.publish = async (routingKey: string, payload: unknown): Promise<void> => {
|
|
27
|
+
if (
|
|
28
|
+
routingKey === PUSH_STATUS_UPDATES_TOPIC &&
|
|
29
|
+
typeof payload === 'object' &&
|
|
30
|
+
payload !== null
|
|
31
|
+
) {
|
|
32
|
+
const sessionId = (payload as { sessionId?: unknown }).sessionId;
|
|
33
|
+
if (typeof sessionId === 'string' && sessionId.trim().length > 0 && sessionId.trim() !== '*') {
|
|
34
|
+
await rawPublish(GetSessionStatusTopic(sessionId), payload);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
await rawPublish(routingKey, payload);
|
|
39
|
+
};
|
|
40
|
+
_wrappedPubSubEngines.add(pubSub);
|
|
41
|
+
return pubSub;
|
|
42
|
+
}
|
|
3
43
|
|
|
4
44
|
/**
|
|
5
45
|
* Singleton manager that holds a reference to the type-graphql PubSubEngine,
|
|
@@ -20,9 +60,10 @@ export class PubSubManager extends BaseSingleton<PubSubManager> {
|
|
|
20
60
|
/**
|
|
21
61
|
* Sets the PubSubEngine instance. Should be called once during server startup
|
|
22
62
|
* after buildSchemaSync creates the PubSub instance.
|
|
63
|
+
* Automatically installs $O(1)$ dynamic session routing for `PUSH_STATUS_UPDATES`.
|
|
23
64
|
*/
|
|
24
65
|
public SetPubSubEngine(pubSub: PubSubEngine): void {
|
|
25
|
-
this._pubSub = pubSub;
|
|
66
|
+
this._pubSub = CreateSessionRoutingPubSub(pubSub);
|
|
26
67
|
}
|
|
27
68
|
|
|
28
69
|
/**
|
|
@@ -34,9 +75,21 @@ export class PubSubManager extends BaseSingleton<PubSubManager> {
|
|
|
34
75
|
|
|
35
76
|
/**
|
|
36
77
|
* Publishes a payload to the specified topic via the PubSubEngine.
|
|
78
|
+
* For `CACHE_INVALIDATION`, automatically stamps a monotonic sequence number and
|
|
79
|
+
* records the event in the active {@link BaseCacheInvalidationBroadcastProvider}'s ring buffer.
|
|
37
80
|
* No-op if the PubSubEngine has not been configured yet.
|
|
38
81
|
*/
|
|
39
82
|
public Publish(topic: string, payload: Record<string, unknown>): void {
|
|
83
|
+
if (topic === CACHE_INVALIDATION_TOPIC) {
|
|
84
|
+
const provider = CacheInvalidationBroadcastManager.Instance.Provider;
|
|
85
|
+
const entityName = typeof payload.entityName === 'string' ? payload.entityName : undefined;
|
|
86
|
+
if (!provider.ShouldBroadcastEntity(entityName)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (payload.sequence === undefined) {
|
|
90
|
+
provider.RecordInvalidation(payload as unknown as CacheInvalidationPayload);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
40
93
|
if (this._pubSub) {
|
|
41
94
|
this._pubSub.publish(topic, payload);
|
|
42
95
|
} else {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
1
2
|
import { Arg, Field, ID, ObjectType, PubSubEngine, Resolver, ResolverFilterData, Root, Subscription } from 'type-graphql';
|
|
2
3
|
import { MJGlobal, UUIDsEqual } from '@memberjunction/global';
|
|
3
4
|
import { UserPayload } from '../types.js';
|
|
5
|
+
import { ResolveSessionScopeIdentity, type SessionAccessPrincipal } from '../realtimeSessions/sessionAccess.js';
|
|
4
6
|
|
|
5
7
|
export const PUSH_STATUS_UPDATES_TOPIC = 'PUSH_STATUS_UPDATES';
|
|
6
8
|
|
|
@@ -94,6 +96,57 @@ export function ParseReplicatedStatusUpdate(raw: string, localServerId: string):
|
|
|
94
96
|
return { sessionId, ownerUserId, message: body, SourceServerId: source };
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Returns the $O(1)$ session-scoped pub/sub topic name for a given `sessionId`.
|
|
101
|
+
* Wildcard (`'*'`) or empty session IDs fall back to the broadcast {@link PUSH_STATUS_UPDATES_TOPIC}.
|
|
102
|
+
*/
|
|
103
|
+
export function GetSessionStatusTopic(sessionId: string): string {
|
|
104
|
+
const normalized = sessionId?.trim();
|
|
105
|
+
if (!normalized || normalized === '*') {
|
|
106
|
+
return PUSH_STATUS_UPDATES_TOPIC;
|
|
107
|
+
}
|
|
108
|
+
return `${PUSH_STATUS_UPDATES_TOPIC}:session:${normalized}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface ParsedMessageCacheEntry {
|
|
112
|
+
parsed: Record<string, unknown> | null;
|
|
113
|
+
isJson: boolean;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const _parsedMessageMemo = new WeakMap<PushStatusNotificationPayload, ParsedMessageCacheEntry>();
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Parses and memoizes the JSON `message` envelope on a {@link PushStatusNotificationPayload}
|
|
120
|
+
* in a `WeakMap` so multiple consumers (`ShouldReplicateStatusUpdate`, filters, hooks) never
|
|
121
|
+
* call `JSON.parse` more than once per payload object.
|
|
122
|
+
*/
|
|
123
|
+
export function ParseStatusUpdateMessage(
|
|
124
|
+
payload: PushStatusNotificationPayload
|
|
125
|
+
): ParsedMessageCacheEntry {
|
|
126
|
+
const cached = _parsedMessageMemo.get(payload);
|
|
127
|
+
if (cached) {
|
|
128
|
+
return cached;
|
|
129
|
+
}
|
|
130
|
+
if (!payload.message) {
|
|
131
|
+
const emptyEntry: ParsedMessageCacheEntry = { parsed: null, isJson: false };
|
|
132
|
+
_parsedMessageMemo.set(payload, emptyEntry);
|
|
133
|
+
return emptyEntry;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const raw: unknown = JSON.parse(payload.message);
|
|
137
|
+
const entry: ParsedMessageCacheEntry = {
|
|
138
|
+
parsed: typeof raw === 'object' && raw !== null ? (raw as Record<string, unknown>) : null,
|
|
139
|
+
isJson: true,
|
|
140
|
+
};
|
|
141
|
+
_parsedMessageMemo.set(payload, entry);
|
|
142
|
+
return entry;
|
|
143
|
+
} catch {
|
|
144
|
+
const plainEntry: ParsedMessageCacheEntry = { parsed: null, isJson: false };
|
|
145
|
+
_parsedMessageMemo.set(payload, plainEntry);
|
|
146
|
+
return plainEntry;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
97
150
|
/**
|
|
98
151
|
* Whether an update is worth sending to other server instances.
|
|
99
152
|
*
|
|
@@ -103,10 +156,20 @@ export function ParseReplicatedStatusUpdate(raw: string, localServerId: string):
|
|
|
103
156
|
* Progress and completion are low-rate and each is individually meaningful, which is exactly the
|
|
104
157
|
* kind of message that must survive landing on the wrong replica.
|
|
105
158
|
*/
|
|
106
|
-
export function ShouldReplicateStatusUpdate(
|
|
159
|
+
export function ShouldReplicateStatusUpdate(
|
|
160
|
+
message?: string,
|
|
161
|
+
payload?: PushStatusNotificationPayload
|
|
162
|
+
): boolean {
|
|
107
163
|
if (!message) {
|
|
108
164
|
return false;
|
|
109
165
|
}
|
|
166
|
+
if (payload && payload.message === message) {
|
|
167
|
+
const entry = ParseStatusUpdateMessage(payload);
|
|
168
|
+
if (!entry.isJson) {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
return entry.parsed?.type !== 'StreamingContent';
|
|
172
|
+
}
|
|
110
173
|
try {
|
|
111
174
|
const parsed: unknown = JSON.parse(message);
|
|
112
175
|
const type = (parsed as { type?: unknown })?.type;
|
|
@@ -150,7 +213,7 @@ export function PublishStatusUpdate(pubSub: PubSubEngine, params: StatusUpdatePa
|
|
|
150
213
|
// Fan out to other instances. Only reached by updates originating HERE: a message arriving from
|
|
151
214
|
// the bus is republished straight onto the local topic and never comes back through this
|
|
152
215
|
// function, so there is no loop to break beyond the SourceServerId check on the receiving side.
|
|
153
|
-
if (_publishHook && ShouldReplicateStatusUpdate(params.message)) {
|
|
216
|
+
if (_publishHook && ShouldReplicateStatusUpdate(params.message, payload)) {
|
|
154
217
|
try {
|
|
155
218
|
_publishHook(payload);
|
|
156
219
|
} catch {
|
|
@@ -170,18 +233,47 @@ export interface StatusUpdatesFilterContext {
|
|
|
170
233
|
userPayload?: UserPayload;
|
|
171
234
|
}
|
|
172
235
|
|
|
236
|
+
/**
|
|
237
|
+
* The owner key of a status update for `user`: its user ID, or, for an anonymous visitor, its user ID plus its scope
|
|
238
|
+
* identity (`ResolveSessionScopeIdentity`). Every anonymous visitor shares one Anonymous user and the session id is
|
|
239
|
+
* chosen by the client (`x-session-id`), so the user ID alone would let one visitor receive another's run events.
|
|
240
|
+
* An anonymous visitor with no scope identity gets no key and receives nothing.
|
|
241
|
+
*/
|
|
242
|
+
export function StatusUpdateOwnerKey(user: SessionAccessPrincipal | null | undefined): string {
|
|
243
|
+
if (!user?.ID) {
|
|
244
|
+
return '';
|
|
245
|
+
}
|
|
246
|
+
if (!user.IsMagicLinkAnonymous) {
|
|
247
|
+
return user.ID;
|
|
248
|
+
}
|
|
249
|
+
const scope = ResolveSessionScopeIdentity(user);
|
|
250
|
+
return scope ? `${user.ID.toLowerCase()}|${scope}` : '';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* The owner key a status update is published with: that of the request's user, or, on a payload elevated by
|
|
255
|
+
* `ElevateUserPayload`, of the user the elevated principal stands in for (a public widget guest). The guest's socket
|
|
256
|
+
* is authenticated as the guest, so an update stamped with the elevated system user would never pass
|
|
257
|
+
* {@link StatusUpdatesFilter} and the guest would wait forever for its run to finish.
|
|
258
|
+
*/
|
|
259
|
+
export function StatusUpdateOwnerID(userPayload: UserPayload | undefined): string {
|
|
260
|
+
return StatusUpdateOwnerKey(userPayload?.ElevatedFrom ?? userPayload?.userRecord);
|
|
261
|
+
}
|
|
262
|
+
|
|
173
263
|
/**
|
|
174
264
|
* Filter predicate for the `statusUpdates` subscription. Exported so it can be unit-tested in
|
|
175
265
|
* isolation (it is the security-critical gate). A push reaches a subscriber only when BOTH hold:
|
|
176
|
-
* 1. the push's `sessionId` matches the subscriber's requested `sessionId` (tab routing), AND
|
|
177
|
-
* 2. the push's `ownerUserId` matches the
|
|
178
|
-
* (`context.userPayload.userRecord
|
|
266
|
+
* 1. the push's `sessionId` matches the subscriber's requested `sessionId` (tab routing), or is `'*'`, AND
|
|
267
|
+
* 2. the push's `ownerUserId` matches the owner key ({@link StatusUpdateOwnerKey}) of the subscriber
|
|
268
|
+
* CONNECTION's authenticated identity (`context.userPayload.userRecord`, established once at WS
|
|
269
|
+
* connect): the user ID for a named user, compared as a UUID; for an anonymous visitor, the user ID
|
|
270
|
+
* plus its scope identity, compared exactly because the scope part is case-significant.
|
|
179
271
|
*
|
|
180
272
|
* Condition (2) is the fix for the session-hijack class (B49): `sessionId` is a client-chosen
|
|
181
273
|
* correlation value, so a subscriber who lifts another user's `sessionId` would previously receive
|
|
182
274
|
* their pushes. Binding delivery to the connection's server-authenticated identity means knowing a
|
|
183
|
-
* `sessionId` is no longer sufficient
|
|
184
|
-
* matches.
|
|
275
|
+
* `sessionId` is no longer sufficient; the scope part does the same between anonymous visitors, who all
|
|
276
|
+
* share one Anonymous user. Fails CLOSED — a missing owner or connection key never matches.
|
|
185
277
|
*/
|
|
186
278
|
export function StatusUpdatesFilter(data: {
|
|
187
279
|
payload: PushStatusNotificationPayload;
|
|
@@ -192,11 +284,13 @@ export function StatusUpdatesFilter(data: {
|
|
|
192
284
|
if (payload.sessionId !== '*' && payload.sessionId !== args.sessionId) {
|
|
193
285
|
return false;
|
|
194
286
|
}
|
|
195
|
-
const
|
|
196
|
-
|
|
287
|
+
const connectionUser: SessionAccessPrincipal | undefined = context?.userPayload?.userRecord;
|
|
288
|
+
const connectionKey = StatusUpdateOwnerKey(connectionUser);
|
|
289
|
+
if (!connectionKey || !payload.ownerUserId) {
|
|
197
290
|
return false; // fail closed — no identity on either side means no delivery
|
|
198
291
|
}
|
|
199
|
-
|
|
292
|
+
// An anonymous visitor's key carries its scope identity (case-significant), so it must match exactly.
|
|
293
|
+
return connectionUser?.IsMagicLinkAnonymous ? payload.ownerUserId === connectionKey : UUIDsEqual(payload.ownerUserId, connectionKey);
|
|
200
294
|
}
|
|
201
295
|
|
|
202
296
|
/** @deprecated Use {@link StatusUpdatesFilter}. */
|
|
@@ -211,7 +305,10 @@ export function statusUpdatesFilter(data: {
|
|
|
211
305
|
@Resolver()
|
|
212
306
|
export class PushStatusResolver {
|
|
213
307
|
@Subscription(() => PushStatusNotification, {
|
|
214
|
-
topics:
|
|
308
|
+
topics: ({ args }: { args: PushStatusNotificationArgs }) =>
|
|
309
|
+
args?.sessionId && args.sessionId !== '*'
|
|
310
|
+
? [GetSessionStatusTopic(args.sessionId), PUSH_STATUS_UPDATES_TOPIC]
|
|
311
|
+
: PUSH_STATUS_UPDATES_TOPIC,
|
|
215
312
|
filter: (data: ResolverFilterData<PushStatusNotificationPayload, PushStatusNotificationArgs, StatusUpdatesFilterContext>) =>
|
|
216
313
|
StatusUpdatesFilter(data),
|
|
217
314
|
})
|