@memberjunction/server 6.2.0-edge.2 → 6.2.0-edge.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/BridgeHostInstance.d.ts +25 -0
- package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -0
- package/dist/agentSessions/BridgeHostInstance.js +30 -0
- package/dist/agentSessions/BridgeHostInstance.js.map +1 -0
- package/dist/agentSessions/HostInstance.d.ts +75 -11
- package/dist/agentSessions/HostInstance.d.ts.map +1 -1
- package/dist/agentSessions/HostInstance.js +99 -28
- package/dist/agentSessions/HostInstance.js.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.js +7 -3
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +173 -25
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +452 -54
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +43 -2
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +99 -8
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/SessionRunIDVerifier.d.ts +63 -0
- package/dist/agentSessions/SessionRunIDVerifier.d.ts.map +1 -0
- package/dist/agentSessions/SessionRunIDVerifier.js +129 -0
- package/dist/agentSessions/SessionRunIDVerifier.js.map +1 -0
- package/dist/agentSessions/index.d.ts +2 -0
- package/dist/agentSessions/index.d.ts.map +1 -1
- package/dist/agentSessions/index.js +10 -3
- package/dist/agentSessions/index.js.map +1 -1
- package/dist/auth/actionAuthorization.d.ts +40 -0
- package/dist/auth/actionAuthorization.d.ts.map +1 -0
- package/dist/auth/actionAuthorization.js +94 -0
- package/dist/auth/actionAuthorization.js.map +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +3 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +6 -3
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/newUsers.d.ts +10 -0
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +80 -11
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/config.d.ts +4567 -71
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +246 -3
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +8 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +25 -34
- package/dist/context.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +1073 -10
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +9188 -3649
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +3 -3
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +62 -6
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +179 -35
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +4 -0
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +37 -1
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +214 -159
- package/dist/index.js.map +1 -1
- package/dist/isolatedProvider.d.ts +20 -0
- package/dist/isolatedProvider.d.ts.map +1 -0
- package/dist/isolatedProvider.js +22 -0
- package/dist/isolatedProvider.js.map +1 -0
- package/dist/postgresqlCompat.d.ts +8 -0
- package/dist/postgresqlCompat.d.ts.map +1 -0
- package/dist/postgresqlCompat.js +19 -0
- package/dist/postgresqlCompat.js.map +1 -0
- package/dist/postgresqlPoolSettings.d.ts +108 -0
- package/dist/postgresqlPoolSettings.d.ts.map +1 -0
- package/dist/postgresqlPoolSettings.js +134 -0
- package/dist/postgresqlPoolSettings.js.map +1 -0
- package/dist/realtimeProxy/RealtimeProxyServer.d.ts +44 -4
- package/dist/realtimeProxy/RealtimeProxyServer.d.ts.map +1 -1
- package/dist/realtimeProxy/RealtimeProxyServer.js +121 -16
- package/dist/realtimeProxy/RealtimeProxyServer.js.map +1 -1
- package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts +171 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts.map +1 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.js +532 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.js.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.d.ts +148 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.js +191 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.js.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts +66 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js +138 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts +38 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.js +98 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts +61 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js +149 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts +57 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts.map +1 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.js +69 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.js.map +1 -0
- package/dist/realtimeSessions/index.d.ts +17 -0
- package/dist/realtimeSessions/index.d.ts.map +1 -0
- package/dist/realtimeSessions/index.js +17 -0
- package/dist/realtimeSessions/index.js.map +1 -0
- package/dist/realtimeSessions/sessionAccess.d.ts +86 -0
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -0
- package/dist/realtimeSessions/sessionAccess.js +90 -0
- package/dist/realtimeSessions/sessionAccess.js.map +1 -0
- package/dist/realtimeSessions/sessionConfigStamps.d.ts +70 -0
- package/dist/realtimeSessions/sessionConfigStamps.d.ts.map +1 -0
- package/dist/realtimeSessions/sessionConfigStamps.js +93 -0
- package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -0
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts +65 -0
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -0
- package/dist/realtimeSessions/subscriptionAuthorization.js +71 -0
- package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -0
- package/dist/realtimeSessions/verificationCore.d.ts +243 -0
- package/dist/realtimeSessions/verificationCore.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationCore.js +356 -0
- package/dist/realtimeSessions/verificationCore.js.map +1 -0
- package/dist/realtimeSessions/verificationPages.d.ts +66 -0
- package/dist/realtimeSessions/verificationPages.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationPages.js +110 -0
- package/dist/realtimeSessions/verificationPages.js.map +1 -0
- package/dist/realtimeSessions/verificationPolicy.d.ts +147 -0
- package/dist/realtimeSessions/verificationPolicy.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationPolicy.js +249 -0
- package/dist/realtimeSessions/verificationPolicy.js.map +1 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts +263 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationWorkflow.js +435 -0
- package/dist/realtimeSessions/verificationWorkflow.js.map +1 -0
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +20 -2
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +31 -2
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +31 -5
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +75 -14
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts +35 -17
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +92 -166
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/CacheStatsResolver.d.ts +27 -0
- package/dist/resolvers/CacheStatsResolver.d.ts.map +1 -1
- package/dist/resolvers/CacheStatsResolver.js +113 -2
- package/dist/resolvers/CacheStatsResolver.js.map +1 -1
- package/dist/resolvers/ClientToolRequestResolver.d.ts +4 -2
- package/dist/resolvers/ClientToolRequestResolver.d.ts.map +1 -1
- package/dist/resolvers/ClientToolRequestResolver.js +28 -10
- package/dist/resolvers/ClientToolRequestResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +7 -23
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +9 -47
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +12 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +83 -2
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +9 -0
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/HumanHandoffResolver.d.ts +107 -0
- package/dist/resolvers/HumanHandoffResolver.d.ts.map +1 -0
- package/dist/resolvers/HumanHandoffResolver.js +330 -0
- package/dist/resolvers/HumanHandoffResolver.js.map +1 -0
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +9 -4
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/MeetingResolver.d.ts +69 -0
- package/dist/resolvers/MeetingResolver.d.ts.map +1 -0
- package/dist/resolvers/MeetingResolver.js +381 -0
- package/dist/resolvers/MeetingResolver.js.map +1 -0
- package/dist/resolvers/RealtimeBridgeResolver.d.ts +88 -3
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +352 -12
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +156 -108
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +395 -293
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RealtimeSessionEventsResolver.d.ts +61 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.d.ts.map +1 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.js +130 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.js.map +1 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts +85 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts.map +1 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.js +188 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.js.map +1 -0
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +2 -0
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +5 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +10 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +68 -11
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +12 -11
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +6 -2
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts +2 -0
- package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.js +23 -6
- package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
- package/dist/resolvers/UserAvatarResolver.d.ts +16 -0
- package/dist/resolvers/UserAvatarResolver.d.ts.map +1 -0
- package/dist/resolvers/UserAvatarResolver.js +124 -0
- package/dist/resolvers/UserAvatarResolver.js.map +1 -0
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +2 -17
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/resolvers/adhocTimeout.d.ts +7 -0
- package/dist/resolvers/adhocTimeout.d.ts.map +1 -0
- package/dist/resolvers/adhocTimeout.js +12 -0
- package/dist/resolvers/adhocTimeout.js.map +1 -0
- package/dist/resolvers/agentVisionConsentAudit.d.ts +37 -0
- package/dist/resolvers/agentVisionConsentAudit.d.ts.map +1 -0
- package/dist/resolvers/agentVisionConsentAudit.js +63 -0
- package/dist/resolvers/agentVisionConsentAudit.js.map +1 -0
- package/dist/resolvers/avatarInputValidation.d.ts +40 -0
- package/dist/resolvers/avatarInputValidation.d.ts.map +1 -0
- package/dist/resolvers/avatarInputValidation.js +97 -0
- package/dist/resolvers/avatarInputValidation.js.map +1 -0
- package/dist/resolvers/currentUserRoles.d.ts +29 -0
- package/dist/resolvers/currentUserRoles.d.ts.map +1 -1
- package/dist/resolvers/currentUserRoles.js +30 -0
- package/dist/resolvers/currentUserRoles.js.map +1 -1
- package/dist/resolvers/meetings/index.d.ts +5 -0
- package/dist/resolvers/meetings/index.d.ts.map +1 -0
- package/dist/resolvers/meetings/index.js +5 -0
- package/dist/resolvers/meetings/index.js.map +1 -0
- package/dist/resolvers/meetings/meetingHelpers.d.ts +17 -0
- package/dist/resolvers/meetings/meetingHelpers.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingHelpers.js +212 -0
- package/dist/resolvers/meetings/meetingHelpers.js.map +1 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts +18 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingMutations.js +439 -0
- package/dist/resolvers/meetings/meetingMutations.js.map +1 -0
- package/dist/resolvers/meetings/meetingQueries.d.ts +7 -0
- package/dist/resolvers/meetings/meetingQueries.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingQueries.js +113 -0
- package/dist/resolvers/meetings/meetingQueries.js.map +1 -0
- package/dist/resolvers/meetings/meetingTypes.d.ts +89 -0
- package/dist/resolvers/meetings/meetingTypes.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingTypes.js +345 -0
- package/dist/resolvers/meetings/meetingTypes.js.map +1 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +8 -5
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +8 -0
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +27 -1
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +4 -3
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +13 -7
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/services/WorkQueueHostService.d.ts +36 -0
- package/dist/services/WorkQueueHostService.d.ts.map +1 -0
- package/dist/services/WorkQueueHostService.js +97 -0
- package/dist/services/WorkQueueHostService.js.map +1 -0
- package/dist/services/workQueueConfig.d.ts +103 -0
- package/dist/services/workQueueConfig.d.ts.map +1 -0
- package/dist/services/workQueueConfig.js +48 -0
- package/dist/services/workQueueConfig.js.map +1 -0
- package/dist/sharedCache.d.ts +105 -0
- package/dist/sharedCache.d.ts.map +1 -0
- package/dist/sharedCache.js +276 -0
- package/dist/sharedCache.js.map +1 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +97 -94
- package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
- package/src/__tests__/AdhocQueryResolver.bugs.test.ts +14 -35
- package/src/__tests__/AdhocQueryResolver.pagination.test.ts +6 -2
- package/src/__tests__/AdhocQueryResolver.scopeGuard.test.ts +3 -3
- package/src/__tests__/AdhocQueryResolver.sqlAuthorizer.test.ts +104 -0
- package/src/__tests__/BridgeHostInstance.test.ts +232 -0
- package/src/__tests__/ClientToolRequestResolver.test.ts +116 -0
- package/src/__tests__/EntityRecordNameResolver.fieldSecurity.test.ts +27 -72
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +285 -0
- package/src/__tests__/HostInstance.test.ts +84 -0
- package/src/__tests__/HumanHandoffResolver.test.ts +250 -0
- package/src/__tests__/MeetingResolver.test.ts +448 -0
- package/src/__tests__/RealtimeBridgeResolver.test.ts +651 -4
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +383 -0
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +682 -58
- package/src/__tests__/RealtimeProxyServer.test.ts +16 -1
- package/src/__tests__/RealtimeRelay.test.ts +876 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
- package/src/__tests__/ResolverBase.adhocReadScope.test.ts +96 -0
- package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +6 -3
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +21 -2
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +291 -0
- package/src/__tests__/ReturningVisitorRecap.test.ts +115 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +169 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +4 -4
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +166 -0
- package/src/__tests__/RunTemplateResolver.test.ts +132 -0
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +63 -0
- package/src/__tests__/SessionJanitor.test.ts +845 -18
- package/src/__tests__/SessionManager.test.ts +213 -17
- package/src/__tests__/SessionRunIDVerifier.test.ts +251 -0
- package/src/__tests__/SyncRolesUsersResolver.userRoles.test.ts +97 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +41 -0
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +50 -3
- package/src/__tests__/UserAvatarResolver.test.ts +255 -0
- package/src/__tests__/UserResolver.currentUser.test.ts +16 -1
- package/src/__tests__/WorkQueueHostService.test.ts +133 -0
- package/src/__tests__/actionAuthorization.test.ts +130 -0
- package/src/__tests__/adhocTimeoutClamp.test.ts +26 -0
- package/src/__tests__/agentVisionConsentAudit.test.ts +118 -0
- package/src/__tests__/avatarInputValidation.test.ts +160 -0
- package/src/__tests__/isolatedProviderTransactions.test.ts +169 -0
- package/src/__tests__/magicLinkService.consume.test.ts +6 -0
- package/src/__tests__/magicLinkService.provisionLog.test.ts +5 -0
- package/src/__tests__/newUsers.template.test.ts +151 -0
- package/src/__tests__/newUsers.test.ts +74 -5
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +17 -2
- package/src/__tests__/postgresqlPoolSettings.test.ts +131 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventService.test.ts +201 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +215 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionVerificationResolver.test.ts +102 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionVerificationService.test.ts +349 -0
- package/src/__tests__/realtimeSessions/RealtimeVerifyRouter.test.ts +131 -0
- package/src/__tests__/realtimeSessions/SlidingWindowRateLimiter.test.ts +56 -0
- package/src/__tests__/realtimeSessions/helpers.ts +4 -0
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +129 -0
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +124 -0
- package/src/__tests__/realtimeSessions/verificationCore.test.ts +355 -0
- package/src/__tests__/realtimeSessions/verificationPages.test.ts +84 -0
- package/src/__tests__/realtimeSessions/verificationPolicy.test.ts +226 -0
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +633 -0
- package/src/__tests__/resolverBase.fls.test.ts +87 -4
- package/src/__tests__/serverExtensionReservedRoots.test.ts +2 -0
- package/src/__tests__/sharedCache.test.ts +310 -0
- package/src/__tests__/translateBracketsToPG.test.ts +20 -0
- package/src/__tests__/widgetGuestElevation.test.ts +44 -0
- package/src/agentSessions/BridgeHostInstance.ts +32 -0
- package/src/agentSessions/HostInstance.ts +124 -28
- package/src/agentSessions/ReturningVisitorRecap.ts +7 -3
- package/src/agentSessions/SessionJanitor.ts +543 -57
- package/src/agentSessions/SessionManager.ts +125 -25
- package/src/agentSessions/SessionRunIDVerifier.ts +171 -0
- package/src/agentSessions/index.ts +10 -3
- package/src/auth/actionAuthorization.ts +116 -0
- package/src/auth/index.ts +3 -8
- package/src/auth/magicLink/MagicLinkService.ts +6 -3
- package/src/auth/newUsers.ts +99 -11
- package/src/config.ts +255 -3
- package/src/context.ts +26 -34
- package/src/generated/graphql-schemas/__mj.ts +22701 -18838
- package/src/generic/OrphanedConversationDetailReconciler.ts +3 -3
- package/src/generic/ResolverBase.ts +210 -36
- package/src/generic/RunViewResolver.ts +37 -2
- package/src/index.ts +236 -170
- package/src/isolatedProvider.ts +22 -0
- package/src/postgresqlCompat.ts +21 -0
- package/src/postgresqlPoolSettings.ts +213 -0
- package/src/realtimeProxy/RealtimeProxyServer.ts +148 -16
- package/src/realtimeProxy/RealtimeRelayTunnel.ts +645 -0
- package/src/realtimeSessions/README.md +179 -0
- package/src/realtimeSessions/RealtimeSessionEventService.ts +274 -0
- package/src/realtimeSessions/RealtimeSessionVerificationService.ts +167 -0
- package/src/realtimeSessions/RealtimeVerifyRouter.ts +108 -0
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +189 -0
- package/src/realtimeSessions/SlidingWindowRateLimiter.ts +92 -0
- package/src/realtimeSessions/index.ts +16 -0
- package/src/realtimeSessions/sessionAccess.ts +141 -0
- package/src/realtimeSessions/sessionConfigStamps.ts +123 -0
- package/src/realtimeSessions/subscriptionAuthorization.ts +116 -0
- package/src/realtimeSessions/verificationCore.ts +502 -0
- package/src/realtimeSessions/verificationPages.ts +149 -0
- package/src/realtimeSessions/verificationPolicy.ts +321 -0
- package/src/realtimeSessions/verificationWorkflow.ts +702 -0
- package/src/realtimeWidget/widgetGuestElevation.ts +34 -2
- package/src/resolvers/ActionResolver.ts +84 -21
- package/src/resolvers/AdhocQueryResolver.ts +105 -187
- package/src/resolvers/CacheStatsResolver.ts +89 -2
- package/src/resolvers/ClientToolRequestResolver.ts +25 -7
- package/src/resolvers/EntityRecordNameResolver.ts +9 -51
- package/src/resolvers/FetchEntityVectorsResolver.ts +97 -2
- package/src/resolvers/GetDataResolver.ts +10 -0
- package/src/resolvers/HumanHandoffResolver.ts +312 -0
- package/src/resolvers/MCPResolver.ts +8 -5
- package/src/resolvers/MeetingResolver.ts +438 -0
- package/src/resolvers/RealtimeBridgeResolver.ts +385 -19
- package/src/resolvers/RealtimeClientSessionResolver.ts +503 -344
- package/src/resolvers/RealtimeSessionEventsResolver.ts +133 -0
- package/src/resolvers/RealtimeSessionVerificationResolver.ts +174 -0
- package/src/resolvers/RemoteBrowserActionResolver.ts +11 -1
- package/src/resolvers/RunAIAgentResolver.ts +78 -11
- package/src/resolvers/RunTemplateResolver.ts +13 -12
- package/src/resolvers/SyncDataResolver.ts +6 -2
- package/src/resolvers/SyncRolesUsersResolver.ts +24 -6
- package/src/resolvers/UserAvatarResolver.ts +111 -0
- package/src/resolvers/UserResolver.ts +2 -16
- package/src/resolvers/adhocTimeout.ts +12 -0
- package/src/resolvers/agentVisionConsentAudit.ts +82 -0
- package/src/resolvers/avatarInputValidation.ts +123 -0
- package/src/resolvers/currentUserRoles.ts +32 -1
- package/src/resolvers/meetings/index.ts +4 -0
- package/src/resolvers/meetings/meetingHelpers.ts +307 -0
- package/src/resolvers/meetings/meetingMutations.ts +556 -0
- package/src/resolvers/meetings/meetingQueries.ts +172 -0
- package/src/resolvers/meetings/meetingTypes.ts +238 -0
- package/src/rest/ViewOperationsHandler.ts +8 -5
- package/src/services/TaskGraphActionRunner.ts +29 -1
- package/src/services/TaskGraphContinuationDeliverer.ts +13 -7
- package/src/services/WorkQueueHostService.ts +129 -0
- package/src/services/workQueueConfig.ts +52 -0
- package/src/sharedCache.ts +302 -0
- package/src/types.ts +12 -0
- package/dist/resolvers/adhoc-query-helpers.d.ts +0 -33
- package/dist/resolvers/adhoc-query-helpers.d.ts.map +0 -1
- package/dist/resolvers/adhoc-query-helpers.js +0 -50
- package/dist/resolvers/adhoc-query-helpers.js.map +0 -1
- package/src/__tests__/adhoc-query-helpers.test.ts +0 -50
- package/src/resolvers/adhoc-query-helpers.ts +0 -67
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import dotenv from 'dotenv';
|
|
|
2
2
|
dotenv.config({ quiet: true });
|
|
3
3
|
import { expressMiddleware } from '@as-integrations/express5';
|
|
4
4
|
import { mergeSchemas } from '@graphql-tools/schema';
|
|
5
|
-
import { Metadata, SetProvider, StartupManager as StartupManagerImport, BaseEntity, RunView, DatabaseProviderBase, ResolveStartupMode } from '@memberjunction/core';
|
|
5
|
+
import { Metadata, SetProvider, StartupManager as StartupManagerImport, BaseEntity, RunView, DatabaseProviderBase, ProviderBase, ResolveStartupMode } from '@memberjunction/core';
|
|
6
6
|
import { UserCache, resolveDbPlatformFromEnv } from '@memberjunction/generic-database-provider';
|
|
7
7
|
import { MJGlobal, MJEventType, ShutdownRegistry } from '@memberjunction/global';
|
|
8
8
|
import { setupSQLServerClient, SQLServerDataProvider, SQLServerProviderConfigData } from '@memberjunction/sqlserver-dataprovider';
|
|
@@ -17,9 +17,10 @@ import { default as fg } from 'fast-glob';
|
|
|
17
17
|
import { useServer } from 'graphql-ws/lib/use/ws';
|
|
18
18
|
import { createServer } from 'node:http';
|
|
19
19
|
import { fileURLToPath } from 'node:url';
|
|
20
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
20
|
+
import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
|
|
21
|
+
import { tmpdir } from 'node:os';
|
|
21
22
|
import { Session as InspectorSession } from 'node:inspector';
|
|
22
|
-
import { sep } from 'node:path';
|
|
23
|
+
import { join, sep } from 'node:path';
|
|
23
24
|
import 'reflect-metadata';
|
|
24
25
|
import { ReplaySubject } from 'rxjs';
|
|
25
26
|
import { buildSchemaSync, getMetadataStorage, GraphQLTimestamp } from 'type-graphql';
|
|
@@ -29,8 +30,10 @@ import { WebSocketServer } from 'ws';
|
|
|
29
30
|
import { RealtimeProxyServer } from './realtimeProxy/RealtimeProxyServer.js';
|
|
30
31
|
import buildApolloServer from './apolloServer/index.js';
|
|
31
32
|
import { configInfo, configFilePath, dbDatabase, dbHost, dbPort, dbUsername, graphqlPort, graphqlRootPath, mj_core_schema, websiteRunFromPackage } from './config.js';
|
|
33
|
+
import { TranslateBracketsToPG } from './postgresqlCompat.js';
|
|
34
|
+
import { BuildPostgreSQLConnectionConfig, DescribeReadOnlyLoginOverreach, PostgreSQLReadOnlyPool, ResolvePostgreSQLEndpoint, ResolvePostgreSQLReadOnlyCredentials, ToPGPoolConfig } from './postgresqlPoolSettings.js';
|
|
32
35
|
import { default as jwt } from 'jsonwebtoken';
|
|
33
|
-
import { contextFunction, CreateUnifiedAuthMiddleware, getUserPayload } from './context.js';
|
|
36
|
+
import { contextFunction, CreateReadOnlyProvider, CreateUnifiedAuthMiddleware, getUserPayload } from './context.js';
|
|
34
37
|
import { requireSystemUserDirective, publicDirective } from './directives/index.js';
|
|
35
38
|
import { variablesLoggingMiddleware } from './logging/variablesLoggingMiddleware.js';
|
|
36
39
|
import { auditResolversForUndecoratedArgs } from './logging/bootAudit.js';
|
|
@@ -45,6 +48,7 @@ import { createRealtimeSdpBrokerRouter } from './rest/RealtimeSdpBrokerHandler.j
|
|
|
45
48
|
import { REALTIME_SDP_EXCHANGE_PATH } from '@memberjunction/ai';
|
|
46
49
|
import { createMagicLinkHandler, createMagicLinkJwksRouter, registerMagicLinkAuthProvider, MAGIC_LINK_MOUNT_PATH } from './auth/magicLink/index.js';
|
|
47
50
|
import { createWidgetHandler, WIDGET_MOUNT_PATH } from './realtimeWidget/index.js';
|
|
51
|
+
import { CreateRealtimeVerifyRouter, REALTIME_VERIFY_MOUNT_PATH, RealtimeSessionEventService, RealtimeSessionVerificationService, ParseReplicatedRealtimeSessionEvent, } from './realtimeSessions/index.js';
|
|
48
52
|
import { resolve } from 'node:path';
|
|
49
53
|
import { DataSourceInfo, raiseEvent } from './types.js';
|
|
50
54
|
import { ScheduledJobsService } from './services/ScheduledJobsService.js';
|
|
@@ -53,16 +57,20 @@ import { LocalCacheManager, TelemetryManager, LogStatus, LogError, SetVerboseLog
|
|
|
53
57
|
import { validateAuthProvidersRegistered } from './auth/index.js';
|
|
54
58
|
import { createAuthProviderCatalogRouter, AUTH_CATALOG_MOUNT_PATH } from './auth/AuthProviderCatalogRouter.js';
|
|
55
59
|
import { GetAPIKeyEngine } from '@memberjunction/api-keys';
|
|
56
|
-
import {
|
|
60
|
+
import { ActionEngineServer } from '@memberjunction/actions';
|
|
61
|
+
import { CreateAdhocSQLAuthorizer } from './resolvers/AdhocQueryResolver.js';
|
|
62
|
+
import { CacheManagerConfigFromSettings, CreateSharedCacheFromEnvironment, StartEngineSweeper, StartMetadataSweep, StartUserCacheChecks, WarmupLeaseMsFromSettings, WirePushStatusFanOut, WireSharedCacheEvents } from './sharedCache.js';
|
|
57
63
|
import { PubSubManager } from './generic/PubSubManager.js';
|
|
58
64
|
import { ReconcileOrphanedConversationDetails } from './generic/OrphanedConversationDetailReconciler.js';
|
|
59
|
-
import {
|
|
65
|
+
import { HANDOFF_OFFER_FANOUT_CHANNEL, HANDOFF_OFFER_TOPIC, SetHandoffOfferPublishHook, ParseReplicatedHandoffOfferUpdate, } from './resolvers/HumanHandoffResolver.js';
|
|
66
|
+
import { RoomHandoffEngine } from '@memberjunction/livekit-room-server';
|
|
60
67
|
import { IntegrationProgressEmitter } from '@memberjunction/integration-progress-artifacts';
|
|
61
68
|
import { PublishIntegrationProgress } from './resolvers/IntegrationProgressResolver.js';
|
|
62
69
|
import { RegisterRSUProgressBridge } from './integration/RSUProgressBridge.js';
|
|
63
70
|
import { ClientToolRequestManager, AgentRunWatchdog } from '@memberjunction/ai-agents';
|
|
64
|
-
import { SessionJanitor } from './agentSessions/index.js';
|
|
71
|
+
import { BindBridgeEngineHostInstance, SessionJanitor, SetHostInstancePort, StartBridgeOrphanReconciliation } from './agentSessions/index.js';
|
|
65
72
|
import { StartTaskGraphDispatcher } from './services/StartTaskGraphDispatcher.js';
|
|
73
|
+
import { MJServerWorkQueueProviderSource, StartWorkQueueHost } from './services/WorkQueueHostService.js';
|
|
66
74
|
import { GetAttachmentService } from '@memberjunction/aiengine';
|
|
67
75
|
import { MJStorageBlobStore } from './services/MJStorageBlobStore.js';
|
|
68
76
|
import { CACHE_INVALIDATION_TOPIC, MayBroadcastRecordData, ConfigureRecordDataBroadcast } from './generic/CacheInvalidationResolver.js';
|
|
@@ -100,6 +108,7 @@ export * from 'type-graphql';
|
|
|
100
108
|
// later importers, which makes schema build fail on ViewResult.RowCount.
|
|
101
109
|
export { Int, Float, ID } from 'type-graphql';
|
|
102
110
|
export { NewUserBase } from './auth/newUsers.js';
|
|
111
|
+
export { CreateIsolatedProvider } from './isolatedProvider.js';
|
|
103
112
|
export { configInfo, DEFAULT_SERVER_CONFIG } from './config.js';
|
|
104
113
|
export { ServerExtensionLoader, BaseServerExtension, DefaultServerExtensionServiceRegistry } from '@memberjunction/server-extensions-core';
|
|
105
114
|
export * from './directives/index.js';
|
|
@@ -146,6 +155,8 @@ export * from './resolvers/GenerateSeedTaxonomyResolver.js';
|
|
|
146
155
|
export * from './resolvers/PipelineProgressResolver.js';
|
|
147
156
|
export * from './resolvers/IntegrationProgressResolver.js';
|
|
148
157
|
export * from './resolvers/IdentityClaimRedemptionResolver.js';
|
|
158
|
+
export * from './resolvers/UserAvatarResolver.js';
|
|
159
|
+
export * from './resolvers/avatarInputValidation.js';
|
|
149
160
|
export * from './resolvers/ClientToolRequestResolver.js';
|
|
150
161
|
export * from './resolvers/AutotagPipelineResolver.js';
|
|
151
162
|
export * from './resolvers/TagGovernanceResolver.js';
|
|
@@ -201,6 +212,10 @@ export * from './resolvers/CurrentUserContextResolver.js';
|
|
|
201
212
|
export * from './resolvers/RSUResolver.js';
|
|
202
213
|
export * from './resolvers/AgentSessionResolver.js';
|
|
203
214
|
export * from './resolvers/RealtimeClientSessionResolver.js';
|
|
215
|
+
export * from './resolvers/RealtimeSessionEventsResolver.js';
|
|
216
|
+
export * from './resolvers/RealtimeSessionVerificationResolver.js';
|
|
217
|
+
export * from './realtimeSessions/index.js';
|
|
218
|
+
export * from './resolvers/MeetingResolver.js';
|
|
204
219
|
export * from './resolvers/RemoteBrowserActionResolver.js';
|
|
205
220
|
export * from './agentSessions/index.js';
|
|
206
221
|
export { GetReadOnlyDataSource, GetReadWriteDataSource, GetReadWriteProvider, GetReadOnlyProvider } from './util.js';
|
|
@@ -234,60 +249,87 @@ function resolveServerVersion() {
|
|
|
234
249
|
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
235
250
|
return pkg.version;
|
|
236
251
|
}
|
|
237
|
-
catch {
|
|
252
|
+
catch (err) {
|
|
253
|
+
LogError('Failed to resolve server version from package.json', undefined, err);
|
|
238
254
|
return undefined;
|
|
239
255
|
}
|
|
240
256
|
}
|
|
241
257
|
/** How often to re-check for conversation details left behind by finished runs. */
|
|
242
258
|
const ORPHAN_DETAIL_SWEEP_INTERVAL_MS = 5 * 60_000;
|
|
243
|
-
/** Redis channel carrying replicated push-status updates between server instances. */
|
|
244
|
-
const PUSH_STATUS_FANOUT_CHANNEL = 'push-status-updates';
|
|
245
259
|
/**
|
|
246
|
-
* Replicate
|
|
247
|
-
*
|
|
248
|
-
* Outbound: every locally-published update is forwarded on a shared channel. Inbound: a message
|
|
249
|
-
* from another instance is republished onto THIS instance's local topic, where the normal
|
|
250
|
-
* subscription filter decides who receives it — so the identity gate (`ownerUserId` vs. the
|
|
251
|
-
* connection's authenticated user) still applies to a replicated message exactly as it does to a
|
|
252
|
-
* local one. The replica has no say in who sees what.
|
|
260
|
+
* Replicate handoff-offer updates across server instances over Redis.
|
|
253
261
|
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
262
|
+
* Outbound: every locally-published offer change is forwarded on a shared Redis channel.
|
|
263
|
+
* Inbound: a message from another instance is republished onto THIS instance's local GraphQL
|
|
264
|
+
* topic (where the subscription filter scopes to the target user) and delivered to RoomHandoffEngine
|
|
265
|
+
* so the call-hosting instance can transition its local flow (e.g. wait for the user to join the room).
|
|
257
266
|
*/
|
|
258
|
-
async function
|
|
267
|
+
async function wireHandoffOfferFanOut(redisProvider, startupLog) {
|
|
259
268
|
try {
|
|
260
|
-
await redisProvider.SubscribeToChannel(
|
|
269
|
+
await redisProvider.SubscribeToChannel(HANDOFF_OFFER_FANOUT_CHANNEL, (raw) => {
|
|
261
270
|
try {
|
|
262
|
-
const payload =
|
|
271
|
+
const payload = ParseReplicatedHandoffOfferUpdate(raw, MJGlobal.Instance.ProcessUUID);
|
|
263
272
|
if (!payload) {
|
|
264
273
|
return;
|
|
265
274
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
ownerUserId: payload.ownerUserId,
|
|
271
|
-
message: payload.message,
|
|
272
|
-
SourceServerId: payload.SourceServerId,
|
|
275
|
+
PubSubManager.Instance.Publish(HANDOFF_OFFER_TOPIC, {
|
|
276
|
+
UserID: payload.UserID,
|
|
277
|
+
Kind: payload.Kind,
|
|
278
|
+
Offer: payload.Offer,
|
|
273
279
|
});
|
|
280
|
+
RoomHandoffEngine.Instance.OnRemoteOfferChange(payload);
|
|
274
281
|
}
|
|
275
|
-
catch {
|
|
282
|
+
catch (err) {
|
|
276
283
|
// A malformed message on a shared channel must not take down the subscriber.
|
|
284
|
+
LogError('Error processing handoff-offer fan-out message', undefined, err);
|
|
277
285
|
}
|
|
278
286
|
});
|
|
279
|
-
|
|
280
|
-
redisProvider.PublishMessage(
|
|
287
|
+
SetHandoffOfferPublishHook((payload) => {
|
|
288
|
+
redisProvider.PublishMessage(HANDOFF_OFFER_FANOUT_CHANNEL, JSON.stringify(payload));
|
|
281
289
|
});
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
// no way to answer it.
|
|
285
|
-
console.log('[MJAPI] Push-status updates: cross-instance fan-out enabled via Redis');
|
|
290
|
+
console.log('[MJAPI] Handoff-offer updates: cross-instance fan-out enabled via Redis');
|
|
291
|
+
startupLog.LogIf('verbose', 'Handoff-offer updates: cross-instance fan-out enabled via Redis');
|
|
286
292
|
}
|
|
287
293
|
catch (err) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
294
|
+
console.warn(`Handoff-offer fan-out unavailable: ${err instanceof Error ? err.message : String(err)}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/** Redis channel carrying replicated realtime session events between server instances. */
|
|
298
|
+
const REALTIME_SESSION_EVENTS_FANOUT_CHANNEL = 'realtime-session-events';
|
|
299
|
+
/**
|
|
300
|
+
* Replicate realtime session events across server instances over Redis.
|
|
301
|
+
*
|
|
302
|
+
* Behind a load balancer the browser's WebSocket (the `RealtimeSessionEvents` subscription) lives on one
|
|
303
|
+
* replica while the request that raises the event — typically the public verify-link redemption — can be
|
|
304
|
+
* handled by another. The session-events topic is an in-process PubSub, so without this an
|
|
305
|
+
* `identity.verified` published on replica B never reaches the subscriber on replica A.
|
|
306
|
+
*
|
|
307
|
+
* Inbound messages are republished onto THIS instance's local topic only (never back through the
|
|
308
|
+
* replication hook, so there is no loop) and are still judged by the subscription filter against the
|
|
309
|
+
* connection's identity — a replica has no say in who sees what. The durable
|
|
310
|
+
* `RealtimeSessionVerificationStatus` query remains the backstop if Redis is down.
|
|
311
|
+
*/
|
|
312
|
+
async function wireRealtimeSessionEventFanOut(redisProvider) {
|
|
313
|
+
try {
|
|
314
|
+
await redisProvider.SubscribeToChannel(REALTIME_SESSION_EVENTS_FANOUT_CHANNEL, (raw) => {
|
|
315
|
+
try {
|
|
316
|
+
const payload = ParseReplicatedRealtimeSessionEvent(raw, MJGlobal.Instance.ProcessUUID);
|
|
317
|
+
if (payload) {
|
|
318
|
+
RealtimeSessionEventService.Instance.PublishReplicated(payload);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
LogError(`Realtime session event fan-out: dropping a malformed replicated event: ${err.message}`);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
RealtimeSessionEventService.Instance.SetReplicationHook((payload) => {
|
|
326
|
+
redisProvider.PublishMessage(REALTIME_SESSION_EVENTS_FANOUT_CHANNEL, JSON.stringify(payload));
|
|
327
|
+
});
|
|
328
|
+
console.log('[MJAPI] Realtime session events: cross-instance fan-out enabled via Redis');
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
// Single-instance delivery still works and the status query covers the rest: degraded, not broken.
|
|
332
|
+
console.warn(`Realtime session event fan-out unavailable: ${err.message}`);
|
|
291
333
|
}
|
|
292
334
|
}
|
|
293
335
|
// Bind MJStorage as the conversation-attachment blob store. The attachment service itself no longer
|
|
@@ -302,6 +344,12 @@ async function wirePushStatusFanOut(redisProvider, startupLog) {
|
|
|
302
344
|
GetAttachmentService().BlobStore = new MJStorageBlobStore();
|
|
303
345
|
export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
304
346
|
const t0 = performance.now();
|
|
347
|
+
// Name this MJAPI instance by its port before anything stamps a session row with its identity, so the janitor's
|
|
348
|
+
// startup recovery closes only the sessions an earlier boot of this instance left, never those of another MJAPI on
|
|
349
|
+
// the same host (#5309).
|
|
350
|
+
SetHostInstancePort(graphqlPort);
|
|
351
|
+
// The realtime bridge engine stamps its bridge rows with the same identity and reconciles orphans by it (#5310).
|
|
352
|
+
BindBridgeEngineHostInstance();
|
|
305
353
|
// Level-gated startup logger. Resolves verbosity from telemetry.level (single
|
|
306
354
|
// operator knob). At `standard` (default), per-phase timings are collapsed into
|
|
307
355
|
// the one-line summary; at `verbose`+ each phase prints inline as before.
|
|
@@ -325,33 +373,62 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
325
373
|
const setupComplete$ = new ReplaySubject(1);
|
|
326
374
|
const dbType = GetDbType();
|
|
327
375
|
const dataSources = [];
|
|
376
|
+
// Shared cache first: the database provider loads metadata and startup engines through
|
|
377
|
+
// it, so the first server to start fills it and later servers read it instead of each querying
|
|
378
|
+
// the database and broadcasting what they loaded. Subscribed before engines load so they hear
|
|
379
|
+
// other servers while they start.
|
|
380
|
+
const sharedCache = CreateSharedCacheFromEnvironment(configInfo.cacheSettings);
|
|
381
|
+
if (sharedCache) {
|
|
382
|
+
await WireSharedCacheEvents(sharedCache, () => (Metadata.Provider instanceof ProviderBase ? Metadata.Provider : undefined)); // global-provider-ok: bootstrap
|
|
383
|
+
// The cross-instance fan-outs ride this connection. Push-status moved into sharedCache.ts
|
|
384
|
+
// with the rest of the Redis wiring; the handoff and realtime-session ones stay here deliberately —
|
|
385
|
+
// they reach into RoomHandoffEngine and RealtimeSessionEventService, and the cache module should not
|
|
386
|
+
// acquire a dependency on either.
|
|
387
|
+
await WirePushStatusFanOut(sharedCache);
|
|
388
|
+
await wireHandoffOfferFanOut(sharedCache, startupLog);
|
|
389
|
+
await wireRealtimeSessionEventFanOut(sharedCache);
|
|
390
|
+
startupLog.LogIf('verbose', `Redis cache provider connected: ${process.env.REDIS_URL}`);
|
|
391
|
+
}
|
|
392
|
+
const cacheManagerConfig = CacheManagerConfigFromSettings(configInfo.cacheSettings);
|
|
393
|
+
const warmupLeaseMs = WarmupLeaseMsFromSettings(configInfo.cacheSettings);
|
|
328
394
|
if (dbType === 'postgresql') {
|
|
329
395
|
// ─── PostgreSQL Path ───────────────────────────────────────────
|
|
330
396
|
startupLog.BeginPhase('Connecting to database');
|
|
331
397
|
startupLog.LogIf('verbose', 'Database type: PostgreSQL');
|
|
332
398
|
const pg = await import('pg');
|
|
333
|
-
const { PostgreSQLDataProvider, PostgreSQLProviderConfigData } = await import('@memberjunction/postgresql-dataprovider');
|
|
334
|
-
const
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
-
const pgPool = new pg.default.Pool({
|
|
340
|
-
host: pgHost,
|
|
341
|
-
port: pgPort,
|
|
342
|
-
user: pgUser,
|
|
343
|
-
password: pgPass,
|
|
344
|
-
database: pgDatabase,
|
|
345
|
-
max: configInfo.databaseSettings.connectionPool?.max ?? 50,
|
|
346
|
-
min: configInfo.databaseSettings.connectionPool?.min ?? 5,
|
|
347
|
-
idleTimeoutMillis: configInfo.databaseSettings.connectionPool?.idleTimeoutMillis ?? 30000,
|
|
348
|
-
connectionTimeoutMillis: configInfo.databaseSettings.connectionPool?.acquireTimeoutMillis ?? 30000,
|
|
349
|
-
});
|
|
399
|
+
const { PostgreSQLDataProvider, PostgreSQLProviderConfigData, MJPostgresTypes } = await import('@memberjunction/postgresql-dataprovider');
|
|
400
|
+
const pgEndpoint = ResolvePostgreSQLEndpoint();
|
|
401
|
+
const { Host: pgHost, Port: pgPort, User: pgUser, Database: pgDatabase } = pgEndpoint;
|
|
402
|
+
// Every API pool carries the statement and idle-in-transaction timeouts from connection #1.
|
|
403
|
+
const pgConnectionConfig = BuildPostgreSQLConnectionConfig(pgEndpoint, configInfo.databaseSettings, 'api');
|
|
404
|
+
const pgPool = new pg.default.Pool(ToPGPoolConfig(pgConnectionConfig));
|
|
350
405
|
// Verify connection
|
|
351
406
|
const testClient = await pgPool.connect();
|
|
352
407
|
await testClient.query('SELECT 1');
|
|
353
408
|
testClient.release();
|
|
354
409
|
startupLog.LogIf('verbose', `PostgreSQL pool connected to ${pgHost}:${pgPort}/${pgDatabase}`);
|
|
410
|
+
// A read-only pool opened with the read-only login, as SQL Server has. Read-only per-request
|
|
411
|
+
// providers (TestQuerySQL and other caller-supplied SQL) share it instead of the primary pool.
|
|
412
|
+
const pgReadOnlyCredentials = ResolvePostgreSQLReadOnlyCredentials(configInfo);
|
|
413
|
+
if (pgReadOnlyCredentials) {
|
|
414
|
+
// A pool a provider runs on must carry the provider's type parsers, so BIGINT and NUMERIC
|
|
415
|
+
// come back as numbers here as they do on the provider's own pool.
|
|
416
|
+
const readOnlyPgPool = new pg.default.Pool({
|
|
417
|
+
...ToPGPoolConfig(BuildPostgreSQLConnectionConfig({ ...pgEndpoint, ...pgReadOnlyCredentials }, configInfo.databaseSettings, 'read-only')),
|
|
418
|
+
types: MJPostgresTypes,
|
|
419
|
+
});
|
|
420
|
+
const readOnlyTestClient = await readOnlyPgPool.connect();
|
|
421
|
+
try {
|
|
422
|
+
for (const warning of await DescribeReadOnlyLoginOverreach(readOnlyTestClient, mj_core_schema)) {
|
|
423
|
+
LogStatus(`WARNING: ${warning}`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
finally {
|
|
427
|
+
readOnlyTestClient.release();
|
|
428
|
+
}
|
|
429
|
+
PostgreSQLReadOnlyPool.Instance.Pool = readOnlyPgPool;
|
|
430
|
+
startupLog.LogIf('verbose', 'Read-only PostgreSQL pool has been initialized.');
|
|
431
|
+
}
|
|
355
432
|
// Create a DataSourceInfo with a MSSQL-compatible wrapper around pg.Pool
|
|
356
433
|
// This allows existing code (types, util, context) to work without changes
|
|
357
434
|
const mssqlCompatPool = createMSSQLCompatPool(pgPool);
|
|
@@ -364,16 +441,8 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
364
441
|
userName: pgUser,
|
|
365
442
|
}));
|
|
366
443
|
// Set up the PostgreSQL provider
|
|
367
|
-
const pgConnectionConfig = {
|
|
368
|
-
Host: pgHost,
|
|
369
|
-
Port: pgPort,
|
|
370
|
-
Database: pgDatabase,
|
|
371
|
-
User: pgUser,
|
|
372
|
-
Password: pgPass,
|
|
373
|
-
MaxConnections: configInfo.databaseSettings.connectionPool?.max ?? 50,
|
|
374
|
-
MinConnections: configInfo.databaseSettings.connectionPool?.min ?? 5,
|
|
375
|
-
};
|
|
376
444
|
const pgConfigData = new PostgreSQLProviderConfigData(pgConnectionConfig, mj_core_schema, cacheRefreshInterval / 1000);
|
|
445
|
+
pgConfigData.LocalStorageProvider = sharedCache ?? undefined;
|
|
377
446
|
const provider = new PostgreSQLDataProvider();
|
|
378
447
|
await provider.Config(pgConfigData);
|
|
379
448
|
SetProvider(provider);
|
|
@@ -383,7 +452,7 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
383
452
|
const sysUser = UserCache.Instance.GetSystemUser();
|
|
384
453
|
const backupSysUser = UserCache.Instance.Users.find(u => u.IsActive && u.Type === 'Owner');
|
|
385
454
|
const pgStartupMode = ResolveStartupMode({ configValue: configInfo.startup?.mode, defaultMode: 'full' });
|
|
386
|
-
await StartupManagerImport.Instance.Startup(false, sysUser || backupSysUser, provider, { mode: pgStartupMode.mode });
|
|
455
|
+
await StartupManagerImport.Instance.Startup(false, sysUser || backupSysUser, provider, { mode: pgStartupMode.mode, cacheManagerConfig, warmupLeaseMs });
|
|
387
456
|
// Both provider sources have now had their turn — config/env at module load, metadata via
|
|
388
457
|
// AuthProviderEngine's startup hook — so "no providers at all" is finally a meaningful check.
|
|
389
458
|
validateAuthProvidersRegistered();
|
|
@@ -396,7 +465,7 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
396
465
|
if (poolAny._pgPool) {
|
|
397
466
|
const thePgPool = poolAny._pgPool;
|
|
398
467
|
// Translate SQL Server bracket syntax to PostgreSQL double-quote syntax
|
|
399
|
-
const pgQuery =
|
|
468
|
+
const pgQuery = TranslateBracketsToPG(query);
|
|
400
469
|
const result = await thePgPool.query(pgQuery);
|
|
401
470
|
return result.rows;
|
|
402
471
|
}
|
|
@@ -414,19 +483,15 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
414
483
|
const pgCodegenPass = process.env.CODEGEN_DB_PASSWORD;
|
|
415
484
|
if (pgCodegenUser && pgCodegenPass) {
|
|
416
485
|
try {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
password: pgCodegenPass,
|
|
422
|
-
database: pgDatabase,
|
|
423
|
-
max: 10,
|
|
424
|
-
});
|
|
486
|
+
// CodeGen and DDL work runs long statements across every entity, so this pool gets the
|
|
487
|
+
// long CodeGen timeout rather than the API one, as the SQL Server CodeGen pool does.
|
|
488
|
+
const codegenPgConnectionConfig = BuildPostgreSQLConnectionConfig({ ...pgEndpoint, User: pgCodegenUser, Password: pgCodegenPass }, configInfo.databaseSettings, 'codegen');
|
|
489
|
+
const codegenPgPool = new pg.default.Pool(ToPGPoolConfig(codegenPgConnectionConfig));
|
|
425
490
|
const codegenTestClient = await codegenPgPool.connect();
|
|
426
491
|
await codegenTestClient.query('SELECT 1');
|
|
427
492
|
codegenTestClient.release();
|
|
428
493
|
const { RuntimeSchemaManager } = await import('@memberjunction/schema-engine');
|
|
429
|
-
const codegenPgConfigData = new PostgreSQLProviderConfigData(
|
|
494
|
+
const codegenPgConfigData = new PostgreSQLProviderConfigData(codegenPgConnectionConfig, mj_core_schema, cacheRefreshInterval / 1000);
|
|
430
495
|
const codegenPgProvider = new PostgreSQLDataProvider();
|
|
431
496
|
await codegenPgProvider.Config(codegenPgConfigData); // separate pool (per-instance manager); does NOT touch the global API provider
|
|
432
497
|
RuntimeSchemaManager.Instance.SetDDLProvider(codegenPgProvider);
|
|
@@ -517,10 +582,11 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
517
582
|
}
|
|
518
583
|
// cacheRefreshInterval is configured in ms; checkRefreshIntervalSeconds declares seconds — see providerConfigUnits.ts
|
|
519
584
|
const config = new SQLServerProviderConfigData(pool, mj_core_schema, MetadataCacheRefreshIntervalSeconds(cacheRefreshInterval));
|
|
585
|
+
config.LocalStorageProvider = sharedCache ?? undefined;
|
|
520
586
|
// MJAPI is a long-running server, so entry-point default is 'full' engine pre-warm;
|
|
521
587
|
// MJ_STARTUP_MODE / mj.config.cjs startup.mode can override per the shared precedence chain
|
|
522
588
|
const startupMode = ResolveStartupMode({ configValue: configInfo.startup?.mode, defaultMode: 'full' });
|
|
523
|
-
await setupSQLServerClient(config, { mode: startupMode.mode });
|
|
589
|
+
await setupSQLServerClient(config, { mode: startupMode.mode, cacheManagerConfig, warmupLeaseMs });
|
|
524
590
|
// See the note on the PostgreSQL path above: this is the first point at which both the
|
|
525
591
|
// config/env providers and the metadata catalog have been registered.
|
|
526
592
|
validateAuthProvidersRegistered();
|
|
@@ -633,76 +699,28 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
633
699
|
tm.SetEnabled(false);
|
|
634
700
|
startupLog.LogIf('verbose', 'Server telemetry disabled');
|
|
635
701
|
}
|
|
636
|
-
//
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
});
|
|
644
|
-
Metadata.Provider.SetLocalStorageProvider(redisProvider); // global-provider-ok: bootstrap (Redis cache wiring)
|
|
645
|
-
await redisProvider.StartListening();
|
|
646
|
-
// Connect Redis pub/sub events to LocalCacheManager callback dispatch
|
|
647
|
-
// so cross-server cache invalidation messages are routed to registered callbacks
|
|
648
|
-
redisProvider.OnCacheChanged((event) => {
|
|
649
|
-
const sourceShort = event.SourceServerId ? event.SourceServerId.substring(0, 8) : 'unknown';
|
|
650
|
-
console.log(`[MJAPI] Redis pub/sub → DispatchCacheChange: ${event.Action} for "${event.CacheKey}" from server ${sourceShort}`);
|
|
651
|
-
LocalCacheManager.Instance.DispatchCacheChange(event);
|
|
652
|
-
// Also broadcast to connected browser clients via GraphQL subscription
|
|
653
|
-
// Extract entity name from the cache key (format: EntityName|Filter|OrderBy|...)
|
|
654
|
-
const entityName = event.CacheKey ? event.CacheKey.split('|')[0] : '';
|
|
655
|
-
if (entityName) {
|
|
656
|
-
PubSubManager.Instance.Publish(CACHE_INVALIDATION_TOPIC, {
|
|
657
|
-
entityName,
|
|
658
|
-
primaryKeyValues: null, // entity-level invalidation
|
|
659
|
-
action: event.Action || 'save',
|
|
660
|
-
sourceServerId: event.SourceServerId || 'unknown',
|
|
661
|
-
timestamp: new Date(),
|
|
662
|
-
});
|
|
663
|
-
}
|
|
664
|
-
});
|
|
665
|
-
// Fan push-status updates across server instances (MJ #4222).
|
|
666
|
-
//
|
|
667
|
-
// Behind a load balancer the browser's WebSocket lives on one replica while the mutation that
|
|
668
|
-
// drives the agent can be handled by another. The push topic is an in-process PubSub, so a
|
|
669
|
-
// completion published on replica B never reaches a subscriber on replica A — the browser waits
|
|
670
|
-
// forever for an event that was delivered to nobody. Replicating progress and completion over
|
|
671
|
-
// Redis closes that, and the durable tail query remains the backstop if Redis is down.
|
|
672
|
-
await wirePushStatusFanOut(redisProvider, startupLog);
|
|
673
|
-
startupLog.LogIf('verbose', `Redis cache provider connected: ${process.env.REDIS_URL}`);
|
|
674
|
-
}
|
|
675
|
-
// If Redis is available, swap LocalCacheManager's storage provider to Redis.
|
|
676
|
-
// LocalCacheManager may have already been initialized (with in-memory provider)
|
|
677
|
-
// during engine loading. SetStorageProvider migrates cached data to Redis.
|
|
678
|
-
if (process.env.REDIS_URL) {
|
|
679
|
-
await LocalCacheManager.Instance.SetStorageProvider(Metadata.Provider.LocalStorageProvider); // global-provider-ok: bootstrap
|
|
680
|
-
startupLog.LogIf('verbose', 'LocalCacheManager: storage provider swapped to Redis');
|
|
681
|
-
}
|
|
682
|
-
// Ensure LocalCacheManager is initialized (no-op if already done during engine loading)
|
|
683
|
-
if (!LocalCacheManager.Instance.IsInitialized) {
|
|
684
|
-
// Build cache config from mj.config.cjs cacheSettings
|
|
685
|
-
const cs = configInfo.cacheSettings;
|
|
686
|
-
const cacheConfig = {
|
|
687
|
-
maxSizeBytes: (cs.maxMemoryMB ?? 150) * 1024 * 1024,
|
|
688
|
-
maxPercentOfCachePerEntity: cs.maxPercentOfCachePerEntity ?? 50,
|
|
689
|
-
defaultTTLMs: (cs.defaultTTLSeconds ?? 0) * 1000,
|
|
690
|
-
evictionSweepIntervalMs: (cs.evictionSweepIntervalSeconds ?? 300) * 1000,
|
|
691
|
-
verboseLogging: cs.verboseLogging ?? false,
|
|
692
|
-
};
|
|
693
|
-
await LocalCacheManager.Instance.Initialize(Metadata.Provider.LocalStorageProvider, cacheConfig); // global-provider-ok: bootstrap
|
|
694
|
-
if (startupLog.IsAtLeast('verbose')) {
|
|
695
|
-
// eslint-disable-next-line no-console
|
|
696
|
-
console.log('LocalCacheManager initialized with cache config:', JSON.stringify({
|
|
697
|
-
maxMemoryMB: cs.maxMemoryMB ?? 150,
|
|
698
|
-
maxPercentOfCachePerEntity: cs.maxPercentOfCachePerEntity ?? 50,
|
|
699
|
-
evictionSweepIntervalSeconds: cs.evictionSweepIntervalSeconds ?? 300,
|
|
700
|
-
}));
|
|
701
|
-
}
|
|
702
|
+
// The database provider already initialized LocalCacheManager from inside its own Config(), with
|
|
703
|
+
// no settings — this call is what makes `cacheSettings` take effect (Initialize merges a config
|
|
704
|
+
// handed to it later). Unconditional on purpose: the guard that used to sit here
|
|
705
|
+
// skipped exactly the case that needed it.
|
|
706
|
+
await LocalCacheManager.Instance.Initialize(Metadata.Provider.LocalStorageProvider, cacheManagerConfig); // global-provider-ok: bootstrap
|
|
707
|
+
if (sharedCache) {
|
|
708
|
+
await LocalCacheManager.Instance.SetStorageProvider(sharedCache);
|
|
702
709
|
}
|
|
710
|
+
const engineSweepMs = StartEngineSweeper(configInfo.cacheSettings);
|
|
711
|
+
startupLog.LogIf('verbose', engineSweepMs > 0 ? `Engine/database sweep every ${engineSweepMs / 1000}s` : 'Engine/database sweep disabled');
|
|
712
|
+
const userCacheCheckMs = StartUserCacheChecks(configInfo.cacheSettings);
|
|
713
|
+
startupLog.LogIf('verbose', userCacheCheckMs > 0 ? `User cache staleness check every ${userCacheCheckMs / 1000}s` : 'User cache staleness check disabled');
|
|
714
|
+
// Costs nothing unless a metadata entity declares TrustServerCacheCompletely = false.
|
|
715
|
+
const metadataSweepMs = StartMetadataSweep(configInfo.cacheSettings, () => (Metadata.Provider instanceof ProviderBase ? Metadata.Provider : undefined)); // global-provider-ok: bootstrap (this process's one provider)
|
|
716
|
+
startupLog.LogIf('verbose', metadataSweepMs > 0 ? `Metadata/database sweep every ${metadataSweepMs / 1000}s (only for entities declaring drift)` : 'Metadata/database sweep disabled');
|
|
703
717
|
// Initialize APIKeyEngine singleton — reads apiKeyGeneration from mj.config.cjs automatically
|
|
704
718
|
// This must happen before any request handler calls GetAPIKeyEngine()
|
|
705
719
|
GetAPIKeyEngine();
|
|
720
|
+
// Actions that run caller-supplied SQL (Run Ad-hoc Query) run only on the read-only login, with
|
|
721
|
+
// ExecuteAdhocQuery's table check and timeout limit.
|
|
722
|
+
ActionEngineServer.Instance.SetReadOnlyProviderFactory(() => CreateReadOnlyProvider(dataSources));
|
|
723
|
+
ActionEngineServer.Instance.SetAdhocSQLAuthorizer(CreateAdhocSQLAuthorizer(configInfo.databaseSettings.requestTimeout));
|
|
706
724
|
setupComplete$.next(true);
|
|
707
725
|
raiseEvent('setupComplete', dataSources, null, this);
|
|
708
726
|
/******TEST HARNESS FOR CHANGE DETECTION */
|
|
@@ -912,7 +930,7 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
912
930
|
const buildMs = performance.now() - tBuild;
|
|
913
931
|
if (cpuProf && profSession) {
|
|
914
932
|
const profile = await new Promise((res, rej) => profSession.post('Profiler.stop', (e, r) => (e ? rej(e) : res(r.profile))));
|
|
915
|
-
const outPath =
|
|
933
|
+
const outPath = join(mkdtempSync(join(tmpdir(), 'mjapi-schema-')), `mjapi_schema_build_${process.pid}.cpuprofile`);
|
|
916
934
|
writeFileSync(outPath, JSON.stringify(profile));
|
|
917
935
|
profSession.disconnect();
|
|
918
936
|
// eslint-disable-next-line no-console
|
|
@@ -1159,6 +1177,18 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
1159
1177
|
}
|
|
1160
1178
|
startupLog.LogIf('verbose', `[Widget] Public routes registered at ${WIDGET_MOUNT_PATH}/session and ${WIDGET_MOUNT_PATH}/session/refresh`);
|
|
1161
1179
|
}
|
|
1180
|
+
// ─── Realtime identity verification: PUBLIC verify-link routes (before auth mw) ───
|
|
1181
|
+
// The person opening the emailed link holds no MJ token — the single-use token is the capability.
|
|
1182
|
+
// GET only renders a confirm button; the POST redeems (mail scanners GET every link). Mounted only
|
|
1183
|
+
// when verification is enabled AND able to send mail AND able to protect its codes (see
|
|
1184
|
+
// realtime.identityVerification config: communicationProvider + hmacSecret).
|
|
1185
|
+
if (configInfo.realtime?.identityVerification?.enabled && !RealtimeSessionVerificationService.Instance.IsEnabled) {
|
|
1186
|
+
console.warn('[RealtimeVerify] realtime.identityVerification.enabled is true but verification is unavailable: it needs a communicationProvider and an hmacSecret of at least 16 characters.');
|
|
1187
|
+
}
|
|
1188
|
+
if (RealtimeSessionVerificationService.Instance.IsEnabled) {
|
|
1189
|
+
app.use(REALTIME_VERIFY_MOUNT_PATH, cors(), CreateRealtimeVerifyRouter());
|
|
1190
|
+
startupLog.LogIf('verbose', `[RealtimeVerify] Public routes registered at ${REALTIME_VERIFY_MOUNT_PATH}/:token (GET) and ${REALTIME_VERIFY_MOUNT_PATH} (POST)`);
|
|
1191
|
+
}
|
|
1162
1192
|
// ─── Server extensions loader & shared service registry ───────────────────
|
|
1163
1193
|
const extensionLoader = new ServerExtensionLoader();
|
|
1164
1194
|
_currentExtensionLoader = extensionLoader;
|
|
@@ -1166,13 +1196,22 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
1166
1196
|
// Backwards-compatibility shim: synthesize ServerExtensionConfig entries from legacy configInfo.telephony
|
|
1167
1197
|
const telephonyExtensionConfigs = [];
|
|
1168
1198
|
if (configInfo.telephony?.enabled) {
|
|
1199
|
+
// Settings every carrier shares (inbound run-as user, call cap, outbound policy). Each carrier's own block is
|
|
1200
|
+
// spread AFTER them, so a carrier can override one explicitly.
|
|
1201
|
+
const sharedTelephonySettings = {
|
|
1202
|
+
inboundRunAsUserEmail: configInfo.telephony.inboundRunAsUserEmail,
|
|
1203
|
+
maxCallSeconds: configInfo.telephony.maxCallSeconds,
|
|
1204
|
+
maxConcurrentCalls: configInfo.telephony.maxConcurrentCalls,
|
|
1205
|
+
transferTargets: configInfo.telephony.transferTargets,
|
|
1206
|
+
outbound: configInfo.telephony.outbound,
|
|
1207
|
+
};
|
|
1169
1208
|
if (configInfo.telephony.twilio) {
|
|
1170
1209
|
telephonyExtensionConfigs.push({
|
|
1171
1210
|
Enabled: true,
|
|
1172
1211
|
DriverClass: 'TwilioTelephonyExtension',
|
|
1173
1212
|
RootPath: '/telephony/twilio',
|
|
1174
1213
|
Phase: 'pre-auth',
|
|
1175
|
-
Settings: configInfo.telephony.twilio,
|
|
1214
|
+
Settings: { ...sharedTelephonySettings, ...configInfo.telephony.twilio },
|
|
1176
1215
|
});
|
|
1177
1216
|
}
|
|
1178
1217
|
if (configInfo.telephony.vonage) {
|
|
@@ -1181,7 +1220,7 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
1181
1220
|
DriverClass: 'VonageTelephonyExtension',
|
|
1182
1221
|
RootPath: '/telephony/vonage',
|
|
1183
1222
|
Phase: 'pre-auth',
|
|
1184
|
-
Settings: configInfo.telephony.vonage,
|
|
1223
|
+
Settings: { ...sharedTelephonySettings, ...configInfo.telephony.vonage },
|
|
1185
1224
|
});
|
|
1186
1225
|
}
|
|
1187
1226
|
if (configInfo.telephony.ringcentral) {
|
|
@@ -1190,7 +1229,16 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
1190
1229
|
DriverClass: 'RingCentralTelephonyExtension',
|
|
1191
1230
|
RootPath: '/telephony/ringcentral',
|
|
1192
1231
|
Phase: 'pre-auth',
|
|
1193
|
-
Settings: configInfo.telephony.ringcentral,
|
|
1232
|
+
Settings: { ...sharedTelephonySettings, ...configInfo.telephony.ringcentral },
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
if (configInfo.telephony.livekitSip) {
|
|
1236
|
+
telephonyExtensionConfigs.push({
|
|
1237
|
+
Enabled: true,
|
|
1238
|
+
DriverClass: 'LiveKitSipExtension',
|
|
1239
|
+
RootPath: '/telephony/livekit-sip',
|
|
1240
|
+
Phase: 'pre-auth',
|
|
1241
|
+
Settings: { ...sharedTelephonySettings, ...configInfo.telephony.livekitSip },
|
|
1194
1242
|
});
|
|
1195
1243
|
}
|
|
1196
1244
|
if (configInfo.telephony.teams?.enabled) {
|
|
@@ -1442,12 +1490,16 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
1442
1490
|
Shutdown: () => { clearInterval(orphanDetailTimer); },
|
|
1443
1491
|
});
|
|
1444
1492
|
}
|
|
1445
|
-
// Launch the AI Agent Session janitor: run own-host orphan recovery once at boot, then
|
|
1446
|
-
//
|
|
1447
|
-
//
|
|
1493
|
+
// Launch the AI Agent Session janitor: run own-host orphan recovery once at boot, then a periodic tick
|
|
1494
|
+
// that closes stale and over-deadline sessions and rebuilds lost realtime recordings from their
|
|
1495
|
+
// crash-recovery shards (storage reads and writes). Self-registers with ShutdownRegistry, so its timer
|
|
1496
|
+
// is cleared by the gracefulShutdown drain below (no explicit Stop() wiring needed here).
|
|
1448
1497
|
if (resumeUser && Metadata.Provider instanceof DatabaseProviderBase) { // global-provider-ok: server startup recovery — boot-time session janitor uses the server's own provider
|
|
1449
1498
|
SessionJanitor.Instance.Start(Metadata.Provider, resumeUser) // global-provider-ok: server-owned background reconciler runs under the server's provider + system user
|
|
1450
1499
|
.catch(err => console.warn(`[SessionJanitor] Startup failed: ${err}`));
|
|
1500
|
+
// The bridge engine's orphan reconcile likewise starts only now that this process holds its port, so it can't
|
|
1501
|
+
// take the live bridges of another MJAPI still serving that port for its own orphans (#5310).
|
|
1502
|
+
StartBridgeOrphanReconciliation(Metadata.Provider, resumeUser); // global-provider-ok: server-owned background reconciler runs under the server's provider + system user
|
|
1451
1503
|
}
|
|
1452
1504
|
// Launch the durable task-graph dispatcher: claim Pending tasks, execute them with a fresh
|
|
1453
1505
|
// provider each, and reconcile claims orphaned by a crash. Without this nothing ever picks up a
|
|
@@ -1480,6 +1532,17 @@ export const Serve = async (resolverPaths, app = CreateApp(), options) => {
|
|
|
1480
1532
|
StartTaskGraphDispatcher(taskGraphPool, resumeUser)
|
|
1481
1533
|
.catch(err => console.warn(`[TaskGraphDispatcher] Startup failed: ${err}`));
|
|
1482
1534
|
}
|
|
1535
|
+
// Start the durable work-queue host where enabled. It plans which subscriptions this instance runs,
|
|
1536
|
+
// re-plans on a timer, and self-registers with ShutdownRegistry, so gracefulShutdown's awaited
|
|
1537
|
+
// ShutdownAll() drains it (up to 2 × shutdownDrainMs) before the HTTP server closes.
|
|
1538
|
+
// Not awaited: a slow engine load must not delay readiness, and a failure never stops the API.
|
|
1539
|
+
const workQueueProvider = Metadata.Provider; // global-provider-ok: server startup — the work-queue host runs on the server's own provider
|
|
1540
|
+
if (configInfo.workQueue?.enabled && workQueueProvider instanceof DatabaseProviderBase) {
|
|
1541
|
+
const workQueuePool = dataSources[0]?.dataSource;
|
|
1542
|
+
const providerSource = new MJServerWorkQueueProviderSource(workQueuePool instanceof sql.ConnectionPool ? workQueuePool : null, workQueueProvider);
|
|
1543
|
+
StartWorkQueueHost(configInfo.workQueue, workQueueProvider, providerSource)
|
|
1544
|
+
.catch(error => console.error('❌ Failed to start the work queue host:', error));
|
|
1545
|
+
}
|
|
1483
1546
|
// Set up graceful shutdown handlers
|
|
1484
1547
|
const gracefulShutdown = async (signal) => {
|
|
1485
1548
|
console.log(`\n${signal} received, shutting down gracefully...`);
|
|
@@ -1923,12 +1986,4 @@ function createMSSQLCompatPool(pgPool) {
|
|
|
1923
1986
|
};
|
|
1924
1987
|
return wrapper;
|
|
1925
1988
|
}
|
|
1926
|
-
/**
|
|
1927
|
-
* Translates SQL Server bracket-quoted identifiers to PostgreSQL double-quoted identifiers.
|
|
1928
|
-
* Converts [schema].[table] to "schema"."table" and handles common T-SQL patterns.
|
|
1929
|
-
*/
|
|
1930
|
-
function translateBracketsToPG(sql) {
|
|
1931
|
-
// Replace [identifier] with "identifier"
|
|
1932
|
-
return sql.replace(/\[([^\]]+)\]/g, '"$1"');
|
|
1933
|
-
}
|
|
1934
1989
|
//# sourceMappingURL=index.js.map
|