@memberjunction/server 6.2.0-edge.0 → 6.2.0-edge.2
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/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.d.ts +2 -0
- package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.js +5 -1
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionManager.js +2 -2
- package/dist/agentSessions/remoteBrowserGoalEngine.d.ts +8 -0
- package/dist/agentSessions/remoteBrowserGoalEngine.d.ts.map +1 -1
- package/dist/agentSessions/remoteBrowserGoalEngine.js +21 -5
- package/dist/agentSessions/remoteBrowserGoalEngine.js.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.d.ts +2 -0
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +5 -1
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/index.d.ts +20 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +20 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +8 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +21 -5
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +9 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +22 -10
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts +17 -15
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +65 -51
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +2 -2
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +2 -2
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/magicLinkCore.d.ts +54 -33
- package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -1
- package/dist/auth/magicLink/magicLinkCore.js +61 -61
- package/dist/auth/magicLink/magicLinkCore.js.map +1 -1
- package/dist/auth/magicLink/redeemLanding.d.ts +4 -0
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
- package/dist/auth/magicLink/redeemLanding.js +12 -4
- package/dist/auth/magicLink/redeemLanding.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +4 -4
- package/dist/auth/principals.d.ts +2 -0
- package/dist/auth/principals.d.ts.map +1 -1
- package/dist/auth/principals.js +6 -2
- package/dist/auth/principals.js.map +1 -1
- package/dist/cache.d.ts +2 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +3 -1
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +346 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +34 -4
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +20 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +27 -19
- package/dist/context.js.map +1 -1
- package/dist/directives/Public.d.ts +2 -0
- package/dist/directives/Public.d.ts.map +1 -1
- package/dist/directives/Public.js +3 -1
- package/dist/directives/Public.js.map +1 -1
- package/dist/directives/RequireSystemUser.d.ts +2 -0
- package/dist/directives/RequireSystemUser.d.ts.map +1 -1
- package/dist/directives/RequireSystemUser.js +3 -1
- package/dist/directives/RequireSystemUser.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +1021 -0
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +7368 -2145
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +94 -4
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +122 -3
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/DeleteOptionsInput.d.ts +8 -1
- package/dist/generic/DeleteOptionsInput.d.ts.map +1 -1
- package/dist/generic/DeleteOptionsInput.js +1 -1
- package/dist/generic/DeleteOptionsInput.js.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.d.ts +18 -2
- package/dist/generic/FireAndForgetHeartbeat.d.ts.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.js +24 -6
- package/dist/generic/FireAndForgetHeartbeat.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts +31 -0
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -0
- package/dist/generic/OrphanedConversationDetailReconciler.js +215 -0
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -0
- package/dist/generic/PushStatusResolver.d.ts +48 -1
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +95 -4
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +18 -2
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +64 -55
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +120 -11
- package/dist/index.js.map +1 -1
- package/dist/integration/CustomColumnPromoter.d.ts +2 -0
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +5 -1
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/integration/EntityMapLifecycle.d.ts +4 -0
- package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
- package/dist/integration/EntityMapLifecycle.js +10 -2
- package/dist/integration/EntityMapLifecycle.js.map +1 -1
- package/dist/logging/NoLog.d.ts +4 -0
- package/dist/logging/NoLog.d.ts.map +1 -1
- package/dist/logging/NoLog.js +10 -2
- package/dist/logging/NoLog.js.map +1 -1
- package/dist/logging/StartupLogger.d.ts +2 -0
- package/dist/logging/StartupLogger.d.ts.map +1 -1
- package/dist/logging/StartupLogger.js +5 -1
- package/dist/logging/StartupLogger.js.map +1 -1
- package/dist/logging/bootAudit.d.ts +11 -7
- package/dist/logging/bootAudit.d.ts.map +1 -1
- package/dist/logging/bootAudit.js +15 -7
- package/dist/logging/bootAudit.js.map +1 -1
- package/dist/logging/boundaryLogPayload.d.ts +4 -0
- package/dist/logging/boundaryLogPayload.d.ts.map +1 -1
- package/dist/logging/boundaryLogPayload.js +5 -1
- package/dist/logging/boundaryLogPayload.js.map +1 -1
- package/dist/logging/secretRedactor.d.ts +2 -0
- package/dist/logging/secretRedactor.d.ts.map +1 -1
- package/dist/logging/secretRedactor.js +8 -4
- package/dist/logging/secretRedactor.js.map +1 -1
- package/dist/logging/shortenForLog.d.ts +2 -0
- package/dist/logging/shortenForLog.d.ts.map +1 -1
- package/dist/logging/shortenForLog.js +7 -3
- package/dist/logging/shortenForLog.js.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.d.ts +2 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.js +8 -6
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
- package/dist/metadataRefreshSignal.d.ts +19 -0
- package/dist/metadataRefreshSignal.d.ts.map +1 -0
- package/dist/metadataRefreshSignal.js +45 -0
- package/dist/metadataRefreshSignal.js.map +1 -0
- package/dist/middleware/MJTenantFilterMiddleware.js +4 -4
- package/dist/multiTenancy/index.d.ts +8 -0
- package/dist/multiTenancy/index.d.ts.map +1 -1
- package/dist/multiTenancy/index.js +21 -5
- package/dist/multiTenancy/index.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts +5 -0
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.js +14 -10
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts +6 -6
- package/dist/realtimeWidget/WidgetSessionService.js +27 -27
- package/dist/realtimeWidget/host-identity.d.ts +5 -1
- package/dist/realtimeWidget/host-identity.d.ts.map +1 -1
- package/dist/realtimeWidget/host-identity.js +11 -3
- package/dist/realtimeWidget/host-identity.js.map +1 -1
- package/dist/realtimeWidget/index.d.ts +2 -2
- package/dist/realtimeWidget/index.d.ts.map +1 -1
- package/dist/realtimeWidget/index.js +2 -2
- package/dist/realtimeWidget/index.js.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts +21 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.js +16 -4
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +48 -0
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +38 -10
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +10 -6
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +14 -6
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +3 -3
- package/dist/resolvers/AgentRunStatusPublisher.d.ts +55 -0
- package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -0
- package/dist/resolvers/AgentRunStatusPublisher.js +141 -0
- package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -0
- package/dist/resolvers/ConversationRunEventsResolver.d.ts +90 -0
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -0
- package/dist/resolvers/ConversationRunEventsResolver.js +283 -0
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.d.ts +98 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.d.ts.map +1 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.js +227 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.js.map +1 -0
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +2 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.js +3 -3
- package/dist/resolvers/GeoResolver.d.ts +2 -2
- package/dist/resolvers/GeoResolver.js +4 -4
- package/dist/resolvers/GetDataResolver.d.ts +14 -0
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +43 -15
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +2 -2
- package/dist/resolvers/ListOperationsResolver.d.ts +20 -0
- package/dist/resolvers/ListOperationsResolver.d.ts.map +1 -1
- package/dist/resolvers/ListOperationsResolver.js +68 -28
- package/dist/resolvers/ListOperationsResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts +11 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +7 -3
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +7 -0
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +16 -2
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +3 -3
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +44 -6
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +93 -37
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +5 -5
- package/dist/resolvers/RunAIAgentResolver.d.ts +8 -18
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +85 -184
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +2 -2
- package/dist/resolvers/RunDecisionResolver.d.ts +149 -0
- package/dist/resolvers/RunDecisionResolver.d.ts.map +1 -0
- package/dist/resolvers/RunDecisionResolver.js +396 -0
- package/dist/resolvers/RunDecisionResolver.js.map +1 -0
- package/dist/resolvers/RunTestResolver.js +5 -5
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts +8 -4
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +5 -5
- package/dist/resolvers/TaskGraphFrameResolver.d.ts +8 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.js +6 -2
- package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
- package/dist/resolvers/VectorizeEntityResolver.d.ts +1 -1
- package/dist/resolvers/VectorizeEntityResolver.d.ts.map +1 -1
- package/dist/resolvers/VectorizeEntityResolver.js +14 -10
- package/dist/resolvers/VectorizeEntityResolver.js.map +1 -1
- package/dist/resolvers/adhoc-query-helpers.d.ts +6 -0
- package/dist/resolvers/adhoc-query-helpers.d.ts.map +1 -1
- package/dist/resolvers/adhoc-query-helpers.js +10 -2
- package/dist/resolvers/adhoc-query-helpers.js.map +1 -1
- package/dist/resolvers/artifact-routing.d.ts +8 -8
- package/dist/resolvers/artifact-routing.js +2 -2
- package/dist/resolvers/artifact-routing.js.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.d.ts +10 -2
- package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.js +24 -8
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
- package/dist/resolvers/peaksSidecar.d.ts +4 -0
- package/dist/resolvers/peaksSidecar.d.ts.map +1 -1
- package/dist/resolvers/peaksSidecar.js +10 -2
- package/dist/resolvers/peaksSidecar.js.map +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts +28 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +20 -4
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/MediaStreamHandler.d.ts +2 -0
- package/dist/rest/MediaStreamHandler.d.ts.map +1 -1
- package/dist/rest/MediaStreamHandler.js +10 -6
- package/dist/rest/MediaStreamHandler.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts +9 -0
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +15 -3
- package/dist/rest/OAuthCallbackHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts +6 -4
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +15 -11
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts +5 -1
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeSdpBrokerHandler.js +12 -4
- package/dist/rest/RealtimeSdpBrokerHandler.js.map +1 -1
- package/dist/rest/SignatureWebhookHandler.d.ts +2 -0
- package/dist/rest/SignatureWebhookHandler.d.ts.map +1 -1
- package/dist/rest/SignatureWebhookHandler.js +5 -1
- package/dist/rest/SignatureWebhookHandler.js.map +1 -1
- package/dist/rest/UploadTokenManager.d.ts +24 -8
- package/dist/rest/UploadTokenManager.d.ts.map +1 -1
- package/dist/rest/UploadTokenManager.js +53 -21
- package/dist/rest/UploadTokenManager.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +20 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +20 -4
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/mediaRange.d.ts +4 -0
- package/dist/rest/mediaRange.d.ts.map +1 -1
- package/dist/rest/mediaRange.js +10 -2
- package/dist/rest/mediaRange.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +4 -0
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +13 -7
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverExtensionReservedRoots.d.ts +2 -0
- package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
- package/dist/serverExtensionReservedRoots.js +5 -1
- package/dist/serverExtensionReservedRoots.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +13 -8
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +16 -15
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -3
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +6 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +13 -5
- package/dist/util.js.map +1 -1
- package/package.json +94 -92
- package/src/__tests__/AgentRunStatusPublisher.test.ts +175 -0
- package/src/__tests__/DeleteOptionsInput.wireShape.test.ts +62 -0
- package/src/__tests__/DuplicateEntryCheckResolver.test.ts +300 -0
- package/src/__tests__/FileResolverPeaks.test.ts +13 -13
- package/src/__tests__/ListOperationsResolver.test.ts +17 -17
- package/src/__tests__/MediaStreamHandler.test.ts +28 -28
- package/src/__tests__/NoLog.test.ts +11 -11
- package/src/__tests__/PrimaryKeyAlwaysMapped.test.ts +10 -10
- package/src/__tests__/RESTEndpointHandler.test.ts +14 -14
- package/src/__tests__/RealtimeBridgeResolver.test.ts +4 -2
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +216 -2
- package/src/__tests__/RealtimeSdpBrokerHandler.test.ts +6 -6
- package/src/__tests__/RefreshAdoptsNewColumns.test.ts +8 -8
- package/src/__tests__/RemoteBrowserActionRecovery.test.ts +7 -1
- package/src/__tests__/RemoteBrowserAudioStream.test.ts +7 -1
- package/src/__tests__/RemoteBrowserGoalEngine.test.ts +18 -18
- package/src/__tests__/RemoteBrowserSnapshot.test.ts +7 -1
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +52 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +398 -0
- package/src/__tests__/RunAIAgentResolver.streaming.test.ts +18 -27
- package/src/__tests__/RunDecisionResolver.test.ts +699 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +131 -0
- package/src/__tests__/TaskGraphFrameResolver.test.ts +2 -2
- package/src/__tests__/VectorizeEntityResolver.test.ts +106 -0
- package/src/__tests__/WidgetSessionService.test.ts +8 -4
- package/src/__tests__/adhoc-query-helpers.test.ts +21 -21
- package/src/__tests__/bootAudit.test.ts +11 -11
- package/src/__tests__/boundaryLogPayload.test.ts +6 -6
- package/src/__tests__/cacheInvalidationRecordData.test.ts +177 -0
- package/src/__tests__/conversationRunEvents.test.ts +399 -0
- package/src/__tests__/databaseAbstraction.test.ts +12 -6
- package/src/__tests__/getDataTokenRedaction.test.ts +7 -7
- package/src/__tests__/initializeProviders.refresh.test.ts +4 -4
- package/src/__tests__/magicLink.test.ts +73 -134
- package/src/__tests__/magicLinkService.consume.test.ts +224 -0
- package/src/__tests__/meetingRecordingRegistration.test.ts +12 -12
- package/src/__tests__/metadataRefreshSignal.test.ts +78 -0
- package/src/__tests__/multiTenancy.security.test.ts +40 -40
- package/src/__tests__/multiTenancy.test.ts +18 -18
- package/src/__tests__/newUsers.test.ts +24 -23
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +283 -0
- package/src/__tests__/principals.test.ts +22 -22
- package/src/__tests__/pushStatusFanOut.test.ts +206 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +8 -8
- package/src/__tests__/secretRedactor.failOpen.test.ts +12 -12
- package/src/__tests__/secretRedactor.test.ts +12 -12
- package/src/__tests__/serverExtensionReservedRoots.test.ts +7 -7
- package/src/__tests__/subscriptionRedaction.test.ts +5 -5
- package/src/__tests__/unifiedAuth.test.ts +15 -9
- package/src/__tests__/visitorIdentity.resolve.test.ts +6 -6
- package/src/__tests__/widget.test.ts +45 -45
- package/src/__tests__/widgetGuestElevation.test.ts +7 -7
- package/src/__tests__/widgetHostIdentity.test.ts +14 -14
- package/src/agentSessions/ReturningVisitorRecap.ts +12 -1
- package/src/agentSessions/SessionManager.ts +2 -2
- package/src/agentSessions/remoteBrowserGoalEngine.ts +30 -5
- package/src/auth/AuthProviderCatalogRouter.ts +6 -1
- package/src/auth/__tests__/backward-compatibility.test.ts +4 -3
- package/src/auth/index.ts +43 -28
- package/src/auth/initializeProviders.ts +25 -5
- package/src/auth/magicLink/MagicLinkRouter.ts +28 -10
- package/src/auth/magicLink/MagicLinkService.ts +71 -52
- package/src/auth/magicLink/index.ts +7 -7
- package/src/auth/magicLink/magicLinkCore.ts +96 -64
- package/src/auth/magicLink/redeemLanding.ts +14 -4
- package/src/auth/magicLink/types.ts +54 -54
- package/src/auth/newUsers.ts +1 -1
- package/src/auth/principals.ts +11 -2
- package/src/cache.ts +4 -1
- package/src/config.ts +37 -4
- package/src/context.ts +37 -24
- package/src/directives/Public.ts +4 -1
- package/src/directives/RequireSystemUser.ts +4 -1
- package/src/generated/graphql-schemas/__mj.ts +3674 -4
- package/src/generic/CacheInvalidationResolver.ts +148 -4
- package/src/generic/DeleteOptionsInput.ts +9 -2
- package/src/generic/FireAndForgetHeartbeat.ts +35 -16
- package/src/generic/OrphanedConversationDetailReconciler.ts +267 -0
- package/src/generic/PushStatusResolver.ts +118 -8
- package/src/generic/ResolverBase.ts +65 -57
- package/src/generic/RunViewResolver.ts +22 -22
- package/src/generic/__tests__/FireAndForgetHeartbeat.test.ts +7 -7
- package/src/index.ts +137 -11
- package/src/integration/CustomColumnPromoter.ts +6 -1
- package/src/integration/EntityMapLifecycle.ts +20 -2
- package/src/logging/NoLog.ts +16 -2
- package/src/logging/StartupLogger.ts +6 -1
- package/src/logging/bootAudit.ts +26 -16
- package/src/logging/boundaryLogPayload.ts +8 -1
- package/src/logging/secretRedactor.ts +14 -9
- package/src/logging/shortenForLog.ts +8 -3
- package/src/logging/variablesLoggingMiddleware.ts +9 -6
- package/src/metadataRefreshSignal.ts +45 -0
- package/src/middleware/MJTenantFilterMiddleware.ts +4 -4
- package/src/multiTenancy/index.ts +29 -5
- package/src/realtimeWidget/WidgetRouter.ts +15 -10
- package/src/realtimeWidget/WidgetSessionService.ts +76 -76
- package/src/realtimeWidget/host-identity.ts +24 -10
- package/src/realtimeWidget/index.ts +3 -3
- package/src/realtimeWidget/visitorIdentity.ts +39 -8
- package/src/realtimeWidget/widgetCore.ts +75 -10
- package/src/realtimeWidget/widgetGuestElevation.ts +25 -12
- package/src/resolvers/AdhocQueryResolver.ts +3 -3
- package/src/resolvers/AgentRunStatusPublisher.ts +175 -0
- package/src/resolvers/AgentSessionResolver.ts +3 -3
- package/src/resolvers/ColorResolver.ts +6 -6
- package/src/resolvers/ComponentRegistryResolver.ts +36 -36
- package/src/resolvers/ConversationRunEventsResolver.ts +308 -0
- package/src/resolvers/DuplicateEntryCheckResolver.ts +232 -0
- package/src/resolvers/EntityCommunicationsResolver.ts +4 -4
- package/src/resolvers/ExecuteRemoteOperationResolver.ts +9 -9
- package/src/resolvers/FetchEntityVectorsResolver.ts +2 -1
- package/src/resolvers/FileResolver.ts +42 -42
- package/src/resolvers/GeoResolver.ts +4 -4
- package/src/resolvers/GetDataResolver.ts +50 -15
- package/src/resolvers/IntegrationDiscoveryResolver.ts +2 -2
- package/src/resolvers/ListOperationsResolver.ts +78 -28
- package/src/resolvers/MCPResolver.ts +30 -15
- package/src/resolvers/MergeRecordsResolver.ts +14 -2
- package/src/resolvers/QueryResolver.ts +13 -13
- package/src/resolvers/RealtimeBridgeResolver.ts +3 -3
- package/src/resolvers/RealtimeClientSessionResolver.ts +96 -38
- package/src/resolvers/RemoteBrowserActionResolver.ts +5 -5
- package/src/resolvers/RunAIAgentResolver.ts +134 -239
- package/src/resolvers/RunAIPromptResolver.ts +22 -22
- package/src/resolvers/RunDecisionResolver.ts +435 -0
- package/src/resolvers/RunTemplateResolver.ts +4 -4
- package/src/resolvers/RunTestResolver.ts +25 -25
- package/src/resolvers/SqlLoggingConfigResolver.ts +56 -56
- package/src/resolvers/TaskGraphFrameResolver.ts +37 -28
- package/src/resolvers/TelemetryResolver.ts +79 -79
- package/src/resolvers/VectorizeEntityResolver.ts +16 -11
- package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +40 -38
- package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +93 -0
- package/src/resolvers/__tests__/artifact-routing.test.ts +23 -23
- package/src/resolvers/adhoc-query-helpers.ts +19 -2
- package/src/resolvers/artifact-routing.ts +19 -19
- package/src/resolvers/meetingRecordingRegistration.ts +44 -10
- package/src/resolvers/peaksSidecar.ts +12 -2
- package/src/rest/EntityCRUDHandler.ts +24 -4
- package/src/rest/MediaStreamHandler.ts +11 -6
- package/src/rest/OAuthCallbackHandler.ts +25 -7
- package/src/rest/RESTEndpointHandler.ts +20 -15
- package/src/rest/RealtimeSdpBrokerHandler.ts +14 -4
- package/src/rest/SignatureWebhookHandler.ts +6 -1
- package/src/rest/UploadTokenManager.ts +66 -30
- package/src/rest/ViewOperationsHandler.ts +24 -4
- package/src/rest/mediaRange.ts +16 -6
- package/src/rest/setupRESTEndpoints.ts +24 -12
- package/src/serverExtensionReservedRoots.ts +6 -1
- package/src/services/TaskGraphActionRunner.ts +16 -15
- package/src/types.ts +21 -16
- package/src/util.ts +16 -6
|
@@ -15,70 +15,70 @@ import { GetReadWriteProvider } from '../util.js';
|
|
|
15
15
|
@ObjectType()
|
|
16
16
|
export class AIPromptRunResult {
|
|
17
17
|
@Field()
|
|
18
|
-
success: boolean;
|
|
18
|
+
success: boolean; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
19
19
|
|
|
20
20
|
@Field({ nullable: true })
|
|
21
|
-
output?: string;
|
|
21
|
+
output?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
22
22
|
|
|
23
23
|
@Field({ nullable: true })
|
|
24
|
-
parsedResult?: string;
|
|
24
|
+
parsedResult?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
25
25
|
|
|
26
26
|
@Field({ nullable: true })
|
|
27
|
-
error?: string;
|
|
27
|
+
error?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
28
28
|
|
|
29
29
|
@Field({ nullable: true })
|
|
30
|
-
executionTimeMs?: number;
|
|
30
|
+
executionTimeMs?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
31
31
|
|
|
32
32
|
@Field({ nullable: true })
|
|
33
|
-
tokensUsed?: number;
|
|
33
|
+
tokensUsed?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
34
34
|
|
|
35
35
|
@Field({ nullable: true })
|
|
36
|
-
promptRunId?: string;
|
|
36
|
+
promptRunId?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
37
37
|
|
|
38
38
|
@Field({ nullable: true })
|
|
39
|
-
rawResult?: string;
|
|
39
|
+
rawResult?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
40
40
|
|
|
41
41
|
@Field({ nullable: true })
|
|
42
|
-
validationResult?: string;
|
|
42
|
+
validationResult?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
43
43
|
|
|
44
44
|
@Field({ nullable: true })
|
|
45
|
-
chatResult?: string;
|
|
45
|
+
chatResult?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
@ObjectType()
|
|
49
49
|
export class SimplePromptResult {
|
|
50
50
|
@Field()
|
|
51
|
-
success: boolean;
|
|
51
|
+
success: boolean; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
52
52
|
|
|
53
53
|
@Field({ nullable: true })
|
|
54
|
-
result?: string;
|
|
54
|
+
result?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
55
55
|
|
|
56
56
|
@Field({ nullable: true })
|
|
57
|
-
resultObject?: string; // JSON stringified object
|
|
57
|
+
resultObject?: string; // JSON stringified object — case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
58
58
|
|
|
59
59
|
@Field()
|
|
60
|
-
modelName: string;
|
|
60
|
+
modelName: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
61
61
|
|
|
62
62
|
@Field({ nullable: true })
|
|
63
|
-
error?: string;
|
|
63
|
+
error?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
64
64
|
|
|
65
65
|
@Field({ nullable: true })
|
|
66
|
-
executionTimeMs?: number;
|
|
66
|
+
executionTimeMs?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
@ObjectType()
|
|
70
70
|
export class EmbedTextResult {
|
|
71
71
|
@Field(() => [[Number]])
|
|
72
|
-
embeddings: number[][];
|
|
72
|
+
embeddings: number[][]; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
73
73
|
|
|
74
74
|
@Field()
|
|
75
|
-
modelName: string;
|
|
75
|
+
modelName: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
76
76
|
|
|
77
77
|
@Field(() => Int)
|
|
78
|
-
vectorDimensions: number;
|
|
78
|
+
vectorDimensions: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
79
79
|
|
|
80
80
|
@Field({ nullable: true })
|
|
81
|
-
error?: string;
|
|
81
|
+
error?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
@@ -418,7 +418,7 @@ export class RunAIPromptResolver extends ResolverBase {
|
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
/** The `AI Model Types.Name` that means "a chat LLM", compared lowercased. */
|
|
421
|
-
private static readonly
|
|
421
|
+
private static readonly simplePromptLLMTypeName = 'llm';
|
|
422
422
|
|
|
423
423
|
/**
|
|
424
424
|
* Selects a runnable model + vendor for simple prompt execution.
|
|
@@ -551,7 +551,7 @@ export class RunAIPromptResolver extends ResolverBase {
|
|
|
551
551
|
*/
|
|
552
552
|
private isLLMModel(model: MJAIModelEntityExtended): boolean {
|
|
553
553
|
const typeName = AIEngine.Instance.ModelTypesByID.get(model.AIModelTypeID)?.Name ?? model.AIModelType;
|
|
554
|
-
return typeName?.trim().toLowerCase() === RunAIPromptResolver.
|
|
554
|
+
return typeName?.trim().toLowerCase() === RunAIPromptResolver.simplePromptLLMTypeName;
|
|
555
555
|
}
|
|
556
556
|
|
|
557
557
|
/**
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field, Int } from 'type-graphql';
|
|
2
|
+
import { AppContext, UserPayload } from '../types.js';
|
|
3
|
+
import { LogError, LogStatus, UserInfo } from '@memberjunction/core';
|
|
4
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
5
|
+
import { MJAIPromptEntityExtended } from '@memberjunction/ai-core-plus';
|
|
6
|
+
import { AIDecisionRunner, AIDecisionParams, AIDecisionRunResult, ParseDecisionQuestions } from '@memberjunction/ai-prompts';
|
|
7
|
+
import { DecisionQuestion } from '@memberjunction/ai';
|
|
8
|
+
import { AIEngine } from '@memberjunction/aiengine';
|
|
9
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
10
|
+
import { IsScopeLimitedPrincipal } from '../auth/scopeLimitedPrincipal.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The result of the `RunDecision` mutation. Every failure, an authorization denial included, comes
|
|
14
|
+
* back as `success: false` with an `errorMessage`: the mutation never throws to the client.
|
|
15
|
+
*/
|
|
16
|
+
@ObjectType()
|
|
17
|
+
export class DecisionRunResult {
|
|
18
|
+
@Field()
|
|
19
|
+
success: boolean; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
|
|
20
|
+
|
|
21
|
+
@Field({ nullable: true })
|
|
22
|
+
errorMessage?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
|
|
23
|
+
|
|
24
|
+
/** The `DecisionAnswer` map by question key, as JSON. Set only on success. */
|
|
25
|
+
@Field({ nullable: true })
|
|
26
|
+
answersJSON?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
|
|
27
|
+
|
|
28
|
+
@Field({ nullable: true })
|
|
29
|
+
promptRunId?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
|
|
30
|
+
|
|
31
|
+
/** The model that answered, after any failover, or the one selected when the call failed. */
|
|
32
|
+
@Field({ nullable: true })
|
|
33
|
+
modelName?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The exact model behind `modelName`, as its driver reports it (`DecisionResult.ResolvedModel`):
|
|
37
|
+
* the vendor's dated model for a vendor decision model, the chat model for LLM Decision. A
|
|
38
|
+
* consumer that calibrates per model needs it: a calibration holds only for the model it was
|
|
39
|
+
* fitted on. Absent when the driver reports none.
|
|
40
|
+
*/
|
|
41
|
+
@Field({ nullable: true })
|
|
42
|
+
resolvedModel?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
|
|
43
|
+
|
|
44
|
+
@Field({ nullable: true })
|
|
45
|
+
executionTimeMs?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The arguments of one `RunDecision` call. */
|
|
49
|
+
interface DecisionRequest {
|
|
50
|
+
State: string;
|
|
51
|
+
Questions: string;
|
|
52
|
+
PromptID?: string;
|
|
53
|
+
PromptName?: string;
|
|
54
|
+
TimeoutMS?: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The prompt a request names: by ID, or by name. */
|
|
58
|
+
interface DecisionPromptReference {
|
|
59
|
+
By: 'ID' | 'Name';
|
|
60
|
+
Value: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** The validated state and questions of one request, and the model-call timeout to use. */
|
|
64
|
+
interface DecisionInputs {
|
|
65
|
+
State: string | Record<string, unknown>;
|
|
66
|
+
Questions: Record<string, DecisionQuestion>;
|
|
67
|
+
TimeoutMS: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Runs typed decisions (Likelihood, Choice, Score) for clients in one round trip, through
|
|
72
|
+
* `AIDecisionRunner`. It is the direct path for latency-sensitive browser callers: the `Run Decision`
|
|
73
|
+
* action does the same work with action-execution overhead on top.
|
|
74
|
+
*
|
|
75
|
+
* The request path adds no entity load: the prompt comes from `AIEngine`'s cache.
|
|
76
|
+
*/
|
|
77
|
+
@Resolver()
|
|
78
|
+
export class RunDecisionResolver extends ResolverBase {
|
|
79
|
+
/** The prompt used when the caller names none, as for the `Run Decision` action. */
|
|
80
|
+
public static readonly DEFAULT_PROMPT_NAME = 'Default Decision';
|
|
81
|
+
|
|
82
|
+
// Server-side bounds on a request. They are cheap backstops, checked before the model is
|
|
83
|
+
// called. Each decision model's own declared limits are the runner's to check.
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The most characters the state may have: about 32,000 tokens at four characters a token, which
|
|
87
|
+
* is Jev's declared input limit. Checked before the state is parsed.
|
|
88
|
+
*/
|
|
89
|
+
public static readonly MAX_STATE_CHARACTERS = 128_000;
|
|
90
|
+
|
|
91
|
+
/** The most characters the questions' JSON may have. Checked before it is parsed. */
|
|
92
|
+
public static readonly MAX_QUESTIONS_CHARACTERS = 128_000;
|
|
93
|
+
|
|
94
|
+
/** The most questions one request may carry. */
|
|
95
|
+
public static readonly MAX_QUESTIONS = 32;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The most options a Choice question, or levels a Score question, may list: Jev's declared
|
|
99
|
+
* `MaxChoiceOptions`.
|
|
100
|
+
*/
|
|
101
|
+
public static readonly MAX_OPTIONS_PER_QUESTION = 255;
|
|
102
|
+
|
|
103
|
+
/** The model-call timeout used when the caller sends none, or one that is not positive. */
|
|
104
|
+
public static readonly DEFAULT_TIMEOUT_MS = 30_000;
|
|
105
|
+
|
|
106
|
+
/** The longest model-call timeout a caller may ask for. A longer one is cut to it. */
|
|
107
|
+
public static readonly MAX_TIMEOUT_MS = 120_000;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Answers typed questions about a state with a Decision-typed prompt.
|
|
111
|
+
*
|
|
112
|
+
* Authorization is `RunAIPrompt`'s: the API-key `prompt:execute` scope check, before any other
|
|
113
|
+
* work (a session without an API key skips it). As `RunAIPrompt` and `RunAIAgent` do, it checks
|
|
114
|
+
* the ID of the prompt that will run, whether the caller named it by ID or by name, so a rule on
|
|
115
|
+
* a prompt's ID holds on both. A denial is returned as `success: false`, not thrown.
|
|
116
|
+
*
|
|
117
|
+
* Scope-limited sessions (magic-link guests and resource-scoped sessions) are refused. The
|
|
118
|
+
* prompt is read from `AIEngine`'s cache, around entity permissions and row-level security, so
|
|
119
|
+
* the confinement those sessions rely on would not apply here. For the same reason, a prompt
|
|
120
|
+
* that cannot run gets one neutral message, whatever the reason, that names nothing the caller
|
|
121
|
+
* did not send.
|
|
122
|
+
*
|
|
123
|
+
* @param state The state the questions are about: text, or the JSON text of an object.
|
|
124
|
+
* @param questions The `DecisionQuestion` map by question key, as JSON: the shape `Run Decision` accepts.
|
|
125
|
+
* @param promptId The decision prompt's ID. Takes precedence over `promptName`.
|
|
126
|
+
* @param promptName The decision prompt's name, matched case-insensitively. Defaults to `Default Decision`.
|
|
127
|
+
* @param timeoutMS Bounds each model call, as the runner's `timeoutMS`. Unset or not positive, it is
|
|
128
|
+
* `DEFAULT_TIMEOUT_MS`; above `MAX_TIMEOUT_MS`, it is cut to it. A call is never unbounded.
|
|
129
|
+
*/
|
|
130
|
+
@Mutation(() => DecisionRunResult)
|
|
131
|
+
async RunDecision(
|
|
132
|
+
@Arg('state') state: string,
|
|
133
|
+
@Arg('questions') questions: string,
|
|
134
|
+
@Ctx() { userPayload }: AppContext,
|
|
135
|
+
@Arg('promptId', { nullable: true }) promptId?: string,
|
|
136
|
+
@Arg('promptName', { nullable: true }) promptName?: string,
|
|
137
|
+
@Arg('timeoutMS', () => Int, { nullable: true }) timeoutMS?: number
|
|
138
|
+
): Promise<DecisionRunResult> {
|
|
139
|
+
const startTime = Date.now();
|
|
140
|
+
try {
|
|
141
|
+
const request: DecisionRequest = { State: state, Questions: questions, PromptID: promptId, PromptName: promptName, TimeoutMS: timeoutMS };
|
|
142
|
+
return await this.runDecision(request, userPayload, startTime);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
145
|
+
LogError(`RunDecision failed: ${message}`, undefined, error);
|
|
146
|
+
return this.failure(message || 'Unknown error occurred', startTime);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Authorizes, validates, resolves the prompt, and runs the decision. Throws only on unexpected errors. */
|
|
151
|
+
private async runDecision(request: DecisionRequest, userPayload: UserPayload, startTime: number): Promise<DecisionRunResult> {
|
|
152
|
+
const reference = this.promptReference(request);
|
|
153
|
+
const authorized = await this.authorizePrompt(reference, userPayload);
|
|
154
|
+
|
|
155
|
+
const currentUser = this.GetUserFromPayload(userPayload);
|
|
156
|
+
if (!currentUser) {
|
|
157
|
+
return this.failure('Unable to determine current user', startTime);
|
|
158
|
+
}
|
|
159
|
+
// A scope-limited session is confined only by entity permissions and RLS, and the prompt comes
|
|
160
|
+
// from the cache, around both. There is no narrower read to fall back to, so it is refused.
|
|
161
|
+
if (IsScopeLimitedPrincipal(currentUser)) {
|
|
162
|
+
return this.failure('RunDecision is not permitted for scope-limited sessions', startTime);
|
|
163
|
+
}
|
|
164
|
+
const inputs = this.validateInputs(request);
|
|
165
|
+
if ('Error' in inputs) {
|
|
166
|
+
return this.failure(inputs.Error, startTime);
|
|
167
|
+
}
|
|
168
|
+
const runner = new AIDecisionRunner();
|
|
169
|
+
const prompt = await this.resolvePrompt(authorized, reference, runner, currentUser, userPayload);
|
|
170
|
+
if (typeof prompt === 'string') {
|
|
171
|
+
return this.failure(prompt, startTime);
|
|
172
|
+
}
|
|
173
|
+
const result = await runner.ExecuteDecision(this.buildDecisionParams(prompt, inputs, currentUser));
|
|
174
|
+
return this.mapRunResult(result, prompt, startTime);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** The prompt the request names: its ID when given, otherwise its name, otherwise the default. */
|
|
178
|
+
private promptReference(request: DecisionRequest): DecisionPromptReference {
|
|
179
|
+
const id = request.PromptID?.trim();
|
|
180
|
+
if (id) {
|
|
181
|
+
return { By: 'ID', Value: id };
|
|
182
|
+
}
|
|
183
|
+
const name = request.PromptName?.trim();
|
|
184
|
+
return { By: 'Name', Value: name || RunDecisionResolver.DEFAULT_PROMPT_NAME };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The API-key `prompt:execute` scope check, made before any other work. The prompt is looked up
|
|
189
|
+
* in `AIEngine`'s cache as it stands, with nothing loaded or logged, and the check is made against
|
|
190
|
+
* its ID. A prompt that is not there is checked against the value the caller sent, so a denied
|
|
191
|
+
* caller learns nothing about which prompts exist: that it was not found is reported only after
|
|
192
|
+
* the check passes.
|
|
193
|
+
*
|
|
194
|
+
* @returns The prompt found, which was authorized by its ID, or undefined when none was found.
|
|
195
|
+
*/
|
|
196
|
+
private async authorizePrompt(
|
|
197
|
+
reference: DecisionPromptReference,
|
|
198
|
+
userPayload: UserPayload
|
|
199
|
+
): Promise<MJAIPromptEntityExtended | undefined> {
|
|
200
|
+
const cached = this.findCachedPrompt(reference);
|
|
201
|
+
await this.CheckAPIKeyScopeAuthorization('prompt:execute', cached?.ID ?? reference.Value, userPayload);
|
|
202
|
+
return cached;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Looks the prompt up in the cache without loading it. A cache that cannot be read counts as not
|
|
207
|
+
* found here, so the error surfaces only after authorization, when the lookup is made again.
|
|
208
|
+
*/
|
|
209
|
+
private findCachedPrompt(reference: DecisionPromptReference): MJAIPromptEntityExtended | undefined {
|
|
210
|
+
try {
|
|
211
|
+
return this.findPrompt(reference);
|
|
212
|
+
} catch {
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Validates the state and the questions and bounds their size, or returns the first problem
|
|
219
|
+
* found. Settles the model-call timeout too.
|
|
220
|
+
*/
|
|
221
|
+
private validateInputs(request: DecisionRequest): DecisionInputs | { Error: string } {
|
|
222
|
+
const tooLong = this.checkInputLengths(request);
|
|
223
|
+
if (tooLong) {
|
|
224
|
+
return { Error: tooLong };
|
|
225
|
+
}
|
|
226
|
+
const state = this.parseState(request.State);
|
|
227
|
+
if ('Error' in state) {
|
|
228
|
+
return state;
|
|
229
|
+
}
|
|
230
|
+
const questions = ParseDecisionQuestions(request.Questions);
|
|
231
|
+
if (!questions.Valid) {
|
|
232
|
+
return { Error: questions.Message };
|
|
233
|
+
}
|
|
234
|
+
const tooMany = this.checkQuestionCounts(questions.Questions);
|
|
235
|
+
if (tooMany) {
|
|
236
|
+
return { Error: tooMany };
|
|
237
|
+
}
|
|
238
|
+
return { State: state.State, Questions: questions.Questions, TimeoutMS: this.effectiveTimeoutMS(request.TimeoutMS) };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** Refuses a state or questions text over its character limit, before either is parsed. */
|
|
242
|
+
private checkInputLengths(request: DecisionRequest): string | undefined {
|
|
243
|
+
const stateLength = typeof request.State === 'string' ? request.State.length : 0;
|
|
244
|
+
if (stateLength > RunDecisionResolver.MAX_STATE_CHARACTERS) {
|
|
245
|
+
return `State has ${stateLength} characters, over the limit of ${RunDecisionResolver.MAX_STATE_CHARACTERS}`;
|
|
246
|
+
}
|
|
247
|
+
const questionsLength = typeof request.Questions === 'string' ? request.Questions.length : 0;
|
|
248
|
+
if (questionsLength > RunDecisionResolver.MAX_QUESTIONS_CHARACTERS) {
|
|
249
|
+
return `Questions JSON has ${questionsLength} characters, over the limit of ${RunDecisionResolver.MAX_QUESTIONS_CHARACTERS}`;
|
|
250
|
+
}
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Refuses more questions than one request may carry, or more options or levels than one question may list. */
|
|
255
|
+
private checkQuestionCounts(questions: Record<string, DecisionQuestion>): string | undefined {
|
|
256
|
+
const questionCount = Object.keys(questions).length;
|
|
257
|
+
if (questionCount > RunDecisionResolver.MAX_QUESTIONS) {
|
|
258
|
+
return `${questionCount} questions exceed the limit of ${RunDecisionResolver.MAX_QUESTIONS} per request`;
|
|
259
|
+
}
|
|
260
|
+
const maxOptions = RunDecisionResolver.MAX_OPTIONS_PER_QUESTION;
|
|
261
|
+
for (const [key, question] of Object.entries(questions)) {
|
|
262
|
+
if (question.Kind === 'Choice' && question.Options.length > maxOptions) {
|
|
263
|
+
return `Choice '${key}' has ${question.Options.length} options, over the limit of ${maxOptions}`;
|
|
264
|
+
}
|
|
265
|
+
if (question.Kind === 'Score' && question.Levels.length > maxOptions) {
|
|
266
|
+
return `Score '${key}' has ${question.Levels.length} levels, over the limit of ${maxOptions}`;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* The caller's timeout, cut to `MAX_TIMEOUT_MS`, or `DEFAULT_TIMEOUT_MS` when it sent none or one
|
|
274
|
+
* that is not positive.
|
|
275
|
+
*/
|
|
276
|
+
private effectiveTimeoutMS(requested: number | undefined): number {
|
|
277
|
+
if (requested == null || !(requested > 0)) {
|
|
278
|
+
return RunDecisionResolver.DEFAULT_TIMEOUT_MS;
|
|
279
|
+
}
|
|
280
|
+
return Math.min(requested, RunDecisionResolver.MAX_TIMEOUT_MS);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Reads the state: the object, when the text is the JSON of a non-empty object, otherwise the text
|
|
285
|
+
* itself. Empty text and an empty object are refused, as the `Run Decision` action refuses them.
|
|
286
|
+
*/
|
|
287
|
+
private parseState(state: string): { State: string | Record<string, unknown> } | { Error: string } {
|
|
288
|
+
const trimmed = typeof state === 'string' ? state.trim() : '';
|
|
289
|
+
if (trimmed.length === 0) {
|
|
290
|
+
return { Error: 'State is required and cannot be empty' };
|
|
291
|
+
}
|
|
292
|
+
const parsed = this.parseJSONObject(trimmed);
|
|
293
|
+
if (!parsed) {
|
|
294
|
+
return { State: trimmed };
|
|
295
|
+
}
|
|
296
|
+
return Object.keys(parsed).length > 0 ? { State: parsed } : { Error: 'State object cannot be empty' };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** The text parsed as a JSON object, or undefined when it is not the JSON of an object. */
|
|
300
|
+
private parseJSONObject(text: string): Record<string, unknown> | undefined {
|
|
301
|
+
if (!text.startsWith('{')) {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
const parsed: unknown = JSON.parse(text);
|
|
306
|
+
return this.isPlainObject(parsed) ? parsed : undefined;
|
|
307
|
+
} catch {
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
313
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* The prompt to run, checked that it can run a decision: that it is Decision-typed and Active.
|
|
318
|
+
* Returns the reason when it cannot.
|
|
319
|
+
*
|
|
320
|
+
* The prompt authorized before is the one used. When there was none, the engine is loaded (a
|
|
321
|
+
* no-op once it is) and the prompt looked up again: one that appears only then is authorized by
|
|
322
|
+
* its ID too, so a request that reaches a cold cache cannot get past a rule on that ID by name.
|
|
323
|
+
*/
|
|
324
|
+
private async resolvePrompt(
|
|
325
|
+
authorized: MJAIPromptEntityExtended | undefined,
|
|
326
|
+
reference: DecisionPromptReference,
|
|
327
|
+
runner: AIDecisionRunner,
|
|
328
|
+
contextUser: UserInfo,
|
|
329
|
+
userPayload: UserPayload
|
|
330
|
+
): Promise<MJAIPromptEntityExtended | string> {
|
|
331
|
+
await AIEngine.Instance.Config(false, contextUser);
|
|
332
|
+
const prompt = authorized ?? (await this.findAndAuthorizeLoadedPrompt(reference, userPayload));
|
|
333
|
+
if (!prompt || !this.canRunDecision(prompt, runner)) {
|
|
334
|
+
return this.unavailablePromptMessage(reference);
|
|
335
|
+
}
|
|
336
|
+
return prompt;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Whether the prompt can run a decision: Decision-typed and Active. When it cannot, the reason,
|
|
341
|
+
* which names the prompt and its status, goes to the server log only.
|
|
342
|
+
*/
|
|
343
|
+
private canRunDecision(prompt: MJAIPromptEntityExtended, runner: AIDecisionRunner): boolean {
|
|
344
|
+
if (!this.isDecisionPrompt(prompt, runner)) {
|
|
345
|
+
LogStatus(`RunDecision: AI Prompt '${prompt.Name}' (${prompt.ID}) is not a Decision prompt: its AI model type must be '${runner.RequiredModelType}'`);
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
if (prompt.Status !== 'Active') {
|
|
349
|
+
LogStatus(`RunDecision: AI Prompt '${prompt.Name}' (${prompt.ID}) is not active (Status: ${prompt.Status})`);
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* The one message for a prompt that cannot run, whether it is missing, not Decision-typed or not
|
|
357
|
+
* Active. It repeats only what the caller sent: this path reads the cache around entity
|
|
358
|
+
* permissions, so it must not tell a caller the name or status of a prompt it may not read.
|
|
359
|
+
*/
|
|
360
|
+
private unavailablePromptMessage(reference: DecisionPromptReference): string {
|
|
361
|
+
const named = reference.By === 'ID' ? `with ID ${reference.Value}` : `'${reference.Value}'`;
|
|
362
|
+
return `AI Prompt ${named} was not found or is not an active Decision prompt`;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** Looks the prompt up in the loaded cache, and authorizes it by its ID when it is found. */
|
|
366
|
+
private async findAndAuthorizeLoadedPrompt(
|
|
367
|
+
reference: DecisionPromptReference,
|
|
368
|
+
userPayload: UserPayload
|
|
369
|
+
): Promise<MJAIPromptEntityExtended | undefined> {
|
|
370
|
+
const prompt = this.findPrompt(reference);
|
|
371
|
+
if (prompt) {
|
|
372
|
+
await this.CheckAPIKeyScopeAuthorization('prompt:execute', prompt.ID, userPayload);
|
|
373
|
+
}
|
|
374
|
+
return prompt;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** Looks the prompt up by ID, or by name case-insensitively, as the `Run Decision` action does. */
|
|
378
|
+
private findPrompt(reference: DecisionPromptReference): MJAIPromptEntityExtended | undefined {
|
|
379
|
+
const prompts = AIEngine.Instance.Prompts;
|
|
380
|
+
if (reference.By === 'ID') {
|
|
381
|
+
return prompts.find(p => UUIDsEqual(p.ID, reference.Value));
|
|
382
|
+
}
|
|
383
|
+
const target = reference.Value.toLowerCase();
|
|
384
|
+
return prompts.find(p => p.Name?.trim().toLowerCase() === target);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Whether the prompt's AI model type is the one `AIDecisionRunner` requires. A prompt with no model
|
|
389
|
+
* type is refused too: the runner would accept it, but nothing marks it as a decision prompt.
|
|
390
|
+
*/
|
|
391
|
+
private isDecisionPrompt(prompt: MJAIPromptEntityExtended, runner: AIDecisionRunner): boolean {
|
|
392
|
+
if (!prompt.AIModelTypeID) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
const required = runner.RequiredModelType.trim().toLowerCase();
|
|
396
|
+
const decisionType = AIEngine.Instance.ModelTypes.find(mt => mt.Name?.trim().toLowerCase() === required);
|
|
397
|
+
return !!decisionType && UUIDsEqual(prompt.AIModelTypeID, decisionType.ID);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private buildDecisionParams(prompt: MJAIPromptEntityExtended, inputs: DecisionInputs, contextUser: UserInfo): AIDecisionParams {
|
|
401
|
+
const params = new AIDecisionParams();
|
|
402
|
+
params.prompt = prompt;
|
|
403
|
+
params.contextUser = contextUser;
|
|
404
|
+
params.State = inputs.State;
|
|
405
|
+
params.Questions = inputs.Questions;
|
|
406
|
+
params.timeoutMS = inputs.TimeoutMS;
|
|
407
|
+
return params;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** Maps the runner's result. The answers are sent only on success, so a caller never acts on partial ones. */
|
|
411
|
+
private mapRunResult(result: AIDecisionRunResult, prompt: MJAIPromptEntityExtended, startTime: number): DecisionRunResult {
|
|
412
|
+
const mapped: DecisionRunResult = {
|
|
413
|
+
success: result.success,
|
|
414
|
+
promptRunId: result.promptRun?.ID,
|
|
415
|
+
modelName: result.modelInfo?.modelName,
|
|
416
|
+
resolvedModel: result.DecisionResult?.ResolvedModel,
|
|
417
|
+
executionTimeMs: Date.now() - startTime,
|
|
418
|
+
};
|
|
419
|
+
if (result.success) {
|
|
420
|
+
mapped.answersJSON = JSON.stringify(result.Answers ?? {});
|
|
421
|
+
} else {
|
|
422
|
+
mapped.errorMessage = result.errorMessage || 'Decision execution failed';
|
|
423
|
+
LogError(`RunDecision failed for prompt '${prompt.Name}': ${mapped.errorMessage}`);
|
|
424
|
+
}
|
|
425
|
+
return mapped;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private failure(errorMessage: string, startTime: number): DecisionRunResult {
|
|
429
|
+
return {
|
|
430
|
+
success: false,
|
|
431
|
+
errorMessage,
|
|
432
|
+
executionTimeMs: Date.now() - startTime,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
}
|
|
@@ -9,16 +9,16 @@ import { GetReadWriteProvider } from '../util.js';
|
|
|
9
9
|
@ObjectType()
|
|
10
10
|
export class TemplateRunResult {
|
|
11
11
|
@Field()
|
|
12
|
-
success: boolean;
|
|
12
|
+
success: boolean; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
13
13
|
|
|
14
14
|
@Field({ nullable: true })
|
|
15
|
-
output?: string;
|
|
15
|
+
output?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
16
16
|
|
|
17
17
|
@Field({ nullable: true })
|
|
18
|
-
error?: string;
|
|
18
|
+
error?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
19
19
|
|
|
20
20
|
@Field({ nullable: true })
|
|
21
|
-
executionTimeMs?: number;
|
|
21
|
+
executionTimeMs?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|