@memberjunction/server 6.2.0-edge.5 → 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 +27 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +3 -3
- package/dist/agentSessions/SessionJanitor.js +3 -3
- package/dist/agentSessions/SessionManager.d.ts +15 -5
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +34 -12
- package/dist/agentSessions/SessionManager.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/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/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 +496 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +61 -0
- 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.map +1 -1
- package/dist/coreRoutes.js +14 -0
- package/dist/coreRoutes.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +635 -14
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +3366 -418
- 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.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 +93 -11
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +65 -25
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +201 -101
- 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 +79 -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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -66
- 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/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 +15 -6
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
- package/dist/realtimeSessions/sessionAccess.d.ts +88 -11
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
- package/dist/realtimeSessions/sessionAccess.js +125 -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 +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/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/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/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +45 -7
- 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.map +1 -1
- package/dist/resolvers/QueryResolver.js +20 -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 +16 -2
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +82 -28
- 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 +209 -64
- 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/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/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 +3 -3
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.js +7 -7
- 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 +22 -5
- package/dist/rest/ViewOperationsHandler.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/TaskGraphContinuationDeliverer.d.ts +5 -0
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +42 -15
- package/dist/services/TaskGraphContinuationDeliverer.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 +98 -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__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
- package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +206 -3
- package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -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__/RemoteBrowserActionResolver.ownership.test.ts +98 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +37 -4
- package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
- package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +176 -0
- 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 +68 -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 +17 -27
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +8 -2
- 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__/SessionManager.test.ts +95 -0
- 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 +7 -2
- package/src/__tests__/WidgetSessionService.test.ts +583 -4
- package/src/__tests__/apiRootBoot.test.ts +1 -1
- 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__/fieldSecurityFixtures.ts +91 -0
- package/src/__tests__/globalCors.test.ts +3 -3
- package/src/__tests__/localDevAuth.test.ts +196 -0
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +57 -1
- package/src/__tests__/realtimeRecordingHandler.test.ts +19 -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 +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__/sessionUserClone.test.ts +5 -1
- 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 +3 -3
- package/src/agentSessions/SessionManager.ts +35 -12
- package/src/auth/AuthProviderCatalogRouter.ts +3 -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/magicLink/MagicLinkKeys.ts +2 -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 +69 -0
- package/src/context.ts +32 -8
- package/src/coreRoutes.ts +15 -0
- package/src/generated/graphql-schemas/__mj.ts +2239 -102
- package/src/generic/CacheInvalidationResolver.ts +135 -78
- package/src/generic/OrphanedConversationDetailReconciler.ts +4 -2
- package/src/generic/PubSubManager.ts +54 -1
- package/src/generic/PushStatusResolver.ts +108 -11
- package/src/generic/ResolverBase.ts +237 -107
- package/src/generic/RunViewResolver.ts +80 -15
- package/src/generic/actionOutputFieldSecurity.ts +75 -0
- package/src/generic/fieldSecurityTransport.ts +62 -0
- package/src/index.ts +127 -68
- package/src/integration/CustomColumnPromoter.ts +6 -1
- 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 +20 -6
- package/src/realtimeSessions/sessionAccess.ts +181 -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 +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/EntityCommunicationsResolver.ts +56 -15
- package/src/resolvers/FetchEntityVectorsResolver.ts +132 -21
- package/src/resolvers/FileCategoryResolver.ts +1 -0
- package/src/resolvers/FileResolver.ts +14 -4
- package/src/resolvers/IntegrationDiscoveryResolver.ts +49 -7
- 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 +15 -6
- package/src/resolvers/RSUResolver.ts +12 -0
- package/src/resolvers/RealtimeClientSessionResolver.ts +104 -33
- package/src/resolvers/RemoteBrowserActionResolver.ts +15 -10
- package/src/resolvers/RunAIAgentResolver.ts +258 -82
- package/src/resolvers/RunTemplateResolver.ts +6 -4
- 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__/MergeRecordsResolver.test.ts +43 -0
- package/src/rest/EntityCRUDHandler.ts +22 -5
- package/src/rest/RESTEndpointHandler.ts +8 -5
- package/src/rest/RealtimeRecordingHandler.ts +13 -10
- package/src/rest/ViewOperationsHandler.ts +24 -6
- package/src/serverRoleConfigUnits.ts +48 -0
- package/src/services/TaskGraphContinuationDeliverer.ts +52 -20
- package/src/types.ts +23 -1
package/src/index.ts
CHANGED
|
@@ -38,7 +38,7 @@ import { default as jwt } from 'jsonwebtoken';
|
|
|
38
38
|
import { contextFunction, CreateReadOnlyProvider, CreateUnifiedAuthMiddleware, getUserPayload } from './context.js';
|
|
39
39
|
import { UserPayload } from './types.js';
|
|
40
40
|
import { requireSystemUserDirective, publicDirective } from './directives/index.js';
|
|
41
|
-
import { variablesLoggingMiddleware } from './logging/variablesLoggingMiddleware.js';
|
|
41
|
+
import { ApplyRootVariablesLoggingMiddleware, variablesLoggingMiddleware } from './logging/variablesLoggingMiddleware.js';
|
|
42
42
|
import { auditResolversForUndecoratedArgs } from './logging/bootAudit.js';
|
|
43
43
|
import { StartupLogger } from './logging/StartupLogger.js';
|
|
44
44
|
import { AuthProviderFactory } from '@memberjunction/auth-providers';
|
|
@@ -46,7 +46,7 @@ import createMSSQLConfig from './orm.js';
|
|
|
46
46
|
import { setupRESTEndpoints } from './rest/setupRESTEndpoints.js';
|
|
47
47
|
import { CreateRealtimeRecordingRouter, REALTIME_RECORDING_MOUNT_PATH } from './rest/RealtimeRecordingHandler.js';
|
|
48
48
|
import { LoadOwnedRealtimeSession } from './realtimeSessions/ownedRealtimeSession.js';
|
|
49
|
-
import {
|
|
49
|
+
import { AuthorizeAnonymousRoomSessions, LoadSessionConversationScope } from './realtimeSessions/sessionAccess.js';
|
|
50
50
|
import { RecordingAssemblyScheduler } from './realtimeSessions/RecordingAssemblyScheduler.js';
|
|
51
51
|
import {
|
|
52
52
|
RealtimeSessionEventService,
|
|
@@ -73,11 +73,11 @@ import {
|
|
|
73
73
|
SetHandoffOfferPublishHook,
|
|
74
74
|
ParseReplicatedHandoffOfferUpdate,
|
|
75
75
|
} from './resolvers/HumanHandoffResolver.js';
|
|
76
|
-
import { RoomHandoffEngine } from '@memberjunction/livekit-room-server';
|
|
76
|
+
import { RoomAuthorizationService, RoomHandoffEngine } from '@memberjunction/livekit-room-server';
|
|
77
77
|
// Type-only: the provider is built in ./sharedCache.ts. Still needed here because the handoff-offer
|
|
78
78
|
// fan-out below stays in this file — see the note at its call site.
|
|
79
79
|
import type { RedisLocalStorageProvider } from '@memberjunction/redis-provider';
|
|
80
|
-
import { IntegrationProgressEmitter } from '@memberjunction/integration-progress-artifacts';
|
|
80
|
+
import { IntegrationProgressEmitter, SweepInterruptedRuns } from '@memberjunction/integration-progress-artifacts';
|
|
81
81
|
import { PublishIntegrationProgress } from './resolvers/IntegrationProgressResolver.js';
|
|
82
82
|
import { RegisterRSUProgressBridge } from './integration/RSUProgressBridge.js';
|
|
83
83
|
import { ClientToolRequestManager, AgentRunWatchdog, SqlRealtimeRecordingLedger } from '@memberjunction/ai-agents';
|
|
@@ -103,10 +103,15 @@ import { ApiRoute, ApiRootPath, ConfiguredPublicUrl } from './apiRoot.js';
|
|
|
103
103
|
import { MountHealthcheckRoute, MountPublicCoreRoutes, MountExtensionHealthRoute, MountAuthCatalogRoute, MountAuthenticatedCoreRoutes } from './coreRoutes.js';
|
|
104
104
|
import { MetadataCacheRefreshIntervalSeconds } from './providerConfigUnits.js';
|
|
105
105
|
import { CreateMetadataRefreshSignalHandler, METADATA_REFRESH_SIGNAL } from './metadataRefreshSignal.js';
|
|
106
|
+
import { CacheInvalidationBroadcastManager } from './broadcast/index.js';
|
|
107
|
+
import { ResolveServerRole, ShouldRunBackgroundWorkers } from './serverRoleConfigUnits.js';
|
|
106
108
|
|
|
107
109
|
const cacheRefreshInterval = configInfo.databaseSettings.metadataCacheRefreshInterval;
|
|
108
110
|
|
|
109
111
|
export { MetadataCacheRefreshIntervalSeconds } from './providerConfigUnits.js';
|
|
112
|
+
export * from './serverRoleConfigUnits.js';
|
|
113
|
+
export * from './broadcast/index.js';
|
|
114
|
+
export { ApplyRootVariablesLoggingMiddleware } from './logging/variablesLoggingMiddleware.js';
|
|
110
115
|
|
|
111
116
|
/**
|
|
112
117
|
* Returns the configured database platform from the `DB_PLATFORM` environment
|
|
@@ -432,6 +437,9 @@ export const Serve = async (resolverPaths: Array<string>, app: Application = Cre
|
|
|
432
437
|
SetHostInstancePort(graphqlPort);
|
|
433
438
|
// The realtime bridge engine stamps its bridge rows with the same identity and reconciles orphans by it (#5310).
|
|
434
439
|
BindBridgeEngineHostInstance();
|
|
440
|
+
// An anonymous visitor may join only the LiveKit agent-session room it owns by scope; the room gate cannot import
|
|
441
|
+
// this package's session-access decision, so it is handed in here, before any resolver runs (MJ#6044).
|
|
442
|
+
RoomAuthorizationService.Instance.SetAnonymousSessionOwnerCheck(AuthorizeAnonymousRoomSessions);
|
|
435
443
|
// Level-gated startup logger. Resolves verbosity from telemetry.level (single
|
|
436
444
|
// operator knob). At `standard` (default), per-phase timings are collapsed into
|
|
437
445
|
// the one-line summary; at `verbose`+ each phase prints inline as before.
|
|
@@ -491,6 +499,8 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
491
499
|
// Every API pool carries the statement and idle-in-transaction timeouts from connection #1.
|
|
492
500
|
const pgConnectionConfig = BuildPostgreSQLConnectionConfig(pgEndpoint, configInfo.databaseSettings, 'api');
|
|
493
501
|
const pgPool = new pg.default.Pool(ToPGPoolConfig(pgConnectionConfig));
|
|
502
|
+
// An idle connection the server drops is emitted on the pool; without a listener Node exits.
|
|
503
|
+
pgPool.on('error', (err) => console.error('[PostgreSQL pool] Idle connection error (connection evicted):', err.message));
|
|
494
504
|
|
|
495
505
|
// Verify connection
|
|
496
506
|
const testClient = await pgPool.connect();
|
|
@@ -508,6 +518,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
508
518
|
...ToPGPoolConfig(BuildPostgreSQLConnectionConfig({ ...pgEndpoint, ...pgReadOnlyCredentials }, configInfo.databaseSettings, 'read-only')),
|
|
509
519
|
types: MJPostgresTypes,
|
|
510
520
|
});
|
|
521
|
+
readOnlyPgPool.on('error', (err) => console.error('[PostgreSQL read-only pool] Idle connection error (connection evicted):', err.message));
|
|
511
522
|
const readOnlyTestClient = await readOnlyPgPool.connect();
|
|
512
523
|
try {
|
|
513
524
|
for (const warning of await DescribeReadOnlyLoginOverreach(readOnlyTestClient, mj_core_schema)) {
|
|
@@ -594,6 +605,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
594
605
|
'codegen',
|
|
595
606
|
);
|
|
596
607
|
const codegenPgPool = new pg.default.Pool(ToPGPoolConfig(codegenPgConnectionConfig));
|
|
608
|
+
codegenPgPool.on('error', (err) => console.error('[PostgreSQL CodeGen pool] Idle connection error (connection evicted):', err.message));
|
|
597
609
|
const codegenTestClient = await codegenPgPool.connect();
|
|
598
610
|
await codegenTestClient.query('SELECT 1');
|
|
599
611
|
codegenTestClient.release();
|
|
@@ -632,7 +644,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
632
644
|
startupLog.LogIf('verbose', 'RSU in-process CodeGen runner initialized (PostgreSQL).');
|
|
633
645
|
|
|
634
646
|
// Inject CodeGen output paths for targeted git staging
|
|
635
|
-
const { initializeConfig } = await import('@memberjunction/codegen-lib');
|
|
647
|
+
const { initializeConfig, ResolveAdditionalSchemaInfoPath } = await import('@memberjunction/codegen-lib');
|
|
636
648
|
const cgConfig = initializeConfig(rsuWorkDir);
|
|
637
649
|
const outputPaths = (cgConfig.output ?? []).map((o: { directory: string }) => o.directory);
|
|
638
650
|
RuntimeSchemaManager.Instance.SetCodeGenOutputPaths(outputPaths);
|
|
@@ -641,9 +653,12 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
641
653
|
// Point RSU's soft PK/FK writer at the SAME file CodeGen reads (mj.config.cjs
|
|
642
654
|
// `additionalSchemaInfo`), or RSU writes soft PKs to its own default path while
|
|
643
655
|
// CodeGen reads a different one and skips integration tables with "No primary key found".
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
656
|
+
// Inject the ABSOLUTE path CodeGen resolves (env override, else relative to the mj.config
|
|
657
|
+
// file's directory) so RSU, the resolvers and CodeGen agree whatever their cwd (#5858).
|
|
658
|
+
const resolvedSchemaInfoPath = ResolveAdditionalSchemaInfoPath();
|
|
659
|
+
if (resolvedSchemaInfoPath) {
|
|
660
|
+
RuntimeSchemaManager.Instance.SetAdditionalSchemaInfoPath(resolvedSchemaInfoPath);
|
|
661
|
+
startupLog.LogIf('verbose', `RSU additionalSchemaInfo path: ${resolvedSchemaInfoPath}`);
|
|
647
662
|
} else if (RuntimeSchemaManager.Instance.IsEnabled) {
|
|
648
663
|
// U5 — boot-time assert: RSU is enabled but CodeGen has NO additionalSchemaInfo path
|
|
649
664
|
// configured, so RSU's soft-PK/FK writes land in a file CodeGen never reads. Every
|
|
@@ -651,7 +666,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
651
666
|
// named, and actionable — grep for RSU_ADDITIONAL_SCHEMA_INFO_DIVERGENCE.
|
|
652
667
|
console.error(
|
|
653
668
|
`[RSU_ADDITIONAL_SCHEMA_INFO_DIVERGENCE] Runtime Schema Update is ENABLED but mj.config.cjs has no ` +
|
|
654
|
-
`'additionalSchemaInfo' setting — RSU writes soft PK/FK definitions to '${
|
|
669
|
+
`'additionalSchemaInfo' setting (and RSU_ADDITIONAL_SCHEMA_INFO_PATH is unset) — RSU writes soft PK/FK definitions to '${RuntimeSchemaManager.Instance.AdditionalSchemaInfoPath}' ` +
|
|
655
670
|
`while CodeGen reads none, so resolved soft primary keys will be silently LOST at codegen time. ` +
|
|
656
671
|
`Set 'additionalSchemaInfo' in mj.config.cjs to the same file so the write path and read path agree.`
|
|
657
672
|
);
|
|
@@ -777,7 +792,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
777
792
|
startupLog.LogIf('verbose', 'RSU in-process CodeGen runner initialized.');
|
|
778
793
|
|
|
779
794
|
// Inject CodeGen output paths for targeted git staging
|
|
780
|
-
const { initializeConfig } = await import('@memberjunction/codegen-lib');
|
|
795
|
+
const { initializeConfig, ResolveAdditionalSchemaInfoPath } = await import('@memberjunction/codegen-lib');
|
|
781
796
|
const codegenConfig = initializeConfig(rsuWorkDir);
|
|
782
797
|
const outputPaths = (codegenConfig.output ?? []).map((o: { directory: string }) => o.directory);
|
|
783
798
|
RuntimeSchemaManager.Instance.SetCodeGenOutputPaths(outputPaths);
|
|
@@ -787,14 +802,17 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
787
802
|
// `additionalSchemaInfo`). Without this, RSU writes soft PKs to its own default
|
|
788
803
|
// path while CodeGen reads a different one and skips every integration table
|
|
789
804
|
// with "No primary key found".
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
805
|
+
// Inject the ABSOLUTE path CodeGen resolves (env override, else relative to the mj.config
|
|
806
|
+
// file's directory) so RSU, the resolvers and CodeGen agree whatever their cwd (#5858).
|
|
807
|
+
const resolvedSchemaInfoPath = ResolveAdditionalSchemaInfoPath();
|
|
808
|
+
if (resolvedSchemaInfoPath) {
|
|
809
|
+
RuntimeSchemaManager.Instance.SetAdditionalSchemaInfoPath(resolvedSchemaInfoPath);
|
|
810
|
+
startupLog.LogIf('verbose', `RSU additionalSchemaInfo path: ${resolvedSchemaInfoPath}`);
|
|
793
811
|
} else if (RuntimeSchemaManager.Instance.IsEnabled) {
|
|
794
812
|
// U5 — boot-time assert: write path ≠ read path (see the PostgreSQL branch for detail).
|
|
795
813
|
console.error(
|
|
796
814
|
`[RSU_ADDITIONAL_SCHEMA_INFO_DIVERGENCE] Runtime Schema Update is ENABLED but mj.config.cjs has no ` +
|
|
797
|
-
`'additionalSchemaInfo' setting — RSU writes soft PK/FK definitions to '${
|
|
815
|
+
`'additionalSchemaInfo' setting (and RSU_ADDITIONAL_SCHEMA_INFO_PATH is unset) — RSU writes soft PK/FK definitions to '${RuntimeSchemaManager.Instance.AdditionalSchemaInfoPath}' ` +
|
|
798
816
|
`while CodeGen reads none, so resolved soft primary keys will be silently LOST at codegen time. ` +
|
|
799
817
|
`Set 'additionalSchemaInfo' in mj.config.cjs to the same file so the write path and read path agree.`
|
|
800
818
|
);
|
|
@@ -1030,6 +1048,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1030
1048
|
// config.ts loads and validates at module scope, so importing it there would pull full config
|
|
1031
1049
|
// validation into every import chain that touches the resolver, unit tests included.
|
|
1032
1050
|
ConfigureRecordDataBroadcast(configInfo.cacheSettings?.recordDataBroadcastEntities);
|
|
1051
|
+
CacheInvalidationBroadcastManager.Instance.Configure(configInfo.cacheSettings?.broadcast);
|
|
1033
1052
|
|
|
1034
1053
|
// Global listener: broadcast CACHE_INVALIDATION to all browser clients whenever
|
|
1035
1054
|
// ANY BaseEntity save/delete occurs on this server — regardless of whether it
|
|
@@ -1052,7 +1071,8 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1052
1071
|
// fires for server-internal saves too (agents, actions, orchestrator), which are exactly
|
|
1053
1072
|
// the ones no browser session asked for.
|
|
1054
1073
|
recordData:
|
|
1055
|
-
beEvent.type === 'save' && MayBroadcastRecordData(entityName)
|
|
1074
|
+
beEvent.type === 'save' && MayBroadcastRecordData(entityName, beEvent.baseEntity.EntityInfo)
|
|
1075
|
+
// fls-guard: MayBroadcastRecordData refuses FLS entities and Record Changes
|
|
1056
1076
|
? JSON.stringify(beEvent.baseEntity.GetAll())
|
|
1057
1077
|
: undefined,
|
|
1058
1078
|
});
|
|
@@ -1103,7 +1123,6 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1103
1123
|
scalarsMap: [{ type: Date, scalar: GraphQLTimestamp }],
|
|
1104
1124
|
emitSchemaFile: websiteRunFromPackage !== 1,
|
|
1105
1125
|
pubSub,
|
|
1106
|
-
globalMiddlewares: [variablesLoggingMiddleware],
|
|
1107
1126
|
});
|
|
1108
1127
|
const buildMs = performance.now() - tBuild;
|
|
1109
1128
|
|
|
@@ -1130,6 +1149,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1130
1149
|
auditResolversForUndecoratedArgs();
|
|
1131
1150
|
|
|
1132
1151
|
const tTransform = performance.now();
|
|
1152
|
+
schema = ApplyRootVariablesLoggingMiddleware(schema);
|
|
1133
1153
|
schema = requireSystemUserDirective.transformer(schema);
|
|
1134
1154
|
schema = publicDirective.transformer(schema);
|
|
1135
1155
|
|
|
@@ -1530,11 +1550,29 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1530
1550
|
// ─── GraphQL middleware (contextFunction reads req.userPayload, no re-auth) ─────
|
|
1531
1551
|
app.use(
|
|
1532
1552
|
graphqlRootPath,
|
|
1533
|
-
cors<cors.CorsRequest>(
|
|
1553
|
+
cors<cors.CorsRequest>({
|
|
1554
|
+
exposedHeaders: ['X-MJ-Cache-Seq', 'X-MJ-Server-ID'],
|
|
1555
|
+
}),
|
|
1534
1556
|
BodyParser.json({ limit: '50mb' }),
|
|
1535
1557
|
// Express 5 leaves req.body as undefined for non-JSON or empty bodies;
|
|
1536
1558
|
// Apollo Server's expressMiddleware requires req.body to be defined.
|
|
1537
|
-
|
|
1559
|
+
// Also piggyback the latest monotonic cache invalidation sequence and server process ID
|
|
1560
|
+
// onto every GraphQL HTTP response so clients can detect and recover missed invalidations.
|
|
1561
|
+
(req, res, next) => {
|
|
1562
|
+
if (req.body === undefined) req.body = {};
|
|
1563
|
+
const broadcastProvider = CacheInvalidationBroadcastManager.Instance.Provider;
|
|
1564
|
+
res.setHeader('X-MJ-Cache-Seq', String(broadcastProvider.CurrentSequence));
|
|
1565
|
+
res.setHeader('X-MJ-Server-ID', broadcastProvider.ServerProcessID);
|
|
1566
|
+
const originalWriteHead = res.writeHead.bind(res);
|
|
1567
|
+
res.writeHead = ((...args: Parameters<typeof res.writeHead>) => {
|
|
1568
|
+
if (!res.headersSent) {
|
|
1569
|
+
res.setHeader('X-MJ-Cache-Seq', String(broadcastProvider.CurrentSequence));
|
|
1570
|
+
res.setHeader('X-MJ-Server-ID', broadcastProvider.ServerProcessID);
|
|
1571
|
+
}
|
|
1572
|
+
return originalWriteHead(...args);
|
|
1573
|
+
}) as typeof res.writeHead;
|
|
1574
|
+
next();
|
|
1575
|
+
},
|
|
1538
1576
|
expressMiddleware(apolloServer, {
|
|
1539
1577
|
context: contextFunction({
|
|
1540
1578
|
setupComplete$,
|
|
@@ -1549,9 +1587,26 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1549
1587
|
app.use(mw);
|
|
1550
1588
|
}
|
|
1551
1589
|
|
|
1590
|
+
const serverRole = ResolveServerRole(configInfo.serverRole ?? process.env.MJ_SERVER_ROLE);
|
|
1591
|
+
const runBackgroundWorkers = ShouldRunBackgroundWorkers(serverRole);
|
|
1592
|
+
if (!runBackgroundWorkers) {
|
|
1593
|
+
LogStatus(`[ServerRole] Running in '${serverRole}' mode — background worker services are disabled on this replica.`);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
// Close out run artifacts a dead process left open, BEFORE anything below can start a new run.
|
|
1597
|
+
//
|
|
1598
|
+
// A killed process (OOM killer, SIGKILL, host reboot) never writes its run's terminal result, so
|
|
1599
|
+
// the run reads as in-flight forever: the wizard spins, the active-operations panel shows a step
|
|
1600
|
+
// that will never advance, and no failure is reported anywhere. Sound only before the first new
|
|
1601
|
+
// run: artifacts are process-local, so anything still in flight as THIS process starts belongs
|
|
1602
|
+
// to a process that no longer exists. That is why it runs here, ahead of the scheduler, the
|
|
1603
|
+
// integration sync worker (its Start() polls immediately), the HTTP listener (a request can
|
|
1604
|
+
// start a discovery) and pending RSU work, and why it is awaited. It needs none of them.
|
|
1605
|
+
await SweepInterruptedRuns(undefined, msg => console.warn(msg));
|
|
1606
|
+
|
|
1552
1607
|
// Initialize and start scheduled jobs service if enabled
|
|
1553
1608
|
let scheduledJobsService: ScheduledJobsService | null = null;
|
|
1554
|
-
if (configInfo.scheduledJobs?.enabled) {
|
|
1609
|
+
if (runBackgroundWorkers && configInfo.scheduledJobs?.enabled) {
|
|
1555
1610
|
try {
|
|
1556
1611
|
scheduledJobsService = new ScheduledJobsService(configInfo.scheduledJobs);
|
|
1557
1612
|
await scheduledJobsService.Initialize();
|
|
@@ -1565,7 +1620,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1565
1620
|
// Initialize and start the integration sync worker if enabled (PR 1 item 8).
|
|
1566
1621
|
// Off by default — deployments that don't opt in keep running syncs inline.
|
|
1567
1622
|
let integrationSyncWorker: IntegrationSyncWorkerService | null = null;
|
|
1568
|
-
if (configInfo.integrationSyncWorker?.enabled) {
|
|
1623
|
+
if (runBackgroundWorkers && configInfo.integrationSyncWorker?.enabled) {
|
|
1569
1624
|
try {
|
|
1570
1625
|
integrationSyncWorker = new IntegrationSyncWorkerService(configInfo.integrationSyncWorker);
|
|
1571
1626
|
await integrationSyncWorker.Initialize();
|
|
@@ -1603,52 +1658,55 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1603
1658
|
}
|
|
1604
1659
|
startupLog.PrintSummary();
|
|
1605
1660
|
|
|
1606
|
-
// Process pending RSU work from pre-restart (entity maps, field maps, sync)
|
|
1607
|
-
processRSUPendingWork().catch(err => console.warn(`RSU pending work processing failed: ${err}`));
|
|
1608
|
-
|
|
1609
|
-
// Resume any integration syncs that were orphaned by the previous process restart
|
|
1610
1661
|
const resumeUser = UserCache.Instance.GetSystemUser();
|
|
1611
|
-
if (resumeUser) {
|
|
1612
|
-
IntegrationEngine.Instance.ResumeOrphanedSyncs(resumeUser)
|
|
1613
|
-
.catch(err => console.warn(`[IntegrationEngine] Orphaned sync resume failed: ${err}`));
|
|
1614
|
-
}
|
|
1615
1662
|
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
// cancellation (via ShutdownRegistry) once it begins tracking this process's first live run.
|
|
1620
|
-
if (resumeUser && Metadata.Provider instanceof DatabaseProviderBase) { // global-provider-ok: server startup recovery — one-shot orphaned-run sweep at boot
|
|
1621
|
-
const sweepUser = resumeUser;
|
|
1622
|
-
const sweepProvider = Metadata.Provider; // global-provider-ok: server startup recovery — one-shot orphaned-run sweep at boot
|
|
1623
|
-
AgentRunWatchdog.SweepOrphanedRuns(sweepProvider, sweepUser)
|
|
1624
|
-
.catch(err => console.warn(`[AgentRunWatchdog] Startup sweep failed: ${err}`));
|
|
1625
|
-
|
|
1626
|
-
// The watchdog repairs the RUN; nothing repaired the conversation detail, which is the row the
|
|
1627
|
-
// chat actually renders from (MJ #4222). A process that dies mid-run leaves a terminal run
|
|
1628
|
-
// beside a message that still claims to be generating, and it spins forever for anyone who
|
|
1629
|
-
// opens it. Runs at boot (closes restart orphans) and on a timer (closes mid-life orphans),
|
|
1630
|
-
// mirroring the watchdog's own two-phase shape.
|
|
1631
|
-
const reconcileOrphans = () =>
|
|
1632
|
-
ReconcileOrphanedConversationDetails(sweepProvider, sweepUser)
|
|
1633
|
-
.catch(err => console.warn(`[OrphanDetailReconciler] Pass failed: ${err}`));
|
|
1634
|
-
void reconcileOrphans();
|
|
1635
|
-
const orphanDetailTimer = setInterval(() => void reconcileOrphans(), ORPHAN_DETAIL_SWEEP_INTERVAL_MS);
|
|
1636
|
-
ShutdownRegistry.Instance.Register({
|
|
1637
|
-
ShutdownName: 'OrphanDetailReconciler',
|
|
1638
|
-
Shutdown: () => { clearInterval(orphanDetailTimer); },
|
|
1639
|
-
});
|
|
1640
|
-
}
|
|
1663
|
+
if (runBackgroundWorkers) {
|
|
1664
|
+
// Process pending RSU work from pre-restart (entity maps, field maps, sync)
|
|
1665
|
+
processRSUPendingWork().catch(err => console.warn(`RSU pending work processing failed: ${err}`));
|
|
1641
1666
|
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
//
|
|
1650
|
-
//
|
|
1651
|
-
|
|
1667
|
+
// Resume any integration syncs that were orphaned by the previous process restart
|
|
1668
|
+
if (resumeUser) {
|
|
1669
|
+
IntegrationEngine.Instance.ResumeOrphanedSyncs(resumeUser)
|
|
1670
|
+
.catch(err => console.warn(`[IntegrationEngine] Orphaned sync resume failed: ${err}`));
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
// Force-fail any agent runs left 'Running' by a process that died (restart/crash/OOM) or whose
|
|
1674
|
+
// terminal-state write never landed. Staleness-based, so it never touches runs another healthy
|
|
1675
|
+
// instance is still heart-beating. The watchdog also self-registers for graceful-shutdown
|
|
1676
|
+
// cancellation (via ShutdownRegistry) once it begins tracking this process's first live run.
|
|
1677
|
+
if (resumeUser && Metadata.Provider instanceof DatabaseProviderBase) { // global-provider-ok: server startup recovery — one-shot orphaned-run sweep at boot
|
|
1678
|
+
const sweepUser = resumeUser;
|
|
1679
|
+
const sweepProvider = Metadata.Provider; // global-provider-ok: server startup recovery — one-shot orphaned-run sweep at boot
|
|
1680
|
+
AgentRunWatchdog.SweepOrphanedRuns(sweepProvider, sweepUser)
|
|
1681
|
+
.catch(err => console.warn(`[AgentRunWatchdog] Startup sweep failed: ${err}`));
|
|
1682
|
+
|
|
1683
|
+
// The watchdog repairs the RUN; nothing repaired the conversation detail, which is the row the
|
|
1684
|
+
// chat actually renders from (MJ #4222). A process that dies mid-run leaves a terminal run
|
|
1685
|
+
// beside a message that still claims to be generating, and it spins forever for anyone who
|
|
1686
|
+
// opens it. Runs at boot (closes restart orphans) and on a timer (closes mid-life orphans),
|
|
1687
|
+
// mirroring the watchdog's own two-phase shape.
|
|
1688
|
+
const reconcileOrphans = () =>
|
|
1689
|
+
ReconcileOrphanedConversationDetails(sweepProvider, sweepUser)
|
|
1690
|
+
.catch(err => console.warn(`[OrphanDetailReconciler] Pass failed: ${err}`));
|
|
1691
|
+
void reconcileOrphans();
|
|
1692
|
+
const orphanDetailTimer = setInterval(() => void reconcileOrphans(), ORPHAN_DETAIL_SWEEP_INTERVAL_MS);
|
|
1693
|
+
ShutdownRegistry.Instance.Register({
|
|
1694
|
+
ShutdownName: 'OrphanDetailReconciler',
|
|
1695
|
+
Shutdown: () => { clearInterval(orphanDetailTimer); },
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
// Launch the AI Agent Session janitor: run own-host orphan recovery once at boot, then a periodic tick
|
|
1700
|
+
// that closes stale and over-deadline sessions and rebuilds lost realtime recordings from their
|
|
1701
|
+
// crash-recovery shards (storage reads and writes). Self-registers with ShutdownRegistry, so its timer
|
|
1702
|
+
// is cleared by the gracefulShutdown drain below (no explicit Stop() wiring needed here).
|
|
1703
|
+
if (resumeUser && Metadata.Provider instanceof DatabaseProviderBase) { // global-provider-ok: server startup recovery — boot-time session janitor uses the server's own provider
|
|
1704
|
+
SessionJanitor.Instance.Start(Metadata.Provider, resumeUser) // global-provider-ok: server-owned background reconciler runs under the server's provider + system user
|
|
1705
|
+
.catch(err => console.warn(`[SessionJanitor] Startup failed: ${err}`));
|
|
1706
|
+
// The bridge engine's orphan reconcile likewise starts only now that this process holds its port, so it can't
|
|
1707
|
+
// take the live bridges of another MJAPI still serving that port for its own orphans (#5310).
|
|
1708
|
+
StartBridgeOrphanReconciliation(Metadata.Provider, resumeUser); // global-provider-ok: server-owned background reconciler runs under the server's provider + system user
|
|
1709
|
+
}
|
|
1652
1710
|
}
|
|
1653
1711
|
|
|
1654
1712
|
// Launch the durable task-graph dispatcher: claim Pending tasks, execute them with a fresh
|
|
@@ -1677,7 +1735,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1677
1735
|
// StartTaskGraphDispatcher); this gives the agent seam the same.
|
|
1678
1736
|
SuppressTaskGraphSubmission('MJ_DISABLE_TASK_GRAPH_DISPATCHER=1 is set on this host');
|
|
1679
1737
|
LogStatus('[TaskGraphDispatcher] Disabled by MJ_DISABLE_TASK_GRAPH_DISPATCHER=1 — this process will neither accept nor execute task graphs.');
|
|
1680
|
-
} else if (resumeUser && taskGraphPool instanceof sql.ConnectionPool) {
|
|
1738
|
+
} else if (runBackgroundWorkers && resumeUser && taskGraphPool instanceof sql.ConnectionPool) {
|
|
1681
1739
|
StartTaskGraphDispatcher(taskGraphPool, resumeUser)
|
|
1682
1740
|
.catch(err => console.warn(`[TaskGraphDispatcher] Startup failed: ${err}`));
|
|
1683
1741
|
}
|
|
@@ -1687,7 +1745,7 @@ const setupComplete$ = new ReplaySubject(1);
|
|
|
1687
1745
|
// ShutdownAll() drains it (up to 2 × shutdownDrainMs) before the HTTP server closes.
|
|
1688
1746
|
// Not awaited: a slow engine load must not delay readiness, and a failure never stops the API.
|
|
1689
1747
|
const workQueueProvider = Metadata.Provider; // global-provider-ok: server startup — the work-queue host runs on the server's own provider
|
|
1690
|
-
if (configInfo.workQueue?.enabled && workQueueProvider instanceof DatabaseProviderBase) {
|
|
1748
|
+
if (runBackgroundWorkers && configInfo.workQueue?.enabled && workQueueProvider instanceof DatabaseProviderBase) {
|
|
1691
1749
|
const workQueuePool = dataSources[0]?.dataSource;
|
|
1692
1750
|
const providerSource = new MJServerWorkQueueProviderSource(workQueuePool instanceof sql.ConnectionPool ? workQueuePool : null, workQueueProvider);
|
|
1693
1751
|
StartWorkQueueHost(configInfo.workQueue, workQueueProvider, providerSource)
|
|
@@ -2193,9 +2251,10 @@ function mountRealtimeRecordingRoutes(app: Application): boolean {
|
|
|
2193
2251
|
}
|
|
2194
2252
|
const graceMs = (): number => configInfo.realtime.recordingAssemblyGraceSeconds * 1000;
|
|
2195
2253
|
const systemUser = UserCache.Instance.GetSystemUser();
|
|
2196
|
-
|
|
2254
|
+
const runWorkers = ShouldRunBackgroundWorkers(ResolveServerRole(configInfo.serverRole ?? process.env.MJ_SERVER_ROLE));
|
|
2255
|
+
if (systemUser && runWorkers) {
|
|
2197
2256
|
RecordingAssemblyScheduler.Instance.Start({ Provider: provider, SystemUser: systemUser, GraceMs: graceMs });
|
|
2198
|
-
} else {
|
|
2257
|
+
} else if (!systemUser) {
|
|
2199
2258
|
LogError('[Realtime] Recording assembly scheduler not started: no system user; the session janitor assembles recordings instead');
|
|
2200
2259
|
}
|
|
2201
2260
|
app.use(ApiRoute(REALTIME_RECORDING_MOUNT_PATH), cors<cors.CorsRequest>(), CreateRealtimeRecordingRouter({
|
|
@@ -2204,7 +2263,7 @@ function mountRealtimeRecordingRoutes(app: Application): boolean {
|
|
|
2204
2263
|
return user ? { ContextUser: user, Provider: provider } : null;
|
|
2205
2264
|
},
|
|
2206
2265
|
LoadOwnedSession: LoadOwnedRealtimeSession,
|
|
2207
|
-
|
|
2266
|
+
LoadConversationScope: LoadSessionConversationScope,
|
|
2208
2267
|
CreateLedger: (ledgerProvider, contextUser) => new SqlRealtimeRecordingLedger(ledgerProvider, contextUser),
|
|
2209
2268
|
Scheduler: RecordingAssemblyScheduler.Instance,
|
|
2210
2269
|
GraceMs: graceMs,
|
|
@@ -300,7 +300,12 @@ export class IntegrationCustomColumnPromoter {
|
|
|
300
300
|
// step with the database.
|
|
301
301
|
let batchResults: RSUPipelineResult[] = [];
|
|
302
302
|
if (batchInputs.length > 0) {
|
|
303
|
-
|
|
303
|
+
// Retrying variant. This runs UNATTENDED, mid-sync, with no operator watching: a
|
|
304
|
+
// transient ExecuteMigration / RunCodeGen / CompileTypeScript / RestartMJAPI failure
|
|
305
|
+
// drops the whole promotion, and the columns simply stay in overflow until something
|
|
306
|
+
// triggers a promotion again. The wrapper replays only those four steps and only while
|
|
307
|
+
// nothing in the batch was applied, so a partially-applied batch is still returned as-is.
|
|
308
|
+
const batch = await RuntimeSchemaManager.Instance.RunPipelineBatchWithRetry(batchInputs);
|
|
304
309
|
batchResults = batch.Results ?? [];
|
|
305
310
|
// M3: make the freshly-created EntityFields + regenerated sprocs visible in-process
|
|
306
311
|
// ONCE for the whole batch. CRITICAL: the spread below builds sproc calls from this
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { MiddlewareFn } from 'type-graphql';
|
|
1
|
+
import type { MiddlewareFn, ResolverData } from 'type-graphql';
|
|
2
2
|
import { getMetadataStorage } from 'type-graphql';
|
|
3
|
-
import { getNamedType } from 'graphql';
|
|
4
|
-
import type { GraphQLArgument } from 'graphql';
|
|
3
|
+
import { defaultFieldResolver, getNamedType } from 'graphql';
|
|
4
|
+
import type { GraphQLArgument, GraphQLField, GraphQLObjectType, GraphQLSchema } from 'graphql';
|
|
5
5
|
import { configInfo } from '../config.js';
|
|
6
6
|
import type { AppContext } from '../types.js';
|
|
7
7
|
import { RedactArg } from './secretRedactor.js';
|
|
@@ -191,6 +191,62 @@ export const VariablesLoggingMiddleware: MiddlewareFn<AppContext> = async (actio
|
|
|
191
191
|
/** @deprecated Use {@link VariablesLoggingMiddleware}. */
|
|
192
192
|
export const variablesLoggingMiddleware: MiddlewareFn<AppContext> = VariablesLoggingMiddleware;
|
|
193
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Attaches {@link VariablesLoggingMiddleware} ONLY to root `Query`, `Mutation`, and `Subscription`
|
|
196
|
+
* fields on the compiled GraphQLSchema instead of registering it via TypeGraphQL `globalMiddlewares`.
|
|
197
|
+
*
|
|
198
|
+
* Registering a global middleware in TypeGraphQL wraps every scalar and child field resolver across
|
|
199
|
+
* all 300+ `@ObjectType` entities in an async middleware chain, allocating $O(\text{Rows} \times \text{Fields})$
|
|
200
|
+
* Promises per query even when `logVariables` is false or `info.path.prev !== undefined`.
|
|
201
|
+
* Wrapping only the root operation fields reduces middleware invocations from ~15,000 per 500-row
|
|
202
|
+
* `RunView` response down to 1.
|
|
203
|
+
*/
|
|
204
|
+
export function ApplyRootVariablesLoggingMiddleware(
|
|
205
|
+
schema: GraphQLSchema,
|
|
206
|
+
middleware: MiddlewareFn<AppContext> = VariablesLoggingMiddleware
|
|
207
|
+
): GraphQLSchema {
|
|
208
|
+
const rootTypes: Array<GraphQLObjectType | null | undefined> = [
|
|
209
|
+
schema.getQueryType(),
|
|
210
|
+
schema.getMutationType(),
|
|
211
|
+
schema.getSubscriptionType(),
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
for (const rootType of rootTypes) {
|
|
215
|
+
if (!rootType) continue;
|
|
216
|
+
const fields = rootType.getFields();
|
|
217
|
+
for (const field of Object.values(fields) as Array<GraphQLField<unknown, AppContext>>) {
|
|
218
|
+
if (field.resolve) {
|
|
219
|
+
const originalResolve = field.resolve;
|
|
220
|
+
field.resolve = (root, args, context, info) => {
|
|
221
|
+
const action: ResolverData<AppContext> = {
|
|
222
|
+
root,
|
|
223
|
+
args: args as Record<string, unknown>,
|
|
224
|
+
context,
|
|
225
|
+
info,
|
|
226
|
+
};
|
|
227
|
+
return middleware(action, async () => originalResolve(root, args, context, info));
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (field.subscribe) {
|
|
231
|
+
const originalSubscribe = field.subscribe;
|
|
232
|
+
field.subscribe = (root, args, context, info) => {
|
|
233
|
+
const action: ResolverData<AppContext> = {
|
|
234
|
+
root,
|
|
235
|
+
args: args as Record<string, unknown>,
|
|
236
|
+
context,
|
|
237
|
+
info,
|
|
238
|
+
};
|
|
239
|
+
return middleware(action, async () =>
|
|
240
|
+
originalSubscribe ? originalSubscribe(root, args, context, info) : defaultFieldResolver(root, args, context, info)
|
|
241
|
+
);
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return schema;
|
|
248
|
+
}
|
|
249
|
+
|
|
194
250
|
/**
|
|
195
251
|
* Heuristic: an arg is "custom" (i.e. needs `@NoLog` discipline because metadata can't redact it)
|
|
196
252
|
* when its GraphQL input type is not a known `Create<X>Input` / `Update<X>Input` for an entity
|
|
@@ -64,9 +64,13 @@ The principal comes from the **server-authenticated** context (`userPayload.user
|
|
|
64
64
|
argument. An id argument only selects *which of the caller's own sessions*.
|
|
65
65
|
|
|
66
66
|
A caller may use a session when `AIAgentSession.UserID` equals their user (`UUIDsEqual`). Widget guests all
|
|
67
|
-
share one Anonymous user, so for an anonymous/magic-link principal that is **not enough**: the
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
share one Anonymous user, so for an anonymous/magic-link principal that is **not enough**: the session's
|
|
68
|
+
conversation `ExternalID` must equal the principal's scope identity (`ResolveSessionScopeIdentity`): the
|
|
69
|
+
signed `MagicLinkScope.ResourceID` when the token carries one, else the anonymous visitor's `mj_sid`.
|
|
70
|
+
`SessionManager` stamps that same value when it creates the conversation. An anonymous principal with
|
|
71
|
+
neither is refused outright. A *named* user with a resource scope must match too, which keeps one person's
|
|
72
|
+
different links apart; but it may also use its own session on a conversation that carries no stamp (one
|
|
73
|
+
started from the Conversations app) when its own row-level security let it read that conversation.
|
|
70
74
|
|
|
71
75
|
- Refusals are uniform ("session not found") whether the session is missing or simply not yours, so ids
|
|
72
76
|
cannot be probed.
|
|
@@ -54,6 +54,7 @@ function toSnapshot(loaded: LoadedSessionForAccess): SessionSnapshot {
|
|
|
54
54
|
AgentSessionID: Session.ID,
|
|
55
55
|
OwnerUserID: Session.UserID,
|
|
56
56
|
ConversationExternalID: loaded.ConversationExternalID,
|
|
57
|
+
ConversationReadable: loaded.ConversationReadable,
|
|
57
58
|
Status: Session.Status,
|
|
58
59
|
ConfigRaw: Session.Config_,
|
|
59
60
|
// `__mj_CreatedAt` is the row's creation instant — i.e. the session start. It is read-only and
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { IMetadataProvider, LogError, UserInfo } from '@memberjunction/core';
|
|
9
9
|
import { UUIDsEqual } from '@memberjunction/global';
|
|
10
10
|
import type { MJAIAgentSessionEntity } from '@memberjunction/core-entities';
|
|
11
|
+
import { AuthorizeSessionAccess, LoadSessionConversationScope } from './sessionAccess.js';
|
|
11
12
|
|
|
12
13
|
const SESSION_ENTITY = 'MJ: AI Agent Sessions';
|
|
13
14
|
|
|
@@ -19,7 +20,7 @@ export class RealtimeSessionNotFoundError extends Error {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
/** The session exists but
|
|
23
|
+
/** The session exists but the caller may not use it: another user owns it, or (for a scoped or anonymous caller) its conversation carries another scope identity. */
|
|
23
24
|
export class RealtimeSessionOwnershipError extends Error {
|
|
24
25
|
constructor(public readonly AgentSessionID: string) {
|
|
25
26
|
super('Not authorized: you do not own this realtime session');
|
|
@@ -28,13 +29,15 @@ export class RealtimeSessionOwnershipError extends Error {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
|
-
* Loads a session under the caller's identity and enforces ownership
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
32
|
+
* Loads a session under the caller's identity and enforces ownership: `UserID === contextUser.ID`, then the
|
|
33
|
+
* scope rule of {@link AuthorizeSessionAccess} (every anonymous visitor shares one Anonymous user, so the
|
|
34
|
+
* session's conversation `ExternalID` must equal the caller's scope identity). It deliberately does NOT
|
|
35
|
+
* reject `Closed` sessions: the final channel-state flush and the recording terminal signal legitimately
|
|
36
|
+
* arrive after the session closed. Loading as the caller also applies the entity's row-level security.
|
|
35
37
|
*
|
|
36
38
|
* @throws RealtimeSessionNotFoundError when the row does not load
|
|
37
|
-
* @throws RealtimeSessionOwnershipError when
|
|
39
|
+
* @throws RealtimeSessionOwnershipError when another user owns the session (logged with both user ids) or
|
|
40
|
+
* the scope rule refuses the caller (logged with the refusal reason)
|
|
38
41
|
*/
|
|
39
42
|
export async function LoadOwnedRealtimeSession(
|
|
40
43
|
agentSessionId: string,
|
|
@@ -51,5 +54,16 @@ export async function LoadOwnedRealtimeSession(
|
|
|
51
54
|
);
|
|
52
55
|
throw new RealtimeSessionOwnershipError(agentSessionId);
|
|
53
56
|
}
|
|
57
|
+
const conversation = await LoadSessionConversationScope(session, contextUser, provider);
|
|
58
|
+
const access = AuthorizeSessionAccess(
|
|
59
|
+
{ SessionUserID: session.UserID, ConversationExternalID: conversation.ExternalID, ConversationReadable: conversation.Readable },
|
|
60
|
+
contextUser,
|
|
61
|
+
);
|
|
62
|
+
if (!access.Allowed) {
|
|
63
|
+
LogError(
|
|
64
|
+
`LoadOwnedRealtimeSession: session access refused (${access.Reason}) — user ${contextUser.ID} attempted to operate on session ${agentSessionId}`,
|
|
65
|
+
);
|
|
66
|
+
throw new RealtimeSessionOwnershipError(agentSessionId);
|
|
67
|
+
}
|
|
54
68
|
return session;
|
|
55
69
|
}
|