@memberjunction/server 6.2.0-edge.5 → 6.2.0-edge.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +3 -3
- package/dist/agentSessions/SessionJanitor.js +3 -3
- package/dist/agentSessions/SessionManager.d.ts +15 -5
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +34 -12
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +2 -0
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +51 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +10 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +37 -1
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/localDevAuth.d.ts +79 -0
- package/dist/auth/localDevAuth.d.ts.map +1 -0
- package/dist/auth/localDevAuth.js +439 -0
- package/dist/auth/localDevAuth.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +2 -2
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +12 -0
- package/dist/auth/magicLink/types.d.ts.map +1 -1
- package/dist/auth/sessionUserClone.d.ts +1 -1
- package/dist/auth/sessionUserClone.d.ts.map +1 -1
- package/dist/auth/sessionUserClone.js +3 -2
- package/dist/auth/sessionUserClone.js.map +1 -1
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts +292 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +442 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -0
- package/dist/broadcast/index.d.ts +6 -0
- package/dist/broadcast/index.d.ts.map +1 -0
- package/dist/broadcast/index.js +6 -0
- package/dist/broadcast/index.js.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts +43 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js +144 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts +46 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js +149 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts +49 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js +131 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts +24 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js +51 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js.map +1 -0
- package/dist/cache.d.ts +3 -2
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +496 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +61 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +3 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +29 -8
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts.map +1 -1
- package/dist/coreRoutes.js +14 -0
- package/dist/coreRoutes.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +635 -14
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +3366 -418
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +50 -30
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +154 -79
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +2 -0
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/PubSubManager.d.ts +10 -0
- package/dist/generic/PubSubManager.d.ts.map +1 -1
- package/dist/generic/PubSubManager.js +44 -1
- package/dist/generic/PubSubManager.js.map +1 -1
- package/dist/generic/PushStatusResolver.d.ts +39 -6
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +93 -11
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +65 -25
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +201 -101
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +11 -3
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +79 -13
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/generic/actionOutputFieldSecurity.d.ts +26 -0
- package/dist/generic/actionOutputFieldSecurity.d.ts.map +1 -0
- package/dist/generic/actionOutputFieldSecurity.js +47 -0
- package/dist/generic/actionOutputFieldSecurity.js.map +1 -0
- package/dist/generic/fieldSecurityTransport.d.ts +30 -0
- package/dist/generic/fieldSecurityTransport.d.ts.map +1 -0
- package/dist/generic/fieldSecurityTransport.js +30 -0
- package/dist/generic/fieldSecurityTransport.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -66
- package/dist/index.js.map +1 -1
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +6 -1
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.d.ts +12 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.js +50 -1
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -1
- package/dist/realtimeSessions/SessionVerificationPortsBase.js +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts +8 -6
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.js +15 -6
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
- package/dist/realtimeSessions/sessionAccess.d.ts +88 -11
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
- package/dist/realtimeSessions/sessionAccess.js +125 -22
- package/dist/realtimeSessions/sessionAccess.js.map +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.js +5 -2
- package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.d.ts +2 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.js +19 -3
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts +67 -7
- package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.js +201 -19
- package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
- package/dist/realtimeWidget/host-identity.d.ts +1 -1
- package/dist/realtimeWidget/host-identity.js +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +20 -1
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +17 -1
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +2 -1
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +19 -1
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +63 -12
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +1 -0
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.d.ts +18 -4
- package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.js +32 -8
- package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
- package/dist/resolvers/AgentSessionResolver.d.ts +10 -4
- package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/AgentSessionResolver.js +40 -17
- package/dist/resolvers/AgentSessionResolver.js.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts +13 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.js +50 -14
- package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +28 -0
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +117 -21
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +1 -0
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +5 -0
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +13 -4
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +45 -7
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +8 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +31 -3
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.d.ts +6 -0
- package/dist/resolvers/PipelineProgressResolver.d.ts.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.js +5 -3
- package/dist/resolvers/PipelineProgressResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +20 -6
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +2 -0
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +15 -6
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RSUResolver.d.ts.map +1 -1
- package/dist/resolvers/RSUResolver.js +12 -0
- package/dist/resolvers/RSUResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +16 -2
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +82 -28
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +11 -9
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +56 -8
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +209 -64
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +4 -4
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTestResolver.js +3 -1
- package/dist/resolvers/RunTestResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +4 -0
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.js +1 -0
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +17 -2
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +60 -15
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts +1 -1
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js +2 -1
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts +6 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +19 -5
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +8 -5
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.d.ts +3 -3
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.js +7 -7
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +6 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +22 -5
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/serverRoleConfigUnits.d.ts +29 -0
- package/dist/serverRoleConfigUnits.d.ts.map +1 -0
- package/dist/serverRoleConfigUnits.js +33 -0
- package/dist/serverRoleConfigUnits.js.map +1 -0
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +5 -0
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +42 -15
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/types.d.ts +23 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +98 -98
- package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
- package/src/__tests__/AdhocQueryResolver.dialect.test.ts +137 -0
- package/src/__tests__/AgentRunStatusPublisher.test.ts +49 -0
- package/src/__tests__/AgentSessionResolver.ownership.test.ts +137 -0
- package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
- package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
- package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +206 -3
- package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
- package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
- package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
- package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +324 -46
- package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +98 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +37 -4
- package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
- package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +176 -0
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +23 -1
- package/src/__tests__/ResolverBase.publishStatusUpdate.test.ts +68 -0
- package/src/__tests__/ResolverBase.userViewCacheAndDedup.test.ts +130 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +68 -13
- package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
- package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +17 -27
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +8 -2
- package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +4 -1
- package/src/__tests__/RunTemplateResolver.test.ts +35 -2
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
- package/src/__tests__/SessionManager.test.ts +95 -0
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +114 -3
- package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
- package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
- package/src/__tests__/ViewOperationsHandler.test.ts +7 -2
- package/src/__tests__/WidgetSessionService.test.ts +583 -4
- package/src/__tests__/apiRootBoot.test.ts +1 -1
- package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
- package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +45 -0
- package/src/__tests__/fieldSecurityFixtures.ts +91 -0
- package/src/__tests__/globalCors.test.ts +3 -3
- package/src/__tests__/localDevAuth.test.ts +196 -0
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +57 -1
- package/src/__tests__/realtimeRecordingHandler.test.ts +19 -2
- package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +29 -1
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.anonymous.test.ts +31 -0
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.namedScoped.test.ts +37 -0
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +146 -7
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
- package/src/__tests__/resolverBase.cloudEventChangedFields.test.ts +157 -0
- package/src/__tests__/resolverBase.fieldSecurityTransport.test.ts +222 -0
- package/src/__tests__/resolverBase.fls.test.ts +146 -97
- package/src/__tests__/restTransport.fieldSecurity.test.ts +148 -0
- package/src/__tests__/runParamsTimeZone.test.ts +179 -0
- package/src/__tests__/runStreams.fieldSecurity.test.ts +100 -0
- package/src/__tests__/runViewProperties.test.ts +114 -0
- package/src/__tests__/scalabilityBenchmarks.test.ts +765 -0
- package/src/__tests__/scalabilityDatabaseIntegration.test.ts +207 -0
- package/src/__tests__/sessionUserClone.test.ts +5 -1
- package/src/__tests__/startupSweepOrder.test.ts +40 -0
- package/src/__tests__/unifiedAuth.test.ts +28 -0
- package/src/__tests__/widgetGuestElevation.test.ts +2 -0
- package/src/agentSessions/SessionJanitor.ts +3 -3
- package/src/agentSessions/SessionManager.ts +35 -12
- package/src/auth/AuthProviderCatalogRouter.ts +3 -0
- package/src/auth/index.ts +56 -12
- package/src/auth/initializeProviders.ts +43 -1
- package/src/auth/localDevAuth.ts +528 -0
- package/src/auth/magicLink/MagicLinkKeys.ts +2 -2
- package/src/auth/magicLink/types.ts +10 -0
- package/src/auth/sessionUserClone.ts +3 -2
- package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +674 -0
- package/src/broadcast/index.ts +5 -0
- package/src/broadcast/providers/AWSIoTCoreBroadcastProvider.ts +180 -0
- package/src/broadcast/providers/AzureWebPubSubBroadcastProvider.ts +182 -0
- package/src/broadcast/providers/GCPPubSubBroadcastProvider.ts +169 -0
- package/src/broadcast/providers/SequencedRoleBucketBroadcastProvider.ts +57 -0
- package/src/cache.ts +2 -1
- package/src/config.ts +69 -0
- package/src/context.ts +32 -8
- package/src/coreRoutes.ts +15 -0
- package/src/generated/graphql-schemas/__mj.ts +2239 -102
- package/src/generic/CacheInvalidationResolver.ts +135 -78
- package/src/generic/OrphanedConversationDetailReconciler.ts +4 -2
- package/src/generic/PubSubManager.ts +54 -1
- package/src/generic/PushStatusResolver.ts +108 -11
- package/src/generic/ResolverBase.ts +237 -107
- package/src/generic/RunViewResolver.ts +80 -15
- package/src/generic/actionOutputFieldSecurity.ts +75 -0
- package/src/generic/fieldSecurityTransport.ts +62 -0
- package/src/index.ts +127 -68
- package/src/integration/CustomColumnPromoter.ts +6 -1
- package/src/logging/variablesLoggingMiddleware.ts +59 -3
- package/src/realtimeSessions/README.md +7 -3
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +20 -6
- package/src/realtimeSessions/sessionAccess.ts +181 -25
- package/src/realtimeSessions/sessionConfigStamps.ts +1 -1
- package/src/realtimeSessions/subscriptionAuthorization.ts +4 -2
- package/src/realtimeSessions/verificationWorkflow.ts +3 -1
- package/src/realtimeWidget/WidgetRouter.ts +22 -4
- package/src/realtimeWidget/WidgetSessionService.ts +252 -17
- package/src/realtimeWidget/host-identity.ts +1 -1
- package/src/realtimeWidget/widgetCore.ts +30 -1
- package/src/realtimeWidget/widgetGuestElevation.ts +2 -1
- package/src/resolvers/ActionResolver.ts +78 -15
- package/src/resolvers/AdhocQueryResolver.ts +1 -0
- package/src/resolvers/AgentRunStatusPublisher.ts +36 -8
- package/src/resolvers/AgentSessionResolver.ts +46 -18
- package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
- package/src/resolvers/FetchEntityVectorsResolver.ts +132 -21
- package/src/resolvers/FileCategoryResolver.ts +1 -0
- package/src/resolvers/FileResolver.ts +14 -4
- package/src/resolvers/IntegrationDiscoveryResolver.ts +49 -7
- package/src/resolvers/MergeRecordsResolver.ts +23 -2
- package/src/resolvers/PipelineProgressResolver.ts +12 -3
- package/src/resolvers/QueryResolver.ts +20 -6
- package/src/resolvers/QuerySystemUserResolver.ts +15 -6
- package/src/resolvers/RSUResolver.ts +12 -0
- package/src/resolvers/RealtimeClientSessionResolver.ts +104 -33
- package/src/resolvers/RemoteBrowserActionResolver.ts +15 -10
- package/src/resolvers/RunAIAgentResolver.ts +258 -82
- package/src/resolvers/RunTemplateResolver.ts +6 -4
- package/src/resolvers/RunTestResolver.ts +3 -1
- package/src/resolvers/SyncDataResolver.ts +4 -0
- package/src/resolvers/TestQuerySQLResolver.ts +1 -0
- package/src/resolvers/TransactionGroupResolver.ts +66 -15
- package/src/resolvers/UserViewResolver.ts +2 -1
- package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
- package/src/rest/EntityCRUDHandler.ts +22 -5
- package/src/rest/RESTEndpointHandler.ts +8 -5
- package/src/rest/RealtimeRecordingHandler.ts +13 -10
- package/src/rest/ViewOperationsHandler.ts +24 -6
- package/src/serverRoleConfigUnits.ts +48 -0
- package/src/services/TaskGraphContinuationDeliverer.ts +52 -20
- package/src/types.ts +23 -1
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, Subscription, Root, ResolverFilterData, ID, Int } from 'type-graphql';
|
|
2
2
|
import { AppContext, UserPayload } from '../types.js';
|
|
3
3
|
import { DatabaseProviderBase, LogError, LogStatus, Metadata, RunView, UserInfo, IMetadataProvider } from '@memberjunction/core';
|
|
4
|
-
import { MJConversationDetailEntity, MJConversationDetailAttachmentEntity, MJConversationDetailArtifactEntity, MJArtifactVersionEntity, MJAIAgentRequestEntity, ArtifactMetadataEngine, ConversationEngine } from '@memberjunction/core-entities';
|
|
4
|
+
import { MJConversationDetailEntity, MJConversationDetailEntityExtended, MJConversationDetailAttachmentEntity, MJConversationDetailArtifactEntity, MJArtifactVersionEntity, MJAIAgentRequestEntity, ArtifactMetadataEngine, ConversationEngine } from '@memberjunction/core-entities';
|
|
5
5
|
import { RouteArtifact } from './artifact-routing.js';
|
|
6
6
|
import { AgentRunner, ArtifactToolManager } from '@memberjunction/ai-agents';
|
|
7
|
-
import { MJAIAgentEntityExtended, MJAIAgentRunEntityExtended, ExecuteAgentResult, ConversationUtility, AttachmentData } from '@memberjunction/ai-core-plus';
|
|
7
|
+
import { MJAIAgentEntityExtended, MJAIAgentRunEntityExtended, ExecuteAgentResult, ConversationUtility, AttachmentData, ContinuationAnnouncementText } from '@memberjunction/ai-core-plus';
|
|
8
8
|
import { AIEngine } from '@memberjunction/aiengine';
|
|
9
9
|
import { ChatMessage, ChatMessageContent } from '@memberjunction/ai';
|
|
10
10
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
11
11
|
import { AgentRunStatusPublisher } from './AgentRunStatusPublisher.js';
|
|
12
|
+
import { ProjectEntityObjectForCaller } from '../generic/fieldSecurityTransport.js';
|
|
12
13
|
import { StartLivenessPulse } from '../generic/FireAndForgetHeartbeat.js';
|
|
14
|
+
import { StatusUpdateOwnerID } from '../generic/PushStatusResolver.js';
|
|
13
15
|
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
14
16
|
import { GetReadWriteProvider } from '../util.js';
|
|
15
17
|
import { ResolveWidgetGuestRunContext, ElevateUserPayload } from '../realtimeWidget/widgetGuestElevation.js';
|
|
18
|
+
import { AuthorizeConversationTurn } from '../realtimeSessions/sessionAccess.js';
|
|
16
19
|
import { IsTrustedAgentRunCaller } from './agent-run-data-guard.js';
|
|
17
20
|
import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
|
|
18
21
|
import { GetAttachmentService } from '@memberjunction/aiengine';
|
|
@@ -32,6 +35,17 @@ function isAgentRunEntity(value: unknown): value is MJAIAgentRunEntityExtended {
|
|
|
32
35
|
return typeof value === 'object' && value !== null && 'ID' in value;
|
|
33
36
|
}
|
|
34
37
|
|
|
38
|
+
/** What a conversation turn asks for, before its agent runs (see `RunAIAgentFromConversationDetail`). */
|
|
39
|
+
interface ConversationTurnRequest {
|
|
40
|
+
UserMessageId: string;
|
|
41
|
+
AgentId: string;
|
|
42
|
+
MaxHistoryMessages: number;
|
|
43
|
+
HistoryFrom?: Date;
|
|
44
|
+
ReplyParentId?: string;
|
|
45
|
+
AnnouncedByAgentId?: string;
|
|
46
|
+
ReplyBranchId?: string | null;
|
|
47
|
+
}
|
|
48
|
+
|
|
35
49
|
@ObjectType()
|
|
36
50
|
export class AIAgentRunResult {
|
|
37
51
|
@Field()
|
|
@@ -173,7 +187,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
173
187
|
* Sanitize ExecuteAgentResult for JSON serialization
|
|
174
188
|
* Removes circular references and non-serializable objects
|
|
175
189
|
*/
|
|
176
|
-
private sanitizeAgentResult(result: ExecuteAgentResult): any {
|
|
190
|
+
private sanitizeAgentResult(result: ExecuteAgentResult, recipient?: UserInfo): any {
|
|
177
191
|
const sanitized: any = {
|
|
178
192
|
success: result.success,
|
|
179
193
|
payload: result.payload,
|
|
@@ -189,8 +203,9 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
189
203
|
|
|
190
204
|
// Safely extract agent run data using GetAll() for proper serialization
|
|
191
205
|
if (result.agentRun && typeof result.agentRun.GetAll === 'function') {
|
|
192
|
-
//
|
|
193
|
-
|
|
206
|
+
// GetAll() for the full serialized object including extended properties, projected for
|
|
207
|
+
// the recipient: the run comes from the agent engine, not from a load bound to them
|
|
208
|
+
sanitized.agentRun = ProjectEntityObjectForCaller(result.agentRun, recipient);
|
|
194
209
|
}
|
|
195
210
|
else {
|
|
196
211
|
// shouldn't ever get here
|
|
@@ -306,7 +321,10 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
306
321
|
/** ExecuteAgentParams.TrustReservedRunData: true only for a caller IsTrustedAgentRunCaller accepts. */
|
|
307
322
|
trustReservedRunData: boolean = false,
|
|
308
323
|
/** The conversation branch of the run — threaded into ExecuteAgentParams.ConversationBranchID. */
|
|
309
|
-
conversationBranchId?: string | null
|
|
324
|
+
conversationBranchId?: string | null,
|
|
325
|
+
/** The reply row this request created on the server for the run (`conversationDetailId` is its ID). The run
|
|
326
|
+
* writes into this instance, so its writes carry the server-authored marker and the user it was made as. */
|
|
327
|
+
replyDetail?: MJConversationDetailEntityExtended
|
|
310
328
|
): Promise<AIAgentRunResult> {
|
|
311
329
|
const startTime = Date.now();
|
|
312
330
|
// Best-effort handle for persistInFlightAgentFailure. Populated from a
|
|
@@ -315,6 +333,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
315
333
|
// run is not marked Failed — the early-failure case we most want to
|
|
316
334
|
// persist, but we have no run object yet.
|
|
317
335
|
const agentRunRef = runRef ?? { current: null as MJAIAgentRunEntityExtended | null };
|
|
336
|
+
// The publisher owns every status message, including the failure completion the catch below sends.
|
|
337
|
+
const statusPublisher = new AgentRunStatusPublisher(pubSub, userPayload, sessionId, conversationDetailId);
|
|
318
338
|
|
|
319
339
|
try {
|
|
320
340
|
LogStatus(`=== RUNNING AI AGENT FOR ID: ${agentId} ===`);
|
|
@@ -348,9 +368,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
348
368
|
|
|
349
369
|
console.log(`🚀 Starting agent execution with sessionId: ${sessionId}`);
|
|
350
370
|
|
|
351
|
-
// The
|
|
352
|
-
//
|
|
353
|
-
const statusPublisher = new AgentRunStatusPublisher(pubSub, userPayload, sessionId);
|
|
371
|
+
// The resolver still copies the run into agentRunRef, including noise steps, for the
|
|
372
|
+
// fire-and-forget liveness pulse.
|
|
354
373
|
const publishProgress = statusPublisher.OnProgress;
|
|
355
374
|
|
|
356
375
|
// Execute the agent in conversation context - handles conversation, artifacts, etc.
|
|
@@ -384,10 +403,13 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
384
403
|
}
|
|
385
404
|
}, {
|
|
386
405
|
conversationDetailId: conversationDetailId, // Use existing if provided
|
|
406
|
+
agentResponseDetail: replyDetail, // the reply row this request created, when it did
|
|
387
407
|
conversationId: conversationId, // LATENCY OPT #2: pre-resolved to skip redundant load in AgentRunner
|
|
388
408
|
userMessage: userMessage, // Provide user message when conversationDetailId not provided
|
|
389
409
|
createArtifacts: createArtifacts || false,
|
|
390
|
-
sourceArtifactId: sourceArtifactId
|
|
410
|
+
sourceArtifactId: sourceArtifactId,
|
|
411
|
+
// A widget guest runs as the system user, but its conversation stays the guest's to write (MJ#4791).
|
|
412
|
+
ConversationWriter: userPayload.ElevatedFrom,
|
|
391
413
|
});
|
|
392
414
|
|
|
393
415
|
const result = conversationResult.agentResult;
|
|
@@ -450,7 +472,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
450
472
|
}
|
|
451
473
|
|
|
452
474
|
// Create sanitized payload for JSON serialization
|
|
453
|
-
const sanitizedResult = this.sanitizeAgentResult(result);
|
|
475
|
+
const sanitizedResult = this.sanitizeAgentResult(result, currentUser);
|
|
454
476
|
const returnResult = JSON.stringify(sanitizedResult);
|
|
455
477
|
|
|
456
478
|
// Publish final events with enriched result data for fire-and-forget clients
|
|
@@ -473,11 +495,18 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
473
495
|
} catch (error) {
|
|
474
496
|
const executionTime = Date.now() - startTime;
|
|
475
497
|
LogError(`AI Agent run failed:`, undefined, error);
|
|
476
|
-
|
|
498
|
+
// Never dereference a non-Error throw: this catch must not itself throw, since executeAIAgent resolves on
|
|
499
|
+
// every failure (executeAgentInBackground relies on it).
|
|
500
|
+
const errorMessage = (error instanceof Error && error.message) || 'Unknown error occurred';
|
|
477
501
|
|
|
478
502
|
// Fire-and-forget clients otherwise leave the run Running and the
|
|
479
503
|
// conversation detail In-Progress (Explorer red-pill timer).
|
|
480
|
-
await this.persistInFlightAgentFailure(p, userPayload, agentRunRef.current, conversationDetailId, errorMessage);
|
|
504
|
+
await this.persistInFlightAgentFailure(p, userPayload, agentRunRef.current, conversationDetailId, errorMessage, replyDetail);
|
|
505
|
+
// A fire-and-forget client has only this message to learn the run ended: without it, it waits out its
|
|
506
|
+
// idle timeout and then reconciles the run as a success. Published after the rows are closed, so a
|
|
507
|
+
// client that reloads the reply on this message reads the error. PublishFinal is the try's last step
|
|
508
|
+
// that can throw, so a run gets one completion or the other, never both.
|
|
509
|
+
statusPublisher.PublishFailure(conversationDetailId, errorMessage);
|
|
481
510
|
|
|
482
511
|
const errorResult = {
|
|
483
512
|
success: false,
|
|
@@ -503,7 +532,9 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
503
532
|
userPayload: UserPayload,
|
|
504
533
|
run: MJAIAgentRunEntityExtended | null | undefined,
|
|
505
534
|
conversationDetailId: string | undefined,
|
|
506
|
-
errorMessage: string
|
|
535
|
+
errorMessage: string,
|
|
536
|
+
/** The run's reply row, when this request created it: written in place, as the server. */
|
|
537
|
+
replyDetail?: MJConversationDetailEntityExtended
|
|
507
538
|
): Promise<void> {
|
|
508
539
|
try {
|
|
509
540
|
if (run && run.Status === 'Running') {
|
|
@@ -520,10 +551,11 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
520
551
|
return;
|
|
521
552
|
}
|
|
522
553
|
if (conversationDetailId) {
|
|
523
|
-
const detail = await provider.GetEntityObject<MJConversationDetailEntity>(
|
|
554
|
+
const detail = replyDetail ?? await provider.GetEntityObject<MJConversationDetailEntity>(
|
|
524
555
|
'MJ: Conversation Details',
|
|
525
556
|
user
|
|
526
557
|
);
|
|
558
|
+
await detail.EnsureSaveComplete(); // the run may still be saving into the same reply instance
|
|
527
559
|
if (await detail.Load(conversationDetailId) && detail.Status === 'In-Progress') {
|
|
528
560
|
await detail.EnsureSaveComplete();
|
|
529
561
|
detail.Status = 'Error';
|
|
@@ -925,16 +957,27 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
925
957
|
}
|
|
926
958
|
|
|
927
959
|
/**
|
|
928
|
-
*
|
|
929
|
-
*
|
|
960
|
+
* Runs an agent's turn in a conversation: the server loads the history (attachments included, so the client never
|
|
961
|
+
* sends them), creates the agent's reply row, and runs the agent into it.
|
|
962
|
+
*
|
|
963
|
+
* Only the server writes agent replies (A19). The reply row (`Role` `AI`, In-Progress, its `ParentID` the user's
|
|
964
|
+
* message) is created here, as the person asking, before the run starts. In fire-and-forget mode the
|
|
965
|
+
* acknowledgement names it, `{ accepted, fireAndForget, conversationDetailId, createdAt }`, and is returned before
|
|
966
|
+
* the run publishes anything; every progress, streaming and completion message carries the same
|
|
967
|
+
* `conversationDetailId`. In synchronous mode the result's `agentRun.ConversationDetailID` names it.
|
|
968
|
+
*
|
|
969
|
+
* Threading, both optional: `replyParentId` puts the reply under another message of the same conversation the
|
|
970
|
+
* caller can read (MJ's chat threads a delegate's reply under the manager's); `announcedByAgentId` has the server
|
|
971
|
+
* first post that agent's fixed line "Continuing with **{agent}** for refinement..." and thread the reply under
|
|
972
|
+
* it, and the acknowledgement then also carries `announcementDetailId`.
|
|
930
973
|
*
|
|
931
|
-
* @param
|
|
974
|
+
* @param userMessageId - The person's message this turn answers, already saved.
|
|
932
975
|
* @param agentId - The agent to execute
|
|
933
976
|
* @param maxHistoryMessages - Maximum number of history messages to include (default: 20)
|
|
934
977
|
*/
|
|
935
978
|
@Mutation(() => AIAgentRunResult)
|
|
936
979
|
async RunAIAgentFromConversationDetail(
|
|
937
|
-
@Arg('
|
|
980
|
+
@Arg('userMessageId') userMessageId: string,
|
|
938
981
|
@Arg('agentId') agentId: string,
|
|
939
982
|
@Ctx() { userPayload, providers, dataSource }: AppContext,
|
|
940
983
|
@Arg('sessionId') sessionId: string,
|
|
@@ -957,11 +1000,17 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
957
1000
|
* run's own conversation reads honour it too. Omitted (clients send it only when set, so an
|
|
958
1001
|
* older client never does), the run reads the whole conversation as before. An unreadable
|
|
959
1002
|
* value fails the request rather than being dropped. */
|
|
960
|
-
@Arg('agentHistoryFrom', { nullable: true }) agentHistoryFrom?: string
|
|
1003
|
+
@Arg('agentHistoryFrom', { nullable: true }) agentHistoryFrom?: string,
|
|
1004
|
+
/** The message the reply threads under, when not the user's message: one in the same conversation the
|
|
1005
|
+
* caller can read. */
|
|
1006
|
+
@Arg('replyParentId', { nullable: true }) replyParentId?: string,
|
|
1007
|
+
/** An active agent (MJ's chat passes its conversation manager) whose fixed line "Continuing with
|
|
1008
|
+
* **{agent}** for refinement..." the server posts before the reply, which then threads under it. */
|
|
1009
|
+
@Arg('announcedByAgentId', { nullable: true }) announcedByAgentId?: string,
|
|
1010
|
+
/** The fork the reply and history run on, when the turn forks from `userMessageId` (such as Regenerate).
|
|
1011
|
+
* Checked to be a branch of the conversation whose path holds `userMessageId`. */
|
|
1012
|
+
@Arg('replyBranchId', { nullable: true }) replyBranchId?: string
|
|
961
1013
|
): Promise<AIAgentRunResult> {
|
|
962
|
-
// Check API key scope authorization for agent execution
|
|
963
|
-
await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
|
|
964
|
-
|
|
965
1014
|
const p = GetReadWriteProvider(providers);
|
|
966
1015
|
const currentUser = this.GetUserFromPayload(userPayload);
|
|
967
1016
|
|
|
@@ -978,10 +1027,20 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
978
1027
|
// AUTHORITATIVELY from the widget instance (never the client-supplied arg) — so a guest needs
|
|
979
1028
|
// no grants to WRITE the AI run entities and cannot run an arbitrary agent under elevation.
|
|
980
1029
|
// Conversation OWNERSHIP is still enforced under the guest principal below: the guest loads its
|
|
981
|
-
// own ConversationDetail through
|
|
982
|
-
//
|
|
1030
|
+
// own ConversationDetail through its role's RLS filters, and startConversationTurn then checks
|
|
1031
|
+
// the conversation's scope stamp against the visitor (MJ#6032), so a detail id from another
|
|
1032
|
+
// visitor's session is refused before any elevated work happens. The reply row is written
|
|
1033
|
+
// as the guest too, never as the elevated principal, which owns no guest's conversation.
|
|
983
1034
|
const widgetElevation = await ResolveWidgetGuestRunContext(userPayload, p);
|
|
984
1035
|
const effectiveAgentId = widgetElevation ? widgetElevation.PinnedAgentId : agentId;
|
|
1036
|
+
// Check API key scope authorization for agent execution against the resolved agent id.
|
|
1037
|
+
await this.CheckAPIKeyScopeAuthorization('agent:execute', effectiveAgentId, userPayload);
|
|
1038
|
+
// A widget guest has one pinned agent and never posts a continuation announcement as another agent;
|
|
1039
|
+
// an API-key caller must hold agent:execute for the announcing agent as well as the running agent.
|
|
1040
|
+
const effectiveAnnouncedByAgentId = widgetElevation ? undefined : announcedByAgentId;
|
|
1041
|
+
if (effectiveAnnouncedByAgentId) {
|
|
1042
|
+
await this.CheckAPIKeyScopeAuthorization('agent:execute', effectiveAnnouncedByAgentId, userPayload);
|
|
1043
|
+
}
|
|
985
1044
|
const effectiveUserPayload = widgetElevation ? ElevateUserPayload(userPayload, widgetElevation.ElevatedUser) : userPayload;
|
|
986
1045
|
// Only the system user or an API key holding the agent:trusted scope may set a run's scope and agent-type
|
|
987
1046
|
// params through data (ExecuteAgentParams.TrustReservedRunData). Judged on the caller's own payload: a widget
|
|
@@ -993,22 +1052,19 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
993
1052
|
try {
|
|
994
1053
|
// Parsed before anything loads: a floor the caller asked for must never be dropped.
|
|
995
1054
|
const historyFrom = parseAgentHistoryFrom(agentHistoryFrom);
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
const conversationId = currentDetail.ConversationID;
|
|
1010
|
-
// The branch the placeholder row was created on decides which path the run reads.
|
|
1011
|
-
const branchId: string | null = currentDetail.BranchID ?? null;
|
|
1055
|
+
const turn = await this.startConversationTurn(p, currentUser, {
|
|
1056
|
+
UserMessageId: userMessageId,
|
|
1057
|
+
AgentId: effectiveAgentId,
|
|
1058
|
+
MaxHistoryMessages: maxHistoryMessages || 20,
|
|
1059
|
+
HistoryFrom: historyFrom,
|
|
1060
|
+
ReplyParentId: replyParentId,
|
|
1061
|
+
AnnouncedByAgentId: effectiveAnnouncedByAgentId,
|
|
1062
|
+
ReplyBranchId: replyBranchId
|
|
1063
|
+
});
|
|
1064
|
+
const reply = turn.Reply;
|
|
1065
|
+
// The turn's branch (the message's own branch, or a validated fork whose path holds the message)
|
|
1066
|
+
// decides which path the run reads.
|
|
1067
|
+
const branchId = turn.BranchId;
|
|
1012
1068
|
|
|
1013
1069
|
// A turn that follows a run the user STOPPED continues that run rather than starting
|
|
1014
1070
|
// over: chain it by LastRunID (the chat client never sends one) and, when the caller
|
|
@@ -1016,7 +1072,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1016
1072
|
let effectiveLastRunId = lastRunId;
|
|
1017
1073
|
let effectiveAutoPopulate = autoPopulateLastRunPayload;
|
|
1018
1074
|
if (!effectiveLastRunId) {
|
|
1019
|
-
const stoppedRunId = await this.findUserStoppedPredecessorRunId(
|
|
1075
|
+
const stoppedRunId = await this.findUserStoppedPredecessorRunId(turn.ConversationId, effectiveAgentId, branchId, currentUser, p);
|
|
1020
1076
|
if (stoppedRunId) {
|
|
1021
1077
|
effectiveLastRunId = stoppedRunId;
|
|
1022
1078
|
if (effectiveAutoPopulate === undefined && payload == null) {
|
|
@@ -1026,41 +1082,32 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1026
1082
|
}
|
|
1027
1083
|
}
|
|
1028
1084
|
|
|
1029
|
-
// Load conversation history with attachments from DB
|
|
1030
|
-
const messages = await this.loadConversationHistoryWithAttachments(
|
|
1031
|
-
conversationId,
|
|
1032
|
-
currentUser,
|
|
1033
|
-
maxHistoryMessages || 20,
|
|
1034
|
-
p,
|
|
1035
|
-
// The UI creates the agent-response placeholder row ('⏳ ...') before invoking
|
|
1036
|
-
// this mutation — exclude it so the model never sees an empty assistant turn.
|
|
1037
|
-
[conversationDetailId],
|
|
1038
|
-
historyFrom,
|
|
1039
|
-
branchId
|
|
1040
|
-
);
|
|
1041
|
-
|
|
1042
|
-
// Convert to JSON string for the existing executeAIAgent method
|
|
1043
|
-
const messagesJson = JSON.stringify(messages);
|
|
1044
|
-
|
|
1045
1085
|
if (fireAndForget) {
|
|
1046
1086
|
// Fire-and-forget mode: start execution in background, return immediately.
|
|
1047
1087
|
// The client will receive the result via WebSocket PubSub completion event.
|
|
1048
1088
|
this.executeAgentInBackground(
|
|
1049
|
-
p, dataSource, effectiveAgentId, effectiveUserPayload,
|
|
1089
|
+
p, dataSource, effectiveAgentId, effectiveUserPayload, turn.MessagesJson, sessionId, pubSub,
|
|
1050
1090
|
data, payload, effectiveLastRunId, effectiveAutoPopulate, configurationId,
|
|
1051
|
-
|
|
1052
|
-
sourceArtifactId, sourceArtifactVersionId,
|
|
1091
|
+
reply.ID, createArtifacts || false, createNotification || false,
|
|
1092
|
+
sourceArtifactId, sourceArtifactVersionId, turn.ConversationId, planMode, requestedSkillIDs,
|
|
1053
1093
|
undefined, // taskGraphDebug
|
|
1054
1094
|
historyFrom,
|
|
1055
1095
|
trustRunData,
|
|
1056
|
-
branchId
|
|
1096
|
+
branchId,
|
|
1097
|
+
reply
|
|
1057
1098
|
);
|
|
1058
1099
|
|
|
1059
1100
|
LogStatus(`🔥 Fire-and-forget: Agent ${effectiveAgentId} execution started in background for session ${sessionId}`);
|
|
1060
1101
|
|
|
1061
1102
|
return {
|
|
1062
1103
|
success: true,
|
|
1063
|
-
result: JSON.stringify({
|
|
1104
|
+
result: JSON.stringify({
|
|
1105
|
+
accepted: true,
|
|
1106
|
+
fireAndForget: true,
|
|
1107
|
+
conversationDetailId: reply.ID,
|
|
1108
|
+
createdAt: reply.__mj_CreatedAt,
|
|
1109
|
+
...(turn.Announcement ? { announcementDetailId: turn.Announcement.ID } : {})
|
|
1110
|
+
})
|
|
1064
1111
|
};
|
|
1065
1112
|
}
|
|
1066
1113
|
|
|
@@ -1070,7 +1117,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1070
1117
|
dataSource,
|
|
1071
1118
|
effectiveAgentId,
|
|
1072
1119
|
effectiveUserPayload,
|
|
1073
|
-
|
|
1120
|
+
turn.MessagesJson,
|
|
1074
1121
|
sessionId,
|
|
1075
1122
|
pubSub,
|
|
1076
1123
|
data,
|
|
@@ -1079,19 +1126,20 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1079
1126
|
effectiveLastRunId,
|
|
1080
1127
|
effectiveAutoPopulate,
|
|
1081
1128
|
configurationId,
|
|
1082
|
-
|
|
1129
|
+
reply.ID,
|
|
1083
1130
|
createArtifacts || false,
|
|
1084
1131
|
createNotification || false,
|
|
1085
1132
|
sourceArtifactId,
|
|
1086
1133
|
sourceArtifactVersionId,
|
|
1087
|
-
|
|
1134
|
+
turn.ConversationId, // LATENCY OPT #2: pass pre-resolved conversationId
|
|
1088
1135
|
undefined, // runRef
|
|
1089
1136
|
planMode,
|
|
1090
1137
|
requestedSkillIDs,
|
|
1091
1138
|
undefined, // taskGraphDebug
|
|
1092
1139
|
historyFrom,
|
|
1093
1140
|
trustRunData,
|
|
1094
|
-
branchId
|
|
1141
|
+
branchId,
|
|
1142
|
+
reply
|
|
1095
1143
|
);
|
|
1096
1144
|
} catch (error) {
|
|
1097
1145
|
const errorMessage = (error as Error).message || 'Unknown error loading conversation history';
|
|
@@ -1104,6 +1152,137 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1104
1152
|
}
|
|
1105
1153
|
}
|
|
1106
1154
|
|
|
1155
|
+
/**
|
|
1156
|
+
* Everything a conversation turn needs before its agent runs: the user's message (read as the caller, so a
|
|
1157
|
+
* message they can't see is "not found", and for an anonymous visitor also checked against the conversation's
|
|
1158
|
+
* scope stamp), the conversation history, the optional announcement line, and the reply
|
|
1159
|
+
* row, created last so the history never holds the empty reply. Every row is written as `user`, the person asking,
|
|
1160
|
+
* and marked as server-authored by {@link AgentRunner.CreateAgentReplyDetail}.
|
|
1161
|
+
*/
|
|
1162
|
+
private async startConversationTurn(
|
|
1163
|
+
p: DatabaseProviderBase,
|
|
1164
|
+
user: UserInfo,
|
|
1165
|
+
request: ConversationTurnRequest
|
|
1166
|
+
): Promise<{ ConversationId: string; BranchId: string | null; MessagesJson: string; Reply: MJConversationDetailEntityExtended; Announcement?: MJConversationDetailEntityExtended }> {
|
|
1167
|
+
// LATENCY OPTIMIZATION (Opt #2 + #3): the user's message is loaded once here for its conversation and
|
|
1168
|
+
// branch, which are threaded through the call chain rather than reloaded downstream.
|
|
1169
|
+
const placement = await this.loadPlacementOf(p, user, request.UserMessageId);
|
|
1170
|
+
const conversationId = placement.ConversationId;
|
|
1171
|
+
// Loading the message as the caller is the whole ownership check for a named user. It is not for an
|
|
1172
|
+
// anonymous visitor: every visitor is the one shared Anonymous user, so under a guest role whose row
|
|
1173
|
+
// filters key on UserID another visitor's message loads fine (MJ#6032). The conversation's scope stamp
|
|
1174
|
+
// decides instead, exactly as it does for the realtime gates — and before any row is written.
|
|
1175
|
+
const access = await AuthorizeConversationTurn(conversationId, user, p);
|
|
1176
|
+
if (!access.Allowed) {
|
|
1177
|
+
LogError(`RunAIAgentFromConversationDetail: anonymous visitor ${user.AnonymousVisitorID ?? '(no visitor id)'} refused a turn in conversation ${conversationId} (${access.Reason})`);
|
|
1178
|
+
throw new Error('Not authorized: you do not own this conversation');
|
|
1179
|
+
}
|
|
1180
|
+
const branchId = request.ReplyBranchId
|
|
1181
|
+
? await this.validateReplyBranch(p, user, conversationId, placement, request.ReplyBranchId)
|
|
1182
|
+
: placement.BranchId;
|
|
1183
|
+
const parentId = request.ReplyParentId
|
|
1184
|
+
? await this.validateReplyParent(p, user, request.ReplyParentId, conversationId)
|
|
1185
|
+
: request.UserMessageId;
|
|
1186
|
+
const messages = await this.loadConversationHistoryWithAttachments(conversationId, user, request.MaxHistoryMessages, p, undefined, request.HistoryFrom, branchId);
|
|
1187
|
+
const runner = new AgentRunner(p);
|
|
1188
|
+
const announcement = request.AnnouncedByAgentId
|
|
1189
|
+
? await this.postContinuationAnnouncement(runner, user, conversationId, branchId, parentId, request.AnnouncedByAgentId, request.AgentId)
|
|
1190
|
+
: undefined;
|
|
1191
|
+
const reply = await runner.CreateAgentReplyDetail({
|
|
1192
|
+
conversationId,
|
|
1193
|
+
branchId,
|
|
1194
|
+
agentId: request.AgentId,
|
|
1195
|
+
contextUser: user,
|
|
1196
|
+
parentId: announcement?.ID ?? parentId,
|
|
1197
|
+
provider: p
|
|
1198
|
+
});
|
|
1199
|
+
return { ConversationId: conversationId, BranchId: branchId, MessagesJson: JSON.stringify(messages), Reply: reply, Announcement: announcement };
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
/** The conversation, branch (null is Main) and sequence of a message, read as `user`; throws when they can't read it. */
|
|
1203
|
+
private async loadPlacementOf(
|
|
1204
|
+
p: DatabaseProviderBase,
|
|
1205
|
+
user: UserInfo,
|
|
1206
|
+
messageId: string
|
|
1207
|
+
): Promise<{ ConversationId: string; BranchId: string | null; Sequence: number }> {
|
|
1208
|
+
const message = await p.GetEntityObject<MJConversationDetailEntity>('MJ: Conversation Details', user);
|
|
1209
|
+
if (!await message.Load(messageId)) {
|
|
1210
|
+
throw new Error(`Conversation detail ${messageId} not found`);
|
|
1211
|
+
}
|
|
1212
|
+
return { ConversationId: message.ConversationID, BranchId: message.BranchID ?? null, Sequence: message.Sequence ?? -1 };
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* When a turn forks from an earlier message (such as Regenerate), the reply and history run on the fork while the
|
|
1217
|
+
* user's message stays on the branch it was written on. Checks that `replyBranchId` is a branch of the turn's
|
|
1218
|
+
* conversation whose path holds the user's message (`IsRowOnBranchPath` rather than exact `ForkFromSequence`
|
|
1219
|
+
* equality is deliberate: `ConversationEngine.ForkPointFrom` sets `ForkFromSequence = message.Sequence` and the
|
|
1220
|
+
* fork belongs to this conversation); returns `replyBranchId`, or throws before any row is created.
|
|
1221
|
+
*/
|
|
1222
|
+
private async validateReplyBranch(
|
|
1223
|
+
p: DatabaseProviderBase,
|
|
1224
|
+
user: UserInfo,
|
|
1225
|
+
conversationId: string,
|
|
1226
|
+
userMessage: { BranchId: string | null; Sequence: number },
|
|
1227
|
+
replyBranchId: string
|
|
1228
|
+
): Promise<string> {
|
|
1229
|
+
if (UUIDsEqual(replyBranchId, userMessage.BranchId)) {
|
|
1230
|
+
return replyBranchId;
|
|
1231
|
+
}
|
|
1232
|
+
if (userMessage.Sequence < 0) {
|
|
1233
|
+
throw new Error(`Conversation detail is not on branch ${replyBranchId}'s path, so the reply cannot be written on that branch`);
|
|
1234
|
+
}
|
|
1235
|
+
const branches = await ConversationEngine.LoadBranchesFresh(conversationId, user, p);
|
|
1236
|
+
const chain = ConversationEngine.BuildBranchChain(branches, replyBranchId);
|
|
1237
|
+
if (!ConversationEngine.IsRowOnBranchPath({ BranchID: userMessage.BranchId, Sequence: userMessage.Sequence }, chain)) {
|
|
1238
|
+
throw new Error(`Conversation detail is not on branch ${replyBranchId}'s path, so the reply cannot be written on that branch`);
|
|
1239
|
+
}
|
|
1240
|
+
return replyBranchId;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* A reply's parent is part of what the reply says, so the server sets it, from a checked input: a message the
|
|
1245
|
+
* caller can read, in the turn's own conversation. Returns its ID; throws otherwise.
|
|
1246
|
+
*/
|
|
1247
|
+
private async validateReplyParent(p: DatabaseProviderBase, user: UserInfo, parentId: string, conversationId: string): Promise<string> {
|
|
1248
|
+
const { ConversationId: parentConversationId } = await this.loadPlacementOf(p, user, parentId);
|
|
1249
|
+
if (!UUIDsEqual(parentConversationId, conversationId)) {
|
|
1250
|
+
throw new Error(`Conversation detail ${parentId} is not in this turn's conversation, so the reply cannot thread under it`);
|
|
1251
|
+
}
|
|
1252
|
+
return parentId;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
/**
|
|
1256
|
+
* Posts the announcing agent's line, "Continuing with **{agent}** for refinement...", as a completed reply of the
|
|
1257
|
+
* announcing agent. Its text is fixed and names the agent from metadata, so a caller chooses only whether it is
|
|
1258
|
+
* posted and by which active agent, never what it says.
|
|
1259
|
+
*/
|
|
1260
|
+
private async postContinuationAnnouncement(
|
|
1261
|
+
runner: AgentRunner,
|
|
1262
|
+
user: UserInfo,
|
|
1263
|
+
conversationId: string,
|
|
1264
|
+
branchId: string | null,
|
|
1265
|
+
parentId: string,
|
|
1266
|
+
announcerId: string,
|
|
1267
|
+
agentId: string
|
|
1268
|
+
): Promise<MJConversationDetailEntityExtended> {
|
|
1269
|
+
await AIEngine.Instance.Config(false, user);
|
|
1270
|
+
const announcer = AIEngine.Instance.GetAgentByID(announcerId);
|
|
1271
|
+
if (!announcer || announcer.Status !== 'Active') {
|
|
1272
|
+
throw new Error(`Agent ${announcerId} cannot announce the turn: it is not an active agent`);
|
|
1273
|
+
}
|
|
1274
|
+
const agentName = AIEngine.Instance.GetAgentByID(agentId)?.Name ?? 'the agent';
|
|
1275
|
+
return runner.CreateAgentReplyDetail({
|
|
1276
|
+
conversationId,
|
|
1277
|
+
branchId,
|
|
1278
|
+
agentId: announcer.ID,
|
|
1279
|
+
contextUser: user,
|
|
1280
|
+
parentId,
|
|
1281
|
+
message: ContinuationAnnouncementText(agentName),
|
|
1282
|
+
status: 'Complete'
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1107
1286
|
/**
|
|
1108
1287
|
* Respond to a pending AIAgentRequest from the dashboard or API.
|
|
1109
1288
|
* Updates the request record with the response and optionally spawns a
|
|
@@ -1283,9 +1462,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1283
1462
|
|
|
1284
1463
|
/**
|
|
1285
1464
|
* Execute agent in background (fire-and-forget).
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
* has already been sent.
|
|
1465
|
+
* The client learns the outcome only from the run's completion status message (executeAIAgent publishes it,
|
|
1466
|
+
* failure included), since the HTTP response has already been sent. A liveness pulse runs until the run ends.
|
|
1289
1467
|
*/
|
|
1290
1468
|
private executeAgentInBackground(
|
|
1291
1469
|
p: DatabaseProviderBase,
|
|
@@ -1317,36 +1495,34 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1317
1495
|
/** ExecuteAgentParams.TrustReservedRunData — see executeAIAgent. */
|
|
1318
1496
|
trustReservedRunData: boolean = false,
|
|
1319
1497
|
/** The conversation branch of the run — threaded through to ExecuteAgentParams.ConversationBranchID. */
|
|
1320
|
-
conversationBranchId?: string | null
|
|
1498
|
+
conversationBranchId?: string | null,
|
|
1499
|
+
/** The reply row this request created for the run — see executeAIAgent. */
|
|
1500
|
+
replyDetail?: MJConversationDetailEntityExtended
|
|
1321
1501
|
): void {
|
|
1322
1502
|
// Ref the liveness pulse reads to enrich heartbeats once the run is created.
|
|
1323
1503
|
const runRef: { current: MJAIAgentRunEntityExtended | null } = { current: null };
|
|
1324
1504
|
const pulse = StartLivenessPulse({
|
|
1325
1505
|
pubSub,
|
|
1326
1506
|
sessionId,
|
|
1327
|
-
ownerUserId: userPayload
|
|
1507
|
+
ownerUserId: StatusUpdateOwnerID(userPayload),
|
|
1328
1508
|
resolver: 'RunAIAgentResolver',
|
|
1329
1509
|
readStatus: () => runRef.current
|
|
1330
1510
|
? { runId: runRef.current.ID, status: runRef.current.Status }
|
|
1331
1511
|
: undefined,
|
|
1332
1512
|
});
|
|
1333
1513
|
|
|
1334
|
-
//
|
|
1514
|
+
// executeAIAgent resolves on every failure and publishes the run's completion itself (PublishFinal, or
|
|
1515
|
+
// PublishFailure from its catch), so nothing here publishes one.
|
|
1335
1516
|
this.executeAIAgent(
|
|
1336
1517
|
p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
|
|
1337
1518
|
data, payload, undefined, lastRunId, autoPopulateLastRunPayload,
|
|
1338
1519
|
configurationId, conversationDetailId, createArtifacts, createNotification,
|
|
1339
1520
|
sourceArtifactId, sourceArtifactVersionId, conversationId, runRef, planMode, requestedSkillIDs, taskGraphDebug,
|
|
1340
|
-
conversationHistoryFrom, trustReservedRunData, conversationBranchId
|
|
1521
|
+
conversationHistoryFrom, trustReservedRunData, conversationBranchId, replyDetail
|
|
1341
1522
|
).catch((error: unknown) => {
|
|
1342
|
-
//
|
|
1343
|
-
//
|
|
1344
|
-
|
|
1345
|
-
LogError(`🔥 Fire-and-forget background execution failed: ${errorMessage}`, undefined, error);
|
|
1346
|
-
|
|
1347
|
-
// Publish error completion event so the client knows the agent failed.
|
|
1348
|
-
// The publisher is created inside executeAIAgent, which rejected before returning one.
|
|
1349
|
-
new AgentRunStatusPublisher(pubSub, userPayload, sessionId).PublishFailure(conversationDetailId, errorMessage);
|
|
1523
|
+
// Only a broken executeAIAgent contract lands here. Logged rather than left as an unhandled rejection;
|
|
1524
|
+
// no completion is published, because executeAIAgent may already have sent one.
|
|
1525
|
+
LogError(`🔥 Fire-and-forget run of agent ${agentId} for session ${sessionId} rejected, which executeAIAgent never should`, undefined, error);
|
|
1350
1526
|
}).finally(() => pulse.Stop());
|
|
1351
1527
|
}
|
|
1352
1528
|
|
|
@@ -84,7 +84,7 @@ export class RunTemplateResolver extends ResolverBase {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
// Load template content (get the first/highest priority content)
|
|
87
|
-
const rv =
|
|
87
|
+
const rv = RunView.FromMetadataProvider(p);
|
|
88
88
|
const templateContentResult = await rv.RunView<MJTemplateContentEntity>({
|
|
89
89
|
EntityName: 'MJ: Template Contents',
|
|
90
90
|
ExtraFilter: `TemplateID = '${templateId}'`,
|
|
@@ -102,12 +102,14 @@ export class RunTemplateResolver extends ResolverBase {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// Configure and render the template
|
|
105
|
-
await TemplateEngineServer.Instance.Config(true /*always refresh to get latest templates*/, currentUser);
|
|
105
|
+
await TemplateEngineServer.Instance.Config(true /*always refresh to get latest templates*/, currentUser, p);
|
|
106
106
|
const result = await TemplateEngineServer.Instance.RenderTemplate(
|
|
107
107
|
templateEntity,
|
|
108
108
|
templateContentResult.Results[0],
|
|
109
|
-
data,
|
|
110
|
-
true // skip validation for execution
|
|
109
|
+
data,
|
|
110
|
+
true, // skip validation for execution
|
|
111
|
+
undefined,
|
|
112
|
+
{ ContextUser: currentUser },
|
|
111
113
|
);
|
|
112
114
|
|
|
113
115
|
const executionTime = Date.now() - startTime;
|
|
@@ -15,6 +15,7 @@ import { AppContext, UserPayload } from '../types.js';
|
|
|
15
15
|
import { LogError, LogStatus, UserInfo } from '@memberjunction/core';
|
|
16
16
|
import { TestEngine } from '@memberjunction/testing-engine';
|
|
17
17
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
18
|
+
import { ProjectEntityObjectForCaller, ProjectableEntityObject } from '../generic/fieldSecurityTransport.js';
|
|
18
19
|
import { StartLivenessPulse } from '../generic/FireAndForgetHeartbeat.js';
|
|
19
20
|
import { TestRunVariables, TestLogMessage, TestRunResult as EngineTestRunResult } from '@memberjunction/testing-engine-base';
|
|
20
21
|
|
|
@@ -447,7 +448,8 @@ export class RunTestResolver extends ResolverBase {
|
|
|
447
448
|
testRunId: (testRun as { ID?: string })?.ID || testId,
|
|
448
449
|
type: 'progress',
|
|
449
450
|
testRun: testRun && typeof (testRun as { GetAll?: () => Record<string, unknown> }).GetAll === 'function'
|
|
450
|
-
|
|
451
|
+
// projected for the recipient: the run object comes from the test engine, not a load bound to them
|
|
452
|
+
? ProjectEntityObjectForCaller(testRun as unknown as ProjectableEntityObject, userPayload.userRecord)
|
|
451
453
|
: undefined,
|
|
452
454
|
progress: {
|
|
453
455
|
currentStep: progress.step,
|
|
@@ -319,6 +319,7 @@ export class SyncDataResolver {
|
|
|
319
319
|
}
|
|
320
320
|
else {
|
|
321
321
|
// pass back the full record as it was JUST BEFORE the delete, often quite useful on the other end
|
|
322
|
+
// fls-guard: system-user-only resolver (@RequireSystemUser)
|
|
322
323
|
result.RecordJSON = await altKeyResult.GetDataObjectJSON({
|
|
323
324
|
includeRelatedEntityData: false,
|
|
324
325
|
excludeFields: [],
|
|
@@ -337,6 +338,7 @@ export class SyncDataResolver {
|
|
|
337
338
|
}
|
|
338
339
|
else if (await entityObject.InnerLoad(pk)) {
|
|
339
340
|
// pass back the full record as it was JUST BEFORE the delete, often quite useful on the other end
|
|
341
|
+
// fls-guard: system-user-only resolver (@RequireSystemUser)
|
|
340
342
|
result.RecordJSON = await entityObject.GetDataObjectJSON({
|
|
341
343
|
includeRelatedEntityData: false,
|
|
342
344
|
excludeFields: [],
|
|
@@ -368,6 +370,7 @@ export class SyncDataResolver {
|
|
|
368
370
|
result.Success = true;
|
|
369
371
|
result.PrimaryKey = new CompositeKey(entityObject.PrimaryKeys.map((pk) => ({FieldName: pk.Name, Value: pk.Value})));
|
|
370
372
|
// pass back the full record AFTER the sync, that's often quite useful on the other end
|
|
373
|
+
// fls-guard: system-user-only resolver (@RequireSystemUser)
|
|
371
374
|
result.RecordJSON = await entityObject.GetDataObjectJSON({
|
|
372
375
|
includeRelatedEntityData: false,
|
|
373
376
|
excludeFields: [],
|
|
@@ -411,6 +414,7 @@ export class SyncDataResolver {
|
|
|
411
414
|
result.PrimaryKey = new CompositeKey(entityObject.PrimaryKeys.map((pk) => ({FieldName: pk.Name, Value: pk.Value})));
|
|
412
415
|
}
|
|
413
416
|
// pass back the full record AFTER the sync, that's often quite useful on the other end
|
|
417
|
+
// fls-guard: system-user-only resolver (@RequireSystemUser)
|
|
414
418
|
result.RecordJSON = await entityObject.GetDataObjectJSON({
|
|
415
419
|
includeRelatedEntityData: false,
|
|
416
420
|
excludeFields: [],
|