@memberjunction/server 6.2.0-edge.4 → 6.2.0-edge.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +91 -30
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +311 -81
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +17 -3
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +44 -10
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/apiRoot.d.ts +32 -0
- package/dist/apiRoot.d.ts.map +1 -0
- package/dist/apiRoot.js +67 -0
- package/dist/apiRoot.js.map +1 -0
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +27 -0
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/LoginScreenEngine.d.ts +22 -0
- package/dist/auth/LoginScreenEngine.d.ts.map +1 -0
- package/dist/auth/LoginScreenEngine.js +57 -0
- package/dist/auth/LoginScreenEngine.js.map +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +52 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +10 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +37 -1
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/localDevAuth.d.ts +79 -0
- package/dist/auth/localDevAuth.d.ts.map +1 -0
- package/dist/auth/localDevAuth.js +439 -0
- package/dist/auth/localDevAuth.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +2 -2
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +3 -2
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +12 -0
- package/dist/auth/magicLink/types.d.ts.map +1 -1
- package/dist/auth/sessionUserClone.d.ts +1 -1
- package/dist/auth/sessionUserClone.d.ts.map +1 -1
- package/dist/auth/sessionUserClone.js +3 -2
- package/dist/auth/sessionUserClone.js.map +1 -1
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts +292 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +442 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -0
- package/dist/broadcast/index.d.ts +6 -0
- package/dist/broadcast/index.d.ts.map +1 -0
- package/dist/broadcast/index.js +6 -0
- package/dist/broadcast/index.js.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts +43 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js +144 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts +46 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js +149 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts +49 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js +131 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts +24 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js +51 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js.map +1 -0
- package/dist/cache.d.ts +3 -2
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +632 -22
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +104 -4
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +3 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +29 -8
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts +29 -0
- package/dist/coreRoutes.d.ts.map +1 -0
- package/dist/coreRoutes.js +156 -0
- package/dist/coreRoutes.js.map +1 -0
- package/dist/generated/graphql-schemas/__mj.d.ts +1016 -29
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +5125 -434
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +85 -30
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +175 -60
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +2 -0
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/PubSubManager.d.ts +10 -0
- package/dist/generic/PubSubManager.d.ts.map +1 -1
- package/dist/generic/PubSubManager.js +44 -1
- package/dist/generic/PubSubManager.js.map +1 -1
- package/dist/generic/PushStatusResolver.d.ts +39 -6
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +94 -12
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +168 -69
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +464 -405
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +11 -3
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +91 -13
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/generic/actionOutputFieldSecurity.d.ts +26 -0
- package/dist/generic/actionOutputFieldSecurity.d.ts.map +1 -0
- package/dist/generic/actionOutputFieldSecurity.js +47 -0
- package/dist/generic/actionOutputFieldSecurity.js.map +1 -0
- package/dist/generic/fieldSecurityTransport.d.ts +30 -0
- package/dist/generic/fieldSecurityTransport.d.ts.map +1 -0
- package/dist/generic/fieldSecurityTransport.js +30 -0
- package/dist/generic/fieldSecurityTransport.js.map +1 -0
- package/dist/globalCors.d.ts +33 -0
- package/dist/globalCors.d.ts.map +1 -0
- package/dist/globalCors.js +58 -0
- package/dist/globalCors.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +230 -222
- package/dist/index.js.map +1 -1
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +6 -1
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.d.ts +12 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.js +50 -1
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
- package/dist/multiTenancy/index.d.ts.map +1 -1
- package/dist/multiTenancy/index.js +22 -2
- package/dist/multiTenancy/index.js.map +1 -1
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -1
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js +2 -1
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -1
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -1
- package/dist/realtimeSessions/RealtimeVerifyRouter.js +2 -1
- package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -1
- package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts +100 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts.map +1 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.js +173 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.js.map +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -1
- package/dist/realtimeSessions/SessionVerificationPortsBase.js +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -1
- package/dist/realtimeSessions/index.d.ts +2 -0
- package/dist/realtimeSessions/index.d.ts.map +1 -1
- package/dist/realtimeSessions/index.js +2 -0
- package/dist/realtimeSessions/index.js.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts +32 -0
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js +56 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
- package/dist/realtimeSessions/sessionAccess.d.ts +91 -8
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
- package/dist/realtimeSessions/sessionAccess.js +127 -20
- package/dist/realtimeSessions/sessionAccess.js.map +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.js +5 -2
- package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.d.ts +2 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.js +19 -3
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts +67 -7
- package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.js +201 -19
- package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
- package/dist/realtimeWidget/host-identity.d.ts +1 -1
- package/dist/realtimeWidget/host-identity.js +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +20 -1
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +17 -1
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +2 -1
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +19 -1
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +63 -12
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +1 -0
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.d.ts +18 -4
- package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.js +32 -8
- package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
- package/dist/resolvers/AgentSessionResolver.d.ts +10 -4
- package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/AgentSessionResolver.js +40 -17
- package/dist/resolvers/AgentSessionResolver.js.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts +5 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.js +9 -7
- package/dist/resolvers/ArtifactFileResolver.js.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.d.ts +8 -4
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.js +6 -6
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
- package/dist/resolvers/DatasetResolver.d.ts +24 -3
- package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
- package/dist/resolvers/DatasetResolver.js +57 -8
- package/dist/resolvers/DatasetResolver.js.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts +13 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.js +50 -14
- package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +3 -2
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +46 -3
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +211 -50
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +1 -0
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +87 -11
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +292 -105
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
- package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js +117 -38
- package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +6 -3
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +49 -9
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +8 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +31 -3
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.d.ts +6 -0
- package/dist/resolvers/PipelineProgressResolver.d.ts.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.js +5 -3
- package/dist/resolvers/PipelineProgressResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts +2 -0
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +33 -6
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +2 -0
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +15 -6
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RSUResolver.d.ts.map +1 -1
- package/dist/resolvers/RSUResolver.js +12 -0
- package/dist/resolvers/RSUResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +18 -10
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +92 -54
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +11 -9
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +56 -8
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +241 -67
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +4 -4
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTestResolver.js +3 -1
- package/dist/resolvers/RunTestResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts +12 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.js +15 -2
- package/dist/resolvers/SearchKnowledgeStreamResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +2 -3
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +4 -0
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts +2 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.js +28 -1
- package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.d.ts +24 -0
- package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.js +66 -13
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +34 -2
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +150 -27
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts +1 -1
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js +2 -1
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/resolvers/agent-run-data-guard.d.ts +31 -0
- package/dist/resolvers/agent-run-data-guard.d.ts.map +1 -0
- package/dist/resolvers/agent-run-data-guard.js +72 -0
- package/dist/resolvers/agent-run-data-guard.js.map +1 -0
- package/dist/rest/EntityCRUDHandler.d.ts +6 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +19 -5
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +8 -5
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.d.ts +49 -0
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -0
- package/dist/rest/RealtimeRecordingHandler.js +383 -0
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -0
- package/dist/rest/ViewOperationsHandler.d.ts +9 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +43 -17
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +6 -0
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +6 -0
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverExtensionReservedRoots.d.ts +12 -10
- package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
- package/dist/serverExtensionReservedRoots.js +14 -17
- package/dist/serverExtensionReservedRoots.js.map +1 -1
- package/dist/serverRoleConfigUnits.d.ts +29 -0
- package/dist/serverRoleConfigUnits.d.ts.map +1 -0
- package/dist/serverRoleConfigUnits.js +33 -0
- package/dist/serverRoleConfigUnits.js.map +1 -0
- package/dist/services/MJStorageBlobStore.d.ts +8 -1
- package/dist/services/MJStorageBlobStore.d.ts.map +1 -1
- package/dist/services/MJStorageBlobStore.js +25 -19
- package/dist/services/MJStorageBlobStore.js.map +1 -1
- package/dist/services/StartTaskGraphDispatcher.js +2 -2
- package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +5 -3
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +27 -5
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphAgentRunner.d.ts +14 -2
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +157 -9
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +59 -2
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +626 -16
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/sharedCache.d.ts.map +1 -1
- package/dist/sharedCache.js +3 -0
- package/dist/sharedCache.js.map +1 -1
- package/dist/types.d.ts +23 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +99 -98
- package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
- package/src/__tests__/AdhocQueryResolver.dialect.test.ts +137 -0
- package/src/__tests__/AgentRunStatusPublisher.test.ts +49 -0
- package/src/__tests__/AgentSessionResolver.ownership.test.ts +137 -0
- package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
- package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
- package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
- package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
- package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +369 -18
- package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
- package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
- package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
- package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
- package/src/__tests__/LoginScreenEngine.test.ts +86 -0
- package/src/__tests__/MJStorageBlobStore.storageGate.test.ts +63 -0
- package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
- package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
- package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +324 -46
- package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
- package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +98 -0
- package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
- package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
- package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +243 -7
- package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
- package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +176 -0
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +23 -1
- package/src/__tests__/ResolverBase.publishStatusUpdate.test.ts +68 -0
- package/src/__tests__/ResolverBase.userViewCacheAndDedup.test.ts +130 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +69 -13
- package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
- package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +20 -28
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +264 -0
- package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +4 -1
- package/src/__tests__/RunTemplateResolver.test.ts +35 -2
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
- package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
- package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
- package/src/__tests__/SessionJanitor.test.ts +365 -10
- package/src/__tests__/SessionManager.test.ts +122 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
- package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +468 -23
- package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
- package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
- package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
- package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
- package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
- package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
- package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
- package/src/__tests__/ViewOperationsHandler.test.ts +7 -2
- package/src/__tests__/WidgetSessionService.test.ts +583 -4
- package/src/__tests__/agent-run-data-guard.test.ts +130 -0
- package/src/__tests__/apiRootBoot.test.ts +202 -0
- package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
- package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +109 -0
- package/src/__tests__/conversationRunEvents.test.ts +56 -14
- package/src/__tests__/fieldSecurityFixtures.ts +91 -0
- package/src/__tests__/globalCors.test.ts +217 -0
- package/src/__tests__/localDevAuth.test.ts +196 -0
- package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
- package/src/__tests__/multiTenancy.security.test.ts +51 -0
- package/src/__tests__/multiTenancy.test.ts +1 -1
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
- package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +64 -1
- package/src/__tests__/realtimeRecordingHandler.test.ts +669 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +29 -1
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.anonymous.test.ts +31 -0
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.namedScoped.test.ts +37 -0
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +146 -7
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
- package/src/__tests__/resolverBase.cloudEventChangedFields.test.ts +157 -0
- package/src/__tests__/resolverBase.fieldSecurityTransport.test.ts +222 -0
- package/src/__tests__/resolverBase.fls.test.ts +146 -97
- package/src/__tests__/restTransport.fieldSecurity.test.ts +148 -0
- package/src/__tests__/runParamsTimeZone.test.ts +179 -0
- package/src/__tests__/runStreams.fieldSecurity.test.ts +100 -0
- package/src/__tests__/runViewProperties.test.ts +114 -0
- package/src/__tests__/scalabilityBenchmarks.test.ts +765 -0
- package/src/__tests__/scalabilityDatabaseIntegration.test.ts +207 -0
- package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
- package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -98
- package/src/__tests__/sessionUserClone.test.ts +5 -1
- package/src/__tests__/sharedCache.test.ts +5 -3
- package/src/__tests__/startupSweepOrder.test.ts +40 -0
- package/src/__tests__/unifiedAuth.test.ts +28 -0
- package/src/__tests__/widgetGuestElevation.test.ts +2 -0
- package/src/agentSessions/SessionJanitor.ts +369 -93
- package/src/agentSessions/SessionManager.ts +45 -10
- package/src/apiRoot.ts +78 -0
- package/src/auth/AuthProviderCatalogRouter.ts +29 -0
- package/src/auth/LoginScreenEngine.ts +50 -0
- package/src/auth/index.ts +57 -12
- package/src/auth/initializeProviders.ts +43 -1
- package/src/auth/localDevAuth.ts +528 -0
- package/src/auth/magicLink/MagicLinkKeys.ts +2 -2
- package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
- package/src/auth/magicLink/types.ts +10 -0
- package/src/auth/sessionUserClone.ts +3 -2
- package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +674 -0
- package/src/broadcast/index.ts +5 -0
- package/src/broadcast/providers/AWSIoTCoreBroadcastProvider.ts +180 -0
- package/src/broadcast/providers/AzureWebPubSubBroadcastProvider.ts +182 -0
- package/src/broadcast/providers/GCPPubSubBroadcastProvider.ts +169 -0
- package/src/broadcast/providers/SequencedRoleBucketBroadcastProvider.ts +57 -0
- package/src/cache.ts +2 -1
- package/src/config.ts +115 -5
- package/src/context.ts +32 -8
- package/src/coreRoutes.ts +181 -0
- package/src/generated/graphql-schemas/__mj.ts +3684 -284
- package/src/generic/CacheInvalidationResolver.ts +172 -60
- package/src/generic/OrphanedConversationDetailReconciler.ts +4 -2
- package/src/generic/PubSubManager.ts +54 -1
- package/src/generic/PushStatusResolver.ts +109 -12
- package/src/generic/ResolverBase.ts +540 -431
- package/src/generic/RunViewResolver.ts +97 -15
- package/src/generic/actionOutputFieldSecurity.ts +75 -0
- package/src/generic/fieldSecurityTransport.ts +62 -0
- package/src/globalCors.ts +71 -0
- package/src/index.ts +239 -238
- package/src/integration/CustomColumnPromoter.ts +6 -1
- package/src/logging/variablesLoggingMiddleware.ts +59 -3
- package/src/multiTenancy/index.ts +24 -2
- package/src/realtimeSessions/README.md +7 -3
- package/src/realtimeSessions/RealtimeSessionVerificationService.ts +2 -1
- package/src/realtimeSessions/RealtimeVerifyRouter.ts +2 -1
- package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
- package/src/realtimeSessions/index.ts +2 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +69 -0
- package/src/realtimeSessions/sessionAccess.ts +183 -23
- package/src/realtimeSessions/sessionConfigStamps.ts +1 -1
- package/src/realtimeSessions/subscriptionAuthorization.ts +4 -2
- package/src/realtimeSessions/verificationWorkflow.ts +3 -1
- package/src/realtimeWidget/WidgetRouter.ts +22 -4
- package/src/realtimeWidget/WidgetSessionService.ts +252 -17
- package/src/realtimeWidget/host-identity.ts +1 -1
- package/src/realtimeWidget/widgetCore.ts +30 -1
- package/src/realtimeWidget/widgetGuestElevation.ts +2 -1
- package/src/resolvers/ActionResolver.ts +78 -15
- package/src/resolvers/AdhocQueryResolver.ts +1 -0
- package/src/resolvers/AgentRunStatusPublisher.ts +36 -8
- package/src/resolvers/AgentSessionResolver.ts +46 -18
- package/src/resolvers/ArtifactFileResolver.ts +9 -8
- package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
- package/src/resolvers/DatasetResolver.ts +70 -10
- package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
- package/src/resolvers/EntityRecordNameResolver.ts +3 -2
- package/src/resolvers/FetchEntityVectorsResolver.ts +248 -55
- package/src/resolvers/FileCategoryResolver.ts +1 -0
- package/src/resolvers/FileResolver.ts +334 -109
- package/src/resolvers/GetDataContextDataResolver.ts +139 -41
- package/src/resolvers/GetDataResolver.ts +6 -3
- package/src/resolvers/IntegrationDiscoveryResolver.ts +53 -9
- package/src/resolvers/MergeRecordsResolver.ts +23 -2
- package/src/resolvers/PipelineProgressResolver.ts +12 -3
- package/src/resolvers/QueryResolver.ts +31 -6
- package/src/resolvers/QuerySystemUserResolver.ts +15 -6
- package/src/resolvers/RSUResolver.ts +12 -0
- package/src/resolvers/RealtimeClientSessionResolver.ts +114 -66
- package/src/resolvers/RemoteBrowserActionResolver.ts +15 -10
- package/src/resolvers/RunAIAgentResolver.ts +296 -85
- package/src/resolvers/RunTemplateResolver.ts +6 -4
- package/src/resolvers/RunTestResolver.ts +3 -1
- package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
- package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
- package/src/resolvers/SyncDataResolver.ts +4 -0
- package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
- package/src/resolvers/TestQuerySQLResolver.ts +69 -13
- package/src/resolvers/TransactionGroupResolver.ts +185 -30
- package/src/resolvers/UserViewResolver.ts +2 -1
- package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
- package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
- package/src/resolvers/agent-run-data-guard.ts +89 -0
- package/src/rest/EntityCRUDHandler.ts +22 -5
- package/src/rest/RESTEndpointHandler.ts +8 -5
- package/src/rest/RealtimeRecordingHandler.ts +467 -0
- package/src/rest/ViewOperationsHandler.ts +52 -18
- package/src/rest/setupRESTEndpoints.ts +6 -0
- package/src/serverExtensionReservedRoots.ts +14 -17
- package/src/serverRoleConfigUnits.ts +48 -0
- package/src/services/MJStorageBlobStore.ts +31 -30
- package/src/services/StartTaskGraphDispatcher.ts +2 -2
- package/src/services/TaskGraphActionRunner.ts +25 -5
- package/src/services/TaskGraphAgentRunner.ts +188 -11
- package/src/services/TaskGraphContinuationDeliverer.ts +738 -16
- package/src/sharedCache.ts +3 -0
- package/src/types.ts +23 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview A fire-and-forget run always ends with one completion on the caller's socket.
|
|
3
|
+
*
|
|
4
|
+
* The widget and Explorer return as soon as the mutation acks, then wait for a `complete` status message. When the
|
|
5
|
+
* run fails (the agent cannot be validated, the run throws, or the agent's reply row cannot be saved), that message
|
|
6
|
+
* must still arrive, exactly once, with the reason, addressed to the owner the caller's socket is authenticated as.
|
|
7
|
+
* For a widget guest that is the guest, not the system user its run is elevated to. Without it the client waits for
|
|
8
|
+
* its idle timeout and then reconciles the run as a success.
|
|
9
|
+
*
|
|
10
|
+
* The liveness pulse of the same run is addressed to the same owner.
|
|
11
|
+
*/
|
|
12
|
+
import 'reflect-metadata'; // must precede any type-graphql decorator evaluation
|
|
13
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
14
|
+
import type { PubSubEngine } from 'type-graphql';
|
|
15
|
+
|
|
16
|
+
vi.mock('type-graphql', () => {
|
|
17
|
+
const decoratorFactory = (..._args: unknown[]) => (..._decorated: unknown[]) => undefined;
|
|
18
|
+
const exportNames = [
|
|
19
|
+
'Resolver', 'Query', 'Mutation', 'Subscription', 'Arg', 'Args', 'ArgsType', 'Ctx', 'Root',
|
|
20
|
+
'Info', 'Field', 'FieldResolver', 'ObjectType', 'InputType', 'InterfaceType', 'Authorized',
|
|
21
|
+
'UseMiddleware', 'Extensions', 'Directive', 'ID', 'Int', 'Float', 'GraphQLISODateTime',
|
|
22
|
+
'GraphQLTimestamp', 'registerEnumType', 'createMethodDecorator', 'createParamDecorator',
|
|
23
|
+
'buildSchema', 'buildSchemaSync', 'PubSub',
|
|
24
|
+
];
|
|
25
|
+
return Object.fromEntries(exportNames.map((name) => [name, decoratorFactory]));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const hoisted = vi.hoisted(() => ({
|
|
29
|
+
runAgentInConversation: vi.fn(),
|
|
30
|
+
agents: new Map<string, { ID: string; Name: string; Status: string }>(),
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
vi.mock('@memberjunction/aiengine', () => ({
|
|
34
|
+
AIEngine: {
|
|
35
|
+
Instance: {
|
|
36
|
+
Config: async () => undefined,
|
|
37
|
+
GetAgentByID: (id: string) => hoisted.agents.get(id),
|
|
38
|
+
CanUserRunAgent: async () => true,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
GetAttachmentService: () => ({}),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
vi.mock('@memberjunction/ai-agents', () => ({
|
|
45
|
+
AgentRunner: class {
|
|
46
|
+
RunAgentInConversation(...args: unknown[]) {
|
|
47
|
+
return hoisted.runAgentInConversation(...args);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
ArtifactToolManager: class {},
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
import { UserInfo } from '@memberjunction/core';
|
|
54
|
+
import { RunAIAgentResolver } from '../resolvers/RunAIAgentResolver.js';
|
|
55
|
+
import { StatusUpdateOwnerID } from '../generic/PushStatusResolver.js';
|
|
56
|
+
import { DEFAULT_PULSE_INTERVAL_MS, HEARTBEAT_MESSAGE_TYPE } from '../generic/FireAndForgetHeartbeat.js';
|
|
57
|
+
import type { AppContext, UserPayload } from '../types.js';
|
|
58
|
+
|
|
59
|
+
const ANONYMOUS_USER_ID = 'AAAAAAAA-0000-4000-8000-0000000000A0';
|
|
60
|
+
const SYSTEM_USER_ID = 'BBBBBBBB-0000-4000-8000-0000000000B0';
|
|
61
|
+
const SESSION = 'session-1';
|
|
62
|
+
|
|
63
|
+
/** A public-widget guest: the shared Anonymous user, told apart by its scope identity. */
|
|
64
|
+
function widgetGuest(): UserInfo {
|
|
65
|
+
const guest = new UserInfo(null, { ID: ANONYMOUS_USER_ID, Email: 'anonymous@magic-link.local' });
|
|
66
|
+
guest.IsMagicLinkAnonymous = true;
|
|
67
|
+
guest.AnonymousVisitorID = 'sid-guest-1';
|
|
68
|
+
return guest;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** The payload a widget guest's run executes under: elevated to the system user, standing in for the guest. */
|
|
72
|
+
function elevatedGuestPayload(): UserPayload {
|
|
73
|
+
return {
|
|
74
|
+
sessionId: SESSION,
|
|
75
|
+
email: 'system@example.com',
|
|
76
|
+
userRecord: new UserInfo(null, { ID: SYSTEM_USER_ID, Email: 'system@example.com' }),
|
|
77
|
+
ElevatedFrom: widgetGuest(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface PublishedEnvelope {
|
|
82
|
+
sessionId: string;
|
|
83
|
+
ownerUserId: string;
|
|
84
|
+
message: { resolver: string; type: string; data: Record<string, unknown> };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function makePubSub(): { pubSub: PubSubEngine; published: () => PublishedEnvelope[] } {
|
|
88
|
+
const publish = vi.fn().mockResolvedValue(undefined);
|
|
89
|
+
const pubSub: PubSubEngine = { publish, subscribe: vi.fn(), unsubscribe: vi.fn(), asyncIterator: vi.fn() };
|
|
90
|
+
const published = (): PublishedEnvelope[] =>
|
|
91
|
+
publish.mock.calls.map((call) => {
|
|
92
|
+
const payload = call[1] as { sessionId: string; ownerUserId: string; message: string };
|
|
93
|
+
return { sessionId: payload.sessionId, ownerUserId: payload.ownerUserId, message: JSON.parse(payload.message) };
|
|
94
|
+
});
|
|
95
|
+
return { pubSub, published };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function completions(envelopes: PublishedEnvelope[]): PublishedEnvelope[] {
|
|
99
|
+
return envelopes.filter((e) => e.message.type === 'StreamingContent' && e.message.data.type === 'complete');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Starts the public RunAIAgent mutation in fire-and-forget mode for `agentId`, answering into `reply-1`. */
|
|
103
|
+
async function startFireAndForget(pubSub: PubSubEngine, userPayload: UserPayload, agentId = 'agent-1') {
|
|
104
|
+
const ctx = { userPayload, providers: [], dataSource: {} } as AppContext;
|
|
105
|
+
return new RunAIAgentResolver().RunAIAgent(
|
|
106
|
+
agentId, ctx, '[{"role":"user","content":"hi"}]', SESSION, pubSub,
|
|
107
|
+
undefined, undefined, undefined, undefined, undefined, undefined,
|
|
108
|
+
'reply-1', // conversationDetailId
|
|
109
|
+
undefined, undefined, undefined, undefined,
|
|
110
|
+
true, // fireAndForget
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Lets the background run settle, then gives any late (double) publish a chance to land. */
|
|
115
|
+
async function settle(published: () => PublishedEnvelope[]): Promise<void> {
|
|
116
|
+
await vi.waitFor(() => expect(completions(published()).length).toBeGreaterThan(0), { timeout: 1000 });
|
|
117
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
beforeEach(() => {
|
|
121
|
+
hoisted.agents.clear();
|
|
122
|
+
hoisted.agents.set('agent-1', { ID: 'agent-1', Name: 'Research', Status: 'Active' });
|
|
123
|
+
hoisted.runAgentInConversation.mockReset();
|
|
124
|
+
vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
125
|
+
vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
afterEach(() => {
|
|
129
|
+
vi.useRealTimers();
|
|
130
|
+
vi.restoreAllMocks();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('RunAIAgent fire-and-forget — the failure completion', () => {
|
|
134
|
+
it("publishes one failed completion with the reason when the agent's reply cannot be saved, to the guest's socket", async () => {
|
|
135
|
+
const reason = "The agent's reply could not be saved: Message exceeds the maximum length";
|
|
136
|
+
hoisted.runAgentInConversation.mockRejectedValue(new Error(reason));
|
|
137
|
+
const { pubSub, published } = makePubSub();
|
|
138
|
+
const userPayload = elevatedGuestPayload();
|
|
139
|
+
|
|
140
|
+
const ack = await startFireAndForget(pubSub, userPayload);
|
|
141
|
+
expect(ack.success).toBe(true); // the ack only says the run started
|
|
142
|
+
|
|
143
|
+
await settle(published);
|
|
144
|
+
const done = completions(published());
|
|
145
|
+
expect(done).toHaveLength(1);
|
|
146
|
+
expect(done[0].message.data).toMatchObject({
|
|
147
|
+
type: 'complete',
|
|
148
|
+
success: false,
|
|
149
|
+
errorMessage: reason,
|
|
150
|
+
conversationDetailId: 'reply-1',
|
|
151
|
+
});
|
|
152
|
+
expect(done[0].sessionId).toBe(SESSION);
|
|
153
|
+
// The guest's owner key, never the system user the run was elevated to.
|
|
154
|
+
expect(done[0].ownerUserId).toBe(StatusUpdateOwnerID(userPayload));
|
|
155
|
+
expect(done[0].ownerUserId).toBe(`${ANONYMOUS_USER_ID.toLowerCase()}|sid-guest-1`);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('publishes one failed completion when the run fails before the agent starts (agent not runnable)', async () => {
|
|
159
|
+
const { pubSub, published } = makePubSub();
|
|
160
|
+
|
|
161
|
+
await startFireAndForget(pubSub, elevatedGuestPayload(), 'missing-agent');
|
|
162
|
+
|
|
163
|
+
await settle(published);
|
|
164
|
+
const done = completions(published());
|
|
165
|
+
expect(done).toHaveLength(1);
|
|
166
|
+
expect(done[0].message.data).toMatchObject({
|
|
167
|
+
success: false,
|
|
168
|
+
errorMessage: 'AI Agent with ID missing-agent not found',
|
|
169
|
+
conversationDetailId: 'reply-1',
|
|
170
|
+
});
|
|
171
|
+
expect(hoisted.runAgentInConversation).not.toHaveBeenCalled();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('publishes only the run\'s own completion when the run returns a failed result (no second completion)', async () => {
|
|
175
|
+
const run = { ID: 'run-1', ConversationDetailID: 'reply-1', ErrorMessage: 'model refused', Steps: [] };
|
|
176
|
+
hoisted.runAgentInConversation.mockResolvedValue({
|
|
177
|
+
agentResult: { success: false, agentRun: run },
|
|
178
|
+
agentResponseDetailId: 'reply-1',
|
|
179
|
+
conversationId: 'conv-1',
|
|
180
|
+
});
|
|
181
|
+
const { pubSub, published } = makePubSub();
|
|
182
|
+
|
|
183
|
+
await startFireAndForget(pubSub, elevatedGuestPayload());
|
|
184
|
+
|
|
185
|
+
await settle(published);
|
|
186
|
+
const done = completions(published());
|
|
187
|
+
expect(done).toHaveLength(1);
|
|
188
|
+
expect(done[0].message.data).toMatchObject({ agentRunId: 'run-1', success: false, errorMessage: 'model refused' });
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe("RunAIAgent fire-and-forget — the liveness pulse", () => {
|
|
193
|
+
it("addresses heartbeats to the guest's owner key, not to the elevated system user", async () => {
|
|
194
|
+
vi.useFakeTimers();
|
|
195
|
+
hoisted.runAgentInConversation.mockReturnValue(new Promise(() => undefined)); // the run is still going
|
|
196
|
+
const { pubSub, published } = makePubSub();
|
|
197
|
+
const userPayload = elevatedGuestPayload();
|
|
198
|
+
|
|
199
|
+
await startFireAndForget(pubSub, userPayload);
|
|
200
|
+
await vi.advanceTimersByTimeAsync(DEFAULT_PULSE_INTERVAL_MS);
|
|
201
|
+
|
|
202
|
+
const heartbeats = published().filter((e) => e.message.type === HEARTBEAT_MESSAGE_TYPE);
|
|
203
|
+
expect(heartbeats.length).toBeGreaterThan(0);
|
|
204
|
+
for (const heartbeat of heartbeats) {
|
|
205
|
+
expect(heartbeat.ownerUserId).toBe(StatusUpdateOwnerID(userPayload));
|
|
206
|
+
expect(heartbeat.ownerUserId).not.toBe(SYSTEM_USER_ID);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
});
|
|
@@ -28,6 +28,7 @@ vi.mock('type-graphql', () => {
|
|
|
28
28
|
|
|
29
29
|
const hoisted = vi.hoisted(() => ({
|
|
30
30
|
runAgentInConversation: vi.fn(),
|
|
31
|
+
reply: { ID: 'reply-1', ConversationID: 'conv-1', __mj_CreatedAt: new Date('2026-10-12T10:00:00.000Z') },
|
|
31
32
|
}));
|
|
32
33
|
|
|
33
34
|
vi.mock('@memberjunction/ai-agents', () => ({
|
|
@@ -35,6 +36,9 @@ vi.mock('@memberjunction/ai-agents', () => ({
|
|
|
35
36
|
RunAgentInConversation(...args: unknown[]) {
|
|
36
37
|
return hoisted.runAgentInConversation(...args);
|
|
37
38
|
}
|
|
39
|
+
async CreateAgentReplyDetail() {
|
|
40
|
+
return hoisted.reply;
|
|
41
|
+
}
|
|
38
42
|
},
|
|
39
43
|
ArtifactToolManager: class {},
|
|
40
44
|
}));
|
|
@@ -94,7 +98,7 @@ async function runMutation(
|
|
|
94
98
|
options: { agentHistoryFrom?: string; fireAndForget?: boolean }
|
|
95
99
|
) {
|
|
96
100
|
return resolver.RunAIAgentFromConversationDetail(
|
|
97
|
-
'
|
|
101
|
+
'user-msg-1', 'agent-1', makeContext(), 'session-1', pubSub,
|
|
98
102
|
undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined,
|
|
99
103
|
undefined, undefined, options.fireAndForget, undefined, undefined,
|
|
100
104
|
options.agentHistoryFrom
|
|
@@ -108,6 +112,8 @@ afterEach(() => {
|
|
|
108
112
|
describe('RunAIAgentFromConversationDetail — agentHistoryFrom', () => {
|
|
109
113
|
let resolver: RunAIAgentResolver;
|
|
110
114
|
let seams: ResolverSeams;
|
|
115
|
+
/** The floor's position in executeAIAgent / executeAgentInBackground: fourth from last, before TrustReservedRunData, the branch, and the reply detail. */
|
|
116
|
+
const FLOOR_ARG = -4;
|
|
111
117
|
|
|
112
118
|
beforeEach(() => {
|
|
113
119
|
({ resolver, seams } = makeResolver());
|
|
@@ -122,9 +128,9 @@ describe('RunAIAgentFromConversationDetail — agentHistoryFrom', () => {
|
|
|
122
128
|
expect(result.success).toBe(true);
|
|
123
129
|
const loaderArgs = seams.loadConversationHistoryWithAttachments.mock.calls[0];
|
|
124
130
|
expect(loaderArgs[0]).toBe('conv-1');
|
|
125
|
-
expect(loaderArgs[4]).
|
|
131
|
+
expect(loaderArgs[4]).toBeUndefined(); // the reply row is created after the history loads, so nothing to exclude
|
|
126
132
|
expect((loaderArgs[5] as Date).toISOString()).toBe(FLOOR_ISO);
|
|
127
|
-
const runFloor = seams.executeAIAgent.mock.calls[0].at(
|
|
133
|
+
const runFloor = seams.executeAIAgent.mock.calls[0].at(FLOOR_ARG) as Date;
|
|
128
134
|
expect(runFloor.toISOString()).toBe(FLOOR_ISO);
|
|
129
135
|
});
|
|
130
136
|
|
|
@@ -133,7 +139,7 @@ describe('RunAIAgentFromConversationDetail — agentHistoryFrom', () => {
|
|
|
133
139
|
|
|
134
140
|
expect(result.success).toBe(true);
|
|
135
141
|
expect(seams.executeAIAgent).not.toHaveBeenCalled();
|
|
136
|
-
const runFloor = seams.executeAgentInBackground.mock.calls[0].at(
|
|
142
|
+
const runFloor = seams.executeAgentInBackground.mock.calls[0].at(FLOOR_ARG) as Date;
|
|
137
143
|
expect(runFloor.toISOString()).toBe(FLOOR_ISO);
|
|
138
144
|
});
|
|
139
145
|
|
|
@@ -141,7 +147,7 @@ describe('RunAIAgentFromConversationDetail — agentHistoryFrom', () => {
|
|
|
141
147
|
await runMutation(resolver, {});
|
|
142
148
|
|
|
143
149
|
expect(seams.loadConversationHistoryWithAttachments.mock.calls[0][5]).toBeUndefined();
|
|
144
|
-
expect(seams.executeAIAgent.mock.calls[0].at(
|
|
150
|
+
expect(seams.executeAIAgent.mock.calls[0].at(FLOOR_ARG)).toBeUndefined();
|
|
145
151
|
});
|
|
146
152
|
|
|
147
153
|
it('fails the request on an unreadable floor, before loading or running anything', async () => {
|
|
@@ -288,10 +294,13 @@ describe('executeAIAgent — status publishing', () => {
|
|
|
288
294
|
expect(completion.success).toBe(true);
|
|
289
295
|
});
|
|
290
296
|
|
|
291
|
-
it('
|
|
297
|
+
it('logs a fire-and-forget run that rejects, and publishes no second completion', async () => {
|
|
298
|
+
// executeAIAgent resolves on every failure and publishes the failure completion itself
|
|
299
|
+
// (RunAIAgentResolver.fireAndForgetCompletion.test.ts). A rejection breaks that contract; the background
|
|
300
|
+
// runner only logs it, with the agent and session, instead of leaving an unhandled rejection.
|
|
292
301
|
const { resolver, seams } = makeResolver();
|
|
293
302
|
seams.executeAIAgent = vi.fn().mockRejectedValue(new Error('background blew up'));
|
|
294
|
-
vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
303
|
+
const errors = vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
295
304
|
vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
296
305
|
const publish = vi.fn().mockResolvedValue(undefined);
|
|
297
306
|
const localPubSub = { publish } as unknown as PubSubEngine;
|
|
@@ -304,28 +313,11 @@ describe('executeAIAgent — status publishing', () => {
|
|
|
304
313
|
{}, {}, 'agent-1', userPayload, '[]', 'session-1', localPubSub,
|
|
305
314
|
undefined, undefined, undefined, undefined, undefined, 'detail-1',
|
|
306
315
|
);
|
|
307
|
-
await vi.waitFor(() =>
|
|
316
|
+
await vi.waitFor(() =>
|
|
317
|
+
expect(errors.mock.calls.some((call) => String(call[0]).includes('agent-1') && String(call[0]).includes('session-1'))).toBe(true),
|
|
318
|
+
);
|
|
308
319
|
|
|
309
|
-
|
|
310
|
-
expect(sent).toHaveLength(1);
|
|
311
|
-
expect(sent[0].type).toBe('StreamingContent');
|
|
312
|
-
expect(sent[0].resolver).toBe('RunAIAgentResolver');
|
|
313
|
-
const completion = sent[0].data as {
|
|
314
|
-
type: string;
|
|
315
|
-
agentRunId: string;
|
|
316
|
-
conversationDetailId: string;
|
|
317
|
-
success: boolean;
|
|
318
|
-
errorMessage: string;
|
|
319
|
-
result: string;
|
|
320
|
-
};
|
|
321
|
-
expect(completion).toMatchObject({
|
|
322
|
-
type: 'complete',
|
|
323
|
-
agentRunId: 'unknown',
|
|
324
|
-
conversationDetailId: 'detail-1',
|
|
325
|
-
success: false,
|
|
326
|
-
errorMessage: 'background blew up',
|
|
327
|
-
result: JSON.stringify({ success: false, errorMessage: 'background blew up' }),
|
|
328
|
-
});
|
|
320
|
+
expect(publish).not.toHaveBeenCalled();
|
|
329
321
|
});
|
|
330
322
|
|
|
331
323
|
it('saves a Running run reported by progress as Failed when the agent throws', async () => {
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Every agent-run entry of `RunAIAgentResolver` tells the run whether it may read the reserved scope
|
|
3
|
+
* and agent-type keys from a client's `data` (`ExecuteAgentParams.TrustReservedRunData`, A12.15).
|
|
4
|
+
*
|
|
5
|
+
* The decision is pinned by `agent-run-data-guard.test.ts`, and what an untrusted run loses by the ai-core-plus and
|
|
6
|
+
* ai-agents suites (`BaseAgent.Execute` drops the keys). These tests pin the call sites: the synchronous and
|
|
7
|
+
* fire-and-forget paths of `RunAIAgent` and `RunAIAgentFromConversationDetail`, the widget-guest path (judged on
|
|
8
|
+
* the guest's own payload, not the system principal it is elevated to), the trusted callers, and an API key with and
|
|
9
|
+
* without the `agent:trusted` scope — each through the real `executeAIAgent`, up to the params handed to
|
|
10
|
+
* `AgentRunner`. The resolver forwards `data` as sent.
|
|
11
|
+
*/
|
|
12
|
+
import 'reflect-metadata'; // must precede any type-graphql decorator evaluation
|
|
13
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
14
|
+
import type { PubSubEngine } from 'type-graphql';
|
|
15
|
+
|
|
16
|
+
// type-graphql's real decorators need emitDecoratorMetadata, which vitest's esbuild transform
|
|
17
|
+
// does not emit; the schema is irrelevant here, so every decorator is a no-op.
|
|
18
|
+
vi.mock('type-graphql', () => {
|
|
19
|
+
const decoratorFactory = (..._args: unknown[]) => (..._decorated: unknown[]) => undefined;
|
|
20
|
+
const exportNames = [
|
|
21
|
+
'Resolver', 'Query', 'Mutation', 'Subscription', 'Arg', 'Args', 'ArgsType', 'Ctx', 'Root',
|
|
22
|
+
'Info', 'Field', 'FieldResolver', 'ObjectType', 'InputType', 'InterfaceType', 'Authorized',
|
|
23
|
+
'UseMiddleware', 'Extensions', 'Directive', 'ID', 'Int', 'Float', 'GraphQLISODateTime',
|
|
24
|
+
'GraphQLTimestamp', 'registerEnumType', 'createMethodDecorator', 'createParamDecorator',
|
|
25
|
+
'buildSchema', 'buildSchemaSync', 'PubSub',
|
|
26
|
+
];
|
|
27
|
+
return Object.fromEntries(exportNames.map((name) => [name, decoratorFactory]));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const hoisted = vi.hoisted(() => ({
|
|
31
|
+
runAgentInConversation: vi.fn(),
|
|
32
|
+
resolveWidgetGuestRunContext: vi.fn(),
|
|
33
|
+
authorize: vi.fn(),
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
// Only the key engine is stubbed: Authorize allows `agent:trusted` for the key whose hash is 'hash-trusted'.
|
|
37
|
+
vi.mock('@memberjunction/api-keys', async (importOriginal) => ({
|
|
38
|
+
...(await importOriginal<typeof import('@memberjunction/api-keys')>()),
|
|
39
|
+
GetAPIKeyEngine: () => ({ Authorize: hoisted.authorize }),
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
vi.mock('@memberjunction/ai-agents', () => ({
|
|
43
|
+
AgentRunner: class {
|
|
44
|
+
async CreateAgentReplyDetail() {
|
|
45
|
+
return { ID: 'reply-1', __mj_CreatedAt: new Date() };
|
|
46
|
+
}
|
|
47
|
+
RunAgentInConversation(...args: unknown[]) {
|
|
48
|
+
return hoisted.runAgentInConversation(...args);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
ArtifactToolManager: class {},
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
// Only the widget lookup is stubbed; ElevateUserPayload is the real one, so the widget-guest test runs
|
|
55
|
+
// against the elevated system-user payload the resolver really builds.
|
|
56
|
+
vi.mock('../realtimeWidget/widgetGuestElevation.js', async (importOriginal) => ({
|
|
57
|
+
...(await importOriginal<typeof import('../realtimeWidget/widgetGuestElevation.js')>()),
|
|
58
|
+
ResolveWidgetGuestRunContext: hoisted.resolveWidgetGuestRunContext,
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
import { UserCache } from '@memberjunction/generic-database-provider';
|
|
62
|
+
import type { UserInfo } from '@memberjunction/core';
|
|
63
|
+
import { RunAIAgentResolver } from '../resolvers/RunAIAgentResolver.js';
|
|
64
|
+
import type { AppContext, UserPayload } from '../types.js';
|
|
65
|
+
|
|
66
|
+
const SCOPE_RECORD_ID = 'B1A2C3D4-0000-4000-8000-00000000A115';
|
|
67
|
+
const ORDINARY = { conversationId: 'conv-1', latestMessageId: 'detail-1', invocationReason: 'user-message' };
|
|
68
|
+
const CLIENT_DATA = JSON.stringify({
|
|
69
|
+
...ORDINARY,
|
|
70
|
+
PrimaryScopeRecordID: SCOPE_RECORD_ID,
|
|
71
|
+
PrimaryScopeEntityName: 'MJ: Companies',
|
|
72
|
+
SecondaryScopes: { TeamID: 'team-other' },
|
|
73
|
+
__agentTypePromptParams: { enableTaskGraphs: true },
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const USER = { ID: 'user-1', Email: 'browser.user@example.com' };
|
|
77
|
+
const SYSTEM_USER = { ID: 'system-user', Email: 'system@example.com' };
|
|
78
|
+
// A widget guest always carries its per-visitor scope id (mj_sid) as its MagicLinkScope.ResourceID, and its
|
|
79
|
+
// conversation is stamped with the same value as ExternalID: that stamp is what tells one guest from another
|
|
80
|
+
// under the shared Anonymous user (MJ#6032), so the fake conversation below carries it.
|
|
81
|
+
const GUEST = { ID: 'guest-1', Email: 'anonymous@magic-link.local', IsMagicLinkAnonymous: true, AnonymousVisitorID: 'sid-1', MagicLinkScope: { ResourceID: 'sid-1' } };
|
|
82
|
+
|
|
83
|
+
type Fn = ReturnType<typeof vi.fn>;
|
|
84
|
+
|
|
85
|
+
/** The private members this test reaches, through an explicit shape (no `any`). */
|
|
86
|
+
interface ResolverSeams {
|
|
87
|
+
CheckAPIKeyScopeAuthorization: Fn;
|
|
88
|
+
GetUserFromPayload: Fn;
|
|
89
|
+
loadConversationHistoryWithAttachments: Fn;
|
|
90
|
+
validateAgent: Fn;
|
|
91
|
+
persistInFlightAgentFailure: Fn;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const pubSub = { publish: vi.fn().mockResolvedValue(undefined) } as unknown as PubSubEngine;
|
|
95
|
+
|
|
96
|
+
function makeResolver(): { resolver: RunAIAgentResolver; seams: ResolverSeams } {
|
|
97
|
+
const resolver = new RunAIAgentResolver();
|
|
98
|
+
const seams = resolver as unknown as ResolverSeams;
|
|
99
|
+
seams.CheckAPIKeyScopeAuthorization = vi.fn().mockResolvedValue(undefined);
|
|
100
|
+
seams.GetUserFromPayload = vi.fn((payload: UserPayload) => payload.userRecord);
|
|
101
|
+
seams.loadConversationHistoryWithAttachments = vi.fn().mockResolvedValue([{ role: 'user', content: 'hi' }]);
|
|
102
|
+
seams.validateAgent = vi.fn().mockResolvedValue({ ID: 'agent-1', Name: 'Test Agent' });
|
|
103
|
+
seams.persistInFlightAgentFailure = vi.fn().mockResolvedValue(undefined);
|
|
104
|
+
return { resolver, seams };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function makeContext(userPayload: Partial<UserPayload>): AppContext {
|
|
108
|
+
const provider = {
|
|
109
|
+
GetEntityObject: vi.fn().mockResolvedValue({ ConversationID: 'conv-1', UserID: GUEST.ID, ExternalID: 'sid-1', Load: vi.fn().mockResolvedValue(true) }),
|
|
110
|
+
};
|
|
111
|
+
return {
|
|
112
|
+
userPayload: { sessionId: 'session-1', email: USER.Email, userRecord: USER, ...userPayload } as UserPayload,
|
|
113
|
+
providers: [{ type: 'Read-Write', provider }],
|
|
114
|
+
dataSource: {},
|
|
115
|
+
} as unknown as AppContext;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** The params the n-th run was handed by the real executeAIAgent (what AgentRunner.RunAgentInConversation received). */
|
|
119
|
+
interface HandedParams {
|
|
120
|
+
data: Record<string, unknown>;
|
|
121
|
+
TrustReservedRunData?: boolean;
|
|
122
|
+
contextUser: { ID: string };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Waits for the n-th run to start (the fire-and-forget path starts it after the resolver has returned). */
|
|
126
|
+
async function handedParams(n = 0): Promise<HandedParams> {
|
|
127
|
+
await vi.waitFor(() => expect(hoisted.runAgentInConversation.mock.calls.length).toBeGreaterThan(n));
|
|
128
|
+
return hoisted.runAgentInConversation.mock.calls[n][0] as HandedParams;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function runAIAgent(resolver: RunAIAgentResolver, ctx: AppContext, fireAndForget?: boolean) {
|
|
132
|
+
return resolver.RunAIAgent(
|
|
133
|
+
'agent-1', ctx, '[{"role":"user","content":"hi"}]', 'session-1', pubSub, CLIENT_DATA,
|
|
134
|
+
undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined,
|
|
135
|
+
fireAndForget
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function runFromDetail(resolver: RunAIAgentResolver, ctx: AppContext, fireAndForget?: boolean) {
|
|
140
|
+
return resolver.RunAIAgentFromConversationDetail(
|
|
141
|
+
'detail-1', 'agent-1', ctx, 'session-1', pubSub, undefined, CLIENT_DATA,
|
|
142
|
+
undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, fireAndForget
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
beforeEach(() => {
|
|
147
|
+
hoisted.resolveWidgetGuestRunContext.mockReset().mockResolvedValue(null);
|
|
148
|
+
// Stop right after the run's params are captured — the rest of the run is out of scope.
|
|
149
|
+
hoisted.runAgentInConversation.mockReset().mockRejectedValue(new Error('stop here'));
|
|
150
|
+
hoisted.authorize.mockReset().mockImplementation(async (apiKeyHash: string, _app: string, scopePath: string) =>
|
|
151
|
+
apiKeyHash === 'hash-trusted' && scopePath === 'agent:trusted'
|
|
152
|
+
? { Allowed: true, MatchedKeyRule: { ScopePath: scopePath }, EvaluatedRules: [] }
|
|
153
|
+
: { Allowed: false, Reason: 'No matching key scope rules', EvaluatedRules: [] });
|
|
154
|
+
vi.spyOn(UserCache.Instance, 'GetSystemUser').mockReturnValue(SYSTEM_USER as UserInfo);
|
|
155
|
+
vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
156
|
+
vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
afterEach(() => {
|
|
160
|
+
vi.restoreAllMocks();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('RunAIAgent — reserved run-data keys', () => {
|
|
164
|
+
it('marks the run untrusted for an interactive user and forwards data as sent', async () => {
|
|
165
|
+
const { resolver } = makeResolver();
|
|
166
|
+
|
|
167
|
+
await runAIAgent(resolver, makeContext({}));
|
|
168
|
+
|
|
169
|
+
const params = await handedParams();
|
|
170
|
+
expect(params.TrustReservedRunData).toBe(false);
|
|
171
|
+
expect(params.data).toEqual(JSON.parse(CLIENT_DATA));
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('marks it untrusted on the fire-and-forget path too', async () => {
|
|
175
|
+
const { resolver } = makeResolver();
|
|
176
|
+
|
|
177
|
+
await runAIAgent(resolver, makeContext({}), true);
|
|
178
|
+
|
|
179
|
+
expect((await handedParams()).TrustReservedRunData).toBe(false);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('marks it trusted for an API key holding agent:trusted, on both paths', async () => {
|
|
183
|
+
const { resolver } = makeResolver();
|
|
184
|
+
const ctx = makeContext({ apiKeyId: 'key-1', apiKeyHash: 'hash-trusted' });
|
|
185
|
+
|
|
186
|
+
await runAIAgent(resolver, ctx);
|
|
187
|
+
await runAIAgent(resolver, ctx, true);
|
|
188
|
+
|
|
189
|
+
expect((await handedParams(0)).TrustReservedRunData).toBe(true);
|
|
190
|
+
expect((await handedParams(1)).TrustReservedRunData).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('marks it untrusted for an API key without agent:trusted, on both paths', async () => {
|
|
194
|
+
const { resolver } = makeResolver();
|
|
195
|
+
const ctx = makeContext({ apiKeyId: 'key-2', apiKeyHash: 'hash-plain' });
|
|
196
|
+
|
|
197
|
+
await runAIAgent(resolver, ctx);
|
|
198
|
+
await runAIAgent(resolver, ctx, true);
|
|
199
|
+
|
|
200
|
+
expect((await handedParams(0)).TrustReservedRunData).toBe(false);
|
|
201
|
+
expect((await handedParams(1)).TrustReservedRunData).toBe(false);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('RunAIAgentFromConversationDetail — reserved run-data keys', () => {
|
|
206
|
+
it('marks the run untrusted for an interactive user on both paths', async () => {
|
|
207
|
+
const { resolver } = makeResolver();
|
|
208
|
+
|
|
209
|
+
await runFromDetail(resolver, makeContext({}));
|
|
210
|
+
await runFromDetail(resolver, makeContext({}), true);
|
|
211
|
+
|
|
212
|
+
expect((await handedParams(0)).TrustReservedRunData).toBe(false);
|
|
213
|
+
expect((await handedParams(1)).TrustReservedRunData).toBe(false);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('marks a widget-guest run untrusted although it executes as the system user', async () => {
|
|
217
|
+
const { resolver } = makeResolver();
|
|
218
|
+
hoisted.resolveWidgetGuestRunContext.mockResolvedValue({
|
|
219
|
+
ElevatedUser: SYSTEM_USER,
|
|
220
|
+
Widget: {},
|
|
221
|
+
PinnedAgentId: 'pinned-agent',
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
await runFromDetail(resolver, makeContext({ email: GUEST.Email, userRecord: GUEST }));
|
|
225
|
+
|
|
226
|
+
const params = await handedParams();
|
|
227
|
+
expect(params.contextUser.ID).toBe(SYSTEM_USER.ID); // the premise: the run is elevated
|
|
228
|
+
expect(params.TrustReservedRunData).toBe(false);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('marks it trusted for the system user, on both paths', async () => {
|
|
232
|
+
const { resolver } = makeResolver();
|
|
233
|
+
const ctx = makeContext({ isSystemUser: true, email: SYSTEM_USER.Email, userRecord: SYSTEM_USER });
|
|
234
|
+
|
|
235
|
+
await runFromDetail(resolver, ctx);
|
|
236
|
+
await runFromDetail(resolver, ctx, true);
|
|
237
|
+
|
|
238
|
+
expect((await handedParams(0)).TrustReservedRunData).toBe(true);
|
|
239
|
+
expect((await handedParams(1)).TrustReservedRunData).toBe(true);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('marks it trusted for an API key holding agent:trusted, and untrusted for one without', async () => {
|
|
243
|
+
const { resolver } = makeResolver();
|
|
244
|
+
|
|
245
|
+
await runFromDetail(resolver, makeContext({ apiKeyId: 'key-1', apiKeyHash: 'hash-trusted' }));
|
|
246
|
+
await runFromDetail(resolver, makeContext({ apiKeyId: 'key-2', apiKeyHash: 'hash-plain' }));
|
|
247
|
+
|
|
248
|
+
expect((await handedParams(0)).TrustReservedRunData).toBe(true);
|
|
249
|
+
expect((await handedParams(1)).TrustReservedRunData).toBe(false);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
describe('RunAIAgentSystemUser — reserved run-data keys', () => {
|
|
254
|
+
it('marks the run trusted for the system user it admits, and forwards data as sent', async () => {
|
|
255
|
+
const { resolver } = makeResolver();
|
|
256
|
+
const ctx = makeContext({ isSystemUser: true, email: SYSTEM_USER.Email, userRecord: SYSTEM_USER });
|
|
257
|
+
|
|
258
|
+
await resolver.RunAIAgentSystemUser('agent-1', ctx, '[]', 'session-1', pubSub, CLIENT_DATA);
|
|
259
|
+
|
|
260
|
+
const params = await handedParams();
|
|
261
|
+
expect(params.TrustReservedRunData).toBe(true);
|
|
262
|
+
expect(params.data).toEqual(JSON.parse(CLIENT_DATA));
|
|
263
|
+
});
|
|
264
|
+
});
|