@memberjunction/server 6.2.0-edge.0 → 6.2.0-edge.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.d.ts +2 -0
- package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.js +5 -1
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionManager.js +2 -2
- package/dist/agentSessions/remoteBrowserGoalEngine.d.ts +8 -0
- package/dist/agentSessions/remoteBrowserGoalEngine.d.ts.map +1 -1
- package/dist/agentSessions/remoteBrowserGoalEngine.js +21 -5
- package/dist/agentSessions/remoteBrowserGoalEngine.js.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.d.ts +2 -0
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +5 -1
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/index.d.ts +20 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +20 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +8 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +21 -5
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +9 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +22 -10
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts +17 -15
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +65 -51
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +2 -2
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +2 -2
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/magicLinkCore.d.ts +54 -33
- package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -1
- package/dist/auth/magicLink/magicLinkCore.js +61 -61
- package/dist/auth/magicLink/magicLinkCore.js.map +1 -1
- package/dist/auth/magicLink/redeemLanding.d.ts +4 -0
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
- package/dist/auth/magicLink/redeemLanding.js +12 -4
- package/dist/auth/magicLink/redeemLanding.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +4 -4
- package/dist/auth/principals.d.ts +2 -0
- package/dist/auth/principals.d.ts.map +1 -1
- package/dist/auth/principals.js +6 -2
- package/dist/auth/principals.js.map +1 -1
- package/dist/cache.d.ts +2 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +3 -1
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +346 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +34 -4
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +20 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +27 -19
- package/dist/context.js.map +1 -1
- package/dist/directives/Public.d.ts +2 -0
- package/dist/directives/Public.d.ts.map +1 -1
- package/dist/directives/Public.js +3 -1
- package/dist/directives/Public.js.map +1 -1
- package/dist/directives/RequireSystemUser.d.ts +2 -0
- package/dist/directives/RequireSystemUser.d.ts.map +1 -1
- package/dist/directives/RequireSystemUser.js +3 -1
- package/dist/directives/RequireSystemUser.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +1021 -0
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +7368 -2145
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +94 -4
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +122 -3
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/DeleteOptionsInput.d.ts +8 -1
- package/dist/generic/DeleteOptionsInput.d.ts.map +1 -1
- package/dist/generic/DeleteOptionsInput.js +1 -1
- package/dist/generic/DeleteOptionsInput.js.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.d.ts +18 -2
- package/dist/generic/FireAndForgetHeartbeat.d.ts.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.js +24 -6
- package/dist/generic/FireAndForgetHeartbeat.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts +31 -0
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -0
- package/dist/generic/OrphanedConversationDetailReconciler.js +215 -0
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -0
- package/dist/generic/PushStatusResolver.d.ts +48 -1
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +95 -4
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +18 -2
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +64 -55
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +120 -11
- package/dist/index.js.map +1 -1
- package/dist/integration/CustomColumnPromoter.d.ts +2 -0
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +5 -1
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/integration/EntityMapLifecycle.d.ts +4 -0
- package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
- package/dist/integration/EntityMapLifecycle.js +10 -2
- package/dist/integration/EntityMapLifecycle.js.map +1 -1
- package/dist/logging/NoLog.d.ts +4 -0
- package/dist/logging/NoLog.d.ts.map +1 -1
- package/dist/logging/NoLog.js +10 -2
- package/dist/logging/NoLog.js.map +1 -1
- package/dist/logging/StartupLogger.d.ts +2 -0
- package/dist/logging/StartupLogger.d.ts.map +1 -1
- package/dist/logging/StartupLogger.js +5 -1
- package/dist/logging/StartupLogger.js.map +1 -1
- package/dist/logging/bootAudit.d.ts +11 -7
- package/dist/logging/bootAudit.d.ts.map +1 -1
- package/dist/logging/bootAudit.js +15 -7
- package/dist/logging/bootAudit.js.map +1 -1
- package/dist/logging/boundaryLogPayload.d.ts +4 -0
- package/dist/logging/boundaryLogPayload.d.ts.map +1 -1
- package/dist/logging/boundaryLogPayload.js +5 -1
- package/dist/logging/boundaryLogPayload.js.map +1 -1
- package/dist/logging/secretRedactor.d.ts +2 -0
- package/dist/logging/secretRedactor.d.ts.map +1 -1
- package/dist/logging/secretRedactor.js +8 -4
- package/dist/logging/secretRedactor.js.map +1 -1
- package/dist/logging/shortenForLog.d.ts +2 -0
- package/dist/logging/shortenForLog.d.ts.map +1 -1
- package/dist/logging/shortenForLog.js +7 -3
- package/dist/logging/shortenForLog.js.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.d.ts +2 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.js +8 -6
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
- package/dist/metadataRefreshSignal.d.ts +19 -0
- package/dist/metadataRefreshSignal.d.ts.map +1 -0
- package/dist/metadataRefreshSignal.js +45 -0
- package/dist/metadataRefreshSignal.js.map +1 -0
- package/dist/middleware/MJTenantFilterMiddleware.js +4 -4
- package/dist/multiTenancy/index.d.ts +8 -0
- package/dist/multiTenancy/index.d.ts.map +1 -1
- package/dist/multiTenancy/index.js +21 -5
- package/dist/multiTenancy/index.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts +5 -0
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.js +14 -10
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts +6 -6
- package/dist/realtimeWidget/WidgetSessionService.js +27 -27
- package/dist/realtimeWidget/host-identity.d.ts +5 -1
- package/dist/realtimeWidget/host-identity.d.ts.map +1 -1
- package/dist/realtimeWidget/host-identity.js +11 -3
- package/dist/realtimeWidget/host-identity.js.map +1 -1
- package/dist/realtimeWidget/index.d.ts +2 -2
- package/dist/realtimeWidget/index.d.ts.map +1 -1
- package/dist/realtimeWidget/index.js +2 -2
- package/dist/realtimeWidget/index.js.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts +21 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.js +16 -4
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +48 -0
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +38 -10
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +10 -6
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +14 -6
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +3 -3
- package/dist/resolvers/AgentRunStatusPublisher.d.ts +55 -0
- package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -0
- package/dist/resolvers/AgentRunStatusPublisher.js +141 -0
- package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -0
- package/dist/resolvers/ConversationRunEventsResolver.d.ts +90 -0
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -0
- package/dist/resolvers/ConversationRunEventsResolver.js +283 -0
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.d.ts +98 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.d.ts.map +1 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.js +227 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.js.map +1 -0
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +2 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.js +3 -3
- package/dist/resolvers/GeoResolver.d.ts +2 -2
- package/dist/resolvers/GeoResolver.js +4 -4
- package/dist/resolvers/GetDataResolver.d.ts +14 -0
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +43 -15
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +2 -2
- package/dist/resolvers/ListOperationsResolver.d.ts +20 -0
- package/dist/resolvers/ListOperationsResolver.d.ts.map +1 -1
- package/dist/resolvers/ListOperationsResolver.js +68 -28
- package/dist/resolvers/ListOperationsResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts +11 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +7 -3
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +7 -0
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +16 -2
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +3 -3
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +44 -6
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +93 -37
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +5 -5
- package/dist/resolvers/RunAIAgentResolver.d.ts +8 -18
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +85 -184
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +2 -2
- package/dist/resolvers/RunDecisionResolver.d.ts +149 -0
- package/dist/resolvers/RunDecisionResolver.d.ts.map +1 -0
- package/dist/resolvers/RunDecisionResolver.js +396 -0
- package/dist/resolvers/RunDecisionResolver.js.map +1 -0
- package/dist/resolvers/RunTestResolver.js +5 -5
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts +8 -4
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +5 -5
- package/dist/resolvers/TaskGraphFrameResolver.d.ts +8 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.js +6 -2
- package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
- package/dist/resolvers/VectorizeEntityResolver.d.ts +1 -1
- package/dist/resolvers/VectorizeEntityResolver.d.ts.map +1 -1
- package/dist/resolvers/VectorizeEntityResolver.js +14 -10
- package/dist/resolvers/VectorizeEntityResolver.js.map +1 -1
- package/dist/resolvers/adhoc-query-helpers.d.ts +6 -0
- package/dist/resolvers/adhoc-query-helpers.d.ts.map +1 -1
- package/dist/resolvers/adhoc-query-helpers.js +10 -2
- package/dist/resolvers/adhoc-query-helpers.js.map +1 -1
- package/dist/resolvers/artifact-routing.d.ts +8 -8
- package/dist/resolvers/artifact-routing.js +2 -2
- package/dist/resolvers/artifact-routing.js.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.d.ts +10 -2
- package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.js +24 -8
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
- package/dist/resolvers/peaksSidecar.d.ts +4 -0
- package/dist/resolvers/peaksSidecar.d.ts.map +1 -1
- package/dist/resolvers/peaksSidecar.js +10 -2
- package/dist/resolvers/peaksSidecar.js.map +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts +28 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +20 -4
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/MediaStreamHandler.d.ts +2 -0
- package/dist/rest/MediaStreamHandler.d.ts.map +1 -1
- package/dist/rest/MediaStreamHandler.js +10 -6
- package/dist/rest/MediaStreamHandler.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts +9 -0
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +15 -3
- package/dist/rest/OAuthCallbackHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts +6 -4
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +15 -11
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts +5 -1
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeSdpBrokerHandler.js +12 -4
- package/dist/rest/RealtimeSdpBrokerHandler.js.map +1 -1
- package/dist/rest/SignatureWebhookHandler.d.ts +2 -0
- package/dist/rest/SignatureWebhookHandler.d.ts.map +1 -1
- package/dist/rest/SignatureWebhookHandler.js +5 -1
- package/dist/rest/SignatureWebhookHandler.js.map +1 -1
- package/dist/rest/UploadTokenManager.d.ts +24 -8
- package/dist/rest/UploadTokenManager.d.ts.map +1 -1
- package/dist/rest/UploadTokenManager.js +53 -21
- package/dist/rest/UploadTokenManager.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +20 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +20 -4
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/mediaRange.d.ts +4 -0
- package/dist/rest/mediaRange.d.ts.map +1 -1
- package/dist/rest/mediaRange.js +10 -2
- package/dist/rest/mediaRange.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +4 -0
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +13 -7
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverExtensionReservedRoots.d.ts +2 -0
- package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
- package/dist/serverExtensionReservedRoots.js +5 -1
- package/dist/serverExtensionReservedRoots.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +13 -8
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +16 -15
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -3
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +6 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +13 -5
- package/dist/util.js.map +1 -1
- package/package.json +94 -92
- package/src/__tests__/AgentRunStatusPublisher.test.ts +175 -0
- package/src/__tests__/DeleteOptionsInput.wireShape.test.ts +62 -0
- package/src/__tests__/DuplicateEntryCheckResolver.test.ts +300 -0
- package/src/__tests__/FileResolverPeaks.test.ts +13 -13
- package/src/__tests__/ListOperationsResolver.test.ts +17 -17
- package/src/__tests__/MediaStreamHandler.test.ts +28 -28
- package/src/__tests__/NoLog.test.ts +11 -11
- package/src/__tests__/PrimaryKeyAlwaysMapped.test.ts +10 -10
- package/src/__tests__/RESTEndpointHandler.test.ts +14 -14
- package/src/__tests__/RealtimeBridgeResolver.test.ts +4 -2
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +216 -2
- package/src/__tests__/RealtimeSdpBrokerHandler.test.ts +6 -6
- package/src/__tests__/RefreshAdoptsNewColumns.test.ts +8 -8
- package/src/__tests__/RemoteBrowserActionRecovery.test.ts +7 -1
- package/src/__tests__/RemoteBrowserAudioStream.test.ts +7 -1
- package/src/__tests__/RemoteBrowserGoalEngine.test.ts +18 -18
- package/src/__tests__/RemoteBrowserSnapshot.test.ts +7 -1
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +52 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +398 -0
- package/src/__tests__/RunAIAgentResolver.streaming.test.ts +18 -27
- package/src/__tests__/RunDecisionResolver.test.ts +699 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +131 -0
- package/src/__tests__/TaskGraphFrameResolver.test.ts +2 -2
- package/src/__tests__/VectorizeEntityResolver.test.ts +106 -0
- package/src/__tests__/WidgetSessionService.test.ts +8 -4
- package/src/__tests__/adhoc-query-helpers.test.ts +21 -21
- package/src/__tests__/bootAudit.test.ts +11 -11
- package/src/__tests__/boundaryLogPayload.test.ts +6 -6
- package/src/__tests__/cacheInvalidationRecordData.test.ts +177 -0
- package/src/__tests__/conversationRunEvents.test.ts +399 -0
- package/src/__tests__/databaseAbstraction.test.ts +12 -6
- package/src/__tests__/getDataTokenRedaction.test.ts +7 -7
- package/src/__tests__/initializeProviders.refresh.test.ts +4 -4
- package/src/__tests__/magicLink.test.ts +73 -134
- package/src/__tests__/magicLinkService.consume.test.ts +224 -0
- package/src/__tests__/meetingRecordingRegistration.test.ts +12 -12
- package/src/__tests__/metadataRefreshSignal.test.ts +78 -0
- package/src/__tests__/multiTenancy.security.test.ts +40 -40
- package/src/__tests__/multiTenancy.test.ts +18 -18
- package/src/__tests__/newUsers.test.ts +24 -23
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +283 -0
- package/src/__tests__/principals.test.ts +22 -22
- package/src/__tests__/pushStatusFanOut.test.ts +206 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +8 -8
- package/src/__tests__/secretRedactor.failOpen.test.ts +12 -12
- package/src/__tests__/secretRedactor.test.ts +12 -12
- package/src/__tests__/serverExtensionReservedRoots.test.ts +7 -7
- package/src/__tests__/subscriptionRedaction.test.ts +5 -5
- package/src/__tests__/unifiedAuth.test.ts +15 -9
- package/src/__tests__/visitorIdentity.resolve.test.ts +6 -6
- package/src/__tests__/widget.test.ts +45 -45
- package/src/__tests__/widgetGuestElevation.test.ts +7 -7
- package/src/__tests__/widgetHostIdentity.test.ts +14 -14
- package/src/agentSessions/ReturningVisitorRecap.ts +12 -1
- package/src/agentSessions/SessionManager.ts +2 -2
- package/src/agentSessions/remoteBrowserGoalEngine.ts +30 -5
- package/src/auth/AuthProviderCatalogRouter.ts +6 -1
- package/src/auth/__tests__/backward-compatibility.test.ts +4 -3
- package/src/auth/index.ts +43 -28
- package/src/auth/initializeProviders.ts +25 -5
- package/src/auth/magicLink/MagicLinkRouter.ts +28 -10
- package/src/auth/magicLink/MagicLinkService.ts +71 -52
- package/src/auth/magicLink/index.ts +7 -7
- package/src/auth/magicLink/magicLinkCore.ts +96 -64
- package/src/auth/magicLink/redeemLanding.ts +14 -4
- package/src/auth/magicLink/types.ts +54 -54
- package/src/auth/newUsers.ts +1 -1
- package/src/auth/principals.ts +11 -2
- package/src/cache.ts +4 -1
- package/src/config.ts +37 -4
- package/src/context.ts +37 -24
- package/src/directives/Public.ts +4 -1
- package/src/directives/RequireSystemUser.ts +4 -1
- package/src/generated/graphql-schemas/__mj.ts +3674 -4
- package/src/generic/CacheInvalidationResolver.ts +148 -4
- package/src/generic/DeleteOptionsInput.ts +9 -2
- package/src/generic/FireAndForgetHeartbeat.ts +35 -16
- package/src/generic/OrphanedConversationDetailReconciler.ts +267 -0
- package/src/generic/PushStatusResolver.ts +118 -8
- package/src/generic/ResolverBase.ts +65 -57
- package/src/generic/RunViewResolver.ts +22 -22
- package/src/generic/__tests__/FireAndForgetHeartbeat.test.ts +7 -7
- package/src/index.ts +137 -11
- package/src/integration/CustomColumnPromoter.ts +6 -1
- package/src/integration/EntityMapLifecycle.ts +20 -2
- package/src/logging/NoLog.ts +16 -2
- package/src/logging/StartupLogger.ts +6 -1
- package/src/logging/bootAudit.ts +26 -16
- package/src/logging/boundaryLogPayload.ts +8 -1
- package/src/logging/secretRedactor.ts +14 -9
- package/src/logging/shortenForLog.ts +8 -3
- package/src/logging/variablesLoggingMiddleware.ts +9 -6
- package/src/metadataRefreshSignal.ts +45 -0
- package/src/middleware/MJTenantFilterMiddleware.ts +4 -4
- package/src/multiTenancy/index.ts +29 -5
- package/src/realtimeWidget/WidgetRouter.ts +15 -10
- package/src/realtimeWidget/WidgetSessionService.ts +76 -76
- package/src/realtimeWidget/host-identity.ts +24 -10
- package/src/realtimeWidget/index.ts +3 -3
- package/src/realtimeWidget/visitorIdentity.ts +39 -8
- package/src/realtimeWidget/widgetCore.ts +75 -10
- package/src/realtimeWidget/widgetGuestElevation.ts +25 -12
- package/src/resolvers/AdhocQueryResolver.ts +3 -3
- package/src/resolvers/AgentRunStatusPublisher.ts +175 -0
- package/src/resolvers/AgentSessionResolver.ts +3 -3
- package/src/resolvers/ColorResolver.ts +6 -6
- package/src/resolvers/ComponentRegistryResolver.ts +36 -36
- package/src/resolvers/ConversationRunEventsResolver.ts +308 -0
- package/src/resolvers/DuplicateEntryCheckResolver.ts +232 -0
- package/src/resolvers/EntityCommunicationsResolver.ts +4 -4
- package/src/resolvers/ExecuteRemoteOperationResolver.ts +9 -9
- package/src/resolvers/FetchEntityVectorsResolver.ts +2 -1
- package/src/resolvers/FileResolver.ts +42 -42
- package/src/resolvers/GeoResolver.ts +4 -4
- package/src/resolvers/GetDataResolver.ts +50 -15
- package/src/resolvers/IntegrationDiscoveryResolver.ts +2 -2
- package/src/resolvers/ListOperationsResolver.ts +78 -28
- package/src/resolvers/MCPResolver.ts +30 -15
- package/src/resolvers/MergeRecordsResolver.ts +14 -2
- package/src/resolvers/QueryResolver.ts +13 -13
- package/src/resolvers/RealtimeBridgeResolver.ts +3 -3
- package/src/resolvers/RealtimeClientSessionResolver.ts +96 -38
- package/src/resolvers/RemoteBrowserActionResolver.ts +5 -5
- package/src/resolvers/RunAIAgentResolver.ts +134 -239
- package/src/resolvers/RunAIPromptResolver.ts +22 -22
- package/src/resolvers/RunDecisionResolver.ts +435 -0
- package/src/resolvers/RunTemplateResolver.ts +4 -4
- package/src/resolvers/RunTestResolver.ts +25 -25
- package/src/resolvers/SqlLoggingConfigResolver.ts +56 -56
- package/src/resolvers/TaskGraphFrameResolver.ts +37 -28
- package/src/resolvers/TelemetryResolver.ts +79 -79
- package/src/resolvers/VectorizeEntityResolver.ts +16 -11
- package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +40 -38
- package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +93 -0
- package/src/resolvers/__tests__/artifact-routing.test.ts +23 -23
- package/src/resolvers/adhoc-query-helpers.ts +19 -2
- package/src/resolvers/artifact-routing.ts +19 -19
- package/src/resolvers/meetingRecordingRegistration.ts +44 -10
- package/src/resolvers/peaksSidecar.ts +12 -2
- package/src/rest/EntityCRUDHandler.ts +24 -4
- package/src/rest/MediaStreamHandler.ts +11 -6
- package/src/rest/OAuthCallbackHandler.ts +25 -7
- package/src/rest/RESTEndpointHandler.ts +20 -15
- package/src/rest/RealtimeSdpBrokerHandler.ts +14 -4
- package/src/rest/SignatureWebhookHandler.ts +6 -1
- package/src/rest/UploadTokenManager.ts +66 -30
- package/src/rest/ViewOperationsHandler.ts +24 -4
- package/src/rest/mediaRange.ts +16 -6
- package/src/rest/setupRESTEndpoints.ts +24 -12
- package/src/serverExtensionReservedRoots.ts +6 -1
- package/src/services/TaskGraphActionRunner.ts +16 -15
- package/src/types.ts +21 -16
- package/src/util.ts +16 -6
package/src/auth/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ export * from './scopeLimitedPrincipal.js';
|
|
|
14
14
|
export * from './actingContextResolver.js';
|
|
15
15
|
export * from './AuthProviderEngine.js';
|
|
16
16
|
export * from './AuthProviderCatalogRouter.js';
|
|
17
|
-
export { initializeAuthProviders, initializeAuthProvidersFromMetadata, refreshAuthProviders, validateAuthProvidersRegistered } from './initializeProviders.js';
|
|
17
|
+
export { InitializeAuthProviders, initializeAuthProviders, InitializeAuthProvidersFromMetadata, initializeAuthProvidersFromMetadata, RefreshAuthProviders, refreshAuthProviders, ValidateAuthProvidersRegistered, validateAuthProvidersRegistered } from './initializeProviders.js';
|
|
18
18
|
|
|
19
19
|
// This is a hard-coded forever constant due to internal migrations
|
|
20
20
|
|
|
@@ -58,7 +58,7 @@ const refreshUserCache = async () => {
|
|
|
58
58
|
* the same domain with different audiences/client IDs), all unique audiences
|
|
59
59
|
* are aggregated into an array. jwt.verify() natively accepts string | string[].
|
|
60
60
|
*/
|
|
61
|
-
export const
|
|
61
|
+
export const GetValidationOptions = (issuer: string): { audience: string | string[]; jwksUri: string } | undefined => {
|
|
62
62
|
const factory = AuthProviderFactory.Instance;
|
|
63
63
|
const providers = factory.getAllByIssuer(issuer);
|
|
64
64
|
|
|
@@ -75,16 +75,19 @@ export const getValidationOptions = (issuer: string): { audience: string | strin
|
|
|
75
75
|
};
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
+
/** @deprecated Use {@link GetValidationOptions}. */
|
|
79
|
+
export const getValidationOptions = GetValidationOptions;
|
|
80
|
+
|
|
78
81
|
/**
|
|
79
82
|
* Backward compatible validationOptions object
|
|
80
83
|
* @deprecated Use getValidationOptions() or AuthProviderRegistry instead
|
|
81
84
|
*/
|
|
82
85
|
export const validationOptions: Record<string, { audience: string | string[]; jwksUri: string }> = new Proxy({}, {
|
|
83
86
|
get: (target, prop: string) => {
|
|
84
|
-
return
|
|
87
|
+
return GetValidationOptions(prop);
|
|
85
88
|
},
|
|
86
89
|
has: (target, prop: string) => {
|
|
87
|
-
return
|
|
90
|
+
return GetValidationOptions(prop) !== undefined;
|
|
88
91
|
},
|
|
89
92
|
ownKeys: () => {
|
|
90
93
|
const factory = AuthProviderFactory.Instance;
|
|
@@ -93,31 +96,31 @@ export const validationOptions: Record<string, { audience: string | string[]; jw
|
|
|
93
96
|
});
|
|
94
97
|
|
|
95
98
|
export class UserPayload {
|
|
96
|
-
aio?: string;
|
|
97
|
-
aud?: string;
|
|
98
|
-
exp?: number;
|
|
99
|
-
iat?: number;
|
|
100
|
-
iss?: string;
|
|
101
|
-
name?: string;
|
|
102
|
-
nbf?: number;
|
|
103
|
-
nonce?: string;
|
|
104
|
-
oid?: string;
|
|
105
|
-
preferred_username?: string;
|
|
106
|
-
rh?: string;
|
|
107
|
-
sub?: string;
|
|
108
|
-
tid?: string;
|
|
109
|
-
uti?: string;
|
|
110
|
-
ver?: string;
|
|
111
|
-
email?: string;
|
|
112
|
-
given_name?: string;
|
|
113
|
-
family_name?: string;
|
|
99
|
+
aio?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
100
|
+
aud?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
101
|
+
exp?: number; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
102
|
+
iat?: number; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
103
|
+
iss?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
104
|
+
name?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
105
|
+
nbf?: number; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
106
|
+
nonce?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
107
|
+
oid?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
108
|
+
preferred_username?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
109
|
+
rh?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
110
|
+
sub?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
111
|
+
tid?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
112
|
+
uti?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
113
|
+
ver?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
114
|
+
email?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
115
|
+
given_name?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
116
|
+
family_name?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member
|
|
114
117
|
[key: string]: unknown; // Allow additional claims
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
/**
|
|
118
121
|
* Gets signing keys for JWT validation
|
|
119
122
|
*/
|
|
120
|
-
export const
|
|
123
|
+
export const GetSigningKeys = (issuer: string) => (header: JwtHeader, cb: SigningKeyCallback) => {
|
|
121
124
|
const factory = AuthProviderFactory.Instance;
|
|
122
125
|
|
|
123
126
|
// Initialize providers if not already done
|
|
@@ -138,10 +141,13 @@ export const getSigningKeys = (issuer: string) => (header: JwtHeader, cb: Signin
|
|
|
138
141
|
provider.getSigningKey(header, cb);
|
|
139
142
|
};
|
|
140
143
|
|
|
144
|
+
/** @deprecated Use {@link GetSigningKeys}. */
|
|
145
|
+
export const getSigningKeys = GetSigningKeys;
|
|
146
|
+
|
|
141
147
|
/**
|
|
142
148
|
* Extracts user information from JWT payload using the appropriate provider
|
|
143
149
|
*/
|
|
144
|
-
export const
|
|
150
|
+
export const ExtractUserInfoFromPayload = (payload: JwtPayload): {
|
|
145
151
|
email?: string;
|
|
146
152
|
firstName?: string;
|
|
147
153
|
lastName?: string;
|
|
@@ -181,20 +187,26 @@ export const extractUserInfoFromPayload = (payload: JwtPayload): {
|
|
|
181
187
|
return provider.extractUserInfo(payload);
|
|
182
188
|
};
|
|
183
189
|
|
|
184
|
-
|
|
190
|
+
/** @deprecated Use {@link ExtractUserInfoFromPayload}. */
|
|
191
|
+
export const extractUserInfoFromPayload = ExtractUserInfoFromPayload;
|
|
192
|
+
|
|
193
|
+
export const GetSystemUser = async (dataSource?: sql.ConnectionPool, attemptCacheUpdateIfNeeded: boolean = true): Promise<UserInfo> => {
|
|
185
194
|
const systemUser = UserCache.Instance.GetSystemUser();
|
|
186
195
|
if (!systemUser) {
|
|
187
196
|
if (dataSource && attemptCacheUpdateIfNeeded) {
|
|
188
197
|
console.warn(`System user not found in cache. Updating cache in attempt to find the user...`);
|
|
189
198
|
|
|
190
199
|
await refreshUserCache();
|
|
191
|
-
return
|
|
200
|
+
return GetSystemUser(dataSource, false); // try one more time but do not update cache next time if not found
|
|
192
201
|
}
|
|
193
202
|
throw new Error(`System user ID '${UserCache.Instance.SYSTEM_USER_ID}' not found in database`);
|
|
194
203
|
}
|
|
195
204
|
return systemUser;
|
|
196
205
|
};
|
|
197
206
|
|
|
207
|
+
/** @deprecated Use {@link GetSystemUser}. */
|
|
208
|
+
export const getSystemUser = GetSystemUser;
|
|
209
|
+
|
|
198
210
|
/**
|
|
199
211
|
* Extracts the lowercased domain portion of an email address.
|
|
200
212
|
*
|
|
@@ -231,7 +243,7 @@ const isDomainAuthorized = (domain: string): boolean =>
|
|
|
231
243
|
* authorization runs against the verified JWT's email domain instead. Retained for audit
|
|
232
244
|
* logging and for the recursive retry call.
|
|
233
245
|
*/
|
|
234
|
-
export const
|
|
246
|
+
export const VerifyUserRecord = async (
|
|
235
247
|
email?: string,
|
|
236
248
|
firstName?: string,
|
|
237
249
|
lastName?: string,
|
|
@@ -311,12 +323,15 @@ export const verifyUserRecord = async (
|
|
|
311
323
|
|
|
312
324
|
await refreshUserCache();
|
|
313
325
|
|
|
314
|
-
return
|
|
326
|
+
return VerifyUserRecord(email, firstName, lastName, requestDomain, dataSource, false); // try one more time but do not update cache next time if not found
|
|
315
327
|
}
|
|
316
328
|
}
|
|
317
329
|
|
|
318
330
|
return user;
|
|
319
331
|
};
|
|
320
332
|
|
|
333
|
+
/** @deprecated Use {@link VerifyUserRecord}. */
|
|
334
|
+
export const verifyUserRecord = VerifyUserRecord;
|
|
335
|
+
|
|
321
336
|
// Initialize providers on module load
|
|
322
337
|
initializeAuthProviders();
|
|
@@ -14,7 +14,7 @@ import { AuthProviderEngine } from './AuthProviderEngine.js';
|
|
|
14
14
|
* {@link initializeAuthProvidersFromMetadata}, which runs later in startup once a database
|
|
15
15
|
* connection and a system user exist.
|
|
16
16
|
*/
|
|
17
|
-
export function
|
|
17
|
+
export function InitializeAuthProviders(): void {
|
|
18
18
|
const factory = AuthProviderFactory.Instance;
|
|
19
19
|
|
|
20
20
|
// Clear any existing providers
|
|
@@ -60,6 +60,11 @@ export function initializeAuthProviders(): void {
|
|
|
60
60
|
// authProviders array at this point, and erroring here would cry wolf on every boot.
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/** @deprecated Use {@link InitializeAuthProviders}. */
|
|
64
|
+
export function initializeAuthProviders(): void {
|
|
65
|
+
return InitializeAuthProviders();
|
|
66
|
+
}
|
|
67
|
+
|
|
63
68
|
/**
|
|
64
69
|
* Layers the metadata provider catalog on top of the config-declared providers.
|
|
65
70
|
*
|
|
@@ -74,7 +79,7 @@ export function initializeAuthProviders(): void {
|
|
|
74
79
|
*
|
|
75
80
|
* @returns the number of providers registered from metadata.
|
|
76
81
|
*/
|
|
77
|
-
export async function
|
|
82
|
+
export async function InitializeAuthProvidersFromMetadata(contextUser?: UserInfo, provider?: IMetadataProvider): Promise<number> {
|
|
78
83
|
try {
|
|
79
84
|
await AuthProviderEngine.Instance.Config(false, contextUser, provider);
|
|
80
85
|
const count = await AuthProviderEngine.Instance.RegisterAll(contextUser);
|
|
@@ -89,6 +94,11 @@ export async function initializeAuthProvidersFromMetadata(contextUser?: UserInfo
|
|
|
89
94
|
}
|
|
90
95
|
}
|
|
91
96
|
|
|
97
|
+
/** @deprecated Use {@link InitializeAuthProvidersFromMetadata}. */
|
|
98
|
+
export async function initializeAuthProvidersFromMetadata(contextUser?: UserInfo, provider?: IMetadataProvider): Promise<number> {
|
|
99
|
+
return InitializeAuthProvidersFromMetadata(contextUser, provider);
|
|
100
|
+
}
|
|
101
|
+
|
|
92
102
|
/**
|
|
93
103
|
* Rebuilds the provider registry from scratch: config-declared providers first, then the
|
|
94
104
|
* metadata catalog layered on top — the same two-source order as startup.
|
|
@@ -119,7 +129,7 @@ export async function initializeAuthProvidersFromMetadata(contextUser?: UserInfo
|
|
|
119
129
|
*
|
|
120
130
|
* @returns the number of providers registered from metadata after the refresh.
|
|
121
131
|
*/
|
|
122
|
-
export async function
|
|
132
|
+
export async function RefreshAuthProviders(contextUser?: UserInfo, provider?: IMetadataProvider): Promise<number> {
|
|
123
133
|
await AuthProviderEngine.Instance.Config(true, contextUser, provider);
|
|
124
134
|
|
|
125
135
|
// Probe the reloaded catalog BEFORE clearing anything: reading Providers throws
|
|
@@ -127,7 +137,7 @@ export async function refreshAuthProviders(contextUser?: UserInfo, provider?: IM
|
|
|
127
137
|
// failure must abort the refresh while the registry is still intact.
|
|
128
138
|
const pendingRows = AuthProviderEngine.Instance.Providers.length;
|
|
129
139
|
|
|
130
|
-
|
|
140
|
+
InitializeAuthProviders();
|
|
131
141
|
const count = await AuthProviderEngine.Instance.RegisterAll(contextUser);
|
|
132
142
|
LogStatus(
|
|
133
143
|
`[Auth] Provider registry refreshed — ${count} of ${pendingRows} metadata provider(s) registered on top of the config-declared set.`
|
|
@@ -135,6 +145,11 @@ export async function refreshAuthProviders(contextUser?: UserInfo, provider?: IM
|
|
|
135
145
|
return count;
|
|
136
146
|
}
|
|
137
147
|
|
|
148
|
+
/** @deprecated Use {@link RefreshAuthProviders}. */
|
|
149
|
+
export async function refreshAuthProviders(contextUser?: UserInfo, provider?: IMetadataProvider): Promise<number> {
|
|
150
|
+
return RefreshAuthProviders(contextUser, provider);
|
|
151
|
+
}
|
|
152
|
+
|
|
138
153
|
/**
|
|
139
154
|
* Reports whether any provider is registered, from either source, and logs a diagnostic when none
|
|
140
155
|
* is.
|
|
@@ -142,7 +157,7 @@ export async function refreshAuthProviders(contextUser?: UserInfo, provider?: IM
|
|
|
142
157
|
* Split out from {@link initializeAuthProviders} because "no providers" is only genuinely wrong
|
|
143
158
|
* once BOTH sources have had their turn.
|
|
144
159
|
*/
|
|
145
|
-
export function
|
|
160
|
+
export function ValidateAuthProvidersRegistered(): boolean {
|
|
146
161
|
const hasProviders = AuthProviderFactory.Instance.hasProviders();
|
|
147
162
|
if (!hasProviders) {
|
|
148
163
|
LogError(
|
|
@@ -152,3 +167,8 @@ export function validateAuthProvidersRegistered(): boolean {
|
|
|
152
167
|
}
|
|
153
168
|
return hasProviders;
|
|
154
169
|
}
|
|
170
|
+
|
|
171
|
+
/** @deprecated Use {@link ValidateAuthProvidersRegistered}. */
|
|
172
|
+
export function validateAuthProvidersRegistered(): boolean {
|
|
173
|
+
return ValidateAuthProvidersRegistered();
|
|
174
|
+
}
|
|
@@ -15,7 +15,7 @@ import { AuthProviderFactory } from '@memberjunction/auth-providers';
|
|
|
15
15
|
import { configInfo, type MagicLinkConfig } from '../../config.js';
|
|
16
16
|
import { MagicLinkKeyManager } from './MagicLinkKeys.js';
|
|
17
17
|
import { MagicLinkService } from './MagicLinkService.js';
|
|
18
|
-
import {
|
|
18
|
+
import { BuildRedeemLandingHtml } from './redeemLanding.js';
|
|
19
19
|
import type { CreateMagicLinkInviteParams, RedeemMagicLinkResult } from './types.js';
|
|
20
20
|
|
|
21
21
|
/** The mount path for both routers (`/magic-link`). */
|
|
@@ -28,7 +28,7 @@ export const MAGIC_LINK_JWKS_PATH = `${MAGIC_LINK_MOUNT_PATH}/jwks.json`;
|
|
|
28
28
|
* Builds the magic-link routers. The caller mounts `publicRouter` before the
|
|
29
29
|
* auth middleware and `authenticatedRouter` after it (both at MAGIC_LINK_MOUNT_PATH).
|
|
30
30
|
*/
|
|
31
|
-
export function
|
|
31
|
+
export function CreateMagicLinkHandler(publicUrl: string, config: MagicLinkConfig): {
|
|
32
32
|
publicRouter: Router;
|
|
33
33
|
authenticatedRouter: Router;
|
|
34
34
|
} {
|
|
@@ -113,7 +113,7 @@ export function createMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
113
113
|
res
|
|
114
114
|
.status(200)
|
|
115
115
|
.type('html')
|
|
116
|
-
.send(
|
|
116
|
+
.send(BuildRedeemLandingHtml(token, `${MAGIC_LINK_MOUNT_PATH}/redeem`));
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
// POST /redeem performs the actual (side-effectful) redemption. Token arrives
|
|
@@ -151,7 +151,7 @@ export function createMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
const body = (req.body ?? {}) as Partial<CreateMagicLinkInviteParams>;
|
|
154
|
-
if (!body.email || !body.
|
|
154
|
+
if (!body.email || !body.ApplicationId) {
|
|
155
155
|
res.status(400).json({ success: false, error: 'email and applicationId are required.' });
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
@@ -159,10 +159,10 @@ export function createMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
159
159
|
const result = await service.CreateInvite(
|
|
160
160
|
{
|
|
161
161
|
email: body.email,
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
ApplicationId: body.ApplicationId,
|
|
163
|
+
RoleId: body.RoleId,
|
|
164
|
+
ExpiresInHours: body.ExpiresInHours,
|
|
165
|
+
MaxUses: body.MaxUses,
|
|
166
166
|
firstName: body.firstName,
|
|
167
167
|
lastName: body.lastName,
|
|
168
168
|
},
|
|
@@ -177,6 +177,14 @@ export function createMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
177
177
|
return { publicRouter, authenticatedRouter };
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
/** @deprecated Use {@link CreateMagicLinkHandler}. */
|
|
181
|
+
export function createMagicLinkHandler(publicUrl: string, config: MagicLinkConfig): {
|
|
182
|
+
publicRouter: Router;
|
|
183
|
+
authenticatedRouter: Router;
|
|
184
|
+
} {
|
|
185
|
+
return CreateMagicLinkHandler(publicUrl, config);
|
|
186
|
+
}
|
|
187
|
+
|
|
180
188
|
/**
|
|
181
189
|
* A minimal PUBLIC router that serves ONLY the JWKS endpoint (the magic-link
|
|
182
190
|
* signing key's public half). Mount this when the full magic-link flow is
|
|
@@ -186,7 +194,7 @@ export function createMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
186
194
|
* request 401s. Assumes the key is already initialized (the widget handler does
|
|
187
195
|
* this via `MagicLinkKeyManager.Instance.Initialize` at startup).
|
|
188
196
|
*/
|
|
189
|
-
export function
|
|
197
|
+
export function CreateMagicLinkJwksRouter(): Router {
|
|
190
198
|
const router = Router();
|
|
191
199
|
router.get('/jwks.json', (_req: Request, res: Response) => {
|
|
192
200
|
res.status(200).json(MagicLinkKeyManager.Instance.GetJWKS());
|
|
@@ -194,6 +202,11 @@ export function createMagicLinkJwksRouter(): Router {
|
|
|
194
202
|
return router;
|
|
195
203
|
}
|
|
196
204
|
|
|
205
|
+
/** @deprecated Use {@link CreateMagicLinkJwksRouter}. */
|
|
206
|
+
export function createMagicLinkJwksRouter(): Router {
|
|
207
|
+
return CreateMagicLinkJwksRouter();
|
|
208
|
+
}
|
|
209
|
+
|
|
197
210
|
/**
|
|
198
211
|
* Registers the `magic-link` auth provider so MJServer's issuer-driven JWT
|
|
199
212
|
* validation accepts MJ-issued session tokens. Issuer = public URL, JWKS URL =
|
|
@@ -202,7 +215,7 @@ export function createMagicLinkJwksRouter(): Router {
|
|
|
202
215
|
* Also appends the provider to `configInfo.authProviders` so a later
|
|
203
216
|
* `initializeAuthProviders()` (which clears + repopulates from config) keeps it.
|
|
204
217
|
*/
|
|
205
|
-
export function
|
|
218
|
+
export function RegisterMagicLinkAuthProvider(publicUrl: string, config: MagicLinkConfig): void {
|
|
206
219
|
const base = publicUrl.replace(/\/$/, '');
|
|
207
220
|
const providerConfig: AuthProviderConfig = {
|
|
208
221
|
name: 'magic-link',
|
|
@@ -224,3 +237,8 @@ export function registerMagicLinkAuthProvider(publicUrl: string, config: MagicLi
|
|
|
224
237
|
LogError(`[MagicLink] Failed to register auth provider: ${e instanceof Error ? e.message : String(e)}`);
|
|
225
238
|
}
|
|
226
239
|
}
|
|
240
|
+
|
|
241
|
+
/** @deprecated Use {@link RegisterMagicLinkAuthProvider}. */
|
|
242
|
+
export function registerMagicLinkAuthProvider(publicUrl: string, config: MagicLinkConfig): void {
|
|
243
|
+
return RegisterMagicLinkAuthProvider(publicUrl, config);
|
|
244
|
+
}
|
|
@@ -35,7 +35,7 @@ import { CommunicationEngine } from '@memberjunction/communication-engine';
|
|
|
35
35
|
import { Message } from '@memberjunction/communication-types';
|
|
36
36
|
import { configInfo, type MagicLinkConfig } from '../../config.js';
|
|
37
37
|
import { MagicLinkKeyManager } from './MagicLinkKeys.js';
|
|
38
|
-
import {
|
|
38
|
+
import { GenerateRawToken, GenerateSessionId, HashToken, EvaluateInvite, BuildSessionClaims, BuildConsumeInvitePostgresSQL, CanIssueInvites, IsRoleGrantable, MAGIC_LINK_TOKEN_PREFIX } from './magicLinkCore.js';
|
|
39
39
|
import type {
|
|
40
40
|
CreateMagicLinkInviteParams,
|
|
41
41
|
CreateMagicLinkInviteResult,
|
|
@@ -48,6 +48,21 @@ const REDEMPTION_ENTITY = 'MJ: Magic Link Redemptions';
|
|
|
48
48
|
/** Shared Anonymous principal — seeded by the Phase-4 migration; must match that UUID. */
|
|
49
49
|
const ANONYMOUS_USER_ID = '273910DF-28F1-45C1-A8F8-6E9AD8E5F008';
|
|
50
50
|
|
|
51
|
+
/** Outcome of the atomic single-use consume — see {@link MagicLinkService.consumeInvite}. */
|
|
52
|
+
type ConsumeOutcome = 'won' | 'lost' | 'failed';
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The SQL Server guarded single-use procedure (migration V202609291627__v6.2.x__MagicLink_Consume_Invite_Sproc).
|
|
56
|
+
* A procedure, not raw DML, because on SQL Server MJ grants its runtime roles EXECUTE on procedures
|
|
57
|
+
* and SELECT on views — never DML on base tables — so on any host whose MJAPI login is not db_owner
|
|
58
|
+
* a raw UPDATE is refused (#4753). Ownership chaining lets the procedure update the table on the
|
|
59
|
+
* caller's behalf. PostgreSQL has no counterpart function; see {@link BuildConsumeInvitePostgresSQL}.
|
|
60
|
+
*/
|
|
61
|
+
const CONSUME_INVITE_PROC = 'spConsumeMagicLinkInvite';
|
|
62
|
+
|
|
63
|
+
/** MagicLinkInvite base table (core schema) — the PostgreSQL consume updates it directly. */
|
|
64
|
+
const INVITE_TABLE = 'MagicLinkInvite';
|
|
65
|
+
|
|
51
66
|
/** Outcome of provisioning a redeeming user. */
|
|
52
67
|
interface ProvisionResult {
|
|
53
68
|
success: boolean;
|
|
@@ -90,11 +105,11 @@ export class MagicLinkService {
|
|
|
90
105
|
// external user already holding a restricted magic-link session — could
|
|
91
106
|
// issue invites and escalate.
|
|
92
107
|
const callerRoleNames = (creatingUser.UserRoles ?? []).map((r) => r.Role).filter((n): n is string => !!n);
|
|
93
|
-
if (!
|
|
108
|
+
if (!CanIssueInvites(creatingUser.Type, callerRoleNames, this.config.inviteIssuerRoleNames)) {
|
|
94
109
|
return { success: false, errorCode: 'forbidden', error: 'Not authorized to issue magic-link invites.' };
|
|
95
110
|
}
|
|
96
111
|
|
|
97
|
-
const roleId = params.
|
|
112
|
+
const roleId = params.RoleId ?? this.resolveRestrictedRoleId(md);
|
|
98
113
|
if (!roleId) {
|
|
99
114
|
return { success: false, error: `Restricted role '${this.config.restrictedRoleName}' not found and no roleId supplied.` };
|
|
100
115
|
}
|
|
@@ -106,7 +121,7 @@ export class MagicLinkService {
|
|
|
106
121
|
if (!roleToGrant) {
|
|
107
122
|
return { success: false, errorCode: 'invalid_role', error: `Role '${roleId}' not found.` };
|
|
108
123
|
}
|
|
109
|
-
if (!
|
|
124
|
+
if (!IsRoleGrantable(roleToGrant.Name, this.config.restrictedRoleName, this.config.grantableRoleNames)) {
|
|
110
125
|
return {
|
|
111
126
|
success: false,
|
|
112
127
|
errorCode: 'invalid_role',
|
|
@@ -114,23 +129,23 @@ export class MagicLinkService {
|
|
|
114
129
|
};
|
|
115
130
|
}
|
|
116
131
|
|
|
117
|
-
const app = md.Applications.find((a) => UUIDsEqual(a.ID, params.
|
|
132
|
+
const app = md.Applications.find((a) => UUIDsEqual(a.ID, params.ApplicationId));
|
|
118
133
|
if (!app) {
|
|
119
|
-
return { success: false, error: `Application '${params.
|
|
134
|
+
return { success: false, error: `Application '${params.ApplicationId}' not found.` };
|
|
120
135
|
}
|
|
121
136
|
|
|
122
|
-
const rawToken =
|
|
123
|
-
const expiresInHours = params.
|
|
137
|
+
const rawToken = GenerateRawToken();
|
|
138
|
+
const expiresInHours = params.ExpiresInHours ?? this.config.defaultExpiresInHours;
|
|
124
139
|
const expiresAt = new Date(Date.now() + expiresInHours * 3600 * 1000);
|
|
125
140
|
|
|
126
141
|
const invite = await md.GetEntityObject<MJMagicLinkInviteEntity>(INVITE_ENTITY, creatingUser);
|
|
127
142
|
invite.NewRecord();
|
|
128
|
-
invite.TokenHash =
|
|
143
|
+
invite.TokenHash = HashToken(rawToken);
|
|
129
144
|
invite.Email = params.email;
|
|
130
|
-
invite.ApplicationID = params.
|
|
145
|
+
invite.ApplicationID = params.ApplicationId;
|
|
131
146
|
invite.RoleID = roleId;
|
|
132
147
|
invite.ExpiresAt = expiresAt;
|
|
133
|
-
invite.MaxUses = params.
|
|
148
|
+
invite.MaxUses = params.MaxUses ?? 1;
|
|
134
149
|
invite.UseCount = 0;
|
|
135
150
|
invite.CreatedByUserID = creatingUser.ID;
|
|
136
151
|
invite.Status = 'Active';
|
|
@@ -143,7 +158,7 @@ export class MagicLinkService {
|
|
|
143
158
|
// the single ApplicationID/RoleID. Additive — the columns stay authoritative for
|
|
144
159
|
// redemption today; this populates the child tables for the eventual switch to
|
|
145
160
|
// multi-scope reads. Best-effort so a child-row hiccup never fails issuance.
|
|
146
|
-
await this.writeInviteScopeChildRows(invite.ID, params.
|
|
161
|
+
await this.writeInviteScopeChildRows(invite.ID, params.ApplicationId, roleId, creatingUser, md);
|
|
147
162
|
|
|
148
163
|
const redemptionUrl = this.buildRedemptionUrl(rawToken);
|
|
149
164
|
|
|
@@ -173,9 +188,9 @@ export class MagicLinkService {
|
|
|
173
188
|
* session JWT. Runs in the public (pre-auth) path, so it uses the global
|
|
174
189
|
* provider and a configured provisioning context user.
|
|
175
190
|
*
|
|
176
|
-
* Single-use is enforced by
|
|
177
|
-
* BEFORE the token is minted — two concurrent
|
|
178
|
-
* link race on the same row and exactly one wins. The consume is the gate:
|
|
191
|
+
* Single-use is enforced by the guarded UPDATE inside the `spConsumeMagicLinkInvite`
|
|
192
|
+
* procedure ({@link consumeInvite}) BEFORE the token is minted — two concurrent
|
|
193
|
+
* redemptions of a single-use link race on the same row and exactly one wins. The consume is the gate:
|
|
179
194
|
* if a later step fails, the use is already burned (fail-closed). That is the
|
|
180
195
|
* correct trade-off for a single-use credential — burning a token on a server
|
|
181
196
|
* error is recoverable (re-issue); allowing replay is not.
|
|
@@ -208,7 +223,7 @@ export class MagicLinkService {
|
|
|
208
223
|
const md = Metadata.Provider; // global-provider-ok: server-side magic-link service; runs under the server's single default provider
|
|
209
224
|
const provider = md as DatabaseProviderBase;
|
|
210
225
|
|
|
211
|
-
const tokenHash =
|
|
226
|
+
const tokenHash = HashToken(rawToken);
|
|
212
227
|
const rv = new RunView();
|
|
213
228
|
const found = await rv.RunView<MJMagicLinkInviteEntity>(
|
|
214
229
|
{
|
|
@@ -231,7 +246,7 @@ export class MagicLinkService {
|
|
|
231
246
|
|
|
232
247
|
// Fast, friendly pre-check (returns a precise reason). NOT the authority —
|
|
233
248
|
// the atomic consume below is what actually enforces single-use.
|
|
234
|
-
const eligibility =
|
|
249
|
+
const eligibility = EvaluateInvite(invite, Date.now());
|
|
235
250
|
if (!eligibility.ok) {
|
|
236
251
|
return done({ success: false, errorCode: eligibility.errorCode, error: `Invite is ${eligibility.errorCode}.` });
|
|
237
252
|
}
|
|
@@ -252,14 +267,18 @@ export class MagicLinkService {
|
|
|
252
267
|
return done({ success: false, errorCode: 'server_error', error: 'Invite role not found.' });
|
|
253
268
|
}
|
|
254
269
|
|
|
255
|
-
// Atomic consume BEFORE minting.
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
|
|
270
|
+
// Atomic consume BEFORE minting. A statement that never ran (permissions,
|
|
271
|
+
// missing procedure, connection) is a server fault, not a lost race — report
|
|
272
|
+
// it as such so operators aren't sent hunting a double-redeem (#4753).
|
|
273
|
+
const consume = await this.consumeInvite(invite, provider, contextUser);
|
|
274
|
+
if (consume === 'failed') {
|
|
275
|
+
return done({ success: false, errorCode: 'server_error', error: 'Could not redeem the invite due to a server error.' });
|
|
276
|
+
}
|
|
277
|
+
if (consume === 'lost') {
|
|
259
278
|
// Lost the race or the invite expired between the pre-check and the
|
|
260
279
|
// consume. The in-memory copy still looks eligible if only the DB-side
|
|
261
280
|
// use count changed, so default that case to 'consumed'.
|
|
262
|
-
const recheck =
|
|
281
|
+
const recheck = EvaluateInvite(invite, Date.now());
|
|
263
282
|
return done({ success: false, errorCode: recheck.ok ? 'consumed' : recheck.errorCode, error: 'Invite already redeemed or expired.' });
|
|
264
283
|
}
|
|
265
284
|
|
|
@@ -273,7 +292,7 @@ export class MagicLinkService {
|
|
|
273
292
|
|
|
274
293
|
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
275
294
|
const isAnon = invite.IdentityMode === 'anonymous';
|
|
276
|
-
const claims =
|
|
295
|
+
const claims = BuildSessionClaims({
|
|
277
296
|
issuer: this.publicUrl,
|
|
278
297
|
audience: this.config.audience,
|
|
279
298
|
inviteId: invite.ID,
|
|
@@ -286,7 +305,7 @@ export class MagicLinkService {
|
|
|
286
305
|
anonymous: isAnon,
|
|
287
306
|
// Per-session id for anon forensics (correlates one session's activity since all
|
|
288
307
|
// anon redemptions share the Anonymous principal). Carried into the redemption audit row.
|
|
289
|
-
sessionId: isAnon ?
|
|
308
|
+
sessionId: isAnon ? GenerateSessionId() : undefined,
|
|
290
309
|
// Resource-share scope (Phase 5): the single shared resource this link grants.
|
|
291
310
|
resourceId: invite.ResourceID ?? undefined,
|
|
292
311
|
nowSeconds,
|
|
@@ -639,39 +658,39 @@ export class MagicLinkService {
|
|
|
639
658
|
}
|
|
640
659
|
|
|
641
660
|
/**
|
|
642
|
-
* Atomically consumes one use of the invite
|
|
643
|
-
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
* (won the race); concurrent redemptions of a single-use link see 0 rows.
|
|
661
|
+
* Atomically consumes one use of the invite with a single guarded UPDATE that re-checks every
|
|
662
|
+
* eligibility condition (Active, not exhausted, not expired) at the DB level, so the increment and
|
|
663
|
+
* the guard are one atomic operation. Concurrent redemptions of a single-use link race on the row
|
|
664
|
+
* and exactly one gets the row back.
|
|
647
665
|
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
652
|
-
*
|
|
653
|
-
*
|
|
666
|
+
* The statement differs per platform because the grants do:
|
|
667
|
+
* - **SQL Server** calls {@link CONSUME_INVITE_PROC} (`EXEC … @ID=@p0`). Runtime roles have
|
|
668
|
+
* EXECUTE on procedures but no DML on base tables (#4753).
|
|
669
|
+
* - **PostgreSQL** runs {@link BuildConsumeInvitePostgresSQL}'s `UPDATE … RETURNING` directly.
|
|
670
|
+
* Runtime roles hold table DML there, and no PG counterpart of the procedure exists.
|
|
671
|
+
* The ID is always a bound parameter.
|
|
654
672
|
*
|
|
655
|
-
*
|
|
673
|
+
* Returns `'won'` (this call consumed a use), `'lost'` (the guard matched nothing: consumed,
|
|
674
|
+
* revoked or expired concurrently) or `'failed'` (the statement never ran — permissions, a missing
|
|
675
|
+
* procedure, a connection error). `'failed'` is kept distinct from `'lost'` on purpose: collapsing
|
|
676
|
+
* them is what made #4753's permission error surface to users as "already redeemed".
|
|
656
677
|
*/
|
|
657
|
-
private async consumeInvite(invite: MJMagicLinkInviteEntity, provider: DatabaseProviderBase, contextUser: UserInfo): Promise<
|
|
678
|
+
private async consumeInvite(invite: MJMagicLinkInviteEntity, provider: DatabaseProviderBase, contextUser: UserInfo): Promise<ConsumeOutcome> {
|
|
679
|
+
const isPg = provider.PlatformKey === 'postgresql';
|
|
680
|
+
const statement = isPg ? `PostgreSQL guarded UPDATE on ${INVITE_TABLE}` : CONSUME_INVITE_PROC;
|
|
658
681
|
try {
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
// OUTPUT/RETURNING yields one row iff the WHERE matched — the atomic single-use gate.
|
|
669
|
-
const sql = buildConsumeInviteSQL(table, isPg ? 'postgresql' : 'sqlserver');
|
|
670
|
-
const rows = await provider.ExecuteSQL<{ ID: string }>(sql, [invite.ID], { isMutation: true }, contextUser);
|
|
671
|
-
return Array.isArray(rows) && rows.length === 1;
|
|
682
|
+
const sql = isPg
|
|
683
|
+
? BuildConsumeInvitePostgresSQL(`${provider.MJCoreSchemaName}.${INVITE_TABLE}`)
|
|
684
|
+
: provider.Dialect.ProcedureCallSyntax(provider.MJCoreSchemaName, CONSUME_INVITE_PROC, [`@ID=${provider.BuildParameterPlaceholder(0)}`]);
|
|
685
|
+
const rows = await provider.ExecuteSQL<{ ID: string }>(sql, [invite.ID], { isMutation: true, description: `MagicLink ${statement}` }, contextUser);
|
|
686
|
+
if (!Array.isArray(rows)) {
|
|
687
|
+
LogError(`[MagicLink] ${statement} returned no result set for invite ${invite.ID}; treating the consume as failed.`);
|
|
688
|
+
return 'failed';
|
|
689
|
+
}
|
|
690
|
+
return rows.length === 1 ? 'won' : 'lost';
|
|
672
691
|
} catch (e) {
|
|
673
|
-
LogError(`[MagicLink]
|
|
674
|
-
return
|
|
692
|
+
LogError(`[MagicLink] ${statement} FAILED for invite ${invite.ID} — the statement never ran, so this is NOT a lost race: ${e instanceof Error ? e.message : String(e)}`);
|
|
693
|
+
return 'failed';
|
|
675
694
|
}
|
|
676
695
|
}
|
|
677
696
|
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
export * from './types.js';
|
|
2
2
|
export {
|
|
3
|
-
generateRawToken,
|
|
4
|
-
hashToken,
|
|
5
|
-
evaluateInvite,
|
|
6
|
-
buildSessionClaims,
|
|
3
|
+
GenerateRawToken, generateRawToken,
|
|
4
|
+
HashToken, hashToken,
|
|
5
|
+
EvaluateInvite, evaluateInvite,
|
|
6
|
+
BuildSessionClaims, buildSessionClaims,
|
|
7
7
|
MAGIC_LINK_TOKEN_PREFIX,
|
|
8
8
|
type InviteEvaluationInput,
|
|
9
9
|
} from './magicLinkCore.js';
|
|
10
10
|
export { MagicLinkKeyManager } from './MagicLinkKeys.js';
|
|
11
11
|
export { MagicLinkService } from './MagicLinkService.js';
|
|
12
12
|
export {
|
|
13
|
-
createMagicLinkHandler,
|
|
14
|
-
createMagicLinkJwksRouter,
|
|
15
|
-
registerMagicLinkAuthProvider,
|
|
13
|
+
CreateMagicLinkHandler, createMagicLinkHandler,
|
|
14
|
+
CreateMagicLinkJwksRouter, createMagicLinkJwksRouter,
|
|
15
|
+
RegisterMagicLinkAuthProvider, registerMagicLinkAuthProvider,
|
|
16
16
|
MAGIC_LINK_MOUNT_PATH,
|
|
17
17
|
MAGIC_LINK_JWKS_PATH,
|
|
18
18
|
} from './MagicLinkRouter.js';
|