@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
|
@@ -14,8 +14,10 @@ import type {
|
|
|
14
14
|
AgentExecutionStreamingCallback,
|
|
15
15
|
ExecuteAgentResult,
|
|
16
16
|
} from '@memberjunction/ai-core-plus';
|
|
17
|
+
import type { EntityInfo } from '@memberjunction/core';
|
|
17
18
|
import type { UserPayload } from '../types.js';
|
|
18
|
-
import { PublishStatusUpdate } from '../generic/PushStatusResolver.js';
|
|
19
|
+
import { PublishStatusUpdate, StatusUpdateOwnerID } from '../generic/PushStatusResolver.js';
|
|
20
|
+
import { ProjectEntityObjectForCaller } from '../generic/fieldSecurityTransport.js';
|
|
19
21
|
|
|
20
22
|
const SIGNIFICANT_STEPS = ['prompt_execution', 'action_execution', 'subagent_execution', 'decision_processing'];
|
|
21
23
|
|
|
@@ -25,7 +27,8 @@ interface StatusRun {
|
|
|
25
27
|
ConversationDetailID?: string;
|
|
26
28
|
ErrorMessage?: string;
|
|
27
29
|
Steps?: Array<{ StepName?: string }>;
|
|
28
|
-
|
|
30
|
+
EntityInfo?: EntityInfo | null;
|
|
31
|
+
GetAll?: () => Record<string, unknown>;
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
export class AgentRunStatusPublisher {
|
|
@@ -34,11 +37,15 @@ export class AgentRunStatusPublisher {
|
|
|
34
37
|
/**
|
|
35
38
|
* @param sessionId Session stamped on the message body. Defaults to the payload's session.
|
|
36
39
|
* The push itself is always addressed to `userPayload.sessionId`, matching the resolver.
|
|
40
|
+
* @param conversationDetailId The run's reply row. When set, every message carries it as
|
|
41
|
+
* `conversationDetailId`, not only the completion, so a client that reconnects mid-run can
|
|
42
|
+
* find its row. When omitted, messages are as before.
|
|
37
43
|
*/
|
|
38
44
|
constructor(
|
|
39
45
|
private readonly pubSub: PubSubEngine,
|
|
40
46
|
private readonly userPayload: UserPayload,
|
|
41
47
|
private readonly sessionId: string = userPayload.sessionId,
|
|
48
|
+
private readonly conversationDetailId?: string,
|
|
42
49
|
) {}
|
|
43
50
|
|
|
44
51
|
/** Latest run observed from a progress event, including steps that are not published. */
|
|
@@ -66,7 +73,8 @@ export class AgentRunStatusPublisher {
|
|
|
66
73
|
sessionId: this.sessionId,
|
|
67
74
|
agentRunId: agentRun.ID,
|
|
68
75
|
type: 'progress',
|
|
69
|
-
|
|
76
|
+
...this.replyRow(),
|
|
77
|
+
agentRun: this.runValues(agentRun),
|
|
70
78
|
progress: {
|
|
71
79
|
currentStep: progress.step,
|
|
72
80
|
percentage: progress.percentage,
|
|
@@ -93,7 +101,8 @@ export class AgentRunStatusPublisher {
|
|
|
93
101
|
sessionId: this.sessionId,
|
|
94
102
|
agentRunId: agentRun.ID,
|
|
95
103
|
type: 'streaming',
|
|
96
|
-
|
|
104
|
+
...this.replyRow(),
|
|
105
|
+
agentRun: this.runValues(agentRun),
|
|
97
106
|
streaming: {
|
|
98
107
|
content: chunk.content,
|
|
99
108
|
isPartial: !chunk.isComplete,
|
|
@@ -122,6 +131,7 @@ export class AgentRunStatusPublisher {
|
|
|
122
131
|
sessionId: this.sessionId,
|
|
123
132
|
agentRunId: agentRun.ID,
|
|
124
133
|
type: 'partial_result',
|
|
134
|
+
...this.replyRow(),
|
|
125
135
|
partialResult: {
|
|
126
136
|
currentStep: lastStep,
|
|
127
137
|
partialOutput: result.payload || undefined,
|
|
@@ -134,7 +144,7 @@ export class AgentRunStatusPublisher {
|
|
|
134
144
|
agentRunId: agentRun?.ID || 'unknown',
|
|
135
145
|
type: 'complete',
|
|
136
146
|
timestamp: new Date(),
|
|
137
|
-
conversationDetailId: conversationDetailId || agentRun?.ConversationDetailID,
|
|
147
|
+
conversationDetailId: conversationDetailId || agentRun?.ConversationDetailID || this.conversationDetailId,
|
|
138
148
|
success: result.success,
|
|
139
149
|
errorMessage: agentRun?.ErrorMessage || undefined,
|
|
140
150
|
result: resultJson || undefined,
|
|
@@ -142,8 +152,9 @@ export class AgentRunStatusPublisher {
|
|
|
142
152
|
}
|
|
143
153
|
|
|
144
154
|
/**
|
|
145
|
-
* Completion for a failure that has no run.
|
|
146
|
-
*
|
|
155
|
+
* Completion for a failure that has no run result. `executeAIAgent` sends it when the run
|
|
156
|
+
* throws (the agent could not start, the run failed, or its reply could not be saved), so a
|
|
157
|
+
* fire-and-forget client learns the reason. A host uses it the same way: when the turn throws
|
|
147
158
|
* instead of returning a result, call `PublishFailure` with the reply row's id
|
|
148
159
|
* and the error. That completion is what tells the chat the reply finished.
|
|
149
160
|
*/
|
|
@@ -160,10 +171,27 @@ export class AgentRunStatusPublisher {
|
|
|
160
171
|
});
|
|
161
172
|
}
|
|
162
173
|
|
|
174
|
+
/** `{ conversationDetailId }` when this run has a reply row, otherwise nothing, so the message keeps its old shape. */
|
|
175
|
+
private replyRow(): { conversationDetailId?: string } {
|
|
176
|
+
return this.conversationDetailId ? { conversationDetailId: this.conversationDetailId } : {};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The run's field values as the recipient may read them. The run object comes from the agent
|
|
181
|
+
* engine, which is not bound to this session's user, so it is projected here.
|
|
182
|
+
*/
|
|
183
|
+
private runValues(agentRun: StatusRun): unknown {
|
|
184
|
+
if (!agentRun.GetAll) {
|
|
185
|
+
return agentRun;
|
|
186
|
+
}
|
|
187
|
+
const getAll = agentRun.GetAll;
|
|
188
|
+
return ProjectEntityObjectForCaller({ EntityInfo: agentRun.EntityInfo, GetAll: () => getAll.call(agentRun) }, this.userPayload?.userRecord);
|
|
189
|
+
}
|
|
190
|
+
|
|
163
191
|
private publish(type: 'ExecutionProgress' | 'StreamingContent', data: unknown): void {
|
|
164
192
|
PublishStatusUpdate(this.pubSub, {
|
|
165
193
|
sessionId: this.userPayload.sessionId,
|
|
166
|
-
ownerUserId: this.userPayload
|
|
194
|
+
ownerUserId: StatusUpdateOwnerID(this.userPayload),
|
|
167
195
|
message: JSON.stringify({
|
|
168
196
|
resolver: 'RunAIAgentResolver',
|
|
169
197
|
type,
|
|
@@ -13,12 +13,30 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
15
15
|
import { AppContext } from '../types.js';
|
|
16
|
-
import { UserInfo, IMetadataProvider
|
|
17
|
-
import { UUIDsEqual } from '@memberjunction/global';
|
|
18
|
-
import { MJAIAgentSessionEntity } from '@memberjunction/core-entities';
|
|
16
|
+
import { UserInfo, IMetadataProvider } from '@memberjunction/core';
|
|
19
17
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
20
18
|
import { GetReadWriteProvider } from '../util.js';
|
|
21
|
-
import { SessionManager, SessionAuthorizationError } from '../agentSessions/index.js';
|
|
19
|
+
import { SessionManager, SessionAuthorizationError, type SessionCloseReason } from '../agentSessions/index.js';
|
|
20
|
+
import {
|
|
21
|
+
LoadOwnedRealtimeSession,
|
|
22
|
+
RealtimeSessionNotFoundError,
|
|
23
|
+
RealtimeSessionOwnershipError,
|
|
24
|
+
} from '../realtimeSessions/ownedRealtimeSession.js';
|
|
25
|
+
|
|
26
|
+
/** The `CloseReason` values a client may stamp on its own session; `Janitor` and `Shutdown` are the server's. */
|
|
27
|
+
const CLIENT_CLOSE_REASONS: readonly SessionCloseReason[] = ['Explicit', 'Error'];
|
|
28
|
+
|
|
29
|
+
/** Reads the mutation's optional `closeReason`: absent means `Explicit`; a server-only or unknown value is refused. */
|
|
30
|
+
function ParseClientCloseReason(closeReason: string | null | undefined): SessionCloseReason {
|
|
31
|
+
if (closeReason == null || closeReason === '') {
|
|
32
|
+
return 'Explicit';
|
|
33
|
+
}
|
|
34
|
+
const match = CLIENT_CLOSE_REASONS.find((r) => r === closeReason);
|
|
35
|
+
if (!match) {
|
|
36
|
+
throw new Error(`Unsupported close reason '${closeReason}': a client may close its session as ${CLIENT_CLOSE_REASONS.join(' or ')}`);
|
|
37
|
+
}
|
|
38
|
+
return match;
|
|
39
|
+
}
|
|
22
40
|
|
|
23
41
|
/** Result of {@link AgentSessionResolver.StartAgentSession}. */
|
|
24
42
|
@ObjectType()
|
|
@@ -77,15 +95,22 @@ export class AgentSessionResolver extends ResolverBase {
|
|
|
77
95
|
/**
|
|
78
96
|
* Close a session. Rejects unless the caller owns it. Returns `true` on a successful (or
|
|
79
97
|
* idempotent) close, `false` if the session can't be loaded.
|
|
98
|
+
*
|
|
99
|
+
* `closeReason` is what the row records as its `CloseReason`: `Explicit` (the default, and what
|
|
100
|
+
* every client sent before the argument existed) when the user or host ended the call, `Error`
|
|
101
|
+
* when the client ended it because the start or the call failed (MJ#6013). The other reasons are
|
|
102
|
+
* the server's own (janitor, shutdown) and are refused from a client.
|
|
80
103
|
*/
|
|
81
104
|
@Mutation(() => Boolean)
|
|
82
105
|
async CloseAgentSession(
|
|
83
106
|
@Arg('agentSessionId') agentSessionId: string,
|
|
84
107
|
@Ctx() { userPayload, providers }: AppContext,
|
|
108
|
+
@Arg('closeReason', () => String, { nullable: true }) closeReason?: string | null,
|
|
85
109
|
): Promise<boolean> {
|
|
110
|
+
const reason = ParseClientCloseReason(closeReason);
|
|
86
111
|
const { contextUser, provider } = this.requireUserAndProvider(userPayload, providers);
|
|
87
|
-
await this.
|
|
88
|
-
return this.sessionManager.CloseSession(agentSessionId, contextUser, provider);
|
|
112
|
+
await this.loadOwnedSession(agentSessionId, contextUser, provider);
|
|
113
|
+
return this.sessionManager.CloseSession(agentSessionId, contextUser, provider, reason);
|
|
89
114
|
}
|
|
90
115
|
|
|
91
116
|
/**
|
|
@@ -98,7 +123,7 @@ export class AgentSessionResolver extends ResolverBase {
|
|
|
98
123
|
@Ctx() { userPayload, providers }: AppContext,
|
|
99
124
|
): Promise<boolean> {
|
|
100
125
|
const { contextUser, provider } = this.requireUserAndProvider(userPayload, providers);
|
|
101
|
-
await this.
|
|
126
|
+
await this.loadOwnedSession(agentSessionId, contextUser, provider);
|
|
102
127
|
return this.sessionManager.Heartbeat(agentSessionId, contextUser, provider);
|
|
103
128
|
}
|
|
104
129
|
|
|
@@ -117,22 +142,25 @@ export class AgentSessionResolver extends ResolverBase {
|
|
|
117
142
|
}
|
|
118
143
|
|
|
119
144
|
/**
|
|
120
|
-
* Inbound ownership gate
|
|
121
|
-
*
|
|
145
|
+
* Inbound ownership gate: delegates to {@link LoadOwnedRealtimeSession} (which enforces both
|
|
146
|
+
* `UserID === contextUser.ID` and `AuthorizeSessionAccess` scope/visitor binding) and maps its
|
|
147
|
+
* typed errors to this resolver's message format.
|
|
122
148
|
*/
|
|
123
|
-
private async
|
|
149
|
+
private async loadOwnedSession(
|
|
124
150
|
agentSessionId: string,
|
|
125
151
|
contextUser: UserInfo,
|
|
126
152
|
provider: IMetadataProvider,
|
|
127
153
|
): Promise<void> {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
154
|
+
try {
|
|
155
|
+
await LoadOwnedRealtimeSession(agentSessionId, contextUser, provider);
|
|
156
|
+
} catch (err) {
|
|
157
|
+
if (err instanceof RealtimeSessionNotFoundError) {
|
|
158
|
+
throw new Error(`Agent session ${agentSessionId} not found`);
|
|
159
|
+
}
|
|
160
|
+
if (err instanceof RealtimeSessionOwnershipError) {
|
|
161
|
+
throw new Error('Not authorized: you do not own this agent session');
|
|
162
|
+
}
|
|
163
|
+
throw err;
|
|
136
164
|
}
|
|
137
165
|
}
|
|
138
166
|
}
|
|
@@ -3,12 +3,14 @@ import { AppContext } from '../types.js';
|
|
|
3
3
|
import { RunViewByIDInput } from '../generic/RunViewResolver.js';
|
|
4
4
|
import { Message } from '@memberjunction/communication-types';
|
|
5
5
|
import { EntityCommunicationsEngine } from '@memberjunction/entity-communications-server';
|
|
6
|
-
import { RunViewParams } from '@memberjunction/core';
|
|
6
|
+
import { DatabaseProviderBase, IMetadataProvider, RunViewParams, UserInfo } from '@memberjunction/core';
|
|
7
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
7
8
|
import { GraphQLJSONObject } from 'graphql-type-json';
|
|
8
9
|
import { TemplateEngineServer } from '@memberjunction/templates';
|
|
9
10
|
import { EntityCommunicationParams } from '@memberjunction/entity-communications-base';
|
|
10
11
|
import { z } from 'zod';
|
|
11
12
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
13
|
+
import { GetReadOnlyProvider } from '../util.js';
|
|
12
14
|
|
|
13
15
|
@InputType()
|
|
14
16
|
export class CommunicationProviderMessageType {
|
|
@@ -168,6 +170,11 @@ export class RunEntityCommunicationResultType {
|
|
|
168
170
|
|
|
169
171
|
@Resolver(RunEntityCommunicationResultType)
|
|
170
172
|
export class ReportResolver extends ResolverBase {
|
|
173
|
+
/**
|
|
174
|
+
* Runs a message against a view of records, as the caller. The recipient and related-entity reads
|
|
175
|
+
* run as the authenticated user, so a preview returns and a send merges only rows and fields that
|
|
176
|
+
* user may read. The view's client-supplied clauses get the same screen as a RunView request.
|
|
177
|
+
*/
|
|
171
178
|
@Query(() => RunEntityCommunicationResultType)
|
|
172
179
|
async RunEntityCommunicationByViewID(
|
|
173
180
|
@Arg('entityID', () => String) entityID: string,
|
|
@@ -177,25 +184,29 @@ export class ReportResolver extends ResolverBase {
|
|
|
177
184
|
@Arg('message', () => CommunicationMessageInput) message: CommunicationMessageInput,
|
|
178
185
|
@Arg('previewOnly', () => Boolean) previewOnly: boolean,
|
|
179
186
|
@Arg('includeProcessedMessages', () => Boolean) includeProcessedMessages: boolean,
|
|
180
|
-
@Ctx() { userPayload }: AppContext
|
|
187
|
+
@Ctx() { userPayload, providers }: AppContext
|
|
181
188
|
): Promise<RunEntityCommunicationResultType> {
|
|
182
189
|
// Check API key scope authorization for communication send
|
|
183
190
|
await this.CheckAPIKeyScopeAuthorization('communication:send', entityID, userPayload);
|
|
184
191
|
|
|
185
192
|
try {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
193
|
+
const contextUser = this.GetUserFromPayload(userPayload);
|
|
194
|
+
if (!contextUser) throw new Error('Unable to determine the acting user for this communication');
|
|
195
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
196
|
+
this.screenClientViewClauses(
|
|
197
|
+
{
|
|
198
|
+
extraFilter: runViewByIDInput.ExtraFilter,
|
|
199
|
+
orderBy: runViewByIDInput.OrderBy,
|
|
200
|
+
userSearchString: runViewByIDInput.UserSearchString,
|
|
201
|
+
overrideExcludeFilter: runViewByIDInput.OverrideExcludeFilter,
|
|
202
|
+
},
|
|
203
|
+
provider as unknown as IMetadataProvider,
|
|
204
|
+
contextUser,
|
|
205
|
+
);
|
|
206
|
+
await this.assertViewBelongsToEntity(runViewByIDInput.ViewID, entityID, provider, contextUser);
|
|
207
|
+
|
|
208
|
+
await EntityCommunicationsEngine.Instance.Config(false, contextUser);
|
|
209
|
+
const newMessage = await this.resolveMessageTemplates(message, contextUser);
|
|
199
210
|
const params: EntityCommunicationParams = {
|
|
200
211
|
EntityID: entityID,
|
|
201
212
|
RunViewParams: <RunViewParams>runViewByIDInput,
|
|
@@ -204,6 +215,8 @@ export class ReportResolver extends ResolverBase {
|
|
|
204
215
|
Message: newMessage,
|
|
205
216
|
PreviewOnly: previewOnly,
|
|
206
217
|
IncludeProcessedMessages: includeProcessedMessages,
|
|
218
|
+
ContextUser: contextUser,
|
|
219
|
+
Provider: provider,
|
|
207
220
|
};
|
|
208
221
|
const result = await EntityCommunicationsEngine.Instance.RunEntityCommunication(params);
|
|
209
222
|
return {
|
|
@@ -222,4 +235,32 @@ export class ReportResolver extends ResolverBase {
|
|
|
222
235
|
};
|
|
223
236
|
}
|
|
224
237
|
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Refuses a view that is not a view of `entityID`, with the same message as for a view that does
|
|
241
|
+
* not exist or that the caller cannot load, so the refusal does not reveal which views exist.
|
|
242
|
+
*/
|
|
243
|
+
private async assertViewBelongsToEntity(viewID: string | undefined, entityID: string, provider: DatabaseProviderBase, contextUser: UserInfo): Promise<void> {
|
|
244
|
+
if (!viewID) return;
|
|
245
|
+
const view = await this.resolveUserViewByID(viewID, provider, contextUser);
|
|
246
|
+
if (!view?.ID || !UUIDsEqual(view.ID, viewID) || !UUIDsEqual(view.EntityID, entityID)) {
|
|
247
|
+
throw new Error('The requested view does not exist or you do not have access to it');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Builds the message, replacing each template the client named with the server's copy of it. */
|
|
252
|
+
private async resolveMessageTemplates(message: CommunicationMessageInput, contextUser: UserInfo): Promise<Message> {
|
|
253
|
+
const newMessage = new Message(message as unknown as Message);
|
|
254
|
+
await TemplateEngineServer.Instance.Config(false, contextUser);
|
|
255
|
+
if (newMessage.BodyTemplate) {
|
|
256
|
+
newMessage.BodyTemplate = TemplateEngineServer.Instance.FindTemplate(newMessage.BodyTemplate.Name);
|
|
257
|
+
}
|
|
258
|
+
if (newMessage.HTMLBodyTemplate) {
|
|
259
|
+
newMessage.HTMLBodyTemplate = TemplateEngineServer.Instance.FindTemplate(newMessage.HTMLBodyTemplate.Name);
|
|
260
|
+
}
|
|
261
|
+
if (newMessage.SubjectTemplate) {
|
|
262
|
+
newMessage.SubjectTemplate = TemplateEngineServer.Instance.FindTemplate(newMessage.SubjectTemplate.Name);
|
|
263
|
+
}
|
|
264
|
+
return newMessage;
|
|
265
|
+
}
|
|
225
266
|
}
|
|
@@ -50,6 +50,12 @@ type LabelledVector = { row: StoredVectorRow; labels: Record<string, string> };
|
|
|
50
50
|
/** Most Entity Record Document IDs named in one `ID IN (...)` filter when fetching VectorJSON. */
|
|
51
51
|
const VECTOR_FETCH_CHUNK_SIZE = 1000;
|
|
52
52
|
|
|
53
|
+
/** Most record keys named in one view when checking which matched records the caller may read. */
|
|
54
|
+
const READABLE_KEY_CHECK_CHUNK_SIZE = 1000;
|
|
55
|
+
|
|
56
|
+
/** A match returned by an external vector index's `QueryIndex`. */
|
|
57
|
+
type IndexMatch = { id: string; values?: number[]; metadata?: Record<string, unknown>; score?: number };
|
|
58
|
+
|
|
53
59
|
/* ───── Resolver ───── */
|
|
54
60
|
|
|
55
61
|
@Resolver()
|
|
@@ -70,15 +76,18 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
const limit = maxRecords ?? 1000;
|
|
79
|
+
// Every read runs on this request's provider.
|
|
80
|
+
const md = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true }) ?? Metadata.Provider;
|
|
81
|
+
const rv = RunView.FromMetadataProvider(md);
|
|
73
82
|
|
|
74
83
|
// Step 1: Load the EntityDocument
|
|
75
|
-
const entityDoc = await this.loadEntityDocument(entityDocumentID, currentUser);
|
|
84
|
+
const entityDoc = await this.loadEntityDocument(entityDocumentID, currentUser, rv);
|
|
76
85
|
if (!entityDoc) {
|
|
77
86
|
return this.errorResult(`EntityDocument not found: ${entityDocumentID}`, startTime);
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
// Step 2: Resolve the VectorIndex
|
|
81
|
-
const vectorIndex = await this.resolveVectorIndex(entityDoc, currentUser);
|
|
90
|
+
const vectorIndex = await this.resolveVectorIndex(entityDoc, currentUser, rv);
|
|
82
91
|
if (!vectorIndex) {
|
|
83
92
|
return this.errorResult(
|
|
84
93
|
`Could not resolve VectorIndex for EntityDocument "${entityDoc.Name}"`,
|
|
@@ -87,7 +96,7 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
// Step 3: Create VectorDB provider instance
|
|
90
|
-
const vectorDBInstance = await this.createVectorDBInstance(vectorIndex, currentUser);
|
|
99
|
+
const vectorDBInstance = await this.createVectorDBInstance(vectorIndex, currentUser, rv);
|
|
91
100
|
if (!vectorDBInstance) {
|
|
92
101
|
return this.errorResult(
|
|
93
102
|
`Could not create VectorDB provider for index "${vectorIndex.Name}"`,
|
|
@@ -100,12 +109,21 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
100
109
|
// document ID rather than the index name, and return matches without vector values.
|
|
101
110
|
// Read the stored Entity Record Document rows instead.
|
|
102
111
|
if (vectorDBInstance.QueryKeyIsEntityDocumentID) {
|
|
103
|
-
const
|
|
104
|
-
const results = await this.fetchStoredVectors(entityDoc, limit, filter, currentUser, md);
|
|
112
|
+
const results = await this.fetchStoredVectors(entityDoc, limit, filter, currentUser, md, rv);
|
|
105
113
|
LogStatus(`FetchEntityVectors: Loaded ${results.length} stored vectors for entity "${entityDoc.Entity}" in ${Date.now() - startTime}ms`);
|
|
106
114
|
return { Success: true, Results: results, TotalCount: results.length, ElapsedMs: Date.now() - startTime };
|
|
107
115
|
}
|
|
108
116
|
|
|
117
|
+
// The external index was built under whoever ran the sync and is not filtered for this
|
|
118
|
+
// caller, so check here that they may read the source entity at all.
|
|
119
|
+
const entityInfo = this.readableEntity(entityDoc.Entity, currentUser, md);
|
|
120
|
+
if (!entityInfo) {
|
|
121
|
+
return this.errorResult(
|
|
122
|
+
`Entity "${entityDoc.Entity}" does not exist or you do not have permission to read it`,
|
|
123
|
+
startTime
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
109
127
|
// Step 4: Query with zero vector + Entity metadata filter.
|
|
110
128
|
// Pinecone's list API doesn't support metadata filtering, but query does.
|
|
111
129
|
// A zero vector returns results in arbitrary order (similarity is meaningless),
|
|
@@ -136,12 +154,15 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
136
154
|
);
|
|
137
155
|
}
|
|
138
156
|
|
|
139
|
-
// Step 5:
|
|
140
|
-
|
|
157
|
+
// Step 5: Keep only matches for records this caller may read (the index is not filtered
|
|
158
|
+
// by row-level security), then convert them without the fields this caller may not read
|
|
159
|
+
const allMatches = (queryResponse.data as { matches?: IndexMatch[] }).matches ?? [];
|
|
160
|
+
const matches = await this.readableMatches(entityInfo, allMatches, currentUser, rv);
|
|
161
|
+
const denied = entityInfo.GetDeniedReadFields(currentUser);
|
|
141
162
|
const results: EntityVectorItem[] = matches.map(match => ({
|
|
142
163
|
ID: match.id,
|
|
143
164
|
Values: match.values ?? [],
|
|
144
|
-
Metadata: JSON.stringify(match.metadata ?? {}),
|
|
165
|
+
Metadata: JSON.stringify(this.withoutDeniedFields(match.metadata ?? {}, denied)),
|
|
145
166
|
}));
|
|
146
167
|
LogStatus(`FetchEntityVectors: Queried ${results.length} vectors for entity "${entityName}" in ${Date.now() - startTime}ms`);
|
|
147
168
|
|
|
@@ -158,12 +179,100 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
158
179
|
}
|
|
159
180
|
}
|
|
160
181
|
|
|
182
|
+
/**
|
|
183
|
+
* The entity's metadata when `contextUser` may read it, else null — whether it is missing or
|
|
184
|
+
* unreadable is deliberately not distinguished.
|
|
185
|
+
*/
|
|
186
|
+
private readableEntity(entityName: string, contextUser: UserInfo, md: IMetadataProvider): EntityInfo | null {
|
|
187
|
+
const entityInfo = md.EntityByName(entityName);
|
|
188
|
+
if (!entityInfo) return null;
|
|
189
|
+
return entityInfo.GetUserPermisions(contextUser)?.CanRead ? entityInfo : null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The matches whose record `contextUser` may read, in their original order. A match is kept only
|
|
194
|
+
* when its `RecordID` metadata names a key of the entity and a view run as `contextUser` returns
|
|
195
|
+
* that record; a match without a usable record ID cannot be checked, so it is dropped.
|
|
196
|
+
*/
|
|
197
|
+
private async readableMatches(entityInfo: EntityInfo, matches: IndexMatch[], contextUser: UserInfo, rv: RunView): Promise<IndexMatch[]> {
|
|
198
|
+
const keyed = matches
|
|
199
|
+
.map(match => ({ match, key: this.matchRecordKey(entityInfo, match) }))
|
|
200
|
+
.filter((m): m is { match: IndexMatch; key: CompositeKey } => m.key !== null);
|
|
201
|
+
if (keyed.length === 0) return [];
|
|
202
|
+
const readable = await this.loadReadableKeys(entityInfo, keyed.map(k => k.key), contextUser, rv);
|
|
203
|
+
return keyed.filter(k => readable.has(this.canonicalKey(k.key))).map(k => k.match);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** The record key a match's `RecordID` metadata names, or null when it names no key of the entity. */
|
|
207
|
+
private matchRecordKey(entityInfo: EntityInfo, match: IndexMatch): CompositeKey | null {
|
|
208
|
+
const recordID = match.metadata?.RecordID;
|
|
209
|
+
if (typeof recordID !== 'string' || recordID.length === 0) return null;
|
|
210
|
+
try {
|
|
211
|
+
return CompositeKey.FromRecordID(entityInfo, recordID);
|
|
212
|
+
} catch {
|
|
213
|
+
return null; // field names that are not the entity's primary key: never put into SQL
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The canonical forms of the keys among `keys` whose record a view run as `contextUser` returns.
|
|
219
|
+
* The keys are checked in lists of at most {@link READABLE_KEY_CHECK_CHUNK_SIZE}, all sent in one
|
|
220
|
+
* `RunViews` batch.
|
|
221
|
+
*/
|
|
222
|
+
private async loadReadableKeys(entityInfo: EntityInfo, keys: CompositeKey[], contextUser: UserInfo, rv: RunView): Promise<Set<string>> {
|
|
223
|
+
const views: RunViewParams[] = [];
|
|
224
|
+
for (let i = 0; i < keys.length; i += READABLE_KEY_CHECK_CHUNK_SIZE) {
|
|
225
|
+
views.push({
|
|
226
|
+
EntityName: entityInfo.Name,
|
|
227
|
+
ExtraFilter: this.keyFilter(entityInfo, keys.slice(i, i + READABLE_KEY_CHECK_CHUNK_SIZE)),
|
|
228
|
+
Fields: entityInfo.PrimaryKeys.map(pk => pk.Name),
|
|
229
|
+
IgnoreMaxRows: true,
|
|
230
|
+
BypassCache: true, // one-off key lists: a cache slot per call would only hold memory
|
|
231
|
+
ResultType: 'simple',
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
const readable = new Set<string>();
|
|
235
|
+
const results = await rv.RunViews<Record<string, unknown>>(views, contextUser);
|
|
236
|
+
for (const result of results) {
|
|
237
|
+
if (!result.Success) {
|
|
238
|
+
throw new Error(`Failed to check access to "${entityInfo.Name}" records: ${result.ErrorMessage}`);
|
|
239
|
+
}
|
|
240
|
+
for (const row of result.Results) {
|
|
241
|
+
readable.add(this.canonicalKey(CompositeKey.FromEntityRecord(entityInfo, row)));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return readable;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** A filter matching exactly `keys`: `PK IN (...)` for a single-column key, one clause per key otherwise. */
|
|
248
|
+
private keyFilter(entityInfo: EntityInfo, keys: CompositeKey[]): string {
|
|
249
|
+
if (entityInfo.PrimaryKeys.length === 1) {
|
|
250
|
+
const values = keys.map(k => `'${EscapeSQLString(String(k.KeyValuePairs[0].Value))}'`).join(',');
|
|
251
|
+
return `${entityInfo.FirstPrimaryKey.Name} IN (${values})`; // first-pk-ok: single-column key, checked above
|
|
252
|
+
}
|
|
253
|
+
return keys.map(k => `(${k.ToWhereClause()})`).join(' OR ');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** A key's field names and values, lower-cased, so keys from the index and from a view compare equal. */
|
|
257
|
+
private canonicalKey(key: CompositeKey): string {
|
|
258
|
+
return key.KeyValuePairs.map(kv => `${kv.FieldName.toLowerCase()}|${String(kv.Value).toLowerCase()}`).join('||');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* A copy of a vector's metadata without the keys naming fields in `denied` (lowercased field
|
|
263
|
+
* names, as `EntityInfo.GetDeniedReadFields` returns them), compared case-insensitively.
|
|
264
|
+
*/
|
|
265
|
+
private withoutDeniedFields(metadata: Record<string, unknown>, denied: Set<string>): Record<string, unknown> {
|
|
266
|
+
if (denied.size === 0) return metadata;
|
|
267
|
+
return Object.fromEntries(Object.entries(metadata).filter(([key]) => !denied.has(key.toLowerCase())));
|
|
268
|
+
}
|
|
269
|
+
|
|
161
270
|
/** Load EntityDocument by ID */
|
|
162
271
|
private async loadEntityDocument(
|
|
163
272
|
entityDocumentID: string,
|
|
164
|
-
contextUser: UserInfo
|
|
273
|
+
contextUser: UserInfo,
|
|
274
|
+
rv: RunView
|
|
165
275
|
): Promise<MJEntityDocumentEntity | null> {
|
|
166
|
-
const rv = new RunView();
|
|
167
276
|
const result = await rv.RunView<MJEntityDocumentEntity>({
|
|
168
277
|
EntityName: 'MJ: Entity Documents',
|
|
169
278
|
ExtraFilter: `ID='${EscapeSQLString(entityDocumentID)}'`,
|
|
@@ -183,9 +292,9 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
183
292
|
*/
|
|
184
293
|
private async resolveVectorIndex(
|
|
185
294
|
entityDoc: MJEntityDocumentEntity,
|
|
186
|
-
contextUser: UserInfo
|
|
295
|
+
contextUser: UserInfo,
|
|
296
|
+
rv: RunView
|
|
187
297
|
): Promise<MJVectorIndexEntity | null> {
|
|
188
|
-
const rv = new RunView();
|
|
189
298
|
|
|
190
299
|
// If the EntityDocument has an explicit VectorIndexID, use it directly
|
|
191
300
|
if (entityDoc.VectorIndexID) {
|
|
@@ -222,9 +331,9 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
222
331
|
/** Create a VectorDBBase provider instance for a given VectorIndex */
|
|
223
332
|
private async createVectorDBInstance(
|
|
224
333
|
vectorIndex: MJVectorIndexEntity,
|
|
225
|
-
contextUser: UserInfo
|
|
334
|
+
contextUser: UserInfo,
|
|
335
|
+
rv: RunView
|
|
226
336
|
): Promise<VectorDBBase | null> {
|
|
227
|
-
const rv = new RunView();
|
|
228
337
|
const dbResult = await rv.RunView<MJVectorDatabaseEntity>({
|
|
229
338
|
EntityName: 'MJ: Vector Databases',
|
|
230
339
|
ExtraFilter: `ID='${vectorIndex.VectorDatabaseID}'`,
|
|
@@ -258,19 +367,20 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
258
367
|
limit: number,
|
|
259
368
|
filter: string | undefined,
|
|
260
369
|
contextUser: UserInfo,
|
|
261
|
-
md: IMetadataProvider
|
|
370
|
+
md: IMetadataProvider,
|
|
371
|
+
rv: RunView
|
|
262
372
|
): Promise<EntityVectorItem[]> {
|
|
263
373
|
const entityInfo = md.EntityByName(entityDoc.Entity);
|
|
264
374
|
if (!entityInfo) {
|
|
265
375
|
throw new Error(`Entity "${entityDoc.Entity}" not found in metadata`);
|
|
266
376
|
}
|
|
267
377
|
const nameFields = this.labelFieldNames(entityInfo);
|
|
268
|
-
const { records, vectors } = await this.loadRecordsAndStoredVectors(entityInfo, entityDoc, nameFields, filter, contextUser);
|
|
378
|
+
const { records, vectors } = await this.loadRecordsAndStoredVectors(entityInfo, entityDoc, nameFields, filter, contextUser, rv);
|
|
269
379
|
const labelsByRecordID = this.mapRecordLabels(entityInfo, nameFields, records);
|
|
270
380
|
|
|
271
381
|
// VectorJSON is the heavy column: list without it, then fetch it only for the items returned.
|
|
272
382
|
const chosen = this.selectLabelledVectors(vectors, labelsByRecordID, limit);
|
|
273
|
-
const valuesByID = await this.loadVectorValues(chosen.map(c => c.row.ID), contextUser);
|
|
383
|
+
const valuesByID = await this.loadVectorValues(chosen.map(c => c.row.ID), contextUser, rv);
|
|
274
384
|
|
|
275
385
|
const results: EntityVectorItem[] = [];
|
|
276
386
|
for (const { row, labels } of chosen) {
|
|
@@ -305,7 +415,7 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
305
415
|
* Fetch `VectorJSON` for the given Entity Record Document IDs, keyed by ID. The ID lists are
|
|
306
416
|
* capped at {@link VECTOR_FETCH_CHUNK_SIZE} per view and all sent in one `RunViews` batch.
|
|
307
417
|
*/
|
|
308
|
-
private async loadVectorValues(ids: string[], contextUser: UserInfo): Promise<Map<string, string>> {
|
|
418
|
+
private async loadVectorValues(ids: string[], contextUser: UserInfo, rv: RunView): Promise<Map<string, string>> {
|
|
309
419
|
const valuesByID = new Map<string, string>();
|
|
310
420
|
if (ids.length === 0) return valuesByID;
|
|
311
421
|
|
|
@@ -321,7 +431,7 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
321
431
|
ResultType: 'simple',
|
|
322
432
|
});
|
|
323
433
|
}
|
|
324
|
-
const results = await
|
|
434
|
+
const results = await rv.RunViews<{ ID: string; VectorJSON: string | null }>(views, contextUser);
|
|
325
435
|
for (const result of results) {
|
|
326
436
|
if (!result.Success) {
|
|
327
437
|
throw new Error(`Failed to load vector values: ${result.ErrorMessage}`);
|
|
@@ -352,10 +462,11 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
352
462
|
entityDoc: MJEntityDocumentEntity,
|
|
353
463
|
nameFields: string[],
|
|
354
464
|
filter: string | undefined,
|
|
355
|
-
contextUser: UserInfo
|
|
465
|
+
contextUser: UserInfo,
|
|
466
|
+
rv: RunView
|
|
356
467
|
): Promise<{ records: Record<string, unknown>[]; vectors: StoredVectorRow[] }> {
|
|
357
468
|
const keyFields = entityInfo.PrimaryKeys.map(pk => pk.Name);
|
|
358
|
-
const [recordResult, docResult] = await
|
|
469
|
+
const [recordResult, docResult] = await rv.RunViews<Record<string, unknown>>([
|
|
359
470
|
{
|
|
360
471
|
EntityName: entityInfo.Name,
|
|
361
472
|
ExtraFilter: filter || undefined,
|
|
@@ -34,6 +34,7 @@ export class FileCategoryResolver extends FileCategoryResolverBase {
|
|
|
34
34
|
fileCategoryEntity.CheckPermissions(EntityPermissionType.Delete, true);
|
|
35
35
|
|
|
36
36
|
await fileCategoryEntity.Load(ID);
|
|
37
|
+
// fls-guard: loaded as the caller; width follows its user
|
|
37
38
|
const returnValue = fileCategoryEntity.GetAll();
|
|
38
39
|
|
|
39
40
|
// Any files using the deleted category fall back to its parent
|