@memberjunction/server 6.2.0-edge.3 → 6.2.0-edge.5
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 +20 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/BridgeHostInstance.d.ts +25 -0
- package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -0
- package/dist/agentSessions/BridgeHostInstance.js +30 -0
- package/dist/agentSessions/BridgeHostInstance.js.map +1 -0
- package/dist/agentSessions/HostInstance.d.ts +75 -11
- package/dist/agentSessions/HostInstance.d.ts.map +1 -1
- package/dist/agentSessions/HostInstance.js +99 -28
- package/dist/agentSessions/HostInstance.js.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.js +7 -3
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +236 -27
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +682 -54
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +48 -3
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +112 -9
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/SessionRunIDVerifier.d.ts +63 -0
- package/dist/agentSessions/SessionRunIDVerifier.d.ts.map +1 -0
- package/dist/agentSessions/SessionRunIDVerifier.js +129 -0
- package/dist/agentSessions/SessionRunIDVerifier.js.map +1 -0
- package/dist/agentSessions/index.d.ts +2 -0
- package/dist/agentSessions/index.d.ts.map +1 -1
- package/dist/agentSessions/index.js +10 -3
- package/dist/agentSessions/index.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 +25 -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/actionAuthorization.d.ts +40 -0
- package/dist/auth/actionAuthorization.d.ts.map +1 -0
- package/dist/auth/actionAuthorization.js +94 -0
- package/dist/auth/actionAuthorization.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 +4 -10
- package/dist/auth/index.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/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +6 -3
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/newUsers.d.ts +10 -0
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +80 -11
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/config.d.ts +2514 -22
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +166 -4
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +8 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +14 -11
- 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 +142 -0
- package/dist/coreRoutes.js.map +1 -0
- package/dist/generated/graphql-schemas/__mj.d.ts +504 -3
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +2456 -7
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +43 -8
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +59 -19
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +3 -3
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/PushStatusResolver.js +1 -1
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +123 -48
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +293 -305
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +16 -0
- package/dist/generic/RunViewResolver.js.map +1 -1
- 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 +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +219 -278
- package/dist/index.js.map +1 -1
- package/dist/isolatedProvider.d.ts +20 -0
- package/dist/isolatedProvider.d.ts.map +1 -0
- package/dist/isolatedProvider.js +22 -0
- package/dist/isolatedProvider.js.map +1 -0
- 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/realtimeProxy/RealtimeProxyServer.d.ts +44 -4
- package/dist/realtimeProxy/RealtimeProxyServer.d.ts.map +1 -1
- package/dist/realtimeProxy/RealtimeProxyServer.js +121 -16
- package/dist/realtimeProxy/RealtimeProxyServer.js.map +1 -1
- package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts +171 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts.map +1 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.js +532 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.js.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.d.ts +148 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.js +191 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.js.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts +66 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js +139 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts +38 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.js +99 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -0
- 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 +61 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js +149 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts +57 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts.map +1 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.js +69 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.js.map +1 -0
- package/dist/realtimeSessions/index.d.ts +19 -0
- package/dist/realtimeSessions/index.d.ts.map +1 -0
- package/dist/realtimeSessions/index.js +19 -0
- package/dist/realtimeSessions/index.js.map +1 -0
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts +30 -0
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js +47 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
- package/dist/realtimeSessions/sessionAccess.d.ts +92 -0
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -0
- package/dist/realtimeSessions/sessionAccess.js +94 -0
- package/dist/realtimeSessions/sessionAccess.js.map +1 -0
- package/dist/realtimeSessions/sessionConfigStamps.d.ts +70 -0
- package/dist/realtimeSessions/sessionConfigStamps.d.ts.map +1 -0
- package/dist/realtimeSessions/sessionConfigStamps.js +93 -0
- package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -0
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts +65 -0
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -0
- package/dist/realtimeSessions/subscriptionAuthorization.js +71 -0
- package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -0
- package/dist/realtimeSessions/verificationCore.d.ts +243 -0
- package/dist/realtimeSessions/verificationCore.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationCore.js +356 -0
- package/dist/realtimeSessions/verificationCore.js.map +1 -0
- package/dist/realtimeSessions/verificationPages.d.ts +66 -0
- package/dist/realtimeSessions/verificationPages.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationPages.js +110 -0
- package/dist/realtimeSessions/verificationPages.js.map +1 -0
- package/dist/realtimeSessions/verificationPolicy.d.ts +147 -0
- package/dist/realtimeSessions/verificationPolicy.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationPolicy.js +249 -0
- package/dist/realtimeSessions/verificationPolicy.js.map +1 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts +263 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationWorkflow.js +435 -0
- package/dist/realtimeSessions/verificationWorkflow.js.map +1 -0
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +20 -2
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +31 -2
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +31 -5
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +75 -14
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts +14 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +21 -5
- package/dist/resolvers/AdhocQueryResolver.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/CacheStatsResolver.d.ts +27 -0
- package/dist/resolvers/CacheStatsResolver.d.ts.map +1 -1
- package/dist/resolvers/CacheStatsResolver.js +113 -2
- package/dist/resolvers/CacheStatsResolver.js.map +1 -1
- package/dist/resolvers/ClientToolRequestResolver.d.ts +4 -2
- package/dist/resolvers/ClientToolRequestResolver.d.ts.map +1 -1
- package/dist/resolvers/ClientToolRequestResolver.js +28 -10
- package/dist/resolvers/ClientToolRequestResolver.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/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 +27 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +148 -2
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +82 -11
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +279 -101
- 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/HumanHandoffResolver.d.ts.map +1 -1
- package/dist/resolvers/HumanHandoffResolver.js +7 -1
- package/dist/resolvers/HumanHandoffResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +4 -2
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +9 -4
- package/dist/resolvers/MCPResolver.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 +13 -0
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts +54 -2
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +155 -10
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +157 -33
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +404 -116
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RealtimeSessionEventsResolver.d.ts +61 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.d.ts.map +1 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.js +130 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.js.map +1 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts +85 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts.map +1 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.js +188 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.js.map +1 -0
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +2 -0
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +5 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +10 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +100 -14
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +12 -11
- package/dist/resolvers/RunTemplateResolver.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 +6 -2
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts +2 -0
- package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.js +23 -6
- package/dist/resolvers/SyncRolesUsersResolver.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 +65 -13
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +19 -2
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +102 -24
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserAvatarResolver.d.ts +16 -0
- package/dist/resolvers/UserAvatarResolver.d.ts.map +1 -0
- package/dist/resolvers/UserAvatarResolver.js +124 -0
- package/dist/resolvers/UserAvatarResolver.js.map +1 -0
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +2 -17
- package/dist/resolvers/UserResolver.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/resolvers/agentVisionConsentAudit.d.ts +37 -0
- package/dist/resolvers/agentVisionConsentAudit.d.ts.map +1 -0
- package/dist/resolvers/agentVisionConsentAudit.js +63 -0
- package/dist/resolvers/agentVisionConsentAudit.js.map +1 -0
- package/dist/resolvers/avatarInputValidation.d.ts +40 -0
- package/dist/resolvers/avatarInputValidation.d.ts.map +1 -0
- package/dist/resolvers/avatarInputValidation.js +97 -0
- package/dist/resolvers/avatarInputValidation.js.map +1 -0
- package/dist/resolvers/currentUserRoles.d.ts +29 -0
- package/dist/resolvers/currentUserRoles.d.ts.map +1 -1
- package/dist/resolvers/currentUserRoles.js +30 -0
- package/dist/resolvers/currentUserRoles.js.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.d.ts +6 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.js +21 -0
- package/dist/resolvers/meetings/meetingMutations.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 +3 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +21 -12
- 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/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 +57 -4
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +607 -18
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/sharedCache.d.ts +105 -0
- package/dist/sharedCache.d.ts.map +1 -0
- package/dist/sharedCache.js +279 -0
- package/dist/sharedCache.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +99 -96
- package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
- package/src/__tests__/AdhocQueryResolver.sqlAuthorizer.test.ts +104 -0
- package/src/__tests__/BridgeHostInstance.test.ts +232 -0
- package/src/__tests__/ClientToolRequestResolver.test.ts +116 -0
- package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
- package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +433 -0
- package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
- package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
- package/src/__tests__/HostInstance.test.ts +84 -0
- package/src/__tests__/HumanHandoffResolver.test.ts +17 -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__/MeetingResolver.test.ts +75 -1
- package/src/__tests__/RealtimeBridgeResolver.test.ts +415 -6
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +383 -0
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +682 -58
- package/src/__tests__/RealtimeProxyServer.test.ts +16 -1
- package/src/__tests__/RealtimeRelay.test.ts +876 -0
- package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
- package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
- package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
- 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 +212 -6
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
- package/src/__tests__/ReturningVisitorRecap.test.ts +115 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +170 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +6 -4
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +258 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +166 -0
- package/src/__tests__/RunTemplateResolver.test.ts +132 -0
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +63 -0
- package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
- package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
- package/src/__tests__/SessionJanitor.test.ts +1203 -21
- package/src/__tests__/SessionManager.test.ts +240 -17
- package/src/__tests__/SessionRunIDVerifier.test.ts +251 -0
- package/src/__tests__/SyncRolesUsersResolver.userRoles.test.ts +97 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
- package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +403 -22
- package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
- package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
- package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
- package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
- package/src/__tests__/UserAvatarResolver.test.ts +255 -0
- package/src/__tests__/UserResolver.currentUser.test.ts +16 -1
- package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
- package/src/__tests__/actionAuthorization.test.ts +130 -0
- package/src/__tests__/agent-run-data-guard.test.ts +130 -0
- package/src/__tests__/agentVisionConsentAudit.test.ts +118 -0
- package/src/__tests__/apiRootBoot.test.ts +202 -0
- package/src/__tests__/avatarInputValidation.test.ts +160 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +64 -0
- package/src/__tests__/conversationRunEvents.test.ts +56 -14
- package/src/__tests__/globalCors.test.ts +217 -0
- package/src/__tests__/isolatedProviderTransactions.test.ts +169 -0
- package/src/__tests__/magicLinkService.consume.test.ts +6 -0
- package/src/__tests__/magicLinkService.provisionLog.test.ts +5 -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__/newUsers.template.test.ts +151 -0
- package/src/__tests__/newUsers.test.ts +74 -5
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +17 -2
- package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +7 -0
- package/src/__tests__/realtimeRecordingHandler.test.ts +652 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventService.test.ts +201 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +215 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionVerificationResolver.test.ts +102 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionVerificationService.test.ts +349 -0
- package/src/__tests__/realtimeSessions/RealtimeVerifyRouter.test.ts +131 -0
- package/src/__tests__/realtimeSessions/SlidingWindowRateLimiter.test.ts +56 -0
- package/src/__tests__/realtimeSessions/helpers.ts +4 -0
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +129 -0
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +124 -0
- package/src/__tests__/realtimeSessions/verificationCore.test.ts +355 -0
- package/src/__tests__/realtimeSessions/verificationPages.test.ts +84 -0
- package/src/__tests__/realtimeSessions/verificationPolicy.test.ts +226 -0
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +633 -0
- package/src/__tests__/resolverBase.fls.test.ts +87 -4
- package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
- package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -96
- package/src/__tests__/sharedCache.test.ts +312 -0
- package/src/__tests__/widgetGuestElevation.test.ts +44 -0
- package/src/agentSessions/BridgeHostInstance.ts +32 -0
- package/src/agentSessions/HostInstance.ts +124 -28
- package/src/agentSessions/ReturningVisitorRecap.ts +7 -3
- package/src/agentSessions/SessionJanitor.ts +821 -59
- package/src/agentSessions/SessionManager.ts +138 -26
- package/src/agentSessions/SessionRunIDVerifier.ts +171 -0
- package/src/agentSessions/index.ts +10 -3
- package/src/apiRoot.ts +78 -0
- package/src/auth/AuthProviderCatalogRouter.ts +26 -0
- package/src/auth/LoginScreenEngine.ts +50 -0
- package/src/auth/actionAuthorization.ts +116 -0
- package/src/auth/index.ts +4 -8
- package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
- package/src/auth/magicLink/MagicLinkService.ts +6 -3
- package/src/auth/newUsers.ts +99 -11
- package/src/config.ts +171 -5
- package/src/context.ts +15 -10
- package/src/coreRoutes.ts +166 -0
- package/src/generated/graphql-schemas/__mj.ts +1815 -57
- package/src/generic/CacheInvalidationResolver.ts +73 -18
- package/src/generic/OrphanedConversationDetailReconciler.ts +3 -3
- package/src/generic/PushStatusResolver.ts +1 -1
- package/src/generic/ResolverBase.ts +335 -326
- package/src/generic/RunViewResolver.ts +21 -0
- package/src/globalCors.ts +71 -0
- package/src/index.ts +231 -300
- package/src/isolatedProvider.ts +22 -0
- package/src/multiTenancy/index.ts +24 -2
- package/src/realtimeProxy/RealtimeProxyServer.ts +148 -16
- package/src/realtimeProxy/RealtimeRelayTunnel.ts +645 -0
- package/src/realtimeSessions/README.md +179 -0
- package/src/realtimeSessions/RealtimeSessionEventService.ts +274 -0
- package/src/realtimeSessions/RealtimeSessionVerificationService.ts +168 -0
- package/src/realtimeSessions/RealtimeVerifyRouter.ts +109 -0
- package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +189 -0
- package/src/realtimeSessions/SlidingWindowRateLimiter.ts +92 -0
- package/src/realtimeSessions/index.ts +18 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +55 -0
- package/src/realtimeSessions/sessionAccess.ts +145 -0
- package/src/realtimeSessions/sessionConfigStamps.ts +123 -0
- package/src/realtimeSessions/subscriptionAuthorization.ts +116 -0
- package/src/realtimeSessions/verificationCore.ts +502 -0
- package/src/realtimeSessions/verificationPages.ts +149 -0
- package/src/realtimeSessions/verificationPolicy.ts +321 -0
- package/src/realtimeSessions/verificationWorkflow.ts +702 -0
- package/src/realtimeWidget/widgetGuestElevation.ts +34 -2
- package/src/resolvers/ActionResolver.ts +84 -21
- package/src/resolvers/AdhocQueryResolver.ts +24 -6
- package/src/resolvers/ArtifactFileResolver.ts +9 -8
- package/src/resolvers/CacheStatsResolver.ts +89 -2
- package/src/resolvers/ClientToolRequestResolver.ts +25 -7
- package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
- package/src/resolvers/DatasetResolver.ts +70 -10
- package/src/resolvers/EntityRecordNameResolver.ts +3 -2
- package/src/resolvers/FetchEntityVectorsResolver.ts +179 -2
- package/src/resolvers/FileResolver.ts +321 -106
- package/src/resolvers/GetDataContextDataResolver.ts +139 -41
- package/src/resolvers/GetDataResolver.ts +6 -3
- package/src/resolvers/HumanHandoffResolver.ts +8 -0
- package/src/resolvers/IntegrationDiscoveryResolver.ts +4 -2
- package/src/resolvers/MCPResolver.ts +8 -5
- package/src/resolvers/QueryResolver.ts +11 -0
- package/src/resolvers/RealtimeBridgeResolver.ts +163 -11
- package/src/resolvers/RealtimeClientSessionResolver.ts +511 -129
- package/src/resolvers/RealtimeSessionEventsResolver.ts +133 -0
- package/src/resolvers/RealtimeSessionVerificationResolver.ts +174 -0
- package/src/resolvers/RemoteBrowserActionResolver.ts +11 -1
- package/src/resolvers/RunAIAgentResolver.ts +116 -14
- package/src/resolvers/RunTemplateResolver.ts +13 -12
- package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
- package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
- package/src/resolvers/SyncDataResolver.ts +6 -2
- package/src/resolvers/SyncRolesUsersResolver.ts +24 -6
- package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
- package/src/resolvers/TestQuerySQLResolver.ts +68 -13
- package/src/resolvers/TransactionGroupResolver.ts +131 -27
- package/src/resolvers/UserAvatarResolver.ts +111 -0
- package/src/resolvers/UserResolver.ts +2 -16
- package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
- package/src/resolvers/agent-run-data-guard.ts +89 -0
- package/src/resolvers/agentVisionConsentAudit.ts +82 -0
- package/src/resolvers/avatarInputValidation.ts +123 -0
- package/src/resolvers/currentUserRoles.ts +32 -1
- package/src/resolvers/meetings/meetingMutations.ts +21 -0
- package/src/rest/RealtimeRecordingHandler.ts +464 -0
- package/src/rest/ViewOperationsHandler.ts +29 -13
- package/src/rest/setupRESTEndpoints.ts +6 -0
- package/src/serverExtensionReservedRoots.ts +14 -17
- 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 +713 -17
- package/src/sharedCache.ts +305 -0
- package/src/types.ts +7 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GraphQL subscription that delivers **realtime session events** to the session they are
|
|
3
|
+
* addressed to — `subscription RealtimeSessionEvents(agentSessionId: String!)`.
|
|
4
|
+
*
|
|
5
|
+
* The event contract lives in `@memberjunction/ai-core-plus` (`realtime-session-events.ts`); the publisher
|
|
6
|
+
* apps call is `RealtimeSessionEventService`. This resolver is the delivery edge, and its whole job is
|
|
7
|
+
* authorization, done twice on purpose:
|
|
8
|
+
*
|
|
9
|
+
* 1. **At subscribe time** ({@link AuthorizeRealtimeSessionSubscription}). The session row is loaded and
|
|
10
|
+
* {@link AuthorizeSessionAccess} must allow the connection's authenticated principal: the session's
|
|
11
|
+
* `UserID` must be the caller's user and — for an anonymous widget guest, who shares one Anonymous
|
|
12
|
+
* user with every other guest — the guest's signed per-session scope must match the session's
|
|
13
|
+
* conversation. A refusal is an error on THIS subscription only (the socket and its other
|
|
14
|
+
* subscriptions are untouched) and is the same "not found" whether the session is missing or simply
|
|
15
|
+
* not yours, so ids cannot be probed.
|
|
16
|
+
* 2. **For every event** ({@link RealtimeSessionEventsFilter}). Each published event carries the owner and
|
|
17
|
+
* scope snapshot of its session; the filter re-applies the same decision against the CONNECTION's
|
|
18
|
+
* identity. Authorization therefore does not rest on a single check at one moment, and a replicated
|
|
19
|
+
* event from another server instance is judged exactly like a local one.
|
|
20
|
+
*
|
|
21
|
+
* In neither check does a client-supplied value decide who receives anything: `agentSessionId` only
|
|
22
|
+
* selects WHICH of the caller's own sessions to listen to; the identity it is checked against comes from
|
|
23
|
+
* the server-authenticated connection context.
|
|
24
|
+
*
|
|
25
|
+
* Events have no replay. A subscriber that was disconnected when an event fired recovers durable state
|
|
26
|
+
* from `RealtimeSessionVerificationStatus` (and from the session itself).
|
|
27
|
+
*
|
|
28
|
+
* @module @memberjunction/server
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { Resolver, Subscription, Root, Arg, ObjectType, Field } from 'type-graphql';
|
|
32
|
+
import { withFilter } from 'graphql-subscriptions';
|
|
33
|
+
import { PubSubManager } from '../generic/PubSubManager.js';
|
|
34
|
+
import {
|
|
35
|
+
AuthorizeRealtimeSessionSubscription,
|
|
36
|
+
RealtimeSessionEventsFilter,
|
|
37
|
+
type RealtimeSessionEventsArgs,
|
|
38
|
+
type RealtimeSessionEventsContext,
|
|
39
|
+
type SubscriptionAuthorizationDeps,
|
|
40
|
+
DEFAULT_SUBSCRIPTION_AUTHORIZATION_DEPS,
|
|
41
|
+
} from '../realtimeSessions/subscriptionAuthorization.js';
|
|
42
|
+
import { REALTIME_SESSION_EVENTS_TOPIC, type RealtimeSessionEventTopicPayload } from '../realtimeSessions/RealtimeSessionEventService.js';
|
|
43
|
+
|
|
44
|
+
/** One session event as the client receives it. The routing snapshot is deliberately NOT exposed. */
|
|
45
|
+
@ObjectType()
|
|
46
|
+
export class RealtimeSessionEventNotification {
|
|
47
|
+
/** Event type, e.g. `identity.verified`. Clients ignore types they do not know. */
|
|
48
|
+
@Field(() => String)
|
|
49
|
+
Type: string;
|
|
50
|
+
|
|
51
|
+
/** The session the event is addressed to. */
|
|
52
|
+
@Field(() => String)
|
|
53
|
+
AgentSessionID: string;
|
|
54
|
+
|
|
55
|
+
/** ISO-8601 instant the server emitted the event. */
|
|
56
|
+
@Field(() => String)
|
|
57
|
+
OccurredAt: string;
|
|
58
|
+
|
|
59
|
+
/** The event payload, JSON-encoded. Parse with `ParseRealtimeSessionEvent` from `@memberjunction/ai-core-plus`. */
|
|
60
|
+
@Field(() => String)
|
|
61
|
+
PayloadJson: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Builds the event stream for one authorized subscription: the shared topic, narrowed by
|
|
66
|
+
* {@link RealtimeSessionEventsFilter}.
|
|
67
|
+
*/
|
|
68
|
+
function openEventStream(
|
|
69
|
+
root: unknown,
|
|
70
|
+
args: RealtimeSessionEventsArgs,
|
|
71
|
+
context: RealtimeSessionEventsContext,
|
|
72
|
+
info: unknown,
|
|
73
|
+
): AsyncIterator<RealtimeSessionEventTopicPayload> {
|
|
74
|
+
const engine = PubSubManager.Instance.PubSubEngine;
|
|
75
|
+
if (!engine) {
|
|
76
|
+
throw new Error('Realtime session events are unavailable: PubSub is not configured.');
|
|
77
|
+
}
|
|
78
|
+
const filtered = withFilter(
|
|
79
|
+
() => engine.asyncIterator<RealtimeSessionEventTopicPayload>(REALTIME_SESSION_EVENTS_TOPIC),
|
|
80
|
+
(payload: RealtimeSessionEventTopicPayload, filterArgs: RealtimeSessionEventsArgs, filterContext: RealtimeSessionEventsContext) =>
|
|
81
|
+
RealtimeSessionEventsFilter({ payload, args: filterArgs, context: filterContext }),
|
|
82
|
+
);
|
|
83
|
+
return filtered(root, args, context, info);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The `subscribe` function: authorize FIRST (asynchronously), then open the stream. Exported (with an
|
|
88
|
+
* injectable `deps` argument graphql-js never passes) so the whole path is testable end to end.
|
|
89
|
+
*
|
|
90
|
+
* graphql-js awaits the value `subscribe` returns and turns a thrown error into a per-operation error
|
|
91
|
+
* result, which is exactly what a refusal should be (a failure of this subscription, not the socket).
|
|
92
|
+
*/
|
|
93
|
+
export async function AuthorizeAndSubscribeToRealtimeSessionEvents(
|
|
94
|
+
root: unknown,
|
|
95
|
+
args: RealtimeSessionEventsArgs,
|
|
96
|
+
context: RealtimeSessionEventsContext,
|
|
97
|
+
info: unknown,
|
|
98
|
+
deps: SubscriptionAuthorizationDeps = DEFAULT_SUBSCRIPTION_AUTHORIZATION_DEPS,
|
|
99
|
+
): Promise<AsyncIterator<RealtimeSessionEventTopicPayload>> {
|
|
100
|
+
await AuthorizeRealtimeSessionSubscription(args, context, deps);
|
|
101
|
+
return openEventStream(root, args, context, info);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@Resolver()
|
|
105
|
+
export class RealtimeSessionEventsResolver {
|
|
106
|
+
/**
|
|
107
|
+
* Subscribe to the events addressed to one of YOUR realtime sessions.
|
|
108
|
+
*
|
|
109
|
+
* @param agentSessionId - the `MJ: AI Agent Sessions` id to listen to. Must be a session the
|
|
110
|
+
* authenticated connection owns (and, for an anonymous widget guest, whose signed scope matches);
|
|
111
|
+
* otherwise the subscription is refused.
|
|
112
|
+
*/
|
|
113
|
+
@Subscription(() => RealtimeSessionEventNotification, {
|
|
114
|
+
// graphql-subscriptions types `ResolverFn` as returning a bare AsyncIterator, but graphql-js
|
|
115
|
+
// AWAITS what `subscribe` returns (execute/subscribe.js: `await resolveFn(...)`), and awaiting is
|
|
116
|
+
// the only way to authorize against the database before opening the stream. The typing gap is in
|
|
117
|
+
// the library; `@ts-expect-error` (not a cast) so this fails to compile the day the type is fixed.
|
|
118
|
+
// @ts-expect-error subscribe may return Promise<AsyncIterator>; see comment above
|
|
119
|
+
subscribe: AuthorizeAndSubscribeToRealtimeSessionEvents,
|
|
120
|
+
})
|
|
121
|
+
RealtimeSessionEvents(
|
|
122
|
+
@Root() payload: RealtimeSessionEventTopicPayload,
|
|
123
|
+
@Arg('agentSessionId', () => String) _agentSessionId: string,
|
|
124
|
+
): RealtimeSessionEventNotification {
|
|
125
|
+
// OwnerUserID / ScopeKey are server-internal filter keys and are intentionally not returned.
|
|
126
|
+
return {
|
|
127
|
+
Type: payload.Type,
|
|
128
|
+
AgentSessionID: payload.AgentSessionID,
|
|
129
|
+
OccurredAt: payload.OccurredAt,
|
|
130
|
+
PayloadJson: payload.PayloadJson,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GraphQL operations for **mid-session identity verification** of a realtime session.
|
|
3
|
+
*
|
|
4
|
+
* A person talking to an agent (often an anonymous widget guest) proves they control an email address
|
|
5
|
+
* without leaving the conversation. Three operations, all callable only as the session's OWN principal:
|
|
6
|
+
*
|
|
7
|
+
* | Operation | Kind | Purpose |
|
|
8
|
+
* |---|---|---|
|
|
9
|
+
* | `RequestRealtimeSessionVerification(agentSessionId, name, email)` | mutation | store a pending verification and email a one-time link + a typed code |
|
|
10
|
+
* | `SubmitRealtimeSessionVerificationCode(agentSessionId, code)` | mutation | redeem the typed code (the fallback for opening the email on another device) |
|
|
11
|
+
* | `RealtimeSessionVerificationStatus(agentSessionId)` | query | read the current state — the durable backstop for a missed `identity.verified` event |
|
|
12
|
+
*
|
|
13
|
+
* The emailed link is redeemed on a different surface — the public `GET/POST /realtime/verify` routes
|
|
14
|
+
* (`RealtimeVerifyRouter`) — because the person opening it holds no MJ token.
|
|
15
|
+
*
|
|
16
|
+
* The decisions, policy and limits live in `realtimeSessions/verificationWorkflow.ts`; this resolver
|
|
17
|
+
* only identifies the caller from the server-authenticated payload and maps the result. Note that it
|
|
18
|
+
* reads `userPayload.userRecord` directly and does **not** use `ResolverBase.GetUserFromPayload`: that
|
|
19
|
+
* helper falls back to an email lookup in the user cache, which would drop an anonymous guest's
|
|
20
|
+
* per-session scope — and a scope-less anonymous principal must never be treated as a named owner of
|
|
21
|
+
* the shared Anonymous user's sessions. No authenticated `userRecord` means no access.
|
|
22
|
+
*
|
|
23
|
+
* @module @memberjunction/server
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, Int } from 'type-graphql';
|
|
27
|
+
import type { UserInfo } from '@memberjunction/core';
|
|
28
|
+
import type { AppContext } from '../types.js';
|
|
29
|
+
import { GetReadWriteProvider } from '../util.js';
|
|
30
|
+
import { NoLog } from '../logging/NoLog.js';
|
|
31
|
+
import { RealtimeSessionVerificationService } from '../realtimeSessions/RealtimeSessionVerificationService.js';
|
|
32
|
+
import type { PrincipalCaller, VerificationOperationResult } from '../realtimeSessions/verificationWorkflow.js';
|
|
33
|
+
|
|
34
|
+
/** Result of every verification operation. */
|
|
35
|
+
@ObjectType()
|
|
36
|
+
export class RealtimeSessionVerificationResult {
|
|
37
|
+
/** True when the operation did what was asked. */
|
|
38
|
+
@Field(() => Boolean)
|
|
39
|
+
Success: boolean;
|
|
40
|
+
|
|
41
|
+
/** The session's verification state after the operation: `unverified`, `pending` or `verified`. */
|
|
42
|
+
@Field(() => String)
|
|
43
|
+
VerificationState: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Machine-readable failure reason when `Success` is false — e.g. `invalid_email`, `consumer_domain`,
|
|
47
|
+
* `domain_blocked`, `rate_limited`, `send_limit_reached`, `invalid_code`, `attempts_exhausted`,
|
|
48
|
+
* `code_expired`, `session_not_found`, `session_closed`, `verification_unavailable`.
|
|
49
|
+
*/
|
|
50
|
+
@Field(() => String, { nullable: true })
|
|
51
|
+
ErrorCode?: string;
|
|
52
|
+
|
|
53
|
+
/** A message safe to show a person. */
|
|
54
|
+
@Field(() => String, { nullable: true })
|
|
55
|
+
Message?: string;
|
|
56
|
+
|
|
57
|
+
/** ISO instant the pending link/code expires. */
|
|
58
|
+
@Field(() => String, { nullable: true })
|
|
59
|
+
ExpiresAt?: string;
|
|
60
|
+
|
|
61
|
+
/** Verification emails this session may still trigger. */
|
|
62
|
+
@Field(() => Int, { nullable: true })
|
|
63
|
+
SendsRemaining?: number;
|
|
64
|
+
|
|
65
|
+
/** Wrong code entries left before the pending verification is voided. */
|
|
66
|
+
@Field(() => Int, { nullable: true })
|
|
67
|
+
AttemptsRemaining?: number;
|
|
68
|
+
|
|
69
|
+
/** Seconds to wait before retrying, when rate limited. */
|
|
70
|
+
@Field(() => Int, { nullable: true })
|
|
71
|
+
RetryAfterSeconds?: number;
|
|
72
|
+
|
|
73
|
+
/** The verified address, once verified. */
|
|
74
|
+
@Field(() => String, { nullable: true })
|
|
75
|
+
VerifiedEmail?: string;
|
|
76
|
+
|
|
77
|
+
/** ISO instant verification completed. */
|
|
78
|
+
@Field(() => String, { nullable: true })
|
|
79
|
+
VerifiedAt?: string;
|
|
80
|
+
|
|
81
|
+
/** The session's new absolute deadline (ISO) when verification extended it. The server enforces it; this is informational. */
|
|
82
|
+
@Field(() => String, { nullable: true })
|
|
83
|
+
MaxSessionDeadlineIso?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Maps the workflow result onto the GraphQL type. */
|
|
87
|
+
function toResult(result: VerificationOperationResult): RealtimeSessionVerificationResult {
|
|
88
|
+
return { ...result };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The result for a caller with no usable authenticated identity. */
|
|
92
|
+
function notAuthenticated(): RealtimeSessionVerificationResult {
|
|
93
|
+
return { Success: false, VerificationState: 'unverified', ErrorCode: 'session_not_found', Message: 'Session not found.' };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@Resolver()
|
|
97
|
+
export class RealtimeSessionVerificationResolver {
|
|
98
|
+
/**
|
|
99
|
+
* Ask to verify an email for your realtime session. Applies the session's policy (business-domain
|
|
100
|
+
* rules, blocked domains, send and rate limits), then emails a one-time link plus a short code.
|
|
101
|
+
*
|
|
102
|
+
* @param agentSessionId - your `MJ: AI Agent Sessions` id
|
|
103
|
+
* @param name - the name to greet in the email (sanitised and length-capped server-side)
|
|
104
|
+
* @param email - the address to verify
|
|
105
|
+
*/
|
|
106
|
+
@Mutation(() => RealtimeSessionVerificationResult)
|
|
107
|
+
async RequestRealtimeSessionVerification(
|
|
108
|
+
@Arg('agentSessionId', () => String) agentSessionId: string,
|
|
109
|
+
@Arg('name', () => String) name: string,
|
|
110
|
+
@Arg('email', () => String) @NoLog email: string,
|
|
111
|
+
@Ctx() context: AppContext,
|
|
112
|
+
): Promise<RealtimeSessionVerificationResult> {
|
|
113
|
+
const caller = this.callerFrom(context);
|
|
114
|
+
if (!caller) {
|
|
115
|
+
return notAuthenticated();
|
|
116
|
+
}
|
|
117
|
+
return toResult(
|
|
118
|
+
await RealtimeSessionVerificationService.Instance.RequestVerification(
|
|
119
|
+
{ AgentSessionID: agentSessionId, Name: name, Email: email },
|
|
120
|
+
caller,
|
|
121
|
+
),
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Redeem the typed code from the verification email. Single use; voided after too many wrong entries.
|
|
127
|
+
*
|
|
128
|
+
* @param agentSessionId - your `MJ: AI Agent Sessions` id
|
|
129
|
+
* @param code - the code from the email (spaces and dashes are ignored)
|
|
130
|
+
*/
|
|
131
|
+
@Mutation(() => RealtimeSessionVerificationResult)
|
|
132
|
+
async SubmitRealtimeSessionVerificationCode(
|
|
133
|
+
@Arg('agentSessionId', () => String) agentSessionId: string,
|
|
134
|
+
@Arg('code', () => String) @NoLog code: string,
|
|
135
|
+
@Ctx() context: AppContext,
|
|
136
|
+
): Promise<RealtimeSessionVerificationResult> {
|
|
137
|
+
const caller = this.callerFrom(context);
|
|
138
|
+
if (!caller) {
|
|
139
|
+
return notAuthenticated();
|
|
140
|
+
}
|
|
141
|
+
return toResult(await RealtimeSessionVerificationService.Instance.SubmitCode({ AgentSessionID: agentSessionId, Code: code }, caller));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Read the current verification state of your realtime session. Use it after a reconnect: session
|
|
146
|
+
* events have no replay, so this is how a client that missed `identity.verified` finds out.
|
|
147
|
+
*
|
|
148
|
+
* @param agentSessionId - your `MJ: AI Agent Sessions` id
|
|
149
|
+
*/
|
|
150
|
+
@Query(() => RealtimeSessionVerificationResult)
|
|
151
|
+
async RealtimeSessionVerificationStatus(
|
|
152
|
+
@Arg('agentSessionId', () => String) agentSessionId: string,
|
|
153
|
+
@Ctx() context: AppContext,
|
|
154
|
+
): Promise<RealtimeSessionVerificationResult> {
|
|
155
|
+
const caller = this.callerFrom(context);
|
|
156
|
+
if (!caller) {
|
|
157
|
+
return notAuthenticated();
|
|
158
|
+
}
|
|
159
|
+
return toResult(await RealtimeSessionVerificationService.Instance.GetStatus({ AgentSessionID: agentSessionId }, caller));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Builds the caller from the server-authenticated payload, or null when there is none. Identity comes
|
|
164
|
+
* from `userPayload.userRecord` ONLY (see the module header).
|
|
165
|
+
*/
|
|
166
|
+
private callerFrom(context: AppContext): PrincipalCaller | null {
|
|
167
|
+
const contextUser = context.userPayload?.userRecord as UserInfo | undefined;
|
|
168
|
+
const provider = GetReadWriteProvider(context.providers);
|
|
169
|
+
if (!contextUser?.ID || !provider) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
return { Kind: 'principal', ContextUser: contextUser, Provider: provider, ClientIp: context.ClientIp };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -24,6 +24,7 @@ import { MJAIAgentSessionEntity, MJAIAgentEntity } from '@memberjunction/core-en
|
|
|
24
24
|
import { NormalizeInstanceKey, RemoteBrowserEngine } from '@memberjunction/remote-browser-server';
|
|
25
25
|
import { BeginBrowserGoalStep, FinalizeBrowserGoalStep, ExtractCoAgentRunID } from '../agentSessions/remoteBrowserGoalEngine.js';
|
|
26
26
|
import { RemoteBrowserGoalRegistry } from '../agentSessions/remoteBrowserGoalRegistry.js';
|
|
27
|
+
import { SessionRunIDVerifier } from '../agentSessions/SessionRunIDVerifier.js';
|
|
27
28
|
import { randomUUID } from 'node:crypto';
|
|
28
29
|
import {
|
|
29
30
|
RemoteBrowserAction,
|
|
@@ -261,6 +262,9 @@ export class RemoteBrowserActionResolver extends ResolverBase {
|
|
|
261
262
|
*/
|
|
262
263
|
private startedScreencasts = new Map<string, number>();
|
|
263
264
|
|
|
265
|
+
/** Checks the co-agent run id read from a session's owner-editable `Config_` before a step is attached to it. */
|
|
266
|
+
private readonly runIDVerifier = new SessionRunIDVerifier();
|
|
267
|
+
|
|
264
268
|
/**
|
|
265
269
|
* Surfaces whose live tab-audio stream this resolver has already started, keyed by
|
|
266
270
|
* {@link RemoteBrowserActionResolver.streamKey} for the same reason the screencast map is. Entries
|
|
@@ -400,7 +404,13 @@ export class RemoteBrowserActionResolver extends ResolverBase {
|
|
|
400
404
|
const providerName = await this.resolveProviderName(session, contextUser, provider);
|
|
401
405
|
// Observability: nest this goal's many prompt runs under ONE "Browser goal" step on the realtime
|
|
402
406
|
// co-agent run (when the session has one). Best-effort — a null step just means the goal runs unlinked.
|
|
403
|
-
|
|
407
|
+
// The owner can edit Config_, so its run id is used only when it is a run of this session.
|
|
408
|
+
const { CoAgentRunID: coAgentRunID } = await this.runIDVerifier.Verify(
|
|
409
|
+
session.ID,
|
|
410
|
+
{ CoAgentRunID: ExtractCoAgentRunID(session.Config_) },
|
|
411
|
+
contextUser,
|
|
412
|
+
provider,
|
|
413
|
+
);
|
|
404
414
|
const goalStep = await BeginBrowserGoalStep(provider, contextUser, coAgentRunID, goal);
|
|
405
415
|
|
|
406
416
|
// ASYNC START: a goal loop can run for minutes; do NOT hold this request open for it (browser
|
|
@@ -13,6 +13,7 @@ import { StartLivenessPulse } from '../generic/FireAndForgetHeartbeat.js';
|
|
|
13
13
|
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
14
14
|
import { GetReadWriteProvider } from '../util.js';
|
|
15
15
|
import { ResolveWidgetGuestRunContext, ElevateUserPayload } from '../realtimeWidget/widgetGuestElevation.js';
|
|
16
|
+
import { IsTrustedAgentRunCaller } from './agent-run-data-guard.js';
|
|
16
17
|
import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
|
|
17
18
|
import { GetAttachmentService } from '@memberjunction/aiengine';
|
|
18
19
|
import { NotificationEngine } from '@memberjunction/notifications';
|
|
@@ -252,6 +253,14 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
252
253
|
throw new Error(`AI Agent "${agentEntity.Name}" is not active (Status: ${agentEntity.Status})`);
|
|
253
254
|
}
|
|
254
255
|
|
|
256
|
+
// Enforce agent run permissions for the calling user
|
|
257
|
+
if (currentUser && typeof AIEngine.Instance.CanUserRunAgent === 'function') {
|
|
258
|
+
const canRun = await AIEngine.Instance.CanUserRunAgent(agentEntity.ID, currentUser);
|
|
259
|
+
if (!canRun) {
|
|
260
|
+
throw new Error(`User does not have permission to run AI Agent "${agentEntity.Name}" (${agentEntity.ID})`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
255
264
|
return agentEntity;
|
|
256
265
|
}
|
|
257
266
|
|
|
@@ -293,7 +302,11 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
293
302
|
taskGraphDebug?: string,
|
|
294
303
|
/** History floor for a conversation run — threaded into ExecuteAgentParams.ConversationHistoryFrom,
|
|
295
304
|
* so the framework's own conversation reads (retrieval tools, artifacts, compaction) honour it too. */
|
|
296
|
-
conversationHistoryFrom?: Date
|
|
305
|
+
conversationHistoryFrom?: Date,
|
|
306
|
+
/** ExecuteAgentParams.TrustReservedRunData: true only for a caller IsTrustedAgentRunCaller accepts. */
|
|
307
|
+
trustReservedRunData: boolean = false,
|
|
308
|
+
/** The conversation branch of the run — threaded into ExecuteAgentParams.ConversationBranchID. */
|
|
309
|
+
conversationBranchId?: string | null
|
|
297
310
|
): Promise<AIAgentRunResult> {
|
|
298
311
|
const startTime = Date.now();
|
|
299
312
|
// Best-effort handle for persistInFlightAgentFailure. Populated from a
|
|
@@ -362,7 +375,10 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
362
375
|
requestedSkillIDs: requestedSkillIDs,
|
|
363
376
|
taskGraphDebug: parseTaskGraphDebug(taskGraphDebug),
|
|
364
377
|
ConversationHistoryFrom: conversationHistoryFrom,
|
|
378
|
+
...(conversationBranchId ? { ConversationBranchID: conversationBranchId } : {}),
|
|
365
379
|
data: parsedData,
|
|
380
|
+
// Whether the run may read the reserved data keys (scope, agent-type params); BaseAgent drops them otherwise.
|
|
381
|
+
TrustReservedRunData: trustReservedRunData,
|
|
366
382
|
context: {
|
|
367
383
|
dataSource: dataSource
|
|
368
384
|
}
|
|
@@ -561,6 +577,9 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
561
577
|
await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
|
|
562
578
|
|
|
563
579
|
const p = GetReadWriteProvider(providers);
|
|
580
|
+
// Only the system user or an API key holding the agent:trusted scope may set a run's scope and agent-type
|
|
581
|
+
// params through data; for anyone else BaseAgent drops those keys (ExecuteAgentParams.TrustReservedRunData).
|
|
582
|
+
const trustRunData = await IsTrustedAgentRunCaller({ UserPayload: userPayload, IsWidgetGuestRun: false, AgentID: agentId });
|
|
564
583
|
|
|
565
584
|
if (fireAndForget) {
|
|
566
585
|
// Fire-and-forget mode: start execution in background, return immediately.
|
|
@@ -569,7 +588,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
569
588
|
p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
|
|
570
589
|
data, payload, lastRunId, autoPopulateLastRunPayload, configurationId,
|
|
571
590
|
conversationDetailId, createArtifacts || false, createNotification || false,
|
|
572
|
-
sourceArtifactId, sourceArtifactVersionId, undefined /*conversationId*/, planMode, requestedSkillIDs, taskGraphDebug
|
|
591
|
+
sourceArtifactId, sourceArtifactVersionId, undefined /*conversationId*/, planMode, requestedSkillIDs, taskGraphDebug,
|
|
592
|
+
undefined /*conversationHistoryFrom*/, trustRunData
|
|
573
593
|
);
|
|
574
594
|
|
|
575
595
|
LogStatus(`🔥 Fire-and-forget: Agent ${agentId} execution started in background for session ${sessionId}`);
|
|
@@ -604,7 +624,9 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
604
624
|
undefined, // runRef
|
|
605
625
|
planMode,
|
|
606
626
|
requestedSkillIDs,
|
|
607
|
-
taskGraphDebug
|
|
627
|
+
taskGraphDebug,
|
|
628
|
+
undefined, // conversationHistoryFrom
|
|
629
|
+
trustRunData
|
|
608
630
|
);
|
|
609
631
|
}
|
|
610
632
|
|
|
@@ -637,6 +659,9 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
637
659
|
@Arg('requestedSkillIDs', () => [String], { nullable: true }) requestedSkillIDs?: string[]
|
|
638
660
|
): Promise<AIAgentRunResult> {
|
|
639
661
|
const p = GetReadWriteProvider(providers);
|
|
662
|
+
// @RequireSystemUser admits only the system user, whom the rule trusts; it is still asked, so every
|
|
663
|
+
// resolver entry that takes a client's data decides the same way.
|
|
664
|
+
const trustRunData = await IsTrustedAgentRunCaller({ UserPayload: userPayload, IsWidgetGuestRun: false, AgentID: agentId });
|
|
640
665
|
return this.executeAIAgent(
|
|
641
666
|
p,
|
|
642
667
|
dataSource,
|
|
@@ -659,7 +684,10 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
659
684
|
undefined, // conversationId (not pre-resolved on this path)
|
|
660
685
|
undefined, // runRef
|
|
661
686
|
planMode,
|
|
662
|
-
requestedSkillIDs
|
|
687
|
+
requestedSkillIDs,
|
|
688
|
+
undefined, // taskGraphDebug
|
|
689
|
+
undefined, // conversationHistoryFrom
|
|
690
|
+
trustRunData
|
|
663
691
|
);
|
|
664
692
|
}
|
|
665
693
|
|
|
@@ -752,6 +780,45 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
752
780
|
}
|
|
753
781
|
}
|
|
754
782
|
|
|
783
|
+
/**
|
|
784
|
+
* The ID of this agent's newest root run in the conversation IF the user stopped it, else
|
|
785
|
+
* null. The query spans the runs that could be the predecessor (settled, or stopped by the
|
|
786
|
+
* user) and the newest decides, so a stopped run that a later settled run already followed
|
|
787
|
+
* is not chained to again. Uses the same filter and recognizer as `BaseAgent.findUserStoppedPredecessorRunId`
|
|
788
|
+
* (`MJAIAgentRunEntityExtended.BuildStoppedPredecessorFilter` / `IsUserStopped`), which carries the stopped run's
|
|
789
|
+
* completed results into the new run's context, so the two cannot pick different runs.
|
|
790
|
+
* Fail-soft: a lookup failure means no chaining, never a failed turn.
|
|
791
|
+
*/
|
|
792
|
+
private async findUserStoppedPredecessorRunId(
|
|
793
|
+
conversationId: string,
|
|
794
|
+
agentId: string,
|
|
795
|
+
branchId: string | null,
|
|
796
|
+
contextUser: UserInfo,
|
|
797
|
+
provider: IMetadataProvider
|
|
798
|
+
): Promise<string | null> {
|
|
799
|
+
try {
|
|
800
|
+
// The run must have replied on this turn's branch path: a run stopped on a sibling branch is not
|
|
801
|
+
// this path's history. The trunk needs no branch rows; a branch needs them to walk its ancestry.
|
|
802
|
+
const branches = branchId ? await ConversationEngine.LoadBranchesFresh(conversationId, contextUser, provider) : [];
|
|
803
|
+
const rv = RunView.FromMetadataProvider(provider);
|
|
804
|
+
const newest = await rv.RunView<{ ID: string; Status: string; CancellationReason: string | null }>({
|
|
805
|
+
EntityName: 'MJ: AI Agent Runs',
|
|
806
|
+
ExtraFilter: MJAIAgentRunEntityExtended.BuildStoppedPredecessorFilter(conversationId, agentId, branchId, branches),
|
|
807
|
+
OrderBy: '__mj_CreatedAt DESC',
|
|
808
|
+
MaxRows: 1,
|
|
809
|
+
Fields: ['ID', 'Status', 'CancellationReason'],
|
|
810
|
+
ResultType: 'simple',
|
|
811
|
+
// The row this looks for was written by the Stop button moments ago; read the database, not a cache.
|
|
812
|
+
BypassCache: true,
|
|
813
|
+
}, contextUser);
|
|
814
|
+
const run = newest.Success ? newest.Results?.[0] : undefined;
|
|
815
|
+
return run && MJAIAgentRunEntityExtended.IsUserStopped(run.Status, run.CancellationReason) ? run.ID : null;
|
|
816
|
+
} catch (error) {
|
|
817
|
+
LogError(`findUserStoppedPredecessorRunId failed; the turn runs unchained: ${error instanceof Error ? error.message : String(error)}`);
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
755
822
|
/**
|
|
756
823
|
* When a continuation run completes (lastRunId was provided), sync the corresponding
|
|
757
824
|
* AIAgentRequest by marking it as responded. This keeps the dashboard accurate when
|
|
@@ -916,6 +983,12 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
916
983
|
const widgetElevation = await ResolveWidgetGuestRunContext(userPayload, p);
|
|
917
984
|
const effectiveAgentId = widgetElevation ? widgetElevation.PinnedAgentId : agentId;
|
|
918
985
|
const effectiveUserPayload = widgetElevation ? ElevateUserPayload(userPayload, widgetElevation.ElevatedUser) : userPayload;
|
|
986
|
+
// Only the system user or an API key holding the agent:trusted scope may set a run's scope and agent-type
|
|
987
|
+
// params through data (ExecuteAgentParams.TrustReservedRunData). Judged on the caller's own payload: a widget
|
|
988
|
+
// guest runs under an elevated server principal but is never trusted.
|
|
989
|
+
const trustRunData = await IsTrustedAgentRunCaller({
|
|
990
|
+
UserPayload: userPayload, IsWidgetGuestRun: widgetElevation !== null, AgentID: agentId,
|
|
991
|
+
});
|
|
919
992
|
|
|
920
993
|
try {
|
|
921
994
|
// Parsed before anything loads: a floor the caller asked for must never be dropped.
|
|
@@ -934,6 +1007,24 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
934
1007
|
throw new Error(`Conversation detail ${conversationDetailId} not found`);
|
|
935
1008
|
}
|
|
936
1009
|
const conversationId = currentDetail.ConversationID;
|
|
1010
|
+
// The branch the placeholder row was created on decides which path the run reads.
|
|
1011
|
+
const branchId: string | null = currentDetail.BranchID ?? null;
|
|
1012
|
+
|
|
1013
|
+
// A turn that follows a run the user STOPPED continues that run rather than starting
|
|
1014
|
+
// over: chain it by LastRunID (the chat client never sends one) and, when the caller
|
|
1015
|
+
// supplied no payload, roll the stopped run's FinalPayload into this run's start.
|
|
1016
|
+
let effectiveLastRunId = lastRunId;
|
|
1017
|
+
let effectiveAutoPopulate = autoPopulateLastRunPayload;
|
|
1018
|
+
if (!effectiveLastRunId) {
|
|
1019
|
+
const stoppedRunId = await this.findUserStoppedPredecessorRunId(conversationId, effectiveAgentId, branchId, currentUser, p);
|
|
1020
|
+
if (stoppedRunId) {
|
|
1021
|
+
effectiveLastRunId = stoppedRunId;
|
|
1022
|
+
if (effectiveAutoPopulate === undefined && payload == null) {
|
|
1023
|
+
effectiveAutoPopulate = true;
|
|
1024
|
+
}
|
|
1025
|
+
LogStatus(`↩️ Continuing from user-stopped run ${stoppedRunId} (chained by LastRunID)`);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
937
1028
|
|
|
938
1029
|
// Load conversation history with attachments from DB
|
|
939
1030
|
const messages = await this.loadConversationHistoryWithAttachments(
|
|
@@ -944,7 +1035,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
944
1035
|
// The UI creates the agent-response placeholder row ('⏳ ...') before invoking
|
|
945
1036
|
// this mutation — exclude it so the model never sees an empty assistant turn.
|
|
946
1037
|
[conversationDetailId],
|
|
947
|
-
historyFrom
|
|
1038
|
+
historyFrom,
|
|
1039
|
+
branchId
|
|
948
1040
|
);
|
|
949
1041
|
|
|
950
1042
|
// Convert to JSON string for the existing executeAIAgent method
|
|
@@ -955,11 +1047,13 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
955
1047
|
// The client will receive the result via WebSocket PubSub completion event.
|
|
956
1048
|
this.executeAgentInBackground(
|
|
957
1049
|
p, dataSource, effectiveAgentId, effectiveUserPayload, messagesJson, sessionId, pubSub,
|
|
958
|
-
data, payload,
|
|
1050
|
+
data, payload, effectiveLastRunId, effectiveAutoPopulate, configurationId,
|
|
959
1051
|
conversationDetailId, createArtifacts || false, createNotification || false,
|
|
960
1052
|
sourceArtifactId, sourceArtifactVersionId, conversationId, planMode, requestedSkillIDs,
|
|
961
1053
|
undefined, // taskGraphDebug
|
|
962
|
-
historyFrom
|
|
1054
|
+
historyFrom,
|
|
1055
|
+
trustRunData,
|
|
1056
|
+
branchId
|
|
963
1057
|
);
|
|
964
1058
|
|
|
965
1059
|
LogStatus(`🔥 Fire-and-forget: Agent ${effectiveAgentId} execution started in background for session ${sessionId}`);
|
|
@@ -982,8 +1076,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
982
1076
|
data,
|
|
983
1077
|
payload,
|
|
984
1078
|
undefined, // templateData
|
|
985
|
-
|
|
986
|
-
|
|
1079
|
+
effectiveLastRunId,
|
|
1080
|
+
effectiveAutoPopulate,
|
|
987
1081
|
configurationId,
|
|
988
1082
|
conversationDetailId,
|
|
989
1083
|
createArtifacts || false,
|
|
@@ -995,7 +1089,9 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
995
1089
|
planMode,
|
|
996
1090
|
requestedSkillIDs,
|
|
997
1091
|
undefined, // taskGraphDebug
|
|
998
|
-
historyFrom
|
|
1092
|
+
historyFrom,
|
|
1093
|
+
trustRunData,
|
|
1094
|
+
branchId
|
|
999
1095
|
);
|
|
1000
1096
|
} catch (error) {
|
|
1001
1097
|
const errorMessage = (error as Error).message || 'Unknown error loading conversation history';
|
|
@@ -1217,7 +1313,11 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1217
1313
|
requestedSkillIDs?: string[],
|
|
1218
1314
|
taskGraphDebug?: string,
|
|
1219
1315
|
/** History floor — threaded through to ExecuteAgentParams.ConversationHistoryFrom. */
|
|
1220
|
-
conversationHistoryFrom?: Date
|
|
1316
|
+
conversationHistoryFrom?: Date,
|
|
1317
|
+
/** ExecuteAgentParams.TrustReservedRunData — see executeAIAgent. */
|
|
1318
|
+
trustReservedRunData: boolean = false,
|
|
1319
|
+
/** The conversation branch of the run — threaded through to ExecuteAgentParams.ConversationBranchID. */
|
|
1320
|
+
conversationBranchId?: string | null
|
|
1221
1321
|
): void {
|
|
1222
1322
|
// Ref the liveness pulse reads to enrich heartbeats once the run is created.
|
|
1223
1323
|
const runRef: { current: MJAIAgentRunEntityExtended | null } = { current: null };
|
|
@@ -1237,7 +1337,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1237
1337
|
data, payload, undefined, lastRunId, autoPopulateLastRunPayload,
|
|
1238
1338
|
configurationId, conversationDetailId, createArtifacts, createNotification,
|
|
1239
1339
|
sourceArtifactId, sourceArtifactVersionId, conversationId, runRef, planMode, requestedSkillIDs, taskGraphDebug,
|
|
1240
|
-
conversationHistoryFrom
|
|
1340
|
+
conversationHistoryFrom, trustReservedRunData, conversationBranchId
|
|
1241
1341
|
).catch((error: unknown) => {
|
|
1242
1342
|
// Background execution failed unexpectedly (executeAIAgent has its own try-catch,
|
|
1243
1343
|
// so this would only fire for truly unexpected errors).
|
|
@@ -1277,7 +1377,9 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1277
1377
|
provider: IMetadataProvider,
|
|
1278
1378
|
excludeDetailIds?: string[],
|
|
1279
1379
|
/** History floor: only rows written at or after it are loaded, and no summary is used. */
|
|
1280
|
-
historyFrom?: Date
|
|
1380
|
+
historyFrom?: Date,
|
|
1381
|
+
/** The branch whose path to load; null reads the trunk. */
|
|
1382
|
+
branchId?: string | null
|
|
1281
1383
|
): Promise<ChatMessage[]> {
|
|
1282
1384
|
// Context windowing (summary boundary + raw tail, or legacy last-N when no
|
|
1283
1385
|
// summary exists) shares ONE fold implementation with all other callers —
|
|
@@ -1294,7 +1396,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1294
1396
|
// the agent against zero history.
|
|
1295
1397
|
// 4. A history floor (`historyFrom`) is applied in the query, so rows before it never
|
|
1296
1398
|
// leave the database, and again in the assembly, which then skips the summary.
|
|
1297
|
-
const rows = await ConversationEngine.LoadWindowRowsFresh(conversationId, contextUser, provider, historyFrom);
|
|
1399
|
+
const rows = await ConversationEngine.LoadWindowRowsFresh(conversationId, contextUser, provider, historyFrom, branchId);
|
|
1298
1400
|
const window = ConversationEngine.AssembleContextWindow(rows, {
|
|
1299
1401
|
maxTailMessages: maxMessages,
|
|
1300
1402
|
excludeDetailIds,
|
|
@@ -2,7 +2,7 @@ import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
|
2
2
|
import { AppContext, UserPayload } from '../types.js';
|
|
3
3
|
import { LogError, LogStatus, Metadata, RunView } from '@memberjunction/core';
|
|
4
4
|
import { MJTemplateContentEntity, MJTemplateEntityExtended } from '@memberjunction/core-entities';
|
|
5
|
-
import { TemplateEngineServer } from '@memberjunction/templates';
|
|
5
|
+
import { GetTemplateRunRefusal, TemplateEngineServer } from '@memberjunction/templates';
|
|
6
6
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
7
7
|
import { GetReadWriteProvider } from '../util.js';
|
|
8
8
|
|
|
@@ -45,6 +45,18 @@ export class RunTemplateResolver extends ResolverBase {
|
|
|
45
45
|
try {
|
|
46
46
|
LogStatus(`=== RUNNING TEMPLATE FOR ID: ${templateId} ===`);
|
|
47
47
|
|
|
48
|
+
// Same rule as the Template.Run remote operation, checked before anything is loaded
|
|
49
|
+
const currentUser = this.GetUserFromPayload(userPayload);
|
|
50
|
+
const p = GetReadWriteProvider(providers);
|
|
51
|
+
const refusal = GetTemplateRunRefusal(currentUser, p);
|
|
52
|
+
if (refusal) {
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
error: refusal,
|
|
56
|
+
executionTimeMs: Date.now() - startTime
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
48
60
|
// Parse context data (JSON string)
|
|
49
61
|
let data = {};
|
|
50
62
|
if (contextData) {
|
|
@@ -59,17 +71,6 @@ export class RunTemplateResolver extends ResolverBase {
|
|
|
59
71
|
}
|
|
60
72
|
}
|
|
61
73
|
|
|
62
|
-
// Get current user from payload
|
|
63
|
-
const currentUser = this.GetUserFromPayload(userPayload);
|
|
64
|
-
if (!currentUser) {
|
|
65
|
-
return {
|
|
66
|
-
success: false,
|
|
67
|
-
error: 'Unable to determine current user',
|
|
68
|
-
executionTimeMs: Date.now() - startTime
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const p = GetReadWriteProvider(providers);
|
|
73
74
|
// Load the template entity
|
|
74
75
|
const templateEntity = await p.GetEntityObject<MJTemplateEntityExtended>('MJ: Templates', currentUser);
|
|
75
76
|
await templateEntity.Load(templateId);
|