@memberjunction/server 6.2.0-edge.6 → 6.2.0-edge.8
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 +69 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/BridgeHostInstance.d.ts +8 -3
- package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -1
- package/dist/agentSessions/BridgeHostInstance.js +14 -4
- package/dist/agentSessions/BridgeHostInstance.js.map +1 -1
- package/dist/agentSessions/HandoffOfferExpiry.d.ts +10 -0
- package/dist/agentSessions/HandoffOfferExpiry.d.ts.map +1 -0
- package/dist/agentSessions/HandoffOfferExpiry.js +18 -0
- package/dist/agentSessions/HandoffOfferExpiry.js.map +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +31 -8
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +85 -41
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +14 -4
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +28 -4
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/conversationBrowsers.d.ts +61 -0
- package/dist/agentSessions/conversationBrowsers.d.ts.map +1 -0
- package/dist/agentSessions/conversationBrowsers.js +118 -0
- package/dist/agentSessions/conversationBrowsers.js.map +1 -0
- package/dist/agentSessions/sessionDeadline.d.ts +43 -0
- package/dist/agentSessions/sessionDeadline.d.ts.map +1 -0
- package/dist/agentSessions/sessionDeadline.js +68 -0
- package/dist/agentSessions/sessionDeadline.js.map +1 -0
- package/dist/auth/APIKeyScopeAuth.d.ts.map +1 -1
- package/dist/auth/APIKeyScopeAuth.js +5 -4
- package/dist/auth/APIKeyScopeAuth.js.map +1 -1
- package/dist/auth/loginEmailResolution.d.ts +41 -0
- package/dist/auth/loginEmailResolution.d.ts.map +1 -0
- package/dist/auth/loginEmailResolution.js +47 -0
- package/dist/auth/loginEmailResolution.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +50 -2
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js +129 -12
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +3 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +23 -5
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts +39 -5
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +221 -9
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +1 -1
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +1 -1
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/redeemLanding.d.ts +2 -2
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
- package/dist/auth/magicLink/redeemLanding.js +7 -4
- package/dist/auth/magicLink/redeemLanding.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +27 -3
- package/dist/auth/magicLink/types.d.ts.map +1 -1
- package/dist/auth/magicLink/types.js +0 -4
- package/dist/auth/magicLink/types.js.map +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +1 -0
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/backgroundSweepConfigUnits.d.ts +231 -0
- package/dist/backgroundSweepConfigUnits.d.ts.map +1 -0
- package/dist/backgroundSweepConfigUnits.js +180 -0
- package/dist/backgroundSweepConfigUnits.js.map +1 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -1
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +2 -1
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -1
- package/dist/config.d.ts +906 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +59 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +41 -12
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts +3 -1
- package/dist/coreRoutes.d.ts.map +1 -1
- package/dist/coreRoutes.js +6 -4
- package/dist/coreRoutes.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +1072 -5
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +10174 -4618
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts +11 -0
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +27 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +50 -5
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +329 -132
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +4 -0
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +47 -7
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/globalCors.d.ts.map +1 -1
- package/dist/globalCors.js +1 -0
- package/dist/globalCors.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +201 -43
- package/dist/index.js.map +1 -1
- package/dist/integration/ConnectionPause.d.ts +121 -0
- package/dist/integration/ConnectionPause.d.ts.map +1 -0
- package/dist/integration/ConnectionPause.js +183 -0
- package/dist/integration/ConnectionPause.js.map +1 -0
- package/dist/integration/CustomColumnPromoter.d.ts +72 -6
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +87 -46
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/integration/EntityMapLifecycle.d.ts +78 -4
- package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
- package/dist/integration/EntityMapLifecycle.js +199 -5
- package/dist/integration/EntityMapLifecycle.js.map +1 -1
- package/dist/integration/InactiveRowWarnings.d.ts +31 -0
- package/dist/integration/InactiveRowWarnings.d.ts.map +1 -1
- package/dist/integration/InactiveRowWarnings.js +29 -0
- package/dist/integration/InactiveRowWarnings.js.map +1 -1
- package/dist/integration/ObjectNamesByID.d.ts +28 -0
- package/dist/integration/ObjectNamesByID.d.ts.map +1 -0
- package/dist/integration/ObjectNamesByID.js +87 -0
- package/dist/integration/ObjectNamesByID.js.map +1 -0
- package/dist/integration/PostRestartIntrospect.d.ts +26 -0
- package/dist/integration/PostRestartIntrospect.d.ts.map +1 -0
- package/dist/integration/PostRestartIntrospect.js +27 -0
- package/dist/integration/PostRestartIntrospect.js.map +1 -0
- package/dist/integration/RSUPostRestartProgress.d.ts +176 -0
- package/dist/integration/RSUPostRestartProgress.d.ts.map +1 -0
- package/dist/integration/RSUPostRestartProgress.js +323 -0
- package/dist/integration/RSUPostRestartProgress.js.map +1 -0
- package/dist/integration/RSUProgressBridge.d.ts +41 -2
- package/dist/integration/RSUProgressBridge.d.ts.map +1 -1
- package/dist/integration/RSUProgressBridge.js +84 -1
- package/dist/integration/RSUProgressBridge.js.map +1 -1
- package/dist/integration/RunArtifactAuthorization.d.ts +39 -0
- package/dist/integration/RunArtifactAuthorization.d.ts.map +1 -0
- package/dist/integration/RunArtifactAuthorization.js +45 -0
- package/dist/integration/RunArtifactAuthorization.js.map +1 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts +9 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -1
- package/dist/integration/SchemaRefreshLaunch.js +3 -2
- package/dist/integration/SchemaRefreshLaunch.js.map +1 -1
- package/dist/integration/ScopedFieldsForBuild.d.ts +46 -0
- package/dist/integration/ScopedFieldsForBuild.d.ts.map +1 -0
- package/dist/integration/ScopedFieldsForBuild.js +91 -0
- package/dist/integration/ScopedFieldsForBuild.js.map +1 -0
- package/dist/integration/TargetConfigGuard.d.ts +40 -0
- package/dist/integration/TargetConfigGuard.d.ts.map +1 -0
- package/dist/integration/TargetConfigGuard.js +40 -0
- package/dist/integration/TargetConfigGuard.js.map +1 -0
- package/dist/logging/StartupLogger.d.ts +50 -0
- package/dist/logging/StartupLogger.d.ts.map +1 -1
- package/dist/logging/StartupLogger.js +15 -22
- package/dist/logging/StartupLogger.js.map +1 -1
- package/dist/middleware/BaseServerMiddleware.d.ts +21 -3
- package/dist/middleware/BaseServerMiddleware.d.ts.map +1 -1
- package/dist/middleware/BaseServerMiddleware.js +4 -2
- package/dist/middleware/BaseServerMiddleware.js.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.js +2 -3
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
- package/dist/realtimeSessions/sessionAccess.d.ts +15 -0
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
- package/dist/realtimeSessions/sessionAccess.js +22 -0
- package/dist/realtimeSessions/sessionAccess.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.js +2 -0
- package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.js +1 -0
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +4 -7
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +1 -0
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/requestOrigin.d.ts +22 -0
- package/dist/requestOrigin.d.ts.map +1 -0
- package/dist/requestOrigin.js +60 -0
- package/dist/requestOrigin.js.map +1 -0
- package/dist/resolvers/AgentRunStatusPublisher.d.ts +10 -0
- package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.js +18 -2
- package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
- package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/AgentSessionResolver.js +6 -2
- package/dist/resolvers/AgentSessionResolver.js.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.d.ts +1 -1
- package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.js +61 -16
- package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.js +2 -0
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
- package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts +6 -0
- package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts.map +1 -1
- package/dist/resolvers/ExecuteRemoteOperationResolver.js +30 -7
- package/dist/resolvers/ExecuteRemoteOperationResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +34 -13
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/InfoResolver.js +1 -1
- package/dist/resolvers/InfoResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +401 -11
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +2690 -1305
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +13 -2
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +38 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +181 -88
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +1 -0
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +6 -0
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +36 -5
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +62 -10
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +217 -34
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +24 -8
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +185 -67
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +5 -3
- package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +19 -18
- package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +3 -1
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +7 -8
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
- package/dist/resolvers/TagGovernanceResolver.d.ts +12 -0
- package/dist/resolvers/TagGovernanceResolver.d.ts.map +1 -1
- package/dist/resolvers/TagGovernanceResolver.js +84 -0
- package/dist/resolvers/TagGovernanceResolver.js.map +1 -1
- package/dist/resolvers/TelemetryResolver.d.ts +13 -8
- package/dist/resolvers/TelemetryResolver.d.ts.map +1 -1
- package/dist/resolvers/TelemetryResolver.js +40 -9
- package/dist/resolvers/TelemetryResolver.js.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.js +2 -0
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.js +34 -4
- package/dist/resolvers/meetings/meetingMutations.js.map +1 -1
- package/dist/rest/MediaAccessKeys.d.ts.map +1 -1
- package/dist/rest/MediaAccessKeys.js +6 -2
- package/dist/rest/MediaAccessKeys.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +11 -5
- package/dist/rest/OAuthCallbackHandler.js.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.d.ts +3 -3
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.js +2 -4
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +2 -1
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +3 -1
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +11 -2
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/services/DurableEntityActionTaskSubmitter.d.ts.map +1 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js +6 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +2 -26
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphAgentRunner.d.ts +6 -0
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +38 -0
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +1 -0
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/services/WorkQueueHostService.d.ts +2 -1
- package/dist/services/WorkQueueHostService.d.ts.map +1 -1
- package/dist/services/WorkQueueHostService.js +19 -4
- package/dist/services/WorkQueueHostService.js.map +1 -1
- package/dist/services/workQueueConfig.d.ts +2 -2
- package/dist/services/workQueueConfig.js +5 -5
- package/dist/services/workQueueConfig.js.map +1 -1
- package/dist/sharedCache.js +1 -1
- package/dist/sharedCache.js.map +1 -1
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +55 -2
- package/dist/util.js.map +1 -1
- package/package.json +107 -100
- package/src/__tests__/APIKeyScopeAuth.test.ts +4 -8
- package/src/__tests__/ActiveOperations.test.ts +68 -0
- package/src/__tests__/AgentSessionResolver.ownership.test.ts +13 -0
- package/src/__tests__/AssertTargetConfigs.test.ts +75 -0
- package/src/__tests__/BatchApplyParity.test.ts +109 -0
- package/src/__tests__/BridgeHostInstance.test.ts +42 -0
- package/src/__tests__/CollectInactiveRowWarnings.test.ts +115 -0
- package/src/__tests__/ConnectionPause.test.ts +192 -0
- package/src/__tests__/ConnectionPauseResolver.test.ts +166 -0
- package/src/__tests__/ConnectionPauseSave.test.ts +143 -0
- package/src/__tests__/CustomColumnPromoterCompletion.test.ts +142 -0
- package/src/__tests__/DeleteConnectionRemovesPerConnectionCatalog.test.ts +51 -0
- package/src/__tests__/DetachedDiscoveryStart.test.ts +65 -0
- package/src/__tests__/DurableEntityActionTaskSubmitter.test.ts +73 -0
- package/src/__tests__/EntityMapLifecycle.rekey.test.ts +252 -0
- package/src/__tests__/ExecuteRemoteOperationResolver.test.ts +213 -0
- package/src/__tests__/HandoffOfferExpiry.test.ts +40 -0
- package/src/__tests__/IntegrationRunArtifactAuthorization.test.ts +126 -0
- package/src/__tests__/MagicLinkKeys.test.ts +102 -0
- package/src/__tests__/MediaAccessKeys.test.ts +57 -10
- package/src/__tests__/NewArrivalsDefaultDisabled.test.ts +50 -0
- package/src/__tests__/ObjectNamesByID.test.ts +176 -0
- package/src/__tests__/PostRestartMapsInCatalogScope.test.ts +146 -0
- package/src/__tests__/QuerySystemUserResolver.childRows.test.ts +80 -0
- package/src/__tests__/QuerySystemUserResolver.collision.test.ts +200 -0
- package/src/__tests__/QuerySystemUserResolver.permissions.test.ts +132 -0
- package/src/__tests__/RSUPostRestartProgress.test.ts +343 -0
- package/src/__tests__/RSUProgressBridge.test.ts +188 -5
- package/src/__tests__/RSUStartupSweepWiring.test.ts +30 -0
- package/src/__tests__/ReactivateRefreshMessage.test.ts +10 -3
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +22 -0
- package/src/__tests__/{RefreshAdoptsNewColumns.test.ts → RefreshReportsNewColumns.test.ts} +25 -16
- package/src/__tests__/RemoteBrowserActionRecovery.test.ts +287 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +3 -0
- package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +6 -4
- package/src/__tests__/RemoteBrowserAudioStream.test.ts +3 -0
- package/src/__tests__/RemoteBrowserSnapshot.test.ts +3 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +327 -26
- package/src/__tests__/ResolverBase.diagnosticSenderRegistrations.test.ts +26 -0
- package/src/__tests__/ResolverBase.encryptedApiZeroReencrypt.test.ts +307 -0
- package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +53 -2
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +60 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +4 -0
- package/src/__tests__/RunAIAgentResolver.consultPredecessor.test.ts +289 -0
- package/src/__tests__/RunAIAgentResolver.handoff.test.ts +649 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +2 -0
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +2 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +87 -12
- package/src/__tests__/RunAIAgentResolver.streaming.test.ts +28 -4
- package/src/__tests__/SchemaEvolutionCustomColumns.test.ts +119 -0
- package/src/__tests__/SchemaRefreshLaunch.test.ts +24 -2
- package/src/__tests__/ScopedFieldsForBuild.test.ts +192 -0
- package/src/__tests__/SessionJanitor.test.ts +195 -4
- package/src/__tests__/SessionManager.test.ts +69 -0
- package/src/__tests__/TagGovernanceAndAutotagResolvers.test.ts +261 -0
- package/src/__tests__/TagGovernanceResolver.test.ts +60 -2
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +2 -2
- package/src/__tests__/TaskGraphAgentRunner.test.ts +272 -16
- package/src/__tests__/ViewOperationsHandler.test.ts +2 -5
- package/src/__tests__/WorkQueueHostService.test.ts +25 -7
- package/src/__tests__/backgroundSweepConfigUnits.test.ts +153 -0
- package/src/__tests__/contextRequestOrigin.test.ts +105 -0
- package/src/__tests__/conversationBrowsers.test.ts +62 -0
- package/src/__tests__/globalCors.test.ts +12 -0
- package/src/__tests__/magicLinkExtensionCapabilities.test.ts +413 -0
- package/src/__tests__/orphanedConversationDetailReconciler.start.test.ts +82 -0
- package/src/__tests__/ownedRealtimeSession.test.ts +14 -0
- package/src/__tests__/realtimeRecordingHandler.test.ts +7 -2
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +79 -1
- package/src/__tests__/requestOrigin.test.ts +104 -0
- package/src/__tests__/review-capture-valid-token-log.test.ts +98 -0
- package/src/__tests__/runStreams.fieldSecurity.test.ts +5 -5
- package/src/__tests__/securityHardeningPr6034.test.ts +120 -0
- package/src/__tests__/sessionDeadline.test.ts +51 -0
- package/src/__tests__/sharedCache.test.ts +11 -0
- package/src/__tests__/unifiedAuth.test.ts +73 -1
- package/src/agentSessions/BridgeHostInstance.ts +20 -5
- package/src/agentSessions/HandoffOfferExpiry.ts +18 -0
- package/src/agentSessions/ReturningVisitorRecap.ts +1 -0
- package/src/agentSessions/SessionJanitor.ts +92 -42
- package/src/agentSessions/SessionManager.ts +38 -8
- package/src/agentSessions/conversationBrowsers.ts +143 -0
- package/src/agentSessions/sessionDeadline.ts +81 -0
- package/src/auth/APIKeyScopeAuth.ts +5 -4
- package/src/auth/__tests__/loginEmailResolution.test.ts +67 -0
- package/src/auth/loginEmailResolution.ts +67 -0
- package/src/auth/magicLink/MagicLinkKeys.ts +146 -14
- package/src/auth/magicLink/MagicLinkRouter.ts +33 -6
- package/src/auth/magicLink/MagicLinkService.ts +250 -10
- package/src/auth/magicLink/index.ts +1 -1
- package/src/auth/magicLink/redeemLanding.ts +7 -4
- package/src/auth/magicLink/types.ts +28 -3
- package/src/auth/newUsers.ts +1 -0
- package/src/backgroundSweepConfigUnits.ts +213 -0
- package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +2 -1
- package/src/config.ts +69 -0
- package/src/context.ts +46 -15
- package/src/coreRoutes.ts +14 -7
- package/src/generated/graphql-schemas/__mj.ts +10360 -6479
- package/src/generic/OrphanedConversationDetailReconciler.ts +32 -1
- package/src/generic/ResolverBase.ts +422 -143
- package/src/generic/RunViewResolver.ts +96 -49
- package/src/globalCors.ts +1 -0
- package/src/index.ts +246 -44
- package/src/integration/ConnectionPause.ts +222 -0
- package/src/integration/CustomColumnPromoter.ts +123 -53
- package/src/integration/EntityMapLifecycle.ts +229 -6
- package/src/integration/InactiveRowWarnings.ts +50 -0
- package/src/integration/ObjectNamesByID.ts +97 -0
- package/src/integration/PostRestartIntrospect.ts +49 -0
- package/src/integration/RSUPostRestartProgress.ts +359 -0
- package/src/integration/RSUProgressBridge.ts +85 -2
- package/src/integration/RunArtifactAuthorization.ts +65 -0
- package/src/integration/SchemaRefreshLaunch.ts +12 -2
- package/src/integration/ScopedFieldsForBuild.ts +113 -0
- package/src/integration/TargetConfigGuard.ts +71 -0
- package/src/logging/StartupLogger.ts +24 -0
- package/src/middleware/BaseServerMiddleware.ts +20 -3
- package/src/realtimeSessions/ownedRealtimeSession.ts +2 -6
- package/src/realtimeSessions/sessionAccess.ts +30 -0
- package/src/realtimeWidget/WidgetSessionService.ts +2 -0
- package/src/realtimeWidget/visitorIdentity.ts +1 -0
- package/src/realtimeWidget/widgetCore.ts +4 -8
- package/src/realtimeWidget/widgetGuestElevation.ts +1 -0
- package/src/requestOrigin.ts +64 -0
- package/src/resolvers/AgentRunStatusPublisher.ts +27 -2
- package/src/resolvers/AgentSessionResolver.ts +6 -2
- package/src/resolvers/AutotagPipelineResolver.ts +59 -14
- package/src/resolvers/ConversationRunEventsResolver.ts +2 -0
- package/src/resolvers/ExecuteRemoteOperationResolver.ts +41 -9
- package/src/resolvers/GetDataResolver.ts +35 -13
- package/src/resolvers/InfoResolver.ts +1 -1
- package/src/resolvers/IntegrationDiscoveryResolver.ts +1522 -203
- package/src/resolvers/MCPResolver.ts +15 -2
- package/src/resolvers/QuerySystemUserResolver.ts +211 -100
- package/src/resolvers/RealtimeBridgeResolver.ts +1 -0
- package/src/resolvers/RealtimeClientSessionResolver.ts +40 -7
- package/src/resolvers/RemoteBrowserActionResolver.ts +242 -32
- package/src/resolvers/RunAIAgentResolver.ts +265 -86
- package/src/resolvers/RunAIPromptResolver.ts +18 -18
- package/src/resolvers/RunTemplateResolver.ts +3 -1
- package/src/resolvers/SqlLoggingConfigResolver.ts +7 -9
- package/src/resolvers/TagGovernanceResolver.ts +65 -0
- package/src/resolvers/TelemetryResolver.ts +44 -9
- package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +52 -0
- package/src/resolvers/meetingRecordingRegistration.ts +2 -0
- package/src/resolvers/meetings/meetingMutations.ts +37 -7
- package/src/rest/MediaAccessKeys.ts +6 -2
- package/src/rest/OAuthCallbackHandler.ts +13 -5
- package/src/rest/RealtimeRecordingHandler.ts +5 -9
- package/src/rest/ViewOperationsHandler.ts +2 -1
- package/src/rest/setupRESTEndpoints.ts +11 -2
- package/src/services/DurableEntityActionTaskSubmitter.ts +10 -2
- package/src/services/TaskGraphActionRunner.ts +2 -23
- package/src/services/TaskGraphAgentRunner.ts +43 -0
- package/src/services/TaskGraphContinuationDeliverer.ts +1 -0
- package/src/services/WorkQueueHostService.ts +26 -4
- package/src/services/workQueueConfig.ts +5 -5
- package/src/sharedCache.ts +1 -1
- package/src/types.ts +18 -0
- package/src/util.ts +55 -3
- package/src/services/TaskOrchestration-Integration.md +0 -188
|
@@ -23,6 +23,19 @@ import { PublishStatusUpdate } from '../generic/PushStatusResolver.js';
|
|
|
23
23
|
import { GraphQLJSONObject } from 'graphql-type-json';
|
|
24
24
|
import { configInfo } from '../config.js';
|
|
25
25
|
|
|
26
|
+
const UUID_SHAPE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Validates that a caller-supplied record id is a UUID before it is interpolated into a SQL
|
|
30
|
+
* filter, and returns it unchanged. A validated UUID cannot carry SQL.
|
|
31
|
+
*/
|
|
32
|
+
function sqlUuid(value: string, argName: string): string {
|
|
33
|
+
if (typeof value !== 'string' || !UUID_SHAPE.test(value)) {
|
|
34
|
+
throw new Error(`${argName} must be a UUID`);
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
|
|
26
39
|
/**
|
|
27
40
|
* Input type for syncing MCP tools
|
|
28
41
|
*/
|
|
@@ -1289,7 +1302,7 @@ export class MCPResolver extends ResolverBase {
|
|
|
1289
1302
|
// First get connection to get server ID
|
|
1290
1303
|
const connResult = await rv.RunView<{ MCPServerID: string }>({
|
|
1291
1304
|
EntityName: 'MJ: MCP Server Connections',
|
|
1292
|
-
ExtraFilter: `ID='${connectionId}'`,
|
|
1305
|
+
ExtraFilter: `ID='${sqlUuid(connectionId, 'connectionId')}'`,
|
|
1293
1306
|
Fields: ['MCPServerID'],
|
|
1294
1307
|
ResultType: 'simple'
|
|
1295
1308
|
}, contextUser);
|
|
@@ -1310,7 +1323,7 @@ export class MCPResolver extends ResolverBase {
|
|
|
1310
1323
|
OAuthRequirePKCE: boolean | null;
|
|
1311
1324
|
}>({
|
|
1312
1325
|
EntityName: 'MJ: MCP Servers',
|
|
1313
|
-
ExtraFilter: `ID='${serverId}'`,
|
|
1326
|
+
ExtraFilter: `ID='${sqlUuid(serverId, 'serverId')}'`,
|
|
1314
1327
|
Fields: [
|
|
1315
1328
|
'OAuthIssuerURL',
|
|
1316
1329
|
'OAuthScopes',
|
|
@@ -6,7 +6,7 @@ import { MJQueryResolver, MJQuery_, MJQueryField_, MJQueryParameter_, MJQueryEnt
|
|
|
6
6
|
import { GetReadWriteProvider } from '../util.js';
|
|
7
7
|
import { DeleteOptionsInput } from '../generic/DeleteOptionsInput.js';
|
|
8
8
|
import { MJQueryEntityServer } from '@memberjunction/core-entities-server';
|
|
9
|
-
import { EscapeSQLString } from '@memberjunction/global';
|
|
9
|
+
import { EscapeSQLString, UUIDsEqual } from '@memberjunction/global';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Minimal shape of a query row returned by RunView lookups (plain object, not entity instance).
|
|
@@ -243,6 +243,14 @@ export class DeleteQueryResultType {
|
|
|
243
243
|
Status?: string;
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
/** A query's child rows, read from the database. */
|
|
247
|
+
interface StoredQueryChildren {
|
|
248
|
+
readonly Fields: MJQueryFieldEntity[];
|
|
249
|
+
readonly Parameters: MJQueryParameterEntity[];
|
|
250
|
+
readonly Entities: MJQueryEntityEntity[];
|
|
251
|
+
readonly Permissions: MJQueryPermissionEntity[];
|
|
252
|
+
}
|
|
253
|
+
|
|
246
254
|
@Resolver()
|
|
247
255
|
export class MJQueryResolverExtended extends MJQueryResolver {
|
|
248
256
|
/**
|
|
@@ -269,6 +277,7 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
269
277
|
}
|
|
270
278
|
|
|
271
279
|
// Check for existing query with same name in the same category
|
|
280
|
+
const requestedName = input.Name;
|
|
272
281
|
const existingQuery = await this.findExistingQuery(provider, input.Name, finalCategoryID, context.userPayload.userRecord);
|
|
273
282
|
|
|
274
283
|
if (existingQuery) {
|
|
@@ -285,84 +294,119 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
285
294
|
}
|
|
286
295
|
}
|
|
287
296
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
Status: input.Status || 'Approved',
|
|
296
|
-
QualityRank: input.QualityRank || 0,
|
|
297
|
-
UsesTemplate: input.UsesTemplate || false,
|
|
298
|
-
AuditQueryRuns: input.AuditQueryRuns || false,
|
|
299
|
-
CacheEnabled: input.CacheEnabled || false,
|
|
300
|
-
CacheTTLMinutes: input.CacheTTLMinutes || null,
|
|
301
|
-
CacheMaxSize: input.CacheMaxSize || null
|
|
297
|
+
return await this.createQueryAsync(provider, input, requestedName, finalCategoryID, context, pubSub);
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
LogError(err);
|
|
301
|
+
return {
|
|
302
|
+
Success: false,
|
|
303
|
+
ErrorMessage: `MJQueryResolverExtended::CreateQuerySystemUser --- Error creating query: ${err instanceof Error ? err.message : String(err)}`
|
|
302
304
|
};
|
|
305
|
+
}
|
|
306
|
+
}
|
|
303
307
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
record.SetMany(fieldsToSet, true);
|
|
308
|
+
/** The most times a create with `AutoResolveCollision` picks a new name after losing a same-name race. */
|
|
309
|
+
private static readonly maxCollisionRetries = 25;
|
|
307
310
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
+
/**
|
|
312
|
+
* Creates the query, handling a same-name race (#6007): when the insert fails and a query with
|
|
313
|
+
* the name now exists (another request created it in between), `AutoResolveCollision` picks a
|
|
314
|
+
* new unique name and tries again, a bounded number of times, and never returns the other
|
|
315
|
+
* request's query. Without it, the query that now exists is returned (create-or-get). Any other
|
|
316
|
+
* failure, including a save-time refusal of the SQL, returns the save's message.
|
|
317
|
+
*
|
|
318
|
+
* @param requestedName - The name the caller asked for; each retry's unique name is built from it.
|
|
319
|
+
*/
|
|
320
|
+
private async createQueryAsync(
|
|
321
|
+
provider: DatabaseProviderBase,
|
|
322
|
+
input: CreateQuerySystemUserInput,
|
|
323
|
+
requestedName: string,
|
|
324
|
+
categoryID: string | null | undefined,
|
|
325
|
+
context: AppContext,
|
|
326
|
+
pubSub: PubSubEngine
|
|
327
|
+
): Promise<QueryMutationResultType> {
|
|
328
|
+
const user = context.userPayload.userRecord;
|
|
329
|
+
for (let attempt = 0; ; attempt++) {
|
|
330
|
+
const record = await this.newQueryRecordAsync(provider, input, categoryID, context, pubSub);
|
|
331
|
+
if (await record.Save()) {
|
|
332
|
+
return this.completeCreateAsync(provider, input, record, user);
|
|
311
333
|
}
|
|
334
|
+
const existing = await this.findExistingQuery(provider, input.Name, categoryID ?? null, user);
|
|
335
|
+
if (!existing) {
|
|
336
|
+
return { Success: false, ErrorMessage: `Failed to create query: ${record.LatestResult?.CompleteMessage || record.LatestResult?.Message || 'the save reported no reason'}` };
|
|
337
|
+
}
|
|
338
|
+
if (!input.AutoResolveCollision) {
|
|
339
|
+
return this.existingQueryResultAsync(provider, existing, input.Name, user);
|
|
340
|
+
}
|
|
341
|
+
if (attempt >= MJQueryResolverExtended.maxCollisionRetries) {
|
|
342
|
+
return { Success: false, ErrorMessage: `Failed to create query '${input.Name}': another request took each unique name tried, ${attempt + 1} times.` };
|
|
343
|
+
}
|
|
344
|
+
const lost = input.Name;
|
|
345
|
+
input.Name = await this.findUniqueName(provider, requestedName, categoryID ?? null, user);
|
|
346
|
+
LogStatus(`[CreateQuery] Lost a name race for "${lost}"; retrying as "${input.Name}"`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
312
349
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
350
|
+
/** A new, unsaved query record holding the input's values. */
|
|
351
|
+
private async newQueryRecordAsync(
|
|
352
|
+
provider: DatabaseProviderBase,
|
|
353
|
+
input: CreateQuerySystemUserInput,
|
|
354
|
+
categoryID: string | null | undefined,
|
|
355
|
+
context: AppContext,
|
|
356
|
+
pubSub: PubSubEngine
|
|
357
|
+
): Promise<MJQueryEntityServer> {
|
|
358
|
+
const record = await provider.GetEntityObject<MJQueryEntityServer>("MJ: Queries", context.userPayload.userRecord);
|
|
359
|
+
// Destructure out non-database fields, keep only fields to persist
|
|
360
|
+
const { Permissions: _permissions, CategoryPath: _categoryPath, ParameterHints: _parameterHints, AutoResolveCollision: _autoResolve, ...fieldsToSet } = {
|
|
361
|
+
...input,
|
|
362
|
+
CategoryID: categoryID || input.CategoryID,
|
|
363
|
+
Status: input.Status || 'Approved',
|
|
364
|
+
QualityRank: input.QualityRank || 0,
|
|
365
|
+
UsesTemplate: input.UsesTemplate || false,
|
|
366
|
+
AuditQueryRuns: input.AuditQueryRuns || false,
|
|
367
|
+
CacheEnabled: input.CacheEnabled || false,
|
|
368
|
+
CacheTTLMinutes: input.CacheTTLMinutes || null,
|
|
369
|
+
CacheMaxSize: input.CacheMaxSize || null
|
|
370
|
+
};
|
|
371
|
+
// Field-level security: refuse a key the caller may not read, or that names no field
|
|
372
|
+
AssertClientInputWritableForUser(record.EntityInfo, fieldsToSet, context.userPayload.userRecord);
|
|
373
|
+
record.SetMany(fieldsToSet, true);
|
|
374
|
+
// Pass caller-provided parameter sample values (used for new parameters and the described renders)
|
|
375
|
+
if (input.ParameterHints && input.ParameterHints.length > 0) {
|
|
376
|
+
record.ParameterHints = new Map(input.ParameterHints.map(h => [h.Name, h.Value]));
|
|
377
|
+
}
|
|
378
|
+
this.ListenForEntityMessages(record, pubSub, context.userPayload);
|
|
379
|
+
return record;
|
|
380
|
+
}
|
|
328
381
|
|
|
329
|
-
|
|
382
|
+
/** After a successful create: the AfterCreate event, the permissions, and the result. */
|
|
383
|
+
private async completeCreateAsync(provider: DatabaseProviderBase, input: CreateQuerySystemUserInput, record: MJQueryEntityServer, user: UserInfo): Promise<QueryMutationResultType> {
|
|
384
|
+
await this.AfterCreate(provider, input); // fire event
|
|
385
|
+
let createdPermissions: MJQueryPermissionEntity[] | undefined;
|
|
386
|
+
if (input.Permissions && input.Permissions.length > 0) {
|
|
387
|
+
try {
|
|
388
|
+
createdPermissions = await this.createPermissions(provider, input.Permissions, record.ID, user);
|
|
389
|
+
} catch (e) {
|
|
390
|
+
return { Success: false, ErrorMessage: `Query '${record.Name}' (ID ${record.ID}) was created, but its permissions were not: ${e instanceof Error ? e.message : String(e)}` };
|
|
330
391
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const existingQuery = await this.findExistingQuery(provider, input.Name, finalCategoryID, context.userPayload.userRecord);
|
|
335
|
-
|
|
336
|
-
if (existingQuery) {
|
|
337
|
-
// Found the query that was created by another request — load it as a full entity
|
|
338
|
-
// so that related metadata (Fields, Parameters, Entities, Permissions) is populated
|
|
339
|
-
LogStatus(`[CreateQuery] Unique constraint detected for query '${input.Name}'. Using existing query (ID: ${existingQuery.ID}) created by concurrent request.`);
|
|
340
|
-
const existingEntity = await provider.GetEntityObject<MJQueryEntityServer>('MJ: Queries', context.userPayload.userRecord);
|
|
341
|
-
if (await existingEntity.Load(existingQuery.ID)) {
|
|
342
|
-
return await this.buildSuccessResult(existingEntity, context.userPayload.userRecord, provider);
|
|
343
|
-
}
|
|
344
|
-
// Entity load failed after confirming the row exists — extremely rare
|
|
345
|
-
return {
|
|
346
|
-
Success: false,
|
|
347
|
-
ErrorMessage: `Found query '${input.Name}' created by concurrent request (ID: ${existingQuery.ID}) but failed to load it as entity`
|
|
348
|
-
};
|
|
349
|
-
}
|
|
392
|
+
}
|
|
393
|
+
return this.buildSuccessResult(record, user, provider, undefined, createdPermissions);
|
|
394
|
+
}
|
|
350
395
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
LogError(err);
|
|
361
|
-
return {
|
|
362
|
-
Success: false,
|
|
363
|
-
ErrorMessage: `MJQueryResolverExtended::CreateQuerySystemUser --- Error creating query: ${err instanceof Error ? err.message : String(err)}`
|
|
364
|
-
};
|
|
396
|
+
/** The create-or-get result: the query another request created with this name. */
|
|
397
|
+
private async existingQueryResultAsync(provider: DatabaseProviderBase, existing: QueryViewRow, name: string, user: UserInfo): Promise<QueryMutationResultType> {
|
|
398
|
+
LogStatus(`[CreateQuery] Unique constraint detected for query '${name}'. Using existing query (ID: ${existing.ID}) created by concurrent request.`);
|
|
399
|
+
const existingEntity = await provider.GetEntityObject<MJQueryEntityServer>('MJ: Queries', user);
|
|
400
|
+
if (await existingEntity.Load(existing.ID)) {
|
|
401
|
+
// The other request may have run on another server, or its rows may not have reached this
|
|
402
|
+
// process's query cache yet, so the child rows are read from the database.
|
|
403
|
+
const children = await this.readStoredChildrenAsync(provider, existing.ID, user);
|
|
404
|
+
return this.buildSuccessResult(existingEntity, user, provider, children);
|
|
365
405
|
}
|
|
406
|
+
return {
|
|
407
|
+
Success: false,
|
|
408
|
+
ErrorMessage: `Found query '${name}' created by concurrent request (ID: ${existing.ID}) but failed to load it as entity`
|
|
409
|
+
};
|
|
366
410
|
}
|
|
367
411
|
|
|
368
412
|
/**
|
|
@@ -372,17 +416,46 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
372
416
|
*
|
|
373
417
|
* @param contextUser The caller the result is for. Field security projects the record for them.
|
|
374
418
|
*/
|
|
375
|
-
private async buildSuccessResult(
|
|
419
|
+
private async buildSuccessResult(
|
|
420
|
+
entity: MJQueryEntityServer,
|
|
421
|
+
contextUser: UserInfo,
|
|
422
|
+
provider: DatabaseProviderBase,
|
|
423
|
+
children?: StoredQueryChildren,
|
|
424
|
+
createdPermissions?: MJQueryPermissionEntity[]
|
|
425
|
+
): Promise<QueryMutationResultType> {
|
|
426
|
+
const permissionsToMap = children?.Permissions ?? createdPermissions ?? entity.QueryPermissions;
|
|
376
427
|
return {
|
|
377
428
|
Success: true,
|
|
378
429
|
// Mapped for the caller, so the field-security projection applies: the record was just
|
|
379
430
|
// saved, and a save re-reads the whole row.
|
|
380
431
|
// fls-guard: projected for contextUser by MapFieldNamesToCodeNames
|
|
381
432
|
Query: await this.MapFieldNamesToCodeNames('MJ: Queries', entity.GetAll(), contextUser, provider) as MJQuery_,
|
|
382
|
-
Fields: this.mapFields(entity.QueryFields),
|
|
383
|
-
Parameters: this.mapParameters(entity.QueryParameters),
|
|
384
|
-
Entities: this.mapEntities(entity.QueryEntities),
|
|
385
|
-
Permissions: this.mapPermissions(
|
|
433
|
+
Fields: this.mapFields(children?.Fields ?? entity.QueryFields),
|
|
434
|
+
Parameters: this.mapParameters(children?.Parameters ?? entity.QueryParameters),
|
|
435
|
+
Entities: this.mapEntities(children?.Entities ?? entity.QueryEntities),
|
|
436
|
+
Permissions: this.mapPermissions(permissionsToMap),
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* A query's child rows read from the database with every cache bypassed. A collection whose
|
|
442
|
+
* read fails comes back empty, as the cache would have given it.
|
|
443
|
+
*/
|
|
444
|
+
private async readStoredChildrenAsync(provider: DatabaseProviderBase, queryID: string, user: UserInfo): Promise<StoredQueryChildren> {
|
|
445
|
+
const filter = `QueryID='${EscapeSQLString(queryID)}'`;
|
|
446
|
+
const view = (entityName: string, orderBy?: string) => ({ EntityName: entityName, ExtraFilter: filter, OrderBy: orderBy, ResultType: 'entity_object' as const, BypassCache: true, IgnoreMaxRows: true });
|
|
447
|
+
const [fields, parameters, entities, permissions] = await provider.RunViews([
|
|
448
|
+
view('MJ: Query Fields', 'Sequence'),
|
|
449
|
+
view('MJ: Query Parameters', 'Name'),
|
|
450
|
+
view('MJ: Query Entities'),
|
|
451
|
+
view('MJ: Query Permissions'),
|
|
452
|
+
], user);
|
|
453
|
+
const rows = <T>(result: { Success: boolean; Results: T[] } | undefined): T[] => (result?.Success ? result.Results : []);
|
|
454
|
+
return {
|
|
455
|
+
Fields: rows<MJQueryFieldEntity>(fields),
|
|
456
|
+
Parameters: rows<MJQueryParameterEntity>(parameters),
|
|
457
|
+
Entities: rows<MJQueryEntityEntity>(entities),
|
|
458
|
+
Permissions: rows<MJQueryPermissionEntity>(permissions),
|
|
386
459
|
};
|
|
387
460
|
}
|
|
388
461
|
|
|
@@ -398,6 +471,10 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
398
471
|
SourceEntityID: f.SourceEntityID,
|
|
399
472
|
SourceEntity: f.SourceEntity,
|
|
400
473
|
SourceFieldName: f.SourceFieldName,
|
|
474
|
+
SourceEntityFieldID: f.SourceEntityFieldID,
|
|
475
|
+
SourceEntityField: f.SourceEntityField,
|
|
476
|
+
SourceObjectName: f.SourceObjectName,
|
|
477
|
+
IsNullable: f.IsNullable,
|
|
401
478
|
IsComputed: f.IsComputed,
|
|
402
479
|
ComputationDescription: f.ComputationDescription,
|
|
403
480
|
IsSummary: f.IsSummary,
|
|
@@ -421,6 +498,7 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
421
498
|
DefaultValue: p.DefaultValue,
|
|
422
499
|
SampleValue: p.SampleValue,
|
|
423
500
|
ValidationFilters: p.ValidationFilters,
|
|
501
|
+
IsServerSet: p.IsServerSet,
|
|
424
502
|
_mj__CreatedAt: p.__mj_CreatedAt,
|
|
425
503
|
_mj__UpdatedAt: p.__mj_UpdatedAt,
|
|
426
504
|
DetectionMethod: p.DetectionMethod,
|
|
@@ -435,6 +513,8 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
435
513
|
QueryID: e.QueryID,
|
|
436
514
|
EntityID: e.EntityID,
|
|
437
515
|
Entity: e.Entity,
|
|
516
|
+
AlternateBaseViewID: e.AlternateBaseViewID,
|
|
517
|
+
AlternateBaseView: e.AlternateBaseView,
|
|
438
518
|
_mj__CreatedAt: e.__mj_CreatedAt,
|
|
439
519
|
_mj__UpdatedAt: e.__mj_UpdatedAt,
|
|
440
520
|
DetectionMethod: e.DetectionMethod,
|
|
@@ -455,15 +535,44 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
455
535
|
}) as MJQueryPermission_);
|
|
456
536
|
}
|
|
457
537
|
|
|
458
|
-
|
|
538
|
+
/**
|
|
539
|
+
* Saves one `MJ: Query Permissions` row per input role for the query.
|
|
540
|
+
*
|
|
541
|
+
* @throws Error naming the role and the save's own message when a row is not saved
|
|
542
|
+
*/
|
|
543
|
+
protected async createPermissions(p: DatabaseProviderBase, permissions: QueryPermissionInputType[], queryID: string, contextUser: UserInfo): Promise<MJQueryPermissionEntity[]> {
|
|
544
|
+
const created: MJQueryPermissionEntity[] = [];
|
|
459
545
|
for (const perm of permissions) {
|
|
460
546
|
const permissionEntity = await p.GetEntityObject<MJQueryPermissionEntity>('MJ: Query Permissions', contextUser);
|
|
461
547
|
if (permissionEntity) {
|
|
462
548
|
permissionEntity.QueryID = queryID;
|
|
463
549
|
permissionEntity.RoleID = perm.RoleID;
|
|
464
|
-
await permissionEntity.Save()
|
|
550
|
+
if (!await permissionEntity.Save()) {
|
|
551
|
+
throw new Error(MJQueryResolverExtended.permissionWriteError('save', perm.RoleID, permissionEntity));
|
|
552
|
+
}
|
|
553
|
+
created.push(permissionEntity);
|
|
465
554
|
}
|
|
466
555
|
}
|
|
556
|
+
return created;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Deletes every `MJ: Query Permissions` row of the query.
|
|
561
|
+
*
|
|
562
|
+
* @throws Error naming the role and the delete's own message when a row is not deleted
|
|
563
|
+
*/
|
|
564
|
+
protected async deletePermissions(queryID: string): Promise<void> {
|
|
565
|
+
for (const perm of QueryEngine.Instance.GetQueryPermissions(queryID)) {
|
|
566
|
+
if (!await perm.Delete()) {
|
|
567
|
+
throw new Error(MJQueryResolverExtended.permissionWriteError('delete', perm.RoleID, perm));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/** The message for a permission row that was not saved or deleted, with the entity's own reason. */
|
|
573
|
+
private static permissionWriteError(action: 'save' | 'delete', roleID: string, entity: MJQueryPermissionEntity): string {
|
|
574
|
+
const reason = entity.LatestResult?.CompleteMessage || entity.LatestResult?.Message || `the ${action} reported no reason`;
|
|
575
|
+
return `Failed to ${action} the query permission for role ${roleID}: ${reason}`;
|
|
467
576
|
}
|
|
468
577
|
|
|
469
578
|
/**
|
|
@@ -498,16 +607,14 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
498
607
|
finalCategoryID = await this.findOrCreateCategoryPath(input.CategoryPath, provider, context.userPayload.userRecord);
|
|
499
608
|
}
|
|
500
609
|
|
|
501
|
-
//
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
if (existingQueryResult.Success && existingQueryResult.Results?.length > 0) {
|
|
507
|
-
// we have a match! Let's return an error
|
|
610
|
+
// A rename, or a move to another category, must not collide with another query's name
|
|
611
|
+
const targetName = input.Name ?? queryEntity.Name;
|
|
612
|
+
const targetCategoryID = finalCategoryID !== undefined ? finalCategoryID : queryEntity.CategoryID;
|
|
613
|
+
const sameName = await this.findExistingQuery(provider, targetName, targetCategoryID ?? null, context.userPayload.userRecord);
|
|
614
|
+
if (sameName && !UUIDsEqual(sameName.ID, queryEntity.ID)) {
|
|
508
615
|
return {
|
|
509
616
|
Success: false,
|
|
510
|
-
ErrorMessage: `Query with name '${
|
|
617
|
+
ErrorMessage: `Query with name '${targetName}' already exists in the specified ${input.CategoryID ? 'category' : 'categoryPath'}`
|
|
511
618
|
};
|
|
512
619
|
}
|
|
513
620
|
|
|
@@ -545,25 +652,25 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
545
652
|
if (!saveResult) {
|
|
546
653
|
return {
|
|
547
654
|
Success: false,
|
|
548
|
-
ErrorMessage: `Failed to update query: ${queryEntity.LatestResult?.Message || '
|
|
655
|
+
ErrorMessage: `Failed to update query: ${queryEntity.LatestResult?.CompleteMessage || queryEntity.LatestResult?.Message || 'the save reported no reason'}`
|
|
549
656
|
};
|
|
550
657
|
}
|
|
551
658
|
|
|
552
659
|
const queryID = queryEntity.ID;
|
|
553
660
|
|
|
554
661
|
// Handle permissions update if provided
|
|
662
|
+
let createdPermissions: MJQueryPermissionEntity[] | undefined;
|
|
555
663
|
if (input.Permissions !== undefined) {
|
|
556
|
-
//
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
await
|
|
664
|
+
// Replace the existing permissions (read from the QueryEngine cache); a failed write stops the update with its reason
|
|
665
|
+
try {
|
|
666
|
+
await this.deletePermissions(queryID);
|
|
667
|
+
createdPermissions = await this.createPermissions(provider, input.Permissions, queryID, context.userPayload.userRecord);
|
|
668
|
+
} catch (e) {
|
|
669
|
+
return { Success: false, ErrorMessage: `Failed to update query permissions: ${e instanceof Error ? e.message : String(e)}` };
|
|
560
670
|
}
|
|
561
|
-
|
|
562
|
-
// Create new permissions
|
|
563
|
-
await this.createPermissions(provider, input.Permissions, queryID, context.userPayload.userRecord);
|
|
564
671
|
}
|
|
565
672
|
|
|
566
|
-
return await this.buildSuccessResult(queryEntity, context.userPayload.userRecord, provider);
|
|
673
|
+
return await this.buildSuccessResult(queryEntity, context.userPayload.userRecord, provider, undefined, createdPermissions);
|
|
567
674
|
|
|
568
675
|
} catch (err) {
|
|
569
676
|
LogError(err);
|
|
@@ -740,12 +847,13 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
740
847
|
): Promise<QueryViewRow | null> {
|
|
741
848
|
try {
|
|
742
849
|
// Query database directly to avoid cache staleness issues
|
|
743
|
-
const categoryFilter = categoryID ? `CategoryID='${categoryID}'` : 'CategoryID IS NULL';
|
|
744
|
-
const nameFilter = `LOWER(Name) = LOWER('${queryName
|
|
850
|
+
const categoryFilter = categoryID ? `CategoryID='${EscapeSQLString(categoryID)}'` : 'CategoryID IS NULL';
|
|
851
|
+
const nameFilter = `LOWER(Name) = LOWER('${EscapeSQLString(queryName)}')`;
|
|
745
852
|
|
|
746
853
|
const result = await provider.RunView<QueryViewRow>({
|
|
747
854
|
EntityName: 'MJ: Queries',
|
|
748
|
-
ExtraFilter: `${nameFilter} AND ${categoryFilter}
|
|
855
|
+
ExtraFilter: `${nameFilter} AND ${categoryFilter}`,
|
|
856
|
+
BypassCache: true
|
|
749
857
|
}, contextUser);
|
|
750
858
|
|
|
751
859
|
if (result.Success && result.Results && result.Results.length > 0) {
|
|
@@ -797,13 +905,16 @@ export class MJQueryResolverExtended extends MJQueryResolver {
|
|
|
797
905
|
private async findCategoryByNameAndParent(provider: DatabaseProviderBase, categoryName: string, parentID: string | null, contextUser: UserInfo): Promise<MJQueryCategoryEntity | null> {
|
|
798
906
|
try {
|
|
799
907
|
// Query database directly to avoid cache staleness issues
|
|
800
|
-
const parentFilter = parentID ? `ParentID='${parentID}'` : 'ParentID IS NULL';
|
|
801
|
-
const nameFilter = `LOWER(Name) = LOWER('${categoryName
|
|
908
|
+
const parentFilter = parentID ? `ParentID='${EscapeSQLString(parentID)}'` : 'ParentID IS NULL';
|
|
909
|
+
const nameFilter = `LOWER(Name) = LOWER('${EscapeSQLString(categoryName)}')`;
|
|
802
910
|
|
|
911
|
+
// Uncached: after losing a race to create the category, the re-check must see the row the
|
|
912
|
+
// other request just wrote.
|
|
803
913
|
const result = await provider.RunView<MJQueryCategoryEntity>({
|
|
804
914
|
EntityName: 'MJ: Query Categories',
|
|
805
915
|
ExtraFilter: `${nameFilter} AND ${parentFilter}`,
|
|
806
|
-
ResultType: 'entity_object'
|
|
916
|
+
ResultType: 'entity_object',
|
|
917
|
+
BypassCache: true
|
|
807
918
|
}, contextUser);
|
|
808
919
|
|
|
809
920
|
if (result.Success && result.Results && result.Results.length > 0) {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
import { Resolver, Mutation, Arg, Ctx, Int, Float, ObjectType, Field, PubSub, PubSubEngine } from 'type-graphql';
|
|
35
35
|
import { AppContext, UserPayload } from '../types.js';
|
|
36
36
|
import { AuthorizationEvaluator, UserInfo, IMetadataProvider, DatabaseProviderBase, LogError, LogErrorEx, LogStatus, RunView, BaseEntity } from '@memberjunction/core';
|
|
37
|
-
import { UUIDsEqual, IsValidUUID } from '@memberjunction/global';
|
|
37
|
+
import { EscapeSQLString, UUIDsEqual, IsValidUUID } from '@memberjunction/global';
|
|
38
38
|
import {
|
|
39
39
|
MJAIAgentEntity,
|
|
40
40
|
MJAIAgentSessionEntity,
|
|
@@ -106,6 +106,14 @@ const SIGNIFICANT_PROGRESS_STEPS = ['prompt_execution', 'action_execution', 'sub
|
|
|
106
106
|
*/
|
|
107
107
|
const MAX_USAGE_DETAILS_JSON_LENGTH = 4096;
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Sessions already logged as having no co-agent prompt run. Usage, transcript and tool-turn relays all read
|
|
111
|
+
* the id, many times per call, so the gap is logged once per session instead of once per relay. Bounded:
|
|
112
|
+
* past {@link MAX_LOGGED_MISSING_PROMPT_RUN_SESSIONS} entries the oldest is dropped (a Set keeps insertion order).
|
|
113
|
+
*/
|
|
114
|
+
const sessionsLoggedWithoutPromptRun = new Set<string>();
|
|
115
|
+
const MAX_LOGGED_MISSING_PROMPT_RUN_SESSIONS = 5000;
|
|
116
|
+
|
|
109
117
|
/** Entity name — centralised so the `MJ:`-prefix convention is applied in exactly one place. */
|
|
110
118
|
const CO_AGENT_ENTITY = 'MJ: AI Agent Co Agents';
|
|
111
119
|
const CONVERSATION_DETAIL_ENTITY = 'MJ: Conversation Details';
|
|
@@ -1330,10 +1338,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
1330
1338
|
return null;
|
|
1331
1339
|
}
|
|
1332
1340
|
if (!config.promptRunID) {
|
|
1333
|
-
|
|
1334
|
-
`RelayRealtimeUsage: session ${session.ID} has no co-agent promptRunID (observability run ` +
|
|
1335
|
-
'creation was skipped or failed) — usage delta dropped.',
|
|
1336
|
-
);
|
|
1341
|
+
this.logMissingPromptRunOnce(session.ID);
|
|
1337
1342
|
return null;
|
|
1338
1343
|
}
|
|
1339
1344
|
const verified = await this.runIDVerifier.Verify(
|
|
@@ -1349,6 +1354,29 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
1349
1354
|
return verified.PromptRunID;
|
|
1350
1355
|
}
|
|
1351
1356
|
|
|
1357
|
+
/**
|
|
1358
|
+
* Logs, once per session, that the session has no co-agent prompt run, so its usage, cost, transcript and
|
|
1359
|
+
* tool turns are not recorded on one. The reason (no active co-agent prompt, or a failed run save) was
|
|
1360
|
+
* logged when the session was prepared.
|
|
1361
|
+
*/
|
|
1362
|
+
private logMissingPromptRunOnce(sessionID: string): void {
|
|
1363
|
+
if (sessionsLoggedWithoutPromptRun.has(sessionID)) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
sessionsLoggedWithoutPromptRun.add(sessionID);
|
|
1367
|
+
if (sessionsLoggedWithoutPromptRun.size > MAX_LOGGED_MISSING_PROMPT_RUN_SESSIONS) {
|
|
1368
|
+
const oldest = sessionsLoggedWithoutPromptRun.values().next().value;
|
|
1369
|
+
if (oldest !== undefined) {
|
|
1370
|
+
sessionsLoggedWithoutPromptRun.delete(oldest);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
LogError(
|
|
1374
|
+
`RealtimeClientSessionResolver: session ${sessionID} has no co-agent promptRunID, so its usage, cost, ` +
|
|
1375
|
+
'transcript and tool turns are not recorded on a prompt run (the reason was logged when the session ' +
|
|
1376
|
+
'was prepared). Logged once per session.',
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1352
1380
|
/**
|
|
1353
1381
|
* Persist an interactive channel's state of record (e.g. the live whiteboard's serialized
|
|
1354
1382
|
* scene) onto the session's `MJ: AI Agent Session Channels` row.
|
|
@@ -2032,9 +2060,10 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
2032
2060
|
const existing = await rv.RunView<MJAIAgentSessionChannelEntity>(
|
|
2033
2061
|
{
|
|
2034
2062
|
EntityName: SESSION_CHANNEL_ENTITY,
|
|
2035
|
-
ExtraFilter: `AgentSessionID='${agentSessionID}' AND ChannelID='${channelID}'`,
|
|
2063
|
+
ExtraFilter: `AgentSessionID='${EscapeSQLString(agentSessionID)}' AND ChannelID='${EscapeSQLString(channelID)}'`,
|
|
2036
2064
|
ResultType: 'entity_object',
|
|
2037
2065
|
MaxRows: 1,
|
|
2066
|
+
SkipTotalRowCount: true,
|
|
2038
2067
|
},
|
|
2039
2068
|
contextUser,
|
|
2040
2069
|
);
|
|
@@ -2423,6 +2452,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
2423
2452
|
Fields: ['ID', 'IsEnabled'],
|
|
2424
2453
|
ResultType: 'simple',
|
|
2425
2454
|
MaxRows: 1,
|
|
2455
|
+
SkipTotalRowCount: true,
|
|
2426
2456
|
},
|
|
2427
2457
|
contextUser,
|
|
2428
2458
|
);
|
|
@@ -2585,6 +2615,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
2585
2615
|
OrderBy: '__mj_CreatedAt DESC',
|
|
2586
2616
|
ResultType: 'simple',
|
|
2587
2617
|
MaxRows: 1,
|
|
2618
|
+
SkipTotalRowCount: true,
|
|
2588
2619
|
},
|
|
2589
2620
|
contextUser,
|
|
2590
2621
|
);
|
|
@@ -2673,9 +2704,10 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
2673
2704
|
const existing = await rv.RunView<MJAIAgentSessionChannelEntity>(
|
|
2674
2705
|
{
|
|
2675
2706
|
EntityName: SESSION_CHANNEL_ENTITY,
|
|
2676
|
-
ExtraFilter: `AgentSessionID='${agentSessionID}' AND ChannelID='${channelID}'`,
|
|
2707
|
+
ExtraFilter: `AgentSessionID='${EscapeSQLString(agentSessionID)}' AND ChannelID='${EscapeSQLString(channelID)}'`,
|
|
2677
2708
|
ResultType: 'entity_object',
|
|
2678
2709
|
MaxRows: 1,
|
|
2710
|
+
SkipTotalRowCount: true,
|
|
2679
2711
|
},
|
|
2680
2712
|
contextUser,
|
|
2681
2713
|
);
|
|
@@ -3014,6 +3046,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
3014
3046
|
ExtraFilter: `AgentSessionID='${session.ID}' AND Role='${mappedRole}'`,
|
|
3015
3047
|
OrderBy: '__mj_CreatedAt DESC',
|
|
3016
3048
|
MaxRows: 1,
|
|
3049
|
+
SkipTotalRowCount: true,
|
|
3017
3050
|
ResultType: 'entity_object',
|
|
3018
3051
|
},
|
|
3019
3052
|
writeUser,
|