@memberjunction/server 6.1.4 → 6.2.0-edge.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.d.ts +2 -0
- package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.js +5 -1
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionManager.js +2 -2
- package/dist/agentSessions/remoteBrowserGoalEngine.d.ts +8 -0
- package/dist/agentSessions/remoteBrowserGoalEngine.d.ts.map +1 -1
- package/dist/agentSessions/remoteBrowserGoalEngine.js +21 -5
- package/dist/agentSessions/remoteBrowserGoalEngine.js.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.d.ts +2 -0
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +5 -1
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/exampleNewUserSubClass.js +2 -1
- package/dist/auth/exampleNewUserSubClass.js.map +1 -1
- package/dist/auth/index.d.ts +20 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +20 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +8 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +21 -5
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +9 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +22 -10
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts +17 -15
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +65 -51
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +2 -2
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +2 -2
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/magicLinkCore.d.ts +54 -33
- package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -1
- package/dist/auth/magicLink/magicLinkCore.js +61 -61
- package/dist/auth/magicLink/magicLinkCore.js.map +1 -1
- package/dist/auth/magicLink/redeemLanding.d.ts +4 -0
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
- package/dist/auth/magicLink/redeemLanding.js +12 -4
- package/dist/auth/magicLink/redeemLanding.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +4 -4
- package/dist/auth/principals.d.ts +2 -0
- package/dist/auth/principals.d.ts.map +1 -1
- package/dist/auth/principals.js +6 -2
- package/dist/auth/principals.js.map +1 -1
- package/dist/cache.d.ts +2 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +3 -1
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +293 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -4
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +20 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +27 -19
- package/dist/context.js.map +1 -1
- package/dist/directives/Public.d.ts +2 -0
- package/dist/directives/Public.d.ts.map +1 -1
- package/dist/directives/Public.js +3 -1
- package/dist/directives/Public.js.map +1 -1
- package/dist/directives/RequireSystemUser.d.ts +2 -0
- package/dist/directives/RequireSystemUser.d.ts.map +1 -1
- package/dist/directives/RequireSystemUser.js +3 -1
- package/dist/directives/RequireSystemUser.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +266 -4
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +1304 -0
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +8 -2
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +7 -3
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.d.ts +3 -1
- package/dist/generic/FireAndForgetHeartbeat.d.ts.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.js +8 -4
- package/dist/generic/FireAndForgetHeartbeat.js.map +1 -1
- package/dist/generic/PushStatusResolver.d.ts +10 -1
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +11 -3
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +27 -1
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +64 -6
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -6
- package/dist/index.js.map +1 -1
- package/dist/integration/CustomColumnPromoter.d.ts +2 -0
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +5 -1
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/integration/EntityMapLifecycle.d.ts +4 -0
- package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
- package/dist/integration/EntityMapLifecycle.js +10 -2
- package/dist/integration/EntityMapLifecycle.js.map +1 -1
- package/dist/logging/NoLog.d.ts +4 -0
- package/dist/logging/NoLog.d.ts.map +1 -1
- package/dist/logging/NoLog.js +10 -2
- package/dist/logging/NoLog.js.map +1 -1
- package/dist/logging/StartupLogger.d.ts +2 -0
- package/dist/logging/StartupLogger.d.ts.map +1 -1
- package/dist/logging/StartupLogger.js +5 -1
- package/dist/logging/StartupLogger.js.map +1 -1
- package/dist/logging/bootAudit.d.ts +11 -7
- package/dist/logging/bootAudit.d.ts.map +1 -1
- package/dist/logging/bootAudit.js +15 -7
- package/dist/logging/bootAudit.js.map +1 -1
- package/dist/logging/boundaryLogPayload.d.ts +4 -0
- package/dist/logging/boundaryLogPayload.d.ts.map +1 -1
- package/dist/logging/boundaryLogPayload.js +5 -1
- package/dist/logging/boundaryLogPayload.js.map +1 -1
- package/dist/logging/secretRedactor.d.ts +2 -0
- package/dist/logging/secretRedactor.d.ts.map +1 -1
- package/dist/logging/secretRedactor.js +8 -4
- package/dist/logging/secretRedactor.js.map +1 -1
- package/dist/logging/shortenForLog.d.ts +2 -0
- package/dist/logging/shortenForLog.d.ts.map +1 -1
- package/dist/logging/shortenForLog.js +7 -3
- package/dist/logging/shortenForLog.js.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.d.ts +2 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.js +8 -6
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
- package/dist/metadataRefreshSignal.d.ts +19 -0
- package/dist/metadataRefreshSignal.d.ts.map +1 -0
- package/dist/metadataRefreshSignal.js +45 -0
- package/dist/metadataRefreshSignal.js.map +1 -0
- package/dist/middleware/MJTenantFilterMiddleware.js +4 -4
- package/dist/multiTenancy/index.d.ts +8 -0
- package/dist/multiTenancy/index.d.ts.map +1 -1
- package/dist/multiTenancy/index.js +21 -5
- package/dist/multiTenancy/index.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts +5 -0
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.js +14 -10
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts +6 -6
- package/dist/realtimeWidget/WidgetSessionService.js +27 -27
- package/dist/realtimeWidget/host-identity.d.ts +5 -1
- package/dist/realtimeWidget/host-identity.d.ts.map +1 -1
- package/dist/realtimeWidget/host-identity.js +11 -3
- package/dist/realtimeWidget/host-identity.js.map +1 -1
- package/dist/realtimeWidget/index.d.ts +2 -2
- package/dist/realtimeWidget/index.d.ts.map +1 -1
- package/dist/realtimeWidget/index.js +2 -2
- package/dist/realtimeWidget/index.js.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts +21 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.js +16 -4
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +48 -0
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +38 -10
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +10 -6
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +14 -6
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +3 -3
- package/dist/resolvers/FetchEntityVectorsResolver.js +2 -2
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.js +3 -3
- package/dist/resolvers/GeoResolver.d.ts +2 -2
- package/dist/resolvers/GeoResolver.js +4 -4
- package/dist/resolvers/GetDataResolver.d.ts +14 -0
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +43 -15
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +2 -2
- package/dist/resolvers/ListOperationsResolver.d.ts +20 -0
- package/dist/resolvers/ListOperationsResolver.d.ts.map +1 -1
- package/dist/resolvers/ListOperationsResolver.js +68 -28
- package/dist/resolvers/ListOperationsResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts +11 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +7 -3
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +2 -1
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +3 -3
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +37 -0
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +101 -11
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +5 -5
- package/dist/resolvers/RunAIAgentResolver.d.ts +10 -4
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +74 -42
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +2 -2
- package/dist/resolvers/RunTestResolver.js +5 -5
- package/dist/resolvers/SearchEntitiesResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchEntitiesResolver.js +3 -1
- package/dist/resolvers/SearchEntitiesResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.d.ts +1 -0
- package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.js +5 -0
- package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.js +1 -0
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts +8 -4
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +5 -5
- package/dist/resolvers/TaskGraphFrameResolver.d.ts +8 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.js +6 -2
- package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +53 -4
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/adhoc-query-helpers.d.ts +6 -0
- package/dist/resolvers/adhoc-query-helpers.d.ts.map +1 -1
- package/dist/resolvers/adhoc-query-helpers.js +10 -2
- package/dist/resolvers/adhoc-query-helpers.js.map +1 -1
- package/dist/resolvers/artifact-routing.d.ts +8 -8
- package/dist/resolvers/artifact-routing.js +2 -2
- package/dist/resolvers/artifact-routing.js.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.d.ts +10 -2
- package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.js +24 -8
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
- package/dist/resolvers/peaksSidecar.d.ts +4 -0
- package/dist/resolvers/peaksSidecar.d.ts.map +1 -1
- package/dist/resolvers/peaksSidecar.js +10 -2
- package/dist/resolvers/peaksSidecar.js.map +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts +28 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +20 -4
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/MediaStreamHandler.d.ts +2 -0
- package/dist/rest/MediaStreamHandler.d.ts.map +1 -1
- package/dist/rest/MediaStreamHandler.js +10 -6
- package/dist/rest/MediaStreamHandler.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts +9 -0
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +15 -3
- package/dist/rest/OAuthCallbackHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts +6 -4
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +15 -11
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts +5 -1
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeSdpBrokerHandler.js +12 -4
- package/dist/rest/RealtimeSdpBrokerHandler.js.map +1 -1
- package/dist/rest/SignatureWebhookHandler.d.ts +2 -0
- package/dist/rest/SignatureWebhookHandler.d.ts.map +1 -1
- package/dist/rest/SignatureWebhookHandler.js +5 -1
- package/dist/rest/SignatureWebhookHandler.js.map +1 -1
- package/dist/rest/UploadTokenManager.d.ts +24 -8
- package/dist/rest/UploadTokenManager.d.ts.map +1 -1
- package/dist/rest/UploadTokenManager.js +53 -21
- package/dist/rest/UploadTokenManager.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +20 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +20 -4
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/mediaRange.d.ts +4 -0
- package/dist/rest/mediaRange.d.ts.map +1 -1
- package/dist/rest/mediaRange.js +10 -2
- package/dist/rest/mediaRange.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +4 -0
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +13 -7
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverExtensionReservedRoots.d.ts +2 -0
- package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
- package/dist/serverExtensionReservedRoots.js +5 -1
- package/dist/serverExtensionReservedRoots.js.map +1 -1
- package/dist/services/MJStorageBlobStore.d.ts +41 -0
- package/dist/services/MJStorageBlobStore.d.ts.map +1 -0
- package/dist/services/MJStorageBlobStore.js +160 -0
- package/dist/services/MJStorageBlobStore.js.map +1 -0
- package/dist/services/TaskGraphActionRunner.d.ts +13 -8
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +16 -15
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -3
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +12 -3
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +19 -8
- package/dist/util.js.map +1 -1
- package/package.json +92 -92
- package/src/__tests__/FileResolverPeaks.test.ts +13 -13
- package/src/__tests__/ListOperationsResolver.test.ts +17 -17
- package/src/__tests__/MediaStreamHandler.test.ts +28 -28
- package/src/__tests__/NoLog.test.ts +11 -11
- package/src/__tests__/PrimaryKeyAlwaysMapped.test.ts +10 -10
- package/src/__tests__/RESTEndpointHandler.test.ts +14 -14
- package/src/__tests__/RealtimeBridgeResolver.test.ts +4 -2
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +229 -0
- package/src/__tests__/RealtimeSdpBrokerHandler.test.ts +6 -6
- package/src/__tests__/RefreshAdoptsNewColumns.test.ts +8 -8
- package/src/__tests__/RemoteBrowserGoalEngine.test.ts +18 -18
- package/src/__tests__/ResolverBase.isaPromotionCreate.test.ts +412 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +228 -0
- package/src/__tests__/SearchEntitiesResolver.readOnlyFallback.test.ts +78 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +129 -0
- package/src/__tests__/TaskGraphFrameResolver.test.ts +2 -2
- package/src/__tests__/TransactionGroupResolver.refusals.test.ts +290 -0
- package/src/__tests__/WidgetSessionService.test.ts +8 -4
- package/src/__tests__/adhoc-query-helpers.test.ts +21 -21
- package/src/__tests__/bootAudit.test.ts +11 -11
- package/src/__tests__/boundaryLogPayload.test.ts +6 -6
- package/src/__tests__/databaseAbstraction.test.ts +12 -6
- package/src/__tests__/getDataTokenRedaction.test.ts +7 -7
- package/src/__tests__/initializeProviders.refresh.test.ts +4 -4
- package/src/__tests__/magicLink.test.ts +73 -134
- package/src/__tests__/magicLinkService.consume.test.ts +224 -0
- package/src/__tests__/meetingRecordingRegistration.test.ts +12 -12
- package/src/__tests__/metadataRefreshSignal.test.ts +78 -0
- package/src/__tests__/multiTenancy.security.test.ts +40 -40
- package/src/__tests__/multiTenancy.test.ts +18 -18
- package/src/__tests__/newUsers.test.ts +24 -23
- package/src/__tests__/principals.test.ts +22 -22
- package/src/__tests__/pushStatusResolver.filter.test.ts +8 -8
- package/src/__tests__/secretRedactor.failOpen.test.ts +12 -12
- package/src/__tests__/secretRedactor.test.ts +12 -12
- package/src/__tests__/serverExtensionReservedRoots.test.ts +7 -7
- package/src/__tests__/subscriptionRedaction.test.ts +5 -5
- package/src/__tests__/unifiedAuth.test.ts +15 -9
- package/src/__tests__/visitorIdentity.resolve.test.ts +6 -6
- package/src/__tests__/widget.test.ts +45 -45
- package/src/__tests__/widgetGuestElevation.test.ts +7 -7
- package/src/__tests__/widgetHostIdentity.test.ts +14 -14
- package/src/agentSessions/ReturningVisitorRecap.ts +12 -1
- package/src/agentSessions/SessionManager.ts +2 -2
- package/src/agentSessions/remoteBrowserGoalEngine.ts +30 -5
- package/src/auth/AuthProviderCatalogRouter.ts +6 -1
- package/src/auth/__tests__/backward-compatibility.test.ts +3 -3
- package/src/auth/exampleNewUserSubClass.ts +2 -2
- package/src/auth/index.ts +43 -28
- package/src/auth/initializeProviders.ts +25 -5
- package/src/auth/magicLink/MagicLinkRouter.ts +28 -10
- package/src/auth/magicLink/MagicLinkService.ts +71 -52
- package/src/auth/magicLink/index.ts +7 -7
- package/src/auth/magicLink/magicLinkCore.ts +96 -64
- package/src/auth/magicLink/redeemLanding.ts +14 -4
- package/src/auth/magicLink/types.ts +54 -54
- package/src/auth/newUsers.ts +1 -1
- package/src/auth/principals.ts +11 -2
- package/src/cache.ts +4 -1
- package/src/config.ts +14 -4
- package/src/context.ts +37 -24
- package/src/directives/Public.ts +4 -1
- package/src/directives/RequireSystemUser.ts +4 -1
- package/src/generated/graphql-schemas/__mj.ts +933 -5
- package/src/generic/CacheInvalidationResolver.ts +12 -4
- package/src/generic/FireAndForgetHeartbeat.ts +19 -14
- package/src/generic/PushStatusResolver.ts +21 -7
- package/src/generic/ResolverBase.ts +66 -5
- package/src/generic/RunViewResolver.ts +22 -22
- package/src/generic/__tests__/FireAndForgetHeartbeat.test.ts +7 -7
- package/src/index.ts +34 -7
- package/src/integration/CustomColumnPromoter.ts +6 -1
- package/src/integration/EntityMapLifecycle.ts +20 -2
- package/src/logging/NoLog.ts +16 -2
- package/src/logging/StartupLogger.ts +6 -1
- package/src/logging/bootAudit.ts +26 -16
- package/src/logging/boundaryLogPayload.ts +8 -1
- package/src/logging/secretRedactor.ts +14 -9
- package/src/logging/shortenForLog.ts +8 -3
- package/src/logging/variablesLoggingMiddleware.ts +9 -6
- package/src/metadataRefreshSignal.ts +45 -0
- package/src/middleware/MJTenantFilterMiddleware.ts +4 -4
- package/src/multiTenancy/index.ts +29 -5
- package/src/realtimeWidget/WidgetRouter.ts +15 -10
- package/src/realtimeWidget/WidgetSessionService.ts +76 -76
- package/src/realtimeWidget/host-identity.ts +24 -10
- package/src/realtimeWidget/index.ts +3 -3
- package/src/realtimeWidget/visitorIdentity.ts +39 -8
- package/src/realtimeWidget/widgetCore.ts +75 -10
- package/src/realtimeWidget/widgetGuestElevation.ts +25 -12
- package/src/resolvers/AdhocQueryResolver.ts +3 -3
- package/src/resolvers/AgentSessionResolver.ts +3 -3
- package/src/resolvers/ColorResolver.ts +6 -6
- package/src/resolvers/ComponentRegistryResolver.ts +36 -36
- package/src/resolvers/EntityCommunicationsResolver.ts +4 -4
- package/src/resolvers/ExecuteRemoteOperationResolver.ts +9 -9
- package/src/resolvers/FetchEntityVectorsResolver.ts +2 -2
- package/src/resolvers/FileResolver.ts +42 -42
- package/src/resolvers/GeoResolver.ts +4 -4
- package/src/resolvers/GetDataResolver.ts +50 -15
- package/src/resolvers/IntegrationDiscoveryResolver.ts +2 -2
- package/src/resolvers/ListOperationsResolver.ts +78 -28
- package/src/resolvers/MCPResolver.ts +30 -15
- package/src/resolvers/QueryResolver.ts +13 -13
- package/src/resolvers/QuerySystemUserResolver.ts +2 -1
- package/src/resolvers/RealtimeBridgeResolver.ts +3 -3
- package/src/resolvers/RealtimeClientSessionResolver.ts +126 -13
- package/src/resolvers/RemoteBrowserActionResolver.ts +5 -5
- package/src/resolvers/RunAIAgentResolver.ts +118 -76
- package/src/resolvers/RunAIPromptResolver.ts +22 -22
- package/src/resolvers/RunTemplateResolver.ts +4 -4
- package/src/resolvers/RunTestResolver.ts +25 -25
- package/src/resolvers/SearchEntitiesResolver.ts +3 -1
- package/src/resolvers/SearchKnowledgeResolver.ts +4 -0
- package/src/resolvers/SearchKnowledgeSystemUserResolver.ts +1 -0
- package/src/resolvers/SqlLoggingConfigResolver.ts +56 -56
- package/src/resolvers/TaskGraphFrameResolver.ts +37 -28
- package/src/resolvers/TelemetryResolver.ts +79 -79
- package/src/resolvers/TransactionGroupResolver.ts +57 -4
- package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +40 -38
- package/src/resolvers/__tests__/artifact-routing.test.ts +23 -23
- package/src/resolvers/adhoc-query-helpers.ts +19 -2
- package/src/resolvers/artifact-routing.ts +19 -19
- package/src/resolvers/meetingRecordingRegistration.ts +44 -10
- package/src/resolvers/peaksSidecar.ts +12 -2
- package/src/rest/EntityCRUDHandler.ts +24 -4
- package/src/rest/MediaStreamHandler.ts +11 -6
- package/src/rest/OAuthCallbackHandler.ts +25 -7
- package/src/rest/RESTEndpointHandler.ts +20 -15
- package/src/rest/RealtimeSdpBrokerHandler.ts +14 -4
- package/src/rest/SignatureWebhookHandler.ts +6 -1
- package/src/rest/UploadTokenManager.ts +66 -30
- package/src/rest/ViewOperationsHandler.ts +24 -4
- package/src/rest/mediaRange.ts +16 -6
- package/src/rest/setupRESTEndpoints.ts +24 -12
- package/src/serverExtensionReservedRoots.ts +6 -1
- package/src/services/MJStorageBlobStore.ts +209 -0
- package/src/services/TaskGraphActionRunner.ts +16 -15
- package/src/types.ts +21 -16
- package/src/util.ts +22 -9
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* singleton nor a database — the seam is `(candidate, users) -> resolution`.
|
|
14
14
|
*/
|
|
15
15
|
import { describe, it, expect } from 'vitest';
|
|
16
|
-
import {
|
|
16
|
+
import { ResolvePrincipalFrom, type ResolvablePrincipal } from '../auth/principals.js';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* The system user's ID, pinned by `UserCache` (`SYSTEM_USER_ID`) and seeded by every baseline.
|
|
@@ -63,14 +63,14 @@ const STOCK_HOST: ResolvablePrincipal[] = [SYSTEM, ANONYMOUS, HOST_ADMIN];
|
|
|
63
63
|
describe('resolvePrincipalFrom', () => {
|
|
64
64
|
describe('the shipped default (#4209)', () => {
|
|
65
65
|
it('resolves the email-shaped default to the seeded System user', () => {
|
|
66
|
-
const result =
|
|
66
|
+
const result = ResolvePrincipalFrom(SHIPPED_DEFAULT, STOCK_HOST, SYSTEM_USER_ID);
|
|
67
67
|
|
|
68
68
|
expect(result.user).toBe(SYSTEM);
|
|
69
69
|
expect(result.reason).toBe('email');
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
it('reports no warning when the default resolves, so a stock host logs nothing', () => {
|
|
73
|
-
const result =
|
|
73
|
+
const result = ResolvePrincipalFrom(SHIPPED_DEFAULT, STOCK_HOST, SYSTEM_USER_ID);
|
|
74
74
|
|
|
75
75
|
expect(result.warning).toBeUndefined();
|
|
76
76
|
});
|
|
@@ -81,8 +81,8 @@ describe('resolvePrincipalFrom', () => {
|
|
|
81
81
|
// `SELECT * FROM vwUsers` carries no ORDER BY and the cache is mutated in place at
|
|
82
82
|
// runtime, so row order differs between boots AND within a process. Attribution must
|
|
83
83
|
// not depend on it: this is what made CreatedByUserID incidental.
|
|
84
|
-
const ordered =
|
|
85
|
-
const reversed =
|
|
84
|
+
const ordered = ResolvePrincipalFrom(SHIPPED_DEFAULT, STOCK_HOST, SYSTEM_USER_ID);
|
|
85
|
+
const reversed = ResolvePrincipalFrom(SHIPPED_DEFAULT, [...STOCK_HOST].reverse(), SYSTEM_USER_ID);
|
|
86
86
|
|
|
87
87
|
expect(reversed.user).toBe(ordered.user);
|
|
88
88
|
});
|
|
@@ -107,7 +107,7 @@ describe('resolvePrincipalFrom', () => {
|
|
|
107
107
|
IsActive: true,
|
|
108
108
|
};
|
|
109
109
|
|
|
110
|
-
const result =
|
|
110
|
+
const result = ResolvePrincipalFrom('support@acme.com', [emailSupport, namedSupport], SYSTEM_USER_ID);
|
|
111
111
|
|
|
112
112
|
expect(result.user).toBe(namedSupport);
|
|
113
113
|
expect(result.reason).toBe('name');
|
|
@@ -125,15 +125,15 @@ describe('resolvePrincipalFrom', () => {
|
|
|
125
125
|
const HIGH: ResolvablePrincipal = { ID: 'FFFFFFFF-0000-0000-0000-00000000000F', Name: 'shared.name', Email: 'high@acme.com', Type: 'User', IsActive: true };
|
|
126
126
|
|
|
127
127
|
it('picks the lowest-ID user when two users share the configured Name', () => {
|
|
128
|
-
const result =
|
|
128
|
+
const result = ResolvePrincipalFrom('shared.name', [HIGH, LOW, SYSTEM], SYSTEM_USER_ID);
|
|
129
129
|
|
|
130
130
|
expect(result.user).toBe(LOW);
|
|
131
131
|
expect(result.reason).toBe('name');
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
it('resolves a duplicated Name identically however the cache is ordered', () => {
|
|
135
|
-
const forward =
|
|
136
|
-
const reversed =
|
|
135
|
+
const forward = ResolvePrincipalFrom('shared.name', [HIGH, LOW, SYSTEM], SYSTEM_USER_ID);
|
|
136
|
+
const reversed = ResolvePrincipalFrom('shared.name', [SYSTEM, LOW, HIGH], SYSTEM_USER_ID);
|
|
137
137
|
|
|
138
138
|
expect(reversed.user).toBe(forward.user);
|
|
139
139
|
});
|
|
@@ -145,7 +145,7 @@ describe('resolvePrincipalFrom', () => {
|
|
|
145
145
|
const lowEmail: ResolvablePrincipal = { ...LOW, Name: 'a.person', Email: 'shared@acme.com' };
|
|
146
146
|
const highEmail: ResolvablePrincipal = { ...HIGH, Name: 'b.person', Email: 'shared@acme.com' };
|
|
147
147
|
|
|
148
|
-
const result =
|
|
148
|
+
const result = ResolvePrincipalFrom('shared@acme.com', [highEmail, lowEmail, SYSTEM], SYSTEM_USER_ID);
|
|
149
149
|
|
|
150
150
|
expect(result.user).toBe(lowEmail);
|
|
151
151
|
expect(result.reason).toBe('email');
|
|
@@ -169,7 +169,7 @@ describe('resolvePrincipalFrom', () => {
|
|
|
169
169
|
};
|
|
170
170
|
|
|
171
171
|
it('does not resolve a deactivated candidate by Email', () => {
|
|
172
|
-
const result =
|
|
172
|
+
const result = ResolvePrincipalFrom('departed@acme.com', [...STOCK_HOST, RETIRED], SYSTEM_USER_ID);
|
|
173
173
|
|
|
174
174
|
expect(result.user).toBe(SYSTEM);
|
|
175
175
|
expect(result.reason).toBe('system');
|
|
@@ -180,14 +180,14 @@ describe('resolvePrincipalFrom', () => {
|
|
|
180
180
|
// most: without it the guarantee holds only for the rungs nobody configures.
|
|
181
181
|
const renamed: ResolvablePrincipal = { ...RETIRED, Name: 'ops-service-account', Email: 'ops@acme.com' };
|
|
182
182
|
|
|
183
|
-
const result =
|
|
183
|
+
const result = ResolvePrincipalFrom('ops-service-account', [...STOCK_HOST, renamed], SYSTEM_USER_ID);
|
|
184
184
|
|
|
185
185
|
expect(result.user).toBe(SYSTEM);
|
|
186
186
|
expect(result.reason).toBe('system');
|
|
187
187
|
});
|
|
188
188
|
|
|
189
189
|
it('reports that the candidate matched but is inactive, not that it matched nothing', () => {
|
|
190
|
-
const result =
|
|
190
|
+
const result = ResolvePrincipalFrom('departed@acme.com', [...STOCK_HOST, RETIRED], SYSTEM_USER_ID);
|
|
191
191
|
|
|
192
192
|
// "matched no user's Name or Email" would send the operator hunting for a typo in a
|
|
193
193
|
// value that is spelled correctly. The fix here is to reactivate the account or name a
|
|
@@ -215,7 +215,7 @@ describe('resolvePrincipalFrom', () => {
|
|
|
215
215
|
IsActive: true,
|
|
216
216
|
};
|
|
217
217
|
|
|
218
|
-
const result =
|
|
218
|
+
const result = ResolvePrincipalFrom('ops@acme.com', [inactiveByName, activeByEmail], SYSTEM_USER_ID);
|
|
219
219
|
|
|
220
220
|
expect(result.user).toBe(activeByEmail);
|
|
221
221
|
expect(result.reason).toBe('email');
|
|
@@ -224,14 +224,14 @@ describe('resolvePrincipalFrom', () => {
|
|
|
224
224
|
});
|
|
225
225
|
describe('fallbacks', () => {
|
|
226
226
|
it('falls back to the System user rather than an arbitrary Owner when the candidate is unresolvable', () => {
|
|
227
|
-
const result =
|
|
227
|
+
const result = ResolvePrincipalFrom('nobody@nowhere.example', STOCK_HOST, SYSTEM_USER_ID);
|
|
228
228
|
|
|
229
229
|
expect(result.user).toBe(SYSTEM);
|
|
230
230
|
expect(result.reason).toBe('system');
|
|
231
231
|
});
|
|
232
232
|
|
|
233
233
|
it('warns when a configured candidate did not resolve, naming the candidate', () => {
|
|
234
|
-
const result =
|
|
234
|
+
const result = ResolvePrincipalFrom('nobody@nowhere.example', STOCK_HOST, SYSTEM_USER_ID);
|
|
235
235
|
|
|
236
236
|
expect(result.warning).toContain('nobody@nowhere.example');
|
|
237
237
|
});
|
|
@@ -239,7 +239,7 @@ describe('resolvePrincipalFrom', () => {
|
|
|
239
239
|
it('falls back to the System user WITHOUT warning when no candidate is configured', () => {
|
|
240
240
|
// Zod defaults this setting to '', so an unset/blank value must not be reported as a
|
|
241
241
|
// misconfiguration — but it must still land somewhere deterministic.
|
|
242
|
-
const result =
|
|
242
|
+
const result = ResolvePrincipalFrom('', STOCK_HOST, SYSTEM_USER_ID);
|
|
243
243
|
|
|
244
244
|
expect(result.user).toBe(SYSTEM);
|
|
245
245
|
expect(result.warning).toBeUndefined();
|
|
@@ -256,7 +256,7 @@ describe('resolvePrincipalFrom', () => {
|
|
|
256
256
|
};
|
|
257
257
|
const users = [laterOwner, HOST_ADMIN, ANONYMOUS];
|
|
258
258
|
|
|
259
|
-
const result =
|
|
259
|
+
const result = ResolvePrincipalFrom('nobody@nowhere.example', users, SYSTEM_USER_ID);
|
|
260
260
|
|
|
261
261
|
expect(result.user).toBe(HOST_ADMIN);
|
|
262
262
|
expect(result.reason).toBe('owner');
|
|
@@ -271,7 +271,7 @@ describe('resolvePrincipalFrom', () => {
|
|
|
271
271
|
IsActive: false,
|
|
272
272
|
};
|
|
273
273
|
|
|
274
|
-
const result =
|
|
274
|
+
const result = ResolvePrincipalFrom('nobody@nowhere.example', [inactiveOwner, HOST_ADMIN], SYSTEM_USER_ID);
|
|
275
275
|
|
|
276
276
|
expect(result.user).toBe(HOST_ADMIN);
|
|
277
277
|
});
|
|
@@ -281,7 +281,7 @@ describe('resolvePrincipalFrom', () => {
|
|
|
281
281
|
// "we never act as a disabled user, except as the one user we reach first".
|
|
282
282
|
const inactiveSystem: ResolvablePrincipal = { ...SYSTEM, IsActive: false };
|
|
283
283
|
|
|
284
|
-
const result =
|
|
284
|
+
const result = ResolvePrincipalFrom('nobody@nowhere.example', [inactiveSystem, HOST_ADMIN], SYSTEM_USER_ID);
|
|
285
285
|
|
|
286
286
|
expect(result.user).toBe(HOST_ADMIN);
|
|
287
287
|
expect(result.reason).toBe('owner');
|
|
@@ -290,13 +290,13 @@ describe('resolvePrincipalFrom', () => {
|
|
|
290
290
|
it('returns no principal when the system user is deactivated and no active Owner remains', () => {
|
|
291
291
|
const inactiveSystem: ResolvablePrincipal = { ...SYSTEM, IsActive: false };
|
|
292
292
|
|
|
293
|
-
const result =
|
|
293
|
+
const result = ResolvePrincipalFrom('nobody@nowhere.example', [inactiveSystem, ANONYMOUS], SYSTEM_USER_ID);
|
|
294
294
|
|
|
295
295
|
expect(result.user).toBeNull();
|
|
296
296
|
});
|
|
297
297
|
|
|
298
298
|
it('returns no principal at all when the cache is empty', () => {
|
|
299
|
-
const result =
|
|
299
|
+
const result = ResolvePrincipalFrom(SHIPPED_DEFAULT, [], SYSTEM_USER_ID);
|
|
300
300
|
|
|
301
301
|
expect(result.user).toBeNull();
|
|
302
302
|
expect(result.reason).toBe('none');
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import 'reflect-metadata';
|
|
12
12
|
import { describe, it, expect } from 'vitest';
|
|
13
|
-
import {
|
|
13
|
+
import { StatusUpdatesFilter, type PushStatusNotificationPayload, type StatusUpdatesFilterContext } from '../generic/PushStatusResolver';
|
|
14
14
|
import type { UserPayload } from '../types';
|
|
15
15
|
|
|
16
16
|
const OWNER = 'AA11BB22-0000-4000-8000-000000000001';
|
|
@@ -28,29 +28,29 @@ function push(overrides: Partial<PushStatusNotificationPayload> = {}): PushStatu
|
|
|
28
28
|
|
|
29
29
|
describe('statusUpdatesFilter (B49 session-hijack gate)', () => {
|
|
30
30
|
it('delivers when sessionId matches AND the connection identity owns the push', () => {
|
|
31
|
-
expect(
|
|
31
|
+
expect(StatusUpdatesFilter({ payload: push(), args: { sessionId: SESSION }, context: ctxFor(OWNER) })).toBe(true);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
it('THE FIX: rejects a matching sessionId when the connection identity is a DIFFERENT user (hijack)', () => {
|
|
35
35
|
// Attacker lifted the victim's sessionId and subscribes with it — but their authenticated
|
|
36
36
|
// connection identity is their own, so delivery must be denied.
|
|
37
|
-
expect(
|
|
37
|
+
expect(StatusUpdatesFilter({ payload: push({ ownerUserId: OWNER }), args: { sessionId: SESSION }, context: ctxFor(ATTACKER) })).toBe(false);
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
it('rejects when the requested sessionId does not match the push', () => {
|
|
41
|
-
expect(
|
|
41
|
+
expect(StatusUpdatesFilter({ payload: push(), args: { sessionId: 'some-other-session' }, context: ctxFor(OWNER) })).toBe(false);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
it('fails closed when the push carries no ownerUserId', () => {
|
|
45
|
-
expect(
|
|
45
|
+
expect(StatusUpdatesFilter({ payload: push({ ownerUserId: '' }), args: { sessionId: SESSION }, context: ctxFor(OWNER) })).toBe(false);
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
it('fails closed when the connection has no authenticated identity', () => {
|
|
49
|
-
expect(
|
|
50
|
-
expect(
|
|
49
|
+
expect(StatusUpdatesFilter({ payload: push(), args: { sessionId: SESSION }, context: ctxFor(undefined) })).toBe(false);
|
|
50
|
+
expect(StatusUpdatesFilter({ payload: push(), args: { sessionId: SESSION }, context: undefined })).toBe(false);
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
it('matches identity case-insensitively (SQL Server upper vs PostgreSQL lower UUIDs)', () => {
|
|
54
|
-
expect(
|
|
54
|
+
expect(StatusUpdatesFilter({ payload: push({ ownerUserId: OWNER.toUpperCase() }), args: { sessionId: SESSION }, context: ctxFor(OWNER.toLowerCase()) })).toBe(true);
|
|
55
55
|
});
|
|
56
56
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
2
|
import type { IMetadataProvider } from '@memberjunction/core';
|
|
3
|
-
import {
|
|
3
|
+
import { RedactArg, ResetUnboundCrudInputWarnings } from '../logging/secretRedactor.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* `redactArg` binds a GraphQL input type to an entity by NAME:
|
|
@@ -42,7 +42,7 @@ afterEach(() => {
|
|
|
42
42
|
|
|
43
43
|
describe('redactArg — entity-bound inputs (the codegen case)', () => {
|
|
44
44
|
it('redacts an encrypted column, keeping the rest', () => {
|
|
45
|
-
const out =
|
|
45
|
+
const out = RedactArg({
|
|
46
46
|
inputTypeName: 'CreateMJCredentialInput',
|
|
47
47
|
rawValue: { Name: 'Stripe', Values: SECRET },
|
|
48
48
|
provider: CREDENTIAL_ENTITY,
|
|
@@ -55,7 +55,7 @@ describe('redactArg — entity-bound inputs (the codegen case)', () => {
|
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
it('emits no warning, because the binding resolved', () => {
|
|
58
|
-
|
|
58
|
+
RedactArg({
|
|
59
59
|
inputTypeName: 'CreateMJCredentialInput',
|
|
60
60
|
rawValue: { Values: SECRET },
|
|
61
61
|
provider: CREDENTIAL_ENTITY,
|
|
@@ -76,14 +76,14 @@ describe('redactArg — name matches the convention but no entity exists', () =>
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
it('falls open — values are logged, which is the defect being surfaced', () => {
|
|
79
|
-
const out =
|
|
79
|
+
const out = RedactArg({ ...unbound });
|
|
80
80
|
// Documents current behaviour: no entity binding and no @NoLog means no
|
|
81
81
|
// redaction source, so the value survives into the log.
|
|
82
82
|
expect(JSON.stringify(out)).toContain(SECRET);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
it('now warns, naming the input type and what to do about it', () => {
|
|
86
|
-
|
|
86
|
+
RedactArg({ ...unbound });
|
|
87
87
|
|
|
88
88
|
expect(console.warn).toHaveBeenCalledTimes(1);
|
|
89
89
|
const message = vi.mocked(console.warn).mock.calls[0][0] as string;
|
|
@@ -94,22 +94,22 @@ describe('redactArg — name matches the convention but no entity exists', () =>
|
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
it('warns only once per input type, however hot the mutation is', () => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
RedactArg({ ...unbound });
|
|
98
|
+
RedactArg({ ...unbound });
|
|
99
|
+
RedactArg({ ...unbound });
|
|
100
100
|
expect(console.warn).toHaveBeenCalledTimes(1);
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
it('warns separately for a different unbound input type', () => {
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
RedactArg({ ...unbound });
|
|
105
|
+
RedactArg({ ...unbound, inputTypeName: 'CreateScheduleInput' });
|
|
106
106
|
expect(console.warn).toHaveBeenCalledTimes(2);
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
describe('redactArg — @NoLog closes the gap the metadata cannot', () => {
|
|
111
111
|
it('redacts a marked field on an input with no entity binding', () => {
|
|
112
|
-
const out =
|
|
112
|
+
const out = RedactArg({
|
|
113
113
|
inputTypeName: 'CreateConnectionInput',
|
|
114
114
|
rawValue: { CredentialName: 'acme', CredentialValues: SECRET },
|
|
115
115
|
provider: CREDENTIAL_ENTITY,
|
|
@@ -123,7 +123,7 @@ describe('redactArg — @NoLog closes the gap the metadata cannot', () => {
|
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
it('a parameter-level mark redacts the whole arg regardless of binding', () => {
|
|
126
|
-
const out =
|
|
126
|
+
const out = RedactArg({
|
|
127
127
|
inputTypeName: 'CreateConnectionInput',
|
|
128
128
|
rawValue: { CredentialValues: SECRET },
|
|
129
129
|
provider: CREDENTIAL_ENTITY,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import type { IMetadataProvider } from '@memberjunction/core';
|
|
3
|
-
import {
|
|
3
|
+
import { RedactArg } from '../logging/secretRedactor.js';
|
|
4
4
|
|
|
5
5
|
type EncryptedField = { Name: string };
|
|
6
6
|
type FakeEntity = { ClassName: string; EncryptedFields: EncryptedField[] };
|
|
@@ -22,7 +22,7 @@ describe('redactArg', () => {
|
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
it('returns "<redacted>" when noLogParameter is set, regardless of other inputs', () => {
|
|
25
|
-
const result =
|
|
25
|
+
const result = RedactArg({
|
|
26
26
|
inputTypeName: 'CreateMJCredentialInput',
|
|
27
27
|
rawValue: { Values: 'FAKE_SECRET_VALUE_DO_NOT_USE' },
|
|
28
28
|
provider: makeProvider([credentialEntity]),
|
|
@@ -33,7 +33,7 @@ describe('redactArg', () => {
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
it('returns "<metadata-not-ready>" when the provider has no entities (bootstrap window)', () => {
|
|
36
|
-
const result =
|
|
36
|
+
const result = RedactArg({
|
|
37
37
|
inputTypeName: 'CreateMJCredentialInput',
|
|
38
38
|
rawValue: { Values: 'FAKE_SECRET_VALUE_DO_NOT_USE' },
|
|
39
39
|
provider: makeProvider([]),
|
|
@@ -44,7 +44,7 @@ describe('redactArg', () => {
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
it('fails open (passes through) when input type does not match Create/Update<X>Input regex', () => {
|
|
47
|
-
const result =
|
|
47
|
+
const result = RedactArg({
|
|
48
48
|
inputTypeName: 'SomeCustomArgs',
|
|
49
49
|
rawValue: { accessToken: 'FAKE_TOKEN' },
|
|
50
50
|
provider: makeProvider([credentialEntity]),
|
|
@@ -55,7 +55,7 @@ describe('redactArg', () => {
|
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
it('fails open when input type matches regex but no entity is found', () => {
|
|
58
|
-
const result =
|
|
58
|
+
const result = RedactArg({
|
|
59
59
|
inputTypeName: 'CreateUnknownEntityInput',
|
|
60
60
|
rawValue: { Foo: 'bar' },
|
|
61
61
|
provider: makeProvider([credentialEntity]),
|
|
@@ -66,7 +66,7 @@ describe('redactArg', () => {
|
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
it('redacts top-level keys matching EntityFieldInfo.Encrypt=true on entity-bound CRUD inputs', () => {
|
|
69
|
-
const result =
|
|
69
|
+
const result = RedactArg({
|
|
70
70
|
inputTypeName: 'CreateMJCredentialInput',
|
|
71
71
|
rawValue: { ID: 'abc-123', Name: 'HubSpot', Values: 'FAKE_SECRET_VALUE_DO_NOT_USE' },
|
|
72
72
|
provider: makeProvider([credentialEntity]),
|
|
@@ -81,7 +81,7 @@ describe('redactArg', () => {
|
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
it('redacts top-level keys in noLogFields even when EncryptedFields does not include them', () => {
|
|
84
|
-
const result =
|
|
84
|
+
const result = RedactArg({
|
|
85
85
|
inputTypeName: 'CreateUserInput',
|
|
86
86
|
rawValue: { Name: 'Alice', SecretToken: 'oops' },
|
|
87
87
|
provider: makeProvider([userEntity]),
|
|
@@ -95,7 +95,7 @@ describe('redactArg', () => {
|
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
it('Update<X>Input is also handled (not just Create<X>Input)', () => {
|
|
98
|
-
const result =
|
|
98
|
+
const result = RedactArg({
|
|
99
99
|
inputTypeName: 'UpdateMJCredentialInput',
|
|
100
100
|
rawValue: { ID: 'abc-123', Values: 'NEW_FAKE_SECRET' },
|
|
101
101
|
provider: makeProvider([credentialEntity]),
|
|
@@ -113,7 +113,7 @@ describe('redactArg', () => {
|
|
|
113
113
|
// resolvers as metadata-bound instead of flooding with false positives. Security is identical:
|
|
114
114
|
// delete inputs carry PK + Options only — no encrypted field, so nothing is redacted, the keys
|
|
115
115
|
// just pass through. See docs/adr/0001-graphql-variables-logging-tiered-by-verbose.md.
|
|
116
|
-
const result =
|
|
116
|
+
const result = RedactArg({
|
|
117
117
|
inputTypeName: 'DeleteMJCredentialInput',
|
|
118
118
|
rawValue: { ID: 'abc-123' },
|
|
119
119
|
provider: makeProvider([credentialEntity]),
|
|
@@ -125,7 +125,7 @@ describe('redactArg', () => {
|
|
|
125
125
|
|
|
126
126
|
it('Delete<X>Input never exposes an encrypted value even if one were somehow present', () => {
|
|
127
127
|
// Defense-in-depth: even if a delete input carried an encrypted field name, it must still mask.
|
|
128
|
-
const result =
|
|
128
|
+
const result = RedactArg({
|
|
129
129
|
inputTypeName: 'DeleteMJCredentialInput',
|
|
130
130
|
rawValue: { ID: 'abc-123', Values: 'FAKE_SECRET_VALUE_DO_NOT_USE' },
|
|
131
131
|
provider: makeProvider([credentialEntity]),
|
|
@@ -136,7 +136,7 @@ describe('redactArg', () => {
|
|
|
136
136
|
});
|
|
137
137
|
|
|
138
138
|
it('only walks TOP-level keys — nested objects with encrypted-field names are not recursed', () => {
|
|
139
|
-
const result =
|
|
139
|
+
const result = RedactArg({
|
|
140
140
|
inputTypeName: 'CreateMJCredentialInput',
|
|
141
141
|
rawValue: {
|
|
142
142
|
Name: 'HubSpot',
|
|
@@ -151,7 +151,7 @@ describe('redactArg', () => {
|
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
it('passes non-object raw values through to shortenForLog', () => {
|
|
154
|
-
const result =
|
|
154
|
+
const result = RedactArg({
|
|
155
155
|
inputTypeName: 'CreateMJCredentialInput',
|
|
156
156
|
rawValue: 'plain-string',
|
|
157
157
|
provider: makeProvider([credentialEntity]),
|
|
@@ -11,7 +11,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
11
11
|
import {
|
|
12
12
|
CORE_CONSTANT_RESERVED_SERVER_EXTENSION_ROOTS,
|
|
13
13
|
CORE_STATIC_RESERVED_SERVER_EXTENSION_ROOTS,
|
|
14
|
-
|
|
14
|
+
CoreReservedServerExtensionRoots,
|
|
15
15
|
} from '../serverExtensionReservedRoots.js';
|
|
16
16
|
import { validateServerExtensionRootPath } from '@memberjunction/server-extensions-core';
|
|
17
17
|
|
|
@@ -58,12 +58,12 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
58
58
|
|
|
59
59
|
it('structurally guarantees every pre-auth app.use / app.get / app.post mount in index.ts is reserved', () => {
|
|
60
60
|
const indexSrc = readFileSync(join(SRC, 'index.ts'), 'utf8');
|
|
61
|
-
const authMiddlewareIndex = indexSrc.indexOf('app.use(
|
|
61
|
+
const authMiddlewareIndex = indexSrc.indexOf('app.use(CreateUnifiedAuthMiddleware');
|
|
62
62
|
expect(authMiddlewareIndex).toBeGreaterThan(0);
|
|
63
63
|
const preAuthSrc = indexSrc.substring(0, authMiddlewareIndex);
|
|
64
64
|
|
|
65
65
|
const mountRegex = /app\.(?:use|get|post)\s*\(\s*([^,\s)]+)/g;
|
|
66
|
-
const reservedRoots =
|
|
66
|
+
const reservedRoots = CoreReservedServerExtensionRoots('/');
|
|
67
67
|
|
|
68
68
|
// Explicit allowlist of known non-path middleware mounts (e.g. app.use(mw), app.use(cors()), app.use(compression(...)))
|
|
69
69
|
const knownNonPathTokens = [
|
|
@@ -71,7 +71,7 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
71
71
|
'express.',
|
|
72
72
|
'compression',
|
|
73
73
|
'cookieParser',
|
|
74
|
-
'
|
|
74
|
+
'CreateUnifiedAuthMiddleware',
|
|
75
75
|
'mw',
|
|
76
76
|
];
|
|
77
77
|
const isKnownNonPath = (t: string): boolean =>
|
|
@@ -120,7 +120,7 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
120
120
|
});
|
|
121
121
|
|
|
122
122
|
it('includes graphqlRootPath and every core mount', () => {
|
|
123
|
-
const roots =
|
|
123
|
+
const roots = CoreReservedServerExtensionRoots('/api');
|
|
124
124
|
expect(roots).toEqual(
|
|
125
125
|
expect.arrayContaining([
|
|
126
126
|
'/api',
|
|
@@ -139,7 +139,7 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
139
139
|
});
|
|
140
140
|
|
|
141
141
|
it('closes the F-M2 bypasses: cased /auth and sibling /healthcheck', () => {
|
|
142
|
-
const extra =
|
|
142
|
+
const extra = CoreReservedServerExtensionRoots('/');
|
|
143
143
|
expect(validateServerExtensionRootPath('/Auth', extra)).toMatch(/reserved prefix/);
|
|
144
144
|
expect(validateServerExtensionRootPath('/healthcheck', extra)).toMatch(/reserved prefix/);
|
|
145
145
|
expect(validateServerExtensionRootPath('/Healthcheck', extra)).toMatch(/reserved prefix/);
|
|
@@ -156,7 +156,7 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
156
156
|
});
|
|
157
157
|
|
|
158
158
|
it('reserves a non-default graphqlRootPath and its nested paths', () => {
|
|
159
|
-
const extra =
|
|
159
|
+
const extra = CoreReservedServerExtensionRoots('/api');
|
|
160
160
|
expect(validateServerExtensionRootPath('/api', extra)).toMatch(/reserved prefix/);
|
|
161
161
|
expect(validateServerExtensionRootPath('/api/graphql', extra)).toMatch(/reserved prefix/);
|
|
162
162
|
expect(validateServerExtensionRootPath('/apiv2', extra)).toBeNull();
|
|
@@ -45,7 +45,7 @@ vi.mock('../config.js', () => ({
|
|
|
45
45
|
},
|
|
46
46
|
}));
|
|
47
47
|
|
|
48
|
-
import {
|
|
48
|
+
import { VariablesLoggingMiddleware } from '../logging/variablesLoggingMiddleware.js';
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Build a synthetic GraphQLResolveInfo-shaped object that matches what type-graphql passes
|
|
@@ -99,7 +99,7 @@ describe('variablesLoggingMiddleware', () => {
|
|
|
99
99
|
|
|
100
100
|
it('skips field resolvers (info.path.prev !== undefined) without logging', async () => {
|
|
101
101
|
const next = vi.fn(async () => 'next-result');
|
|
102
|
-
const result = await
|
|
102
|
+
const result = await VariablesLoggingMiddleware(
|
|
103
103
|
{
|
|
104
104
|
root: undefined,
|
|
105
105
|
args: { x: 1 },
|
|
@@ -126,7 +126,7 @@ describe('variablesLoggingMiddleware', () => {
|
|
|
126
126
|
],
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
-
await
|
|
129
|
+
await VariablesLoggingMiddleware(
|
|
130
130
|
{
|
|
131
131
|
root: undefined,
|
|
132
132
|
args: { input: { ID: 'abc', Name: 'HubSpot', Values: 'FAKE_SECRET' } },
|
|
@@ -165,7 +165,7 @@ describe('variablesLoggingMiddleware', () => {
|
|
|
165
165
|
Entities: [{ ClassName: 'SomeUnrelatedEntity', EncryptedFields: [] }],
|
|
166
166
|
};
|
|
167
167
|
|
|
168
|
-
await
|
|
168
|
+
await VariablesLoggingMiddleware(
|
|
169
169
|
{
|
|
170
170
|
root: undefined,
|
|
171
171
|
args: { token: 'plaintext-leak' },
|
|
@@ -196,7 +196,7 @@ describe('variablesLoggingMiddleware', () => {
|
|
|
196
196
|
const next = vi.fn(async () => undefined);
|
|
197
197
|
const fakeProvider = { Entities: [] };
|
|
198
198
|
|
|
199
|
-
await
|
|
199
|
+
await VariablesLoggingMiddleware(
|
|
200
200
|
{
|
|
201
201
|
root: undefined,
|
|
202
202
|
args: { input: { Values: 'FAKE_SECRET' } },
|
|
@@ -59,16 +59,22 @@ vi.mock('jsonwebtoken', () => ({
|
|
|
59
59
|
}));
|
|
60
60
|
|
|
61
61
|
vi.mock('../auth/index.js', () => ({
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
GetSigningKeys: mockGetSigningKeys,
|
|
63
|
+
get getSigningKeys() { return this.GetSigningKeys; },
|
|
64
|
+
GetSystemUser: vi.fn(),
|
|
65
|
+
get getSystemUser() { return this.GetSystemUser; },
|
|
66
|
+
GetValidationOptions: mockGetValidationOptions,
|
|
67
|
+
get getValidationOptions() { return this.GetValidationOptions; },
|
|
68
|
+
VerifyUserRecord: mockVerifyUserRecord,
|
|
69
|
+
get verifyUserRecord() { return this.VerifyUserRecord; },
|
|
70
|
+
ExtractUserInfoFromPayload: mockExtractUserInfo,
|
|
71
|
+
get extractUserInfoFromPayload() { return this.ExtractUserInfoFromPayload; },
|
|
67
72
|
}));
|
|
68
73
|
|
|
69
74
|
vi.mock('../cache.js', () => {
|
|
70
75
|
const map = new Map<string, boolean>();
|
|
71
|
-
return {
|
|
76
|
+
return { AuthCache: map,
|
|
77
|
+
get authCache() { return this.AuthCache; } };
|
|
72
78
|
});
|
|
73
79
|
|
|
74
80
|
vi.mock('../config.js', () => ({
|
|
@@ -95,7 +101,7 @@ vi.mock('@memberjunction/api-keys', () => ({
|
|
|
95
101
|
GetAPIKeyEngine: vi.fn(),
|
|
96
102
|
}));
|
|
97
103
|
|
|
98
|
-
import {
|
|
104
|
+
import { CreateUnifiedAuthMiddleware } from '../context.js';
|
|
99
105
|
import type { Request, Response, NextFunction } from 'express';
|
|
100
106
|
import type { DataSourceInfo } from '../types.js';
|
|
101
107
|
|
|
@@ -178,11 +184,11 @@ function setupSuccessfulAuth() {
|
|
|
178
184
|
// ─── Tests ──────────────────────────────────────────────────────────────────
|
|
179
185
|
|
|
180
186
|
describe('createUnifiedAuthMiddleware', () => {
|
|
181
|
-
let middleware: ReturnType<typeof
|
|
187
|
+
let middleware: ReturnType<typeof CreateUnifiedAuthMiddleware>;
|
|
182
188
|
|
|
183
189
|
beforeEach(() => {
|
|
184
190
|
vi.clearAllMocks();
|
|
185
|
-
middleware =
|
|
191
|
+
middleware = CreateUnifiedAuthMiddleware(mockDataSources);
|
|
186
192
|
});
|
|
187
193
|
|
|
188
194
|
describe('OPTIONS passthrough', () => {
|
|
@@ -13,7 +13,7 @@ vi.mock('@memberjunction/core', async (importOriginal) => {
|
|
|
13
13
|
};
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { ResolveIdentityByEmail } from '../realtimeWidget/visitorIdentity.js';
|
|
17
17
|
import type { EntityInfo, IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
18
18
|
|
|
19
19
|
type LookupParams = { EntityName: string; ExtraFilter: string; Fields: string[] };
|
|
@@ -32,7 +32,7 @@ describe('resolveIdentityByEmail — the configured identity entity can have ANY
|
|
|
32
32
|
it('selects the real key column and returns its bare value for a single non-ID key', async () => {
|
|
33
33
|
runViewMock.mockResolvedValue({ Success: true, Results: [{ individual_id: 4711 }] });
|
|
34
34
|
const provider = makeProvider({ ID: 'ent-persons', PrimaryKeys: [{ Name: 'individual_id' }] });
|
|
35
|
-
const out = await
|
|
35
|
+
const out = await ResolveIdentityByEmail('ada@example.com', user, provider, { entityName: 'Persons', EmailField: 'EmailAddress' });
|
|
36
36
|
expect(lastParams().Fields).toEqual(['individual_id']);
|
|
37
37
|
expect(lastParams().ExtraFilter).toBe("EmailAddress = 'ada@example.com'");
|
|
38
38
|
expect(out).toEqual({ entityId: 'ent-persons', recordId: '4711' });
|
|
@@ -41,7 +41,7 @@ describe('resolveIdentityByEmail — the configured identity entity can have ANY
|
|
|
41
41
|
it('selects EVERY key column and carries a composite key as a full segment, not its first column', async () => {
|
|
42
42
|
runViewMock.mockResolvedValue({ Success: true, Results: [{ OrderID: '11055', LineNo: 3 }] });
|
|
43
43
|
const provider = makeProvider({ ID: 'ent-lines', PrimaryKeys: [{ Name: 'OrderID' }, { Name: 'LineNo' }] });
|
|
44
|
-
const out = await
|
|
44
|
+
const out = await ResolveIdentityByEmail('x@y.com', user, provider, { entityName: 'Order Lines' });
|
|
45
45
|
expect(lastParams().Fields).toEqual(['OrderID', 'LineNo']);
|
|
46
46
|
expect(out).toEqual({ entityId: 'ent-lines', recordId: 'OrderID|11055||LineNo|3' });
|
|
47
47
|
});
|
|
@@ -49,13 +49,13 @@ describe('resolveIdentityByEmail — the configured identity entity can have ANY
|
|
|
49
49
|
it('stays anonymous when no row matches or a key column is null', async () => {
|
|
50
50
|
const provider = makeProvider({ ID: 'ent-users', PrimaryKeys: [{ Name: 'ID' }] });
|
|
51
51
|
runViewMock.mockResolvedValue({ Success: true, Results: [] });
|
|
52
|
-
expect(await
|
|
52
|
+
expect(await ResolveIdentityByEmail('none@y.com', user, provider)).toBeUndefined();
|
|
53
53
|
runViewMock.mockResolvedValue({ Success: true, Results: [{ ID: null }] });
|
|
54
|
-
expect(await
|
|
54
|
+
expect(await ResolveIdentityByEmail('null@y.com', user, provider)).toBeUndefined();
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
it('stays anonymous when the configured entity is not in metadata', async () => {
|
|
58
|
-
expect(await
|
|
58
|
+
expect(await ResolveIdentityByEmail('a@b.com', user, makeProvider(undefined), { entityName: 'Nope' })).toBeUndefined();
|
|
59
59
|
expect(runViewMock).not.toHaveBeenCalled();
|
|
60
60
|
});
|
|
61
61
|
});
|