@memberjunction/server 6.2.0-edge.3 → 6.2.0-edge.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/BridgeHostInstance.d.ts +25 -0
- package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -0
- package/dist/agentSessions/BridgeHostInstance.js +30 -0
- package/dist/agentSessions/BridgeHostInstance.js.map +1 -0
- package/dist/agentSessions/HostInstance.d.ts +75 -11
- package/dist/agentSessions/HostInstance.d.ts.map +1 -1
- package/dist/agentSessions/HostInstance.js +99 -28
- package/dist/agentSessions/HostInstance.js.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.js +7 -3
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +236 -27
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +682 -54
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +48 -3
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +112 -9
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/SessionRunIDVerifier.d.ts +63 -0
- package/dist/agentSessions/SessionRunIDVerifier.d.ts.map +1 -0
- package/dist/agentSessions/SessionRunIDVerifier.js +129 -0
- package/dist/agentSessions/SessionRunIDVerifier.js.map +1 -0
- package/dist/agentSessions/index.d.ts +2 -0
- package/dist/agentSessions/index.d.ts.map +1 -1
- package/dist/agentSessions/index.js +10 -3
- package/dist/agentSessions/index.js.map +1 -1
- package/dist/apiRoot.d.ts +32 -0
- package/dist/apiRoot.d.ts.map +1 -0
- package/dist/apiRoot.js +67 -0
- package/dist/apiRoot.js.map +1 -0
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +25 -0
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/LoginScreenEngine.d.ts +22 -0
- package/dist/auth/LoginScreenEngine.d.ts.map +1 -0
- package/dist/auth/LoginScreenEngine.js +57 -0
- package/dist/auth/LoginScreenEngine.js.map +1 -0
- package/dist/auth/actionAuthorization.d.ts +40 -0
- package/dist/auth/actionAuthorization.d.ts.map +1 -0
- package/dist/auth/actionAuthorization.js +94 -0
- package/dist/auth/actionAuthorization.js.map +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +4 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +3 -2
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +6 -3
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/newUsers.d.ts +10 -0
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +80 -11
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/config.d.ts +2514 -22
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +166 -4
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +8 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +14 -11
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts +29 -0
- package/dist/coreRoutes.d.ts.map +1 -0
- package/dist/coreRoutes.js +142 -0
- package/dist/coreRoutes.js.map +1 -0
- package/dist/generated/graphql-schemas/__mj.d.ts +504 -3
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +2456 -7
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +43 -8
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +59 -19
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +3 -3
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/PushStatusResolver.js +1 -1
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +123 -48
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +293 -305
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +16 -0
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/globalCors.d.ts +33 -0
- package/dist/globalCors.d.ts.map +1 -0
- package/dist/globalCors.js +58 -0
- package/dist/globalCors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +219 -278
- package/dist/index.js.map +1 -1
- package/dist/isolatedProvider.d.ts +20 -0
- package/dist/isolatedProvider.d.ts.map +1 -0
- package/dist/isolatedProvider.js +22 -0
- package/dist/isolatedProvider.js.map +1 -0
- package/dist/multiTenancy/index.d.ts.map +1 -1
- package/dist/multiTenancy/index.js +22 -2
- package/dist/multiTenancy/index.js.map +1 -1
- package/dist/realtimeProxy/RealtimeProxyServer.d.ts +44 -4
- package/dist/realtimeProxy/RealtimeProxyServer.d.ts.map +1 -1
- package/dist/realtimeProxy/RealtimeProxyServer.js +121 -16
- package/dist/realtimeProxy/RealtimeProxyServer.js.map +1 -1
- package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts +171 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts.map +1 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.js +532 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.js.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.d.ts +148 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.js +191 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.js.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts +66 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js +139 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts +38 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.js +99 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts +100 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts.map +1 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.js +173 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.js.map +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts +61 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js +149 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts +57 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts.map +1 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.js +69 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.js.map +1 -0
- package/dist/realtimeSessions/index.d.ts +19 -0
- package/dist/realtimeSessions/index.d.ts.map +1 -0
- package/dist/realtimeSessions/index.js +19 -0
- package/dist/realtimeSessions/index.js.map +1 -0
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts +30 -0
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js +47 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
- package/dist/realtimeSessions/sessionAccess.d.ts +92 -0
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -0
- package/dist/realtimeSessions/sessionAccess.js +94 -0
- package/dist/realtimeSessions/sessionAccess.js.map +1 -0
- package/dist/realtimeSessions/sessionConfigStamps.d.ts +70 -0
- package/dist/realtimeSessions/sessionConfigStamps.d.ts.map +1 -0
- package/dist/realtimeSessions/sessionConfigStamps.js +93 -0
- package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -0
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts +65 -0
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -0
- package/dist/realtimeSessions/subscriptionAuthorization.js +71 -0
- package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -0
- package/dist/realtimeSessions/verificationCore.d.ts +243 -0
- package/dist/realtimeSessions/verificationCore.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationCore.js +356 -0
- package/dist/realtimeSessions/verificationCore.js.map +1 -0
- package/dist/realtimeSessions/verificationPages.d.ts +66 -0
- package/dist/realtimeSessions/verificationPages.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationPages.js +110 -0
- package/dist/realtimeSessions/verificationPages.js.map +1 -0
- package/dist/realtimeSessions/verificationPolicy.d.ts +147 -0
- package/dist/realtimeSessions/verificationPolicy.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationPolicy.js +249 -0
- package/dist/realtimeSessions/verificationPolicy.js.map +1 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts +263 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationWorkflow.js +435 -0
- package/dist/realtimeSessions/verificationWorkflow.js.map +1 -0
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +20 -2
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +31 -2
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +31 -5
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +75 -14
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts +14 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +21 -5
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts +5 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.js +9 -7
- package/dist/resolvers/ArtifactFileResolver.js.map +1 -1
- package/dist/resolvers/CacheStatsResolver.d.ts +27 -0
- package/dist/resolvers/CacheStatsResolver.d.ts.map +1 -1
- package/dist/resolvers/CacheStatsResolver.js +113 -2
- package/dist/resolvers/CacheStatsResolver.js.map +1 -1
- package/dist/resolvers/ClientToolRequestResolver.d.ts +4 -2
- package/dist/resolvers/ClientToolRequestResolver.d.ts.map +1 -1
- package/dist/resolvers/ClientToolRequestResolver.js +28 -10
- package/dist/resolvers/ClientToolRequestResolver.js.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.d.ts +8 -4
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.js +6 -6
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
- package/dist/resolvers/DatasetResolver.d.ts +24 -3
- package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
- package/dist/resolvers/DatasetResolver.js +57 -8
- package/dist/resolvers/DatasetResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +3 -2
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +27 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +148 -2
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +82 -11
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +279 -101
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
- package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js +117 -38
- package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +6 -3
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/HumanHandoffResolver.d.ts.map +1 -1
- package/dist/resolvers/HumanHandoffResolver.js +7 -1
- package/dist/resolvers/HumanHandoffResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +4 -2
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +9 -4
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts +2 -0
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +13 -0
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts +54 -2
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +155 -10
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +157 -33
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +404 -116
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RealtimeSessionEventsResolver.d.ts +61 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.d.ts.map +1 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.js +130 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.js.map +1 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts +85 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts.map +1 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.js +188 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.js.map +1 -0
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +2 -0
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +5 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +10 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +100 -14
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +12 -11
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts +12 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.js +15 -2
- package/dist/resolvers/SearchKnowledgeStreamResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +2 -3
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +6 -2
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts +2 -0
- package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.js +23 -6
- package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts +2 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.js +28 -1
- package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.d.ts +24 -0
- package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.js +65 -13
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +19 -2
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +102 -24
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserAvatarResolver.d.ts +16 -0
- package/dist/resolvers/UserAvatarResolver.d.ts.map +1 -0
- package/dist/resolvers/UserAvatarResolver.js +124 -0
- package/dist/resolvers/UserAvatarResolver.js.map +1 -0
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +2 -17
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/resolvers/agent-run-data-guard.d.ts +31 -0
- package/dist/resolvers/agent-run-data-guard.d.ts.map +1 -0
- package/dist/resolvers/agent-run-data-guard.js +72 -0
- package/dist/resolvers/agent-run-data-guard.js.map +1 -0
- package/dist/resolvers/agentVisionConsentAudit.d.ts +37 -0
- package/dist/resolvers/agentVisionConsentAudit.d.ts.map +1 -0
- package/dist/resolvers/agentVisionConsentAudit.js +63 -0
- package/dist/resolvers/agentVisionConsentAudit.js.map +1 -0
- package/dist/resolvers/avatarInputValidation.d.ts +40 -0
- package/dist/resolvers/avatarInputValidation.d.ts.map +1 -0
- package/dist/resolvers/avatarInputValidation.js +97 -0
- package/dist/resolvers/avatarInputValidation.js.map +1 -0
- package/dist/resolvers/currentUserRoles.d.ts +29 -0
- package/dist/resolvers/currentUserRoles.d.ts.map +1 -1
- package/dist/resolvers/currentUserRoles.js +30 -0
- package/dist/resolvers/currentUserRoles.js.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.d.ts +6 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.js +21 -0
- package/dist/resolvers/meetings/meetingMutations.js.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.d.ts +49 -0
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -0
- package/dist/rest/RealtimeRecordingHandler.js +383 -0
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -0
- package/dist/rest/ViewOperationsHandler.d.ts +3 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +21 -12
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +6 -0
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +6 -0
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverExtensionReservedRoots.d.ts +12 -10
- package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
- package/dist/serverExtensionReservedRoots.js +14 -17
- package/dist/serverExtensionReservedRoots.js.map +1 -1
- package/dist/services/MJStorageBlobStore.d.ts +8 -1
- package/dist/services/MJStorageBlobStore.d.ts.map +1 -1
- package/dist/services/MJStorageBlobStore.js +25 -19
- package/dist/services/MJStorageBlobStore.js.map +1 -1
- package/dist/services/StartTaskGraphDispatcher.js +2 -2
- package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +5 -3
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +27 -5
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphAgentRunner.d.ts +14 -2
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +157 -9
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +57 -4
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +607 -18
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/sharedCache.d.ts +105 -0
- package/dist/sharedCache.d.ts.map +1 -0
- package/dist/sharedCache.js +279 -0
- package/dist/sharedCache.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +99 -96
- package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
- package/src/__tests__/AdhocQueryResolver.sqlAuthorizer.test.ts +104 -0
- package/src/__tests__/BridgeHostInstance.test.ts +232 -0
- package/src/__tests__/ClientToolRequestResolver.test.ts +116 -0
- package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
- package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +433 -0
- package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
- package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
- package/src/__tests__/HostInstance.test.ts +84 -0
- package/src/__tests__/HumanHandoffResolver.test.ts +17 -0
- package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
- package/src/__tests__/LoginScreenEngine.test.ts +86 -0
- package/src/__tests__/MJStorageBlobStore.storageGate.test.ts +63 -0
- package/src/__tests__/MeetingResolver.test.ts +75 -1
- package/src/__tests__/RealtimeBridgeResolver.test.ts +415 -6
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +383 -0
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +682 -58
- package/src/__tests__/RealtimeProxyServer.test.ts +16 -1
- package/src/__tests__/RealtimeRelay.test.ts +876 -0
- package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
- package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
- package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
- package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
- package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +212 -6
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
- package/src/__tests__/ReturningVisitorRecap.test.ts +115 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +170 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +6 -4
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +258 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +166 -0
- package/src/__tests__/RunTemplateResolver.test.ts +132 -0
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +63 -0
- package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
- package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
- package/src/__tests__/SessionJanitor.test.ts +1203 -21
- package/src/__tests__/SessionManager.test.ts +240 -17
- package/src/__tests__/SessionRunIDVerifier.test.ts +251 -0
- package/src/__tests__/SyncRolesUsersResolver.userRoles.test.ts +97 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
- package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +403 -22
- package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
- package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
- package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
- package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
- package/src/__tests__/UserAvatarResolver.test.ts +255 -0
- package/src/__tests__/UserResolver.currentUser.test.ts +16 -1
- package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
- package/src/__tests__/actionAuthorization.test.ts +130 -0
- package/src/__tests__/agent-run-data-guard.test.ts +130 -0
- package/src/__tests__/agentVisionConsentAudit.test.ts +118 -0
- package/src/__tests__/apiRootBoot.test.ts +202 -0
- package/src/__tests__/avatarInputValidation.test.ts +160 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +64 -0
- package/src/__tests__/conversationRunEvents.test.ts +56 -14
- package/src/__tests__/globalCors.test.ts +217 -0
- package/src/__tests__/isolatedProviderTransactions.test.ts +169 -0
- package/src/__tests__/magicLinkService.consume.test.ts +6 -0
- package/src/__tests__/magicLinkService.provisionLog.test.ts +5 -0
- package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
- package/src/__tests__/multiTenancy.security.test.ts +51 -0
- package/src/__tests__/multiTenancy.test.ts +1 -1
- package/src/__tests__/newUsers.template.test.ts +151 -0
- package/src/__tests__/newUsers.test.ts +74 -5
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +17 -2
- package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +7 -0
- package/src/__tests__/realtimeRecordingHandler.test.ts +652 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventService.test.ts +201 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +215 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionVerificationResolver.test.ts +102 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionVerificationService.test.ts +349 -0
- package/src/__tests__/realtimeSessions/RealtimeVerifyRouter.test.ts +131 -0
- package/src/__tests__/realtimeSessions/SlidingWindowRateLimiter.test.ts +56 -0
- package/src/__tests__/realtimeSessions/helpers.ts +4 -0
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +129 -0
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +124 -0
- package/src/__tests__/realtimeSessions/verificationCore.test.ts +355 -0
- package/src/__tests__/realtimeSessions/verificationPages.test.ts +84 -0
- package/src/__tests__/realtimeSessions/verificationPolicy.test.ts +226 -0
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +633 -0
- package/src/__tests__/resolverBase.fls.test.ts +87 -4
- package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
- package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -96
- package/src/__tests__/sharedCache.test.ts +312 -0
- package/src/__tests__/widgetGuestElevation.test.ts +44 -0
- package/src/agentSessions/BridgeHostInstance.ts +32 -0
- package/src/agentSessions/HostInstance.ts +124 -28
- package/src/agentSessions/ReturningVisitorRecap.ts +7 -3
- package/src/agentSessions/SessionJanitor.ts +821 -59
- package/src/agentSessions/SessionManager.ts +138 -26
- package/src/agentSessions/SessionRunIDVerifier.ts +171 -0
- package/src/agentSessions/index.ts +10 -3
- package/src/apiRoot.ts +78 -0
- package/src/auth/AuthProviderCatalogRouter.ts +26 -0
- package/src/auth/LoginScreenEngine.ts +50 -0
- package/src/auth/actionAuthorization.ts +116 -0
- package/src/auth/index.ts +4 -8
- package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
- package/src/auth/magicLink/MagicLinkService.ts +6 -3
- package/src/auth/newUsers.ts +99 -11
- package/src/config.ts +171 -5
- package/src/context.ts +15 -10
- package/src/coreRoutes.ts +166 -0
- package/src/generated/graphql-schemas/__mj.ts +1815 -57
- package/src/generic/CacheInvalidationResolver.ts +73 -18
- package/src/generic/OrphanedConversationDetailReconciler.ts +3 -3
- package/src/generic/PushStatusResolver.ts +1 -1
- package/src/generic/ResolverBase.ts +335 -326
- package/src/generic/RunViewResolver.ts +21 -0
- package/src/globalCors.ts +71 -0
- package/src/index.ts +231 -300
- package/src/isolatedProvider.ts +22 -0
- package/src/multiTenancy/index.ts +24 -2
- package/src/realtimeProxy/RealtimeProxyServer.ts +148 -16
- package/src/realtimeProxy/RealtimeRelayTunnel.ts +645 -0
- package/src/realtimeSessions/README.md +179 -0
- package/src/realtimeSessions/RealtimeSessionEventService.ts +274 -0
- package/src/realtimeSessions/RealtimeSessionVerificationService.ts +168 -0
- package/src/realtimeSessions/RealtimeVerifyRouter.ts +109 -0
- package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +189 -0
- package/src/realtimeSessions/SlidingWindowRateLimiter.ts +92 -0
- package/src/realtimeSessions/index.ts +18 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +55 -0
- package/src/realtimeSessions/sessionAccess.ts +145 -0
- package/src/realtimeSessions/sessionConfigStamps.ts +123 -0
- package/src/realtimeSessions/subscriptionAuthorization.ts +116 -0
- package/src/realtimeSessions/verificationCore.ts +502 -0
- package/src/realtimeSessions/verificationPages.ts +149 -0
- package/src/realtimeSessions/verificationPolicy.ts +321 -0
- package/src/realtimeSessions/verificationWorkflow.ts +702 -0
- package/src/realtimeWidget/widgetGuestElevation.ts +34 -2
- package/src/resolvers/ActionResolver.ts +84 -21
- package/src/resolvers/AdhocQueryResolver.ts +24 -6
- package/src/resolvers/ArtifactFileResolver.ts +9 -8
- package/src/resolvers/CacheStatsResolver.ts +89 -2
- package/src/resolvers/ClientToolRequestResolver.ts +25 -7
- package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
- package/src/resolvers/DatasetResolver.ts +70 -10
- package/src/resolvers/EntityRecordNameResolver.ts +3 -2
- package/src/resolvers/FetchEntityVectorsResolver.ts +179 -2
- package/src/resolvers/FileResolver.ts +321 -106
- package/src/resolvers/GetDataContextDataResolver.ts +139 -41
- package/src/resolvers/GetDataResolver.ts +6 -3
- package/src/resolvers/HumanHandoffResolver.ts +8 -0
- package/src/resolvers/IntegrationDiscoveryResolver.ts +4 -2
- package/src/resolvers/MCPResolver.ts +8 -5
- package/src/resolvers/QueryResolver.ts +11 -0
- package/src/resolvers/RealtimeBridgeResolver.ts +163 -11
- package/src/resolvers/RealtimeClientSessionResolver.ts +511 -129
- package/src/resolvers/RealtimeSessionEventsResolver.ts +133 -0
- package/src/resolvers/RealtimeSessionVerificationResolver.ts +174 -0
- package/src/resolvers/RemoteBrowserActionResolver.ts +11 -1
- package/src/resolvers/RunAIAgentResolver.ts +116 -14
- package/src/resolvers/RunTemplateResolver.ts +13 -12
- package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
- package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
- package/src/resolvers/SyncDataResolver.ts +6 -2
- package/src/resolvers/SyncRolesUsersResolver.ts +24 -6
- package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
- package/src/resolvers/TestQuerySQLResolver.ts +68 -13
- package/src/resolvers/TransactionGroupResolver.ts +131 -27
- package/src/resolvers/UserAvatarResolver.ts +111 -0
- package/src/resolvers/UserResolver.ts +2 -16
- package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
- package/src/resolvers/agent-run-data-guard.ts +89 -0
- package/src/resolvers/agentVisionConsentAudit.ts +82 -0
- package/src/resolvers/avatarInputValidation.ts +123 -0
- package/src/resolvers/currentUserRoles.ts +32 -1
- package/src/resolvers/meetings/meetingMutations.ts +21 -0
- package/src/rest/RealtimeRecordingHandler.ts +464 -0
- package/src/rest/ViewOperationsHandler.ts +29 -13
- package/src/rest/setupRESTEndpoints.ts +6 -0
- package/src/serverExtensionReservedRoots.ts +14 -17
- package/src/services/MJStorageBlobStore.ts +31 -30
- package/src/services/StartTaskGraphDispatcher.ts +2 -2
- package/src/services/TaskGraphActionRunner.ts +25 -5
- package/src/services/TaskGraphAgentRunner.ts +188 -11
- package/src/services/TaskGraphContinuationDeliverer.ts +713 -17
- package/src/sharedCache.ts +305 -0
- package/src/types.ts +7 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// ResolverBase transitively pulls in type-graphql decorators, which need the
|
|
2
|
+
// Reflect.metadata polyfill at import time.
|
|
3
|
+
import 'reflect-metadata';
|
|
4
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
5
|
+
import { CompositeKey, DatabaseProviderBase, EntityInfo, EntityPermissionType, Metadata, RowLevelSecurityFilterInfo, UserInfo } from '@memberjunction/core';
|
|
6
|
+
import type { DeleteSQLResult, IMetadataProvider, QueryExecutionSpec, RunQueryResult, SaveSQLResult } from '@memberjunction/core';
|
|
7
|
+
import { EntityRecordNameResolver } from '../resolvers/EntityRecordNameResolver.js';
|
|
8
|
+
import type { AppContext, UserPayload } from '../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The record-name queries against a real provider whose database only records what it is sent.
|
|
12
|
+
* The lookup the resolver causes carries the acting user's read row filter, binds the key value,
|
|
13
|
+
* refuses a key that is not the entity's primary key, and never runs without an acting user.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const CLIENTS_ID = 'E0000000-0000-0000-0000-0000000000C1';
|
|
17
|
+
const ACCOUNT_MANAGER_ROLE_ID = 'B0000000-0000-0000-0000-0000000000C1';
|
|
18
|
+
const OWN_CLIENTS_FILTER_ID = 'F0000000-0000-0000-0000-0000000000C1';
|
|
19
|
+
const MANAGER_ID = 'C0000000-0000-0000-0000-0000000000C1';
|
|
20
|
+
const CLIENT_ID_VALUE = '33333333-3333-3333-3333-333333333333';
|
|
21
|
+
|
|
22
|
+
const ROW_FILTERS: RowLevelSecurityFilterInfo[] = [
|
|
23
|
+
new RowLevelSecurityFilterInfo({ ID: OWN_CLIENTS_FILTER_ID, Name: 'Own clients', FilterText: "AccountManagerID = '{{UserID}}'" }),
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/** `Clients`: account managers read only the clients they manage. */
|
|
27
|
+
function clientsEntity(): EntityInfo {
|
|
28
|
+
return new EntityInfo({
|
|
29
|
+
ID: CLIENTS_ID, Name: 'Clients', SchemaName: 'dbo', BaseTable: 'Client', BaseView: 'vwClients',
|
|
30
|
+
Permissions: [
|
|
31
|
+
{ ID: 'perm-manager', EntityID: CLIENTS_ID, RoleID: ACCOUNT_MANAGER_ROLE_ID, CanRead: true, ReadRLSFilterID: OWN_CLIENTS_FILTER_ID, Type: 'Allow' },
|
|
32
|
+
],
|
|
33
|
+
Fields: [
|
|
34
|
+
{ ID: 'cl-id', EntityID: CLIENTS_ID, Sequence: 1, Name: 'ID', Type: 'uniqueidentifier', IsPrimaryKey: true, NeedsQuotes: true },
|
|
35
|
+
{ ID: 'cl-name', EntityID: CLIENTS_ID, Sequence: 2, Name: 'Name', Type: 'nvarchar', IsNameField: true, NeedsQuotes: true },
|
|
36
|
+
{ ID: 'cl-tier', EntityID: CLIENTS_ID, Sequence: 3, Name: 'Tier', Type: 'int', NeedsQuotes: false },
|
|
37
|
+
{ ID: 'cl-manager', EntityID: CLIENTS_ID, Sequence: 4, Name: 'AccountManagerID', Type: 'uniqueidentifier', NeedsQuotes: true },
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface SentQuery {
|
|
43
|
+
SQL: string;
|
|
44
|
+
Parameters: unknown[] | undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** A SQL Server-shaped provider over `Clients`, whose database answers every query with one row. */
|
|
48
|
+
class RecordingProvider extends DatabaseProviderBase {
|
|
49
|
+
public Sent: SentQuery[] = [];
|
|
50
|
+
private readonly entities = [clientsEntity()];
|
|
51
|
+
|
|
52
|
+
public override get Entities(): EntityInfo[] {
|
|
53
|
+
return this.entities;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public override get RowLevelSecurityFilters(): RowLevelSecurityFilterInfo[] {
|
|
57
|
+
return ROW_FILTERS;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async ExecuteSQL<T>(sql: string, parameters?: unknown[]): Promise<Array<T>> {
|
|
61
|
+
this.Sent.push({ SQL: sql, Parameters: parameters });
|
|
62
|
+
return [{ Name: 'Acme Manufacturing' }] as T[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public override BuildParameterPlaceholder(index: number): string { return `@p${index}`; }
|
|
66
|
+
protected get UUIDFunctionPattern(): RegExp { return /^newid\(\)$/i; }
|
|
67
|
+
protected get DBDefaultFunctionPattern(): RegExp { return /^getdate\(\)$/i; }
|
|
68
|
+
public QuoteIdentifier(name: string): string { return `[${name}]`; }
|
|
69
|
+
public QuoteSchemaAndView(schema: string, obj: string): string { return `[${schema}].[${obj}]`; }
|
|
70
|
+
protected BuildChildDiscoverySQL(): string { return ''; }
|
|
71
|
+
protected BuildHardLinkDependencySQL(): string { return ''; }
|
|
72
|
+
protected BuildSoftLinkDependencySQL(): string { return ''; }
|
|
73
|
+
protected async GenerateSaveSQL(): Promise<SaveSQLResult> { return { fullSQL: '' }; }
|
|
74
|
+
protected GenerateDeleteSQL(): DeleteSQLResult { return { fullSQL: '' }; }
|
|
75
|
+
protected BuildRecordChangeSQL(): { sql: string; parameters?: unknown[] } | null { return null; }
|
|
76
|
+
protected BuildSiblingRecordChangeSQL(): string { return ''; }
|
|
77
|
+
async BeginTransaction(): Promise<void> {}
|
|
78
|
+
async CommitTransaction(): Promise<void> {}
|
|
79
|
+
async RollbackTransaction(): Promise<void> {}
|
|
80
|
+
protected async InternalExecuteQueryFromSpec(_spec: QueryExecutionSpec): Promise<RunQueryResult> {
|
|
81
|
+
throw new Error('Not supported.');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const MANAGER = new UserInfo(null, {
|
|
86
|
+
ID: MANAGER_ID, Name: 'Morgan', Email: 'morgan@example.com', IsActive: true,
|
|
87
|
+
UserRoles: [{ UserID: MANAGER_ID, RoleID: ACCOUNT_MANAGER_ROLE_ID, Role: 'Account Managers' }],
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
function key(fieldName: string, value: string): CompositeKey {
|
|
91
|
+
return new CompositeKey([{ FieldName: fieldName, Value: value }]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
describe('EntityRecordNameResolver lookups under row-level security', () => {
|
|
95
|
+
let provider: RecordingProvider;
|
|
96
|
+
let savedProvider: IMetadataProvider;
|
|
97
|
+
let context: AppContext;
|
|
98
|
+
const resolver = new EntityRecordNameResolver();
|
|
99
|
+
|
|
100
|
+
beforeEach(() => {
|
|
101
|
+
provider = new RecordingProvider();
|
|
102
|
+
// Row filters resolve through the global provider.
|
|
103
|
+
savedProvider = Metadata.Provider;
|
|
104
|
+
Metadata.Provider = provider;
|
|
105
|
+
const userPayload: UserPayload = { email: MANAGER.Email, userRecord: MANAGER, sessionId: 'session-1' };
|
|
106
|
+
context = { dataSource: undefined, dataSources: [], providers: [{ provider, type: 'Read-Only' }], userPayload };
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
afterEach(() => {
|
|
110
|
+
Metadata.Provider = savedProvider;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
function managerRowFilter(): string {
|
|
114
|
+
return provider.EntityByName('Clients').GetEffectiveRowFilterWhereClause(MANAGER, EntityPermissionType.Read, '');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
it("looks the name up under the acting user's read row filter, with the key value bound", async () => {
|
|
118
|
+
const rowFilter = managerRowFilter();
|
|
119
|
+
expect(rowFilter).toContain(MANAGER_ID);
|
|
120
|
+
|
|
121
|
+
const result = await resolver.GetEntityRecordName('Clients', key('ID', CLIENT_ID_VALUE), context);
|
|
122
|
+
|
|
123
|
+
expect(result.Success).toBe(true);
|
|
124
|
+
expect(provider.Sent).toEqual([
|
|
125
|
+
{ SQL: `SELECT [Name] FROM [dbo].[vwClients] WHERE [ID]=@p0 AND (${rowFilter})`, Parameters: [CLIENT_ID_VALUE] },
|
|
126
|
+
]);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('applies the row filter to each item of a batch', async () => {
|
|
130
|
+
const rowFilter = managerRowFilter();
|
|
131
|
+
|
|
132
|
+
const results = await resolver.GetEntityRecordNames([{ EntityName: 'Clients', CompositeKey: key('ID', CLIENT_ID_VALUE) }], context);
|
|
133
|
+
|
|
134
|
+
expect(results.map(r => r.Success)).toEqual([true]);
|
|
135
|
+
expect(provider.Sent.map(q => q.SQL)).toEqual([`SELECT [Name] FROM [dbo].[vwClients] WHERE [ID]=@p0 AND (${rowFilter})`]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('refuses a key field that is not a primary key, without querying', async () => {
|
|
139
|
+
const result = await resolver.GetEntityRecordName('Clients', key('Tier', '1'), context);
|
|
140
|
+
|
|
141
|
+
expect(result.Success).toBe(false);
|
|
142
|
+
expect(result.RecordName).toBeUndefined();
|
|
143
|
+
expect(provider.Sent).toHaveLength(0);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('looks no name up when there is no acting user', async () => {
|
|
147
|
+
const result = await resolver.InnerGetEntityRecordName(provider, 'Clients', key('ID', CLIENT_ID_VALUE));
|
|
148
|
+
|
|
149
|
+
expect(result.Success).toBe(false);
|
|
150
|
+
expect(provider.Sent).toHaveLength(0);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
3
|
+
import { UserInfo, type DatabaseProviderBase, type EntityInfo, type RunViewParams } from '@memberjunction/core';
|
|
4
|
+
import { MJGlobal } from '@memberjunction/global';
|
|
5
|
+
import type { VectorDBBase } from '@memberjunction/ai-vectordb';
|
|
6
|
+
|
|
7
|
+
type ViewResult = { Success: boolean; Results: unknown[]; ErrorMessage?: string };
|
|
8
|
+
type RunViewHandler = (params: RunViewParams, contextUser: UserInfo | undefined) => ViewResult;
|
|
9
|
+
|
|
10
|
+
// Vitest's transform emits no decorator metadata, so type-graphql can't infer field types —
|
|
11
|
+
// stub the decorators; these tests exercise the resolver method, not the schema.
|
|
12
|
+
vi.mock('type-graphql', () => {
|
|
13
|
+
const decoratorFactory = (..._args: unknown[]) => (..._decorated: unknown[]) => undefined;
|
|
14
|
+
const exportNames = [
|
|
15
|
+
'Resolver', 'Query', 'Mutation', 'Subscription', 'Arg', 'Args', 'ArgsType', 'Ctx', 'Root',
|
|
16
|
+
'Info', 'Field', 'FieldResolver', 'ObjectType', 'InputType', 'InterfaceType', 'Authorized',
|
|
17
|
+
'UseMiddleware', 'Extensions', 'Directive', 'ID', 'Int', 'Float', 'GraphQLISODateTime',
|
|
18
|
+
'GraphQLTimestamp', 'registerEnumType', 'createMethodDecorator', 'createParamDecorator',
|
|
19
|
+
'buildSchema', 'buildSchemaSync', 'PubSub',
|
|
20
|
+
];
|
|
21
|
+
return Object.fromEntries(exportNames.map((name) => [name, decoratorFactory]));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const runViewCalls: Array<{ params: RunViewParams; contextUser: UserInfo | undefined }> = [];
|
|
25
|
+
/** Each RunViews call, as the list of entity names it batched. */
|
|
26
|
+
const runViewsBatches: string[][] = [];
|
|
27
|
+
let runViewHandler: RunViewHandler = () => ({ Success: true, Results: [] });
|
|
28
|
+
|
|
29
|
+
vi.mock('@memberjunction/core', async (importOriginal) => {
|
|
30
|
+
const actual = await importOriginal<typeof import('@memberjunction/core')>();
|
|
31
|
+
class MockRunView {
|
|
32
|
+
async RunView(params: RunViewParams, contextUser?: UserInfo): Promise<ViewResult> {
|
|
33
|
+
runViewCalls.push({ params, contextUser });
|
|
34
|
+
return runViewHandler(params, contextUser);
|
|
35
|
+
}
|
|
36
|
+
async RunViews(params: RunViewParams[], contextUser?: UserInfo): Promise<ViewResult[]> {
|
|
37
|
+
runViewsBatches.push(params.map((p) => p.EntityName ?? ''));
|
|
38
|
+
return Promise.all(params.map((p) => this.RunView(p, contextUser)));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { ...actual, RunView: MockRunView, LogStatus: () => undefined, LogError: () => undefined };
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// GetAIAPIKey resolves through the ClassFactory too; keep it off the CreateInstance spy below.
|
|
45
|
+
vi.mock('@memberjunction/ai', async (importOriginal) => {
|
|
46
|
+
const actual = await importOriginal<typeof import('@memberjunction/ai')>();
|
|
47
|
+
return { ...actual, GetAIAPIKey: () => 'test-key' };
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
vi.mock('@memberjunction/aiengine', async (importOriginal) => {
|
|
51
|
+
const actual = await importOriginal<typeof import('@memberjunction/aiengine')>();
|
|
52
|
+
return { ...actual, AIEngine: { Instance: { GetProviderIndexName: () => 'provider-index-name' } } };
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
import { FetchEntityVectorsResolver } from '../resolvers/FetchEntityVectorsResolver.js';
|
|
56
|
+
import type { AppContext } from '../types.js';
|
|
57
|
+
|
|
58
|
+
/* ───── fixtures ───── */
|
|
59
|
+
|
|
60
|
+
const DOC_ID = 'DOC-1';
|
|
61
|
+
const contextUser = new UserInfo();
|
|
62
|
+
|
|
63
|
+
const membersEntity = {
|
|
64
|
+
Name: 'Members',
|
|
65
|
+
PrimaryKeys: [{ Name: 'ID' }],
|
|
66
|
+
Fields: [
|
|
67
|
+
{ Name: 'ID', IsNameField: false },
|
|
68
|
+
{ Name: 'FirstName', IsNameField: true },
|
|
69
|
+
{ Name: 'LastName', IsNameField: true },
|
|
70
|
+
{ Name: 'Email', IsNameField: false },
|
|
71
|
+
],
|
|
72
|
+
NameField: undefined,
|
|
73
|
+
} as unknown as EntityInfo;
|
|
74
|
+
|
|
75
|
+
const orderLinesEntity = {
|
|
76
|
+
Name: 'Order Lines',
|
|
77
|
+
PrimaryKeys: [{ Name: 'OrderID' }, { Name: 'LineNo' }],
|
|
78
|
+
Fields: [
|
|
79
|
+
{ Name: 'OrderID', IsNameField: false },
|
|
80
|
+
{ Name: 'LineNo', IsNameField: false },
|
|
81
|
+
{ Name: 'Description', IsNameField: false },
|
|
82
|
+
],
|
|
83
|
+
NameField: { Name: 'Description' },
|
|
84
|
+
} as unknown as EntityInfo;
|
|
85
|
+
|
|
86
|
+
function fakeVectorDB(queryKeyIsEntityDocumentID: boolean) {
|
|
87
|
+
const queryIndex = vi.fn().mockResolvedValue({
|
|
88
|
+
success: true,
|
|
89
|
+
data: { matches: [{ id: 'pc-1', values: [0.5, 0.5], metadata: { Entity: 'Members', RecordID: 'a' } }] },
|
|
90
|
+
});
|
|
91
|
+
const db = { QueryKeyIsEntityDocumentID: queryKeyIsEntityDocumentID, QueryIndex: queryIndex } as unknown as VectorDBBase;
|
|
92
|
+
return { db, queryIndex };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function appContext(entityInfo: EntityInfo): AppContext {
|
|
96
|
+
const provider = { EntityByName: (name: string) => (name === entityInfo.Name ? entityInfo : undefined) } as unknown as DatabaseProviderBase;
|
|
97
|
+
return {
|
|
98
|
+
userPayload: { email: 'test@example.com', sessionId: 's', userRecord: contextUser },
|
|
99
|
+
providers: [{ type: 'Read-Only', provider }],
|
|
100
|
+
} as unknown as AppContext;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Route RunView by entity: the doc → index → database lookups, then the case-specific views. */
|
|
104
|
+
function routeViews(entityName: string, views: Record<string, (params: RunViewParams) => ViewResult>): void {
|
|
105
|
+
runViewHandler = (params) => {
|
|
106
|
+
switch (params.EntityName) {
|
|
107
|
+
case 'MJ: Entity Documents':
|
|
108
|
+
return { Success: true, Results: [{ ID: DOC_ID, Name: 'Doc', Entity: entityName, VectorIndexID: 'VI-1' }] };
|
|
109
|
+
case 'MJ: Vector Indexes':
|
|
110
|
+
return { Success: true, Results: [{ ID: 'VI-1', Name: 'Index', VectorDatabaseID: 'VDB-1', Dimensions: 2 }] };
|
|
111
|
+
case 'MJ: Vector Databases':
|
|
112
|
+
return { Success: true, Results: [{ ID: 'VDB-1', ClassKey: 'TestVectorDB' }] };
|
|
113
|
+
default: {
|
|
114
|
+
const view = views[params.EntityName ?? ''];
|
|
115
|
+
return view ? view(params) : { Success: false, Results: [], ErrorMessage: `unexpected view ${params.EntityName}` };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const storedRows = [
|
|
122
|
+
{ ID: 'ERD-1', RecordID: 'AAA', VectorJSON: '[0.1,0.2]' },
|
|
123
|
+
{ ID: 'ERD-2', RecordID: 'bbb', VectorJSON: '[0.3,0.4]' },
|
|
124
|
+
{ ID: 'ERD-3', RecordID: 'ccc', VectorJSON: '[0.5,0.6]' },
|
|
125
|
+
];
|
|
126
|
+
const memberRows = [
|
|
127
|
+
{ ID: 'aaa', FirstName: 'Ada', LastName: 'Lovelace' },
|
|
128
|
+
{ ID: 'bbb', FirstName: 'Grace', LastName: 'Hopper' },
|
|
129
|
+
{ ID: 'ccc', FirstName: 'Alan', LastName: null },
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* A fake `MJ: Entity Record Documents` view over `rows`: returns only the requested `Fields`, and
|
|
134
|
+
* only the rows named by an `ID IN ('a','b')` filter when one is given.
|
|
135
|
+
*/
|
|
136
|
+
function erdView(rows: Array<Record<string, string>>) {
|
|
137
|
+
return (params: RunViewParams): ViewResult => {
|
|
138
|
+
const idList = /^ID IN \((.*)\)$/.exec(params.ExtraFilter ?? '');
|
|
139
|
+
const ids = idList ? new Set(idList[1].split(',').map((v) => v.trim().replace(/^'|'$/g, ''))) : undefined;
|
|
140
|
+
const picked = ids ? rows.filter((r) => ids.has(r.ID)) : rows;
|
|
141
|
+
const fields = params.Fields ?? Object.keys(rows[0] ?? {});
|
|
142
|
+
return { Success: true, Results: picked.map((r) => Object.fromEntries(fields.map((f) => [f, r[f]]))) };
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** The VectorJSON fetches: Entity Record Documents views filtered by ID. */
|
|
147
|
+
function vectorFetches() {
|
|
148
|
+
return callsFor('MJ: Entity Record Documents').filter((c) => c.params.ExtraFilter?.startsWith('ID IN ('));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function callsFor(entityName: string) {
|
|
152
|
+
return runViewCalls.filter((c) => c.params.EntityName === entityName);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* ───── tests ───── */
|
|
156
|
+
|
|
157
|
+
describe('FetchEntityVectorsResolver', () => {
|
|
158
|
+
let createInstanceSpy: ReturnType<typeof vi.spyOn>;
|
|
159
|
+
|
|
160
|
+
beforeEach(() => {
|
|
161
|
+
runViewCalls.length = 0;
|
|
162
|
+
runViewsBatches.length = 0;
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
afterEach(() => {
|
|
166
|
+
createInstanceSpy?.mockRestore();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
function useVectorDB(queryKeyIsEntityDocumentID: boolean) {
|
|
170
|
+
const fake = fakeVectorDB(queryKeyIsEntityDocumentID);
|
|
171
|
+
createInstanceSpy = vi.spyOn(MJGlobal.Instance.ClassFactory, 'CreateInstance').mockReturnValue(fake.db);
|
|
172
|
+
return fake;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
describe('local vector store (QueryKeyIsEntityDocumentID)', () => {
|
|
176
|
+
it('reads VectorJSON for the document with the context user instead of calling QueryIndex', async () => {
|
|
177
|
+
const { queryIndex } = useVectorDB(true);
|
|
178
|
+
routeViews('Members', {
|
|
179
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
180
|
+
Members: () => ({ Success: true, Results: memberRows }),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, undefined, appContext(membersEntity));
|
|
184
|
+
|
|
185
|
+
expect(result.ErrorMessage).toBeUndefined();
|
|
186
|
+
expect(result.Success).toBe(true);
|
|
187
|
+
expect(queryIndex).not.toHaveBeenCalled();
|
|
188
|
+
expect(result.TotalCount).toBe(3);
|
|
189
|
+
expect(result.Results.map((r) => r.ID)).toEqual(['ERD-1', 'ERD-2', 'ERD-3']);
|
|
190
|
+
expect(result.Results.map((r) => r.Values)).toEqual([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]]);
|
|
191
|
+
|
|
192
|
+
const [listCall, vectorCall] = callsFor('MJ: Entity Record Documents');
|
|
193
|
+
expect(listCall.contextUser).toBe(contextUser);
|
|
194
|
+
expect(listCall.params.ExtraFilter).toBe(`EntityDocumentID='${DOC_ID}' AND VectorJSON IS NOT NULL`);
|
|
195
|
+
expect(listCall.params.Fields).toEqual(['ID', 'RecordID']);
|
|
196
|
+
expect(listCall.params.ResultType).toBe('simple');
|
|
197
|
+
expect(listCall.params.IgnoreMaxRows).toBe(true);
|
|
198
|
+
expect(vectorCall.contextUser).toBe(contextUser);
|
|
199
|
+
expect(vectorCall.params.ExtraFilter).toBe("ID IN ('ERD-1','ERD-2','ERD-3')");
|
|
200
|
+
expect(vectorCall.params.Fields).toEqual(['ID', 'VectorJSON']);
|
|
201
|
+
expect(vectorCall.params.ResultType).toBe('simple');
|
|
202
|
+
expect(vectorCall.params.IgnoreMaxRows).toBe(true);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('bypasses the server RunView cache for both Entity Record Documents views, so Fields is honoured', async () => {
|
|
206
|
+
useVectorDB(true);
|
|
207
|
+
routeViews('Members', {
|
|
208
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
209
|
+
Members: () => ({ Success: true, Results: memberRows }),
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, undefined, appContext(membersEntity));
|
|
213
|
+
|
|
214
|
+
const erdCalls = callsFor('MJ: Entity Record Documents');
|
|
215
|
+
expect(erdCalls).toHaveLength(2);
|
|
216
|
+
expect(erdCalls.map((c) => c.params.BypassCache)).toEqual([true, true]);
|
|
217
|
+
expect(callsFor('Members')[0].params.BypassCache).toBeUndefined();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('labels each item with Entity, RecordID and the record name fields (RecordID matched case-insensitively)', async () => {
|
|
221
|
+
useVectorDB(true);
|
|
222
|
+
routeViews('Members', {
|
|
223
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
224
|
+
Members: () => ({ Success: true, Results: memberRows }),
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, undefined, appContext(membersEntity));
|
|
228
|
+
|
|
229
|
+
expect(result.Results.map((r) => JSON.parse(r.Metadata))).toEqual([
|
|
230
|
+
{ Entity: 'Members', RecordID: 'AAA', FirstName: 'Ada', LastName: 'Lovelace' },
|
|
231
|
+
{ Entity: 'Members', RecordID: 'bbb', FirstName: 'Grace', LastName: 'Hopper' },
|
|
232
|
+
{ Entity: 'Members', RecordID: 'ccc', FirstName: 'Alan' },
|
|
233
|
+
]);
|
|
234
|
+
const [membersCall] = callsFor('Members');
|
|
235
|
+
expect(membersCall.contextUser).toBe(contextUser);
|
|
236
|
+
expect(membersCall.params.Fields).toEqual(['ID', 'FirstName', 'LastName']);
|
|
237
|
+
expect(membersCall.params.ResultType).toBe('simple');
|
|
238
|
+
expect(membersCall.params.ExtraFilter).toBeUndefined();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('honours the filter: passes it to the entity view and drops vectors whose record did not pass', async () => {
|
|
242
|
+
useVectorDB(true);
|
|
243
|
+
const filter = "LastName = 'Hopper'";
|
|
244
|
+
routeViews('Members', {
|
|
245
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
246
|
+
Members: (params) => ({
|
|
247
|
+
Success: true,
|
|
248
|
+
Results: params.ExtraFilter === filter ? memberRows.filter((r) => r.LastName === 'Hopper') : memberRows,
|
|
249
|
+
}),
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, filter, appContext(membersEntity));
|
|
253
|
+
|
|
254
|
+
expect(result.Success).toBe(true);
|
|
255
|
+
expect(callsFor('Members')[0].params.ExtraFilter).toBe(filter);
|
|
256
|
+
expect(result.TotalCount).toBe(1);
|
|
257
|
+
expect(result.Results[0].ID).toBe('ERD-2');
|
|
258
|
+
expect(JSON.parse(result.Results[0].Metadata)).toEqual({ Entity: 'Members', RecordID: 'bbb', FirstName: 'Grace', LastName: 'Hopper' });
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('stops at maxRecords', async () => {
|
|
262
|
+
useVectorDB(true);
|
|
263
|
+
routeViews('Members', {
|
|
264
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
265
|
+
Members: () => ({ Success: true, Results: memberRows }),
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, 2, undefined, appContext(membersEntity));
|
|
269
|
+
|
|
270
|
+
expect(result.Results.map((r) => r.ID)).toEqual(['ERD-1', 'ERD-2']);
|
|
271
|
+
expect(result.TotalCount).toBe(2);
|
|
272
|
+
expect(vectorFetches().map((c) => c.params.ExtraFilter)).toEqual(["ID IN ('ERD-1','ERD-2')"]);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('fetches VectorJSON only for vectors whose record passed the filter', async () => {
|
|
276
|
+
useVectorDB(true);
|
|
277
|
+
const filter = "LastName = 'Hopper'";
|
|
278
|
+
routeViews('Members', {
|
|
279
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
280
|
+
Members: () => ({ Success: true, Results: memberRows.filter((r) => r.LastName === 'Hopper') }),
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, filter, appContext(membersEntity));
|
|
284
|
+
|
|
285
|
+
expect(result.Results.map((r) => r.Values)).toEqual([[0.3, 0.4]]);
|
|
286
|
+
expect(vectorFetches().map((c) => c.params.ExtraFilter)).toEqual(["ID IN ('ERD-2')"]);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('runs no VectorJSON fetch when no stored vector belongs to a readable record', async () => {
|
|
290
|
+
useVectorDB(true);
|
|
291
|
+
routeViews('Members', {
|
|
292
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
293
|
+
Members: () => ({ Success: true, Results: [] }),
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, undefined, appContext(membersEntity));
|
|
297
|
+
|
|
298
|
+
expect(result.Success).toBe(true);
|
|
299
|
+
expect(result.Results).toEqual([]);
|
|
300
|
+
expect(vectorFetches()).toHaveLength(0);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('splits a large VectorJSON fetch into ID lists of at most 1000, sent in one RunViews batch', async () => {
|
|
304
|
+
useVectorDB(true);
|
|
305
|
+
const ids = Array.from({ length: 1500 }, (_, i) => `id-${i}`);
|
|
306
|
+
routeViews('Members', {
|
|
307
|
+
'MJ: Entity Record Documents': erdView(ids.map((id, i) => ({ ID: `ERD-${i}`, RecordID: id, VectorJSON: `[${i}]` }))),
|
|
308
|
+
Members: () => ({ Success: true, Results: ids.map((id) => ({ ID: id, FirstName: id, LastName: null })) }),
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, 1500, undefined, appContext(membersEntity));
|
|
312
|
+
|
|
313
|
+
expect(result.TotalCount).toBe(1500);
|
|
314
|
+
expect(result.Results[1499]).toMatchObject({ ID: 'ERD-1499', Values: [1499] });
|
|
315
|
+
const fetchSizes = vectorFetches().map((c) => (c.params.ExtraFilter ?? '').split(',').length);
|
|
316
|
+
expect(fetchSizes).toEqual([1000, 500]);
|
|
317
|
+
expect(runViewsBatches[1]).toEqual(['MJ: Entity Record Documents', 'MJ: Entity Record Documents']);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('returns an error result when the VectorJSON fetch fails', async () => {
|
|
321
|
+
useVectorDB(true);
|
|
322
|
+
const listing = erdView(storedRows);
|
|
323
|
+
routeViews('Members', {
|
|
324
|
+
'MJ: Entity Record Documents': (params) =>
|
|
325
|
+
params.ExtraFilter?.startsWith('ID IN (') ? { Success: false, Results: [], ErrorMessage: 'deadlock' } : listing(params),
|
|
326
|
+
Members: () => ({ Success: true, Results: memberRows }),
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, undefined, appContext(membersEntity));
|
|
330
|
+
|
|
331
|
+
expect(result.Success).toBe(false);
|
|
332
|
+
expect(result.Results).toEqual([]);
|
|
333
|
+
expect(result.ErrorMessage).toBe('Failed to load vector values: deadlock');
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('matches composite-key records by the compact RecordID segment and falls back to NameField for labels', async () => {
|
|
337
|
+
useVectorDB(true);
|
|
338
|
+
routeViews('Order Lines', {
|
|
339
|
+
'MJ: Entity Record Documents': erdView([{ ID: 'ERD-9', RecordID: 'OrderID|o-1||LineNo|2', VectorJSON: '[1,0]' }]),
|
|
340
|
+
'Order Lines': () => ({ Success: true, Results: [{ OrderID: 'o-1', LineNo: 2, Description: 'Brie wheel' }] }),
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, undefined, appContext(orderLinesEntity));
|
|
344
|
+
|
|
345
|
+
expect(result.Success).toBe(true);
|
|
346
|
+
expect(result.Results).toHaveLength(1);
|
|
347
|
+
expect(JSON.parse(result.Results[0].Metadata)).toEqual({
|
|
348
|
+
Entity: 'Order Lines',
|
|
349
|
+
RecordID: 'OrderID|o-1||LineNo|2',
|
|
350
|
+
Description: 'Brie wheel',
|
|
351
|
+
});
|
|
352
|
+
expect(callsFor('Order Lines')[0].params.Fields).toEqual(['OrderID', 'LineNo', 'Description']);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('returns an error result when the entity records cannot be loaded (e.g. an invalid filter)', async () => {
|
|
356
|
+
useVectorDB(true);
|
|
357
|
+
routeViews('Members', {
|
|
358
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
359
|
+
Members: () => ({ Success: false, Results: [], ErrorMessage: 'bad filter' }),
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, 'nonsense', appContext(membersEntity));
|
|
363
|
+
|
|
364
|
+
expect(result.Success).toBe(false);
|
|
365
|
+
expect(result.Results).toEqual([]);
|
|
366
|
+
expect(result.ErrorMessage).toBe('Failed to load "Members" records: bad filter');
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('returns an error result when the stored vectors cannot be loaded', async () => {
|
|
370
|
+
useVectorDB(true);
|
|
371
|
+
routeViews('Members', {
|
|
372
|
+
'MJ: Entity Record Documents': () => ({ Success: false, Results: [], ErrorMessage: 'timeout' }),
|
|
373
|
+
Members: () => ({ Success: true, Results: memberRows }),
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, undefined, appContext(membersEntity));
|
|
377
|
+
|
|
378
|
+
expect(result.Success).toBe(false);
|
|
379
|
+
expect(result.Results).toEqual([]);
|
|
380
|
+
expect(result.TotalCount).toBe(0);
|
|
381
|
+
expect(result.ErrorMessage).toBe('Failed to load stored vectors: timeout');
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('returns an error result, and runs neither view, when the document names an entity missing from metadata', async () => {
|
|
385
|
+
const { queryIndex } = useVectorDB(true);
|
|
386
|
+
routeViews('Retired Entity', {
|
|
387
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, undefined, appContext(membersEntity));
|
|
391
|
+
|
|
392
|
+
expect(result.Success).toBe(false);
|
|
393
|
+
expect(result.Results).toEqual([]);
|
|
394
|
+
expect(result.ErrorMessage).toBe('Entity "Retired Entity" not found in metadata');
|
|
395
|
+
expect(queryIndex).not.toHaveBeenCalled();
|
|
396
|
+
expect(callsFor('MJ: Entity Record Documents')).toHaveLength(0);
|
|
397
|
+
expect(runViewsBatches).toHaveLength(0);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('lists the entity records and the stored vectors in one RunViews batch, then fetches the vector values', async () => {
|
|
401
|
+
useVectorDB(true);
|
|
402
|
+
routeViews('Members', {
|
|
403
|
+
'MJ: Entity Record Documents': erdView(storedRows),
|
|
404
|
+
Members: () => ({ Success: true, Results: memberRows }),
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, undefined, undefined, appContext(membersEntity));
|
|
408
|
+
|
|
409
|
+
expect(runViewsBatches).toEqual([['Members', 'MJ: Entity Record Documents'], ['MJ: Entity Record Documents']]);
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
describe('index-keyed providers (Pinecone path, unchanged)', () => {
|
|
414
|
+
it('queries the provider index by name and never reads Entity Record Documents', async () => {
|
|
415
|
+
const { queryIndex } = useVectorDB(false);
|
|
416
|
+
routeViews('Members', {});
|
|
417
|
+
|
|
418
|
+
const result = await new FetchEntityVectorsResolver().FetchEntityVectors(DOC_ID, 50, undefined, appContext(membersEntity));
|
|
419
|
+
|
|
420
|
+
expect(result.Success).toBe(true);
|
|
421
|
+
expect(queryIndex).toHaveBeenCalledTimes(1);
|
|
422
|
+
const query = queryIndex.mock.calls[0][0];
|
|
423
|
+
expect(query.id).toBe('provider-index-name');
|
|
424
|
+
expect(query.topK).toBe(50);
|
|
425
|
+
expect(query.includeValues).toBe(true);
|
|
426
|
+
expect(query.filter).toEqual({ Entity: { $eq: 'Members' } });
|
|
427
|
+
expect(query.vector).toHaveLength(2);
|
|
428
|
+
expect(result.Results).toEqual([{ ID: 'pc-1', Values: [0.5, 0.5], Metadata: JSON.stringify({ Entity: 'Members', RecordID: 'a' }) }]);
|
|
429
|
+
expect(callsFor('MJ: Entity Record Documents')).toHaveLength(0);
|
|
430
|
+
expect(callsFor('Members')).toHaveLength(0);
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
});
|