@memberjunction/server 6.1.0-edge.1 → 6.1.0-edge.3
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/LICENSE +180 -4
- package/dist/auth/AuthProviderCatalogRouter.d.ts +31 -0
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -0
- package/dist/auth/AuthProviderCatalogRouter.js +69 -0
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -0
- package/dist/auth/AuthProviderEngine.d.ts +96 -0
- package/dist/auth/AuthProviderEngine.d.ts.map +1 -0
- package/dist/auth/AuthProviderEngine.js +245 -0
- package/dist/auth/AuthProviderEngine.js.map +1 -0
- package/dist/auth/exampleNewUserSubClass.js +1 -1
- package/dist/auth/exampleNewUserSubClass.js.map +1 -1
- package/dist/auth/index.d.ts +11 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +65 -18
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +64 -1
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +117 -5
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +1 -1
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/newUsers.js +1 -1
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/config.d.ts +89 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +52 -35
- package/dist/config.js.map +1 -1
- package/dist/context.js +2 -2
- package/dist/context.js.map +1 -1
- package/dist/generated/generated.d.ts +540 -1595
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +2755 -16857
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +20 -4
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +58 -21
- 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 +31 -0
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +183 -54
- package/dist/index.js.map +1 -1
- package/dist/integration/RSUProgressBridge.d.ts +83 -0
- package/dist/integration/RSUProgressBridge.d.ts.map +1 -0
- package/dist/integration/RSUProgressBridge.js +230 -0
- package/dist/integration/RSUProgressBridge.js.map +1 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts +52 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -0
- package/dist/integration/SchemaRefreshLaunch.js +50 -0
- package/dist/integration/SchemaRefreshLaunch.js.map +1 -0
- package/dist/logging/secretRedactor.d.ts +9 -0
- package/dist/logging/secretRedactor.d.ts.map +1 -1
- package/dist/logging/secretRedactor.js +39 -0
- package/dist/logging/secretRedactor.js.map +1 -1
- package/dist/middleware/BaseServerMiddleware.d.ts +5 -0
- package/dist/middleware/BaseServerMiddleware.d.ts.map +1 -1
- package/dist/middleware/BaseServerMiddleware.js +5 -0
- package/dist/middleware/BaseServerMiddleware.js.map +1 -1
- package/dist/providerConfigUnits.d.ts +20 -0
- package/dist/providerConfigUnits.d.ts.map +1 -0
- package/dist/providerConfigUnits.js +22 -0
- package/dist/providerConfigUnits.js.map +1 -0
- package/dist/realtimeWidget/WidgetSessionService.js +1 -1
- package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +12 -0
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.js +1 -1
- package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
- package/dist/resolvers/EntityPermissionResolver.js +1 -1
- package/dist/resolvers/EntityPermissionResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +34 -4
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +218 -28
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +85 -3
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +302 -82
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts +5 -4
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +29 -14
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +12 -3
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +33 -14
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +10 -0
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +5 -0
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +3 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +20 -7
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/SearchEntitiesResolver.js +1 -1
- package/dist/resolvers/SearchEntitiesResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.js +2 -2
- package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts +18 -0
- package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.js +75 -0
- package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.js +1 -1
- package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
- package/dist/resolvers/UserResolver.d.ts +19 -17
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +66 -67
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/resolvers/currentUserRoles.d.ts +19 -0
- package/dist/resolvers/currentUserRoles.d.ts.map +1 -0
- package/dist/resolvers/currentUserRoles.js +36 -0
- package/dist/resolvers/currentUserRoles.js.map +1 -0
- package/dist/rest/MediaAccessKeys.d.ts +17 -0
- package/dist/rest/MediaAccessKeys.d.ts.map +1 -1
- package/dist/rest/MediaAccessKeys.js +42 -1
- package/dist/rest/MediaAccessKeys.js.map +1 -1
- package/dist/rest/MediaStreamHandler.d.ts +3 -2
- package/dist/rest/MediaStreamHandler.d.ts.map +1 -1
- package/dist/rest/MediaStreamHandler.js +83 -2
- package/dist/rest/MediaStreamHandler.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts +49 -1
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +130 -44
- package/dist/rest/OAuthCallbackHandler.js.map +1 -1
- package/dist/rest/SignatureWebhookHandler.js +1 -1
- package/dist/rest/SignatureWebhookHandler.js.map +1 -1
- package/dist/rest/UploadTokenManager.d.ts +90 -0
- package/dist/rest/UploadTokenManager.d.ts.map +1 -0
- package/dist/rest/UploadTokenManager.js +156 -0
- package/dist/rest/UploadTokenManager.js.map +1 -0
- package/dist/services/DurableEntityActionTaskSubmitter.d.ts +26 -0
- package/dist/services/DurableEntityActionTaskSubmitter.d.ts.map +1 -0
- package/dist/services/DurableEntityActionTaskSubmitter.js +55 -0
- package/dist/services/DurableEntityActionTaskSubmitter.js.map +1 -0
- package/dist/services/IntegrationSyncWorkerService.d.ts +48 -0
- package/dist/services/IntegrationSyncWorkerService.d.ts.map +1 -0
- package/dist/services/IntegrationSyncWorkerService.js +132 -0
- package/dist/services/IntegrationSyncWorkerService.js.map +1 -0
- package/dist/services/ScheduledJobsService.js +1 -1
- package/dist/services/ScheduledJobsService.js.map +1 -1
- package/dist/services/StartTaskGraphDispatcher.d.ts +0 -10
- package/dist/services/StartTaskGraphDispatcher.d.ts.map +1 -1
- package/dist/services/StartTaskGraphDispatcher.js +37 -2
- package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +34 -0
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -0
- package/dist/services/TaskGraphActionRunner.js +95 -0
- package/dist/services/TaskGraphActionRunner.js.map +1 -0
- package/dist/services/TaskGraphAgentRunner.d.ts +20 -0
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +53 -0
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +12 -1
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/services/TaskGraphPromptRunner.d.ts +31 -0
- package/dist/services/TaskGraphPromptRunner.d.ts.map +1 -0
- package/dist/services/TaskGraphPromptRunner.js +134 -0
- package/dist/services/TaskGraphPromptRunner.js.map +1 -0
- package/dist/telephony/RingCentralTelephonyService.js +1 -1
- package/dist/telephony/RingCentralTelephonyService.js.map +1 -1
- package/dist/telephony/TwilioTelephonyRouter.js +1 -1
- package/dist/telephony/TwilioTelephonyRouter.js.map +1 -1
- package/dist/telephony/VonageTelephonyRouter.js +1 -1
- package/dist/telephony/VonageTelephonyRouter.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +91 -91
- package/src/__tests__/APIKeyScopeAuth.test.ts +475 -0
- package/src/__tests__/AuthProviderEngine.test.ts +278 -0
- package/src/__tests__/EntityCRUDHandler.test.ts +378 -0
- package/src/__tests__/IntegrationSyncWorkerService.test.ts +275 -0
- package/src/__tests__/OAuthCallbackHandler.openRedirect.test.ts +117 -0
- package/src/__tests__/OAuthCallbackHandler.xss.test.ts +4 -1
- package/src/__tests__/RESTEndpointHandler.test.ts +672 -0
- package/src/__tests__/RSUProgressBridge.test.ts +250 -0
- package/src/__tests__/RealtimeBridgeResolver.test.ts +10 -2
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +1 -1
- package/src/__tests__/ResolverBase.frozenRecordMapping.test.ts +133 -0
- package/src/__tests__/ResolverBase.transportMapping.test.ts +289 -0
- package/src/__tests__/SchemaRefreshLaunch.test.ts +114 -0
- package/src/__tests__/SessionManager.test.ts +1 -1
- package/src/__tests__/UserResolver.currentUser.test.ts +87 -0
- package/src/__tests__/ViewOperationsHandler.test.ts +277 -0
- package/src/__tests__/WidgetSessionService.test.ts +1 -1
- package/src/__tests__/config-units.test.ts +74 -0
- package/src/__tests__/databaseAbstraction.test.ts +1 -1
- package/src/__tests__/initializeProviders.refresh.test.ts +146 -0
- package/src/__tests__/magicLinkService.provisionLog.test.ts +1 -1
- package/src/__tests__/mjapi-bootstrap.test.ts +0 -6
- package/src/__tests__/newUsers.test.ts +726 -0
- package/src/__tests__/resolverBase.rls.test.ts +3 -0
- package/src/__tests__/secretRedactor.failOpen.test.ts +135 -0
- package/src/__tests__/uploadTokenManager.test.ts +159 -0
- package/src/__tests__/widgetGuestElevation.test.ts +1 -1
- package/src/auth/AuthProviderCatalogRouter.ts +76 -0
- package/src/auth/AuthProviderEngine.ts +253 -0
- package/src/auth/exampleNewUserSubClass.ts +1 -1
- package/src/auth/index.ts +69 -21
- package/src/auth/initializeProviders.ts +128 -7
- package/src/auth/magicLink/MagicLinkService.ts +1 -1
- package/src/auth/newUsers.ts +1 -1
- package/src/config.ts +55 -36
- package/src/context.ts +2 -2
- package/src/generated/generated.ts +2038 -10529
- package/src/generic/ResolverBase.ts +63 -21
- package/src/generic/RunViewResolver.ts +31 -0
- package/src/index.ts +199 -56
- package/src/integration/RSUProgressBridge.ts +248 -0
- package/src/integration/SchemaRefreshLaunch.ts +77 -0
- package/src/logging/secretRedactor.ts +43 -0
- package/src/middleware/BaseServerMiddleware.ts +5 -0
- package/src/providerConfigUnits.ts +21 -0
- package/src/realtimeWidget/WidgetSessionService.ts +1 -1
- package/src/realtimeWidget/widgetGuestElevation.ts +1 -1
- package/src/resolvers/ActionResolver.ts +13 -0
- package/src/resolvers/ComponentRegistryResolver.ts +1 -1
- package/src/resolvers/EntityPermissionResolver.ts +1 -1
- package/src/resolvers/FileResolver.ts +200 -40
- package/src/resolvers/IntegrationDiscoveryResolver.ts +328 -70
- package/src/resolvers/PotentialDuplicateRecordResolver.ts +1 -1
- package/src/resolvers/QueryResolver.ts +25 -11
- package/src/resolvers/QuerySystemUserResolver.ts +28 -13
- package/src/resolvers/RealtimeClientSessionResolver.ts +13 -0
- package/src/resolvers/RunAIAgentResolver.ts +21 -6
- package/src/resolvers/SearchEntitiesResolver.ts +1 -1
- package/src/resolvers/SqlLoggingConfigResolver.ts +1 -2
- package/src/resolvers/SyncRolesUsersResolver.ts +2 -2
- package/src/resolvers/TaskGraphFrameResolver.ts +67 -0
- package/src/resolvers/UserFavoriteResolver.ts +1 -1
- package/src/resolvers/UserResolver.ts +99 -60
- package/src/resolvers/currentUserRoles.ts +47 -0
- package/src/rest/MediaAccessKeys.ts +47 -1
- package/src/rest/MediaStreamHandler.ts +98 -3
- package/src/rest/OAuthCallbackHandler.ts +150 -42
- package/src/rest/SignatureWebhookHandler.ts +1 -1
- package/src/rest/UploadTokenManager.ts +211 -0
- package/src/services/DurableEntityActionTaskSubmitter.ts +78 -0
- package/src/services/IntegrationSyncWorkerService.ts +141 -0
- package/src/services/ScheduledJobsService.ts +1 -1
- package/src/services/StartTaskGraphDispatcher.ts +38 -1
- package/src/services/TaskGraphActionRunner.ts +99 -0
- package/src/services/TaskGraphAgentRunner.ts +58 -1
- package/src/services/TaskGraphContinuationDeliverer.ts +11 -1
- package/src/services/TaskGraphPromptRunner.ts +144 -0
- package/src/telephony/RingCentralTelephonyService.ts +1 -1
- package/src/telephony/TwilioTelephonyRouter.ts +1 -1
- package/src/telephony/VonageTelephonyRouter.ts +1 -1
- package/src/types.ts +6 -0
package/src/index.ts
CHANGED
|
@@ -5,9 +5,9 @@ dotenv.config({ quiet: true });
|
|
|
5
5
|
import { expressMiddleware } from '@as-integrations/express5';
|
|
6
6
|
import { mergeSchemas } from '@graphql-tools/schema';
|
|
7
7
|
import { Metadata, DatabasePlatform, SetProvider, StartupManager as StartupManagerImport, BaseEntity, BaseEntityEvent, RunView, DatabaseProviderBase, ResolveStartupMode } from '@memberjunction/core';
|
|
8
|
-
import { resolveDbPlatformFromEnv } from '@memberjunction/generic-database-provider';
|
|
8
|
+
import { UserCache, resolveDbPlatformFromEnv } from '@memberjunction/generic-database-provider';
|
|
9
9
|
import { MJGlobal, MJEventType, UUIDsEqual, ShutdownRegistry } from '@memberjunction/global';
|
|
10
|
-
import { setupSQLServerClient, SQLServerDataProvider, SQLServerProviderConfigData
|
|
10
|
+
import { setupSQLServerClient, SQLServerDataProvider, SQLServerProviderConfigData } from '@memberjunction/sqlserver-dataprovider';
|
|
11
11
|
import { extendConnectionPoolWithQuery } from './util.js';
|
|
12
12
|
import { registerIntegrationCustomColumnPromoter } from './integration/CustomColumnPromoter.js';
|
|
13
13
|
import { DisableUnselectedEntityMaps, ReenableFieldMapsForEntityMap } from './integration/EntityMapLifecycle.js';
|
|
@@ -19,11 +19,12 @@ import { default as fg } from 'fast-glob';
|
|
|
19
19
|
import { useServer } from 'graphql-ws/lib/use/ws';
|
|
20
20
|
import { createServer } from 'node:http';
|
|
21
21
|
import { fileURLToPath } from 'node:url';
|
|
22
|
-
import { readFileSync } from 'node:fs';
|
|
22
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
23
|
+
import { Session as InspectorSession } from 'node:inspector';
|
|
23
24
|
import { sep } from 'node:path';
|
|
24
25
|
import 'reflect-metadata';
|
|
25
26
|
import { ReplaySubject } from 'rxjs';
|
|
26
|
-
import { BuildSchemaOptions, buildSchemaSync, GraphQLTimestamp, PubSubEngine } from 'type-graphql';
|
|
27
|
+
import { BuildSchemaOptions, buildSchemaSync, getMetadataStorage, GraphQLTimestamp, PubSubEngine } from 'type-graphql';
|
|
27
28
|
import { PubSub } from 'graphql-subscriptions';
|
|
28
29
|
import sql from 'mssql';
|
|
29
30
|
import { WebSocketServer } from 'ws';
|
|
@@ -56,14 +57,17 @@ import { DataSourceInfo, raiseEvent } from './types.js';
|
|
|
56
57
|
|
|
57
58
|
import { ExternalChangeDetectorEngine } from '@memberjunction/external-change-detection';
|
|
58
59
|
import { ScheduledJobsService } from './services/ScheduledJobsService.js';
|
|
60
|
+
import { IntegrationSyncWorkerService } from './services/IntegrationSyncWorkerService.js';
|
|
59
61
|
import { LocalCacheManager, StartupManager, TelemetryManager, TelemetryLevel, LogStatus, SetVerboseLogging } from '@memberjunction/core';
|
|
60
|
-
import { getSystemUser } from './auth/index.js';
|
|
62
|
+
import { getSystemUser, validateAuthProvidersRegistered } from './auth/index.js';
|
|
63
|
+
import { createAuthProviderCatalogRouter, AUTH_CATALOG_MOUNT_PATH } from './auth/AuthProviderCatalogRouter.js';
|
|
61
64
|
import { GetAPIKeyEngine } from '@memberjunction/api-keys';
|
|
62
65
|
import { RedisLocalStorageProvider } from '@memberjunction/redis-provider';
|
|
63
66
|
import { GenericDatabaseProvider } from '@memberjunction/generic-database-provider';
|
|
64
67
|
import { PubSubManager } from './generic/PubSubManager.js';
|
|
65
68
|
import { IntegrationProgressEmitter } from '@memberjunction/integration-progress-artifacts';
|
|
66
69
|
import { PublishIntegrationProgress } from './resolvers/IntegrationProgressResolver.js';
|
|
70
|
+
import { RegisterRSUProgressBridge } from './integration/RSUProgressBridge.js';
|
|
67
71
|
import { ClientToolRequestManager, AgentRunWatchdog } from '@memberjunction/ai-agents';
|
|
68
72
|
import { SessionJanitor } from './agentSessions/index.js';
|
|
69
73
|
import { StartTaskGraphDispatcher } from './services/StartTaskGraphDispatcher.js';
|
|
@@ -78,9 +82,12 @@ import {
|
|
|
78
82
|
MJScheduledJobEntity,
|
|
79
83
|
} from '@memberjunction/core-entities';
|
|
80
84
|
import { ServerExtensionLoader, ServerExtensionConfig } from '@memberjunction/server-extensions-core';
|
|
85
|
+
import { MetadataCacheRefreshIntervalSeconds } from './providerConfigUnits.js';
|
|
81
86
|
|
|
82
87
|
const cacheRefreshInterval = configInfo.databaseSettings.metadataCacheRefreshInterval;
|
|
83
88
|
|
|
89
|
+
export { MetadataCacheRefreshIntervalSeconds } from './providerConfigUnits.js';
|
|
90
|
+
|
|
84
91
|
/**
|
|
85
92
|
* Returns the configured database platform from the `DB_PLATFORM` environment
|
|
86
93
|
* variable, falling back to `'sqlserver'` when the env var is unset. An
|
|
@@ -99,6 +106,10 @@ export function getDbType(): DatabasePlatform {
|
|
|
99
106
|
|
|
100
107
|
export { MaxLength } from 'class-validator';
|
|
101
108
|
export * from 'type-graphql';
|
|
109
|
+
// Named re-export so Open App generated resolvers get a live ESM binding for
|
|
110
|
+
// Int/Float/ID. `export *` from type-graphql can leave these undefined for
|
|
111
|
+
// later importers, which makes schema build fail on ViewResult.RowCount.
|
|
112
|
+
export { Int, Float, ID } from 'type-graphql';
|
|
102
113
|
export { NewUserBase } from './auth/newUsers.js';
|
|
103
114
|
export { configInfo, DEFAULT_SERVER_CONFIG } from './config.js';
|
|
104
115
|
export { ServerExtensionLoader, BaseServerExtension } from '@memberjunction/server-extensions-core';
|
|
@@ -153,6 +164,7 @@ export * from './resolvers/QueryResolver.js';
|
|
|
153
164
|
export * from './services/TaskGraphProviderFactory.js';
|
|
154
165
|
export * from './services/TaskGraphAgentRunner.js';
|
|
155
166
|
export * from './services/StartTaskGraphDispatcher.js';
|
|
167
|
+
export * from './services/TaskGraphPromptRunner.js';
|
|
156
168
|
export * from './services/TaskGraphContinuationDeliverer.js';
|
|
157
169
|
export * from './resolvers/TaskGraphFrameResolver.js';
|
|
158
170
|
export * from './resolvers/TestQuerySQLResolver.js';
|
|
@@ -202,6 +214,7 @@ import type { RequestHandler, ErrorRequestHandler } from 'express';
|
|
|
202
214
|
import type { ApolloServerPlugin } from '@apollo/server';
|
|
203
215
|
import type { GraphQLSchema } from 'graphql';
|
|
204
216
|
import { BaseServerMiddleware } from './middleware/BaseServerMiddleware.js';
|
|
217
|
+
import { SuppressTaskGraphSubmission } from '@memberjunction/ai-core-plus';
|
|
205
218
|
|
|
206
219
|
export type MJServerOptions = {
|
|
207
220
|
onBeforeServe?: () => void | Promise<void>;
|
|
@@ -328,8 +341,8 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
328
341
|
await provider.Config(pgConfigData);
|
|
329
342
|
SetProvider(provider);
|
|
330
343
|
|
|
331
|
-
//
|
|
332
|
-
await
|
|
344
|
+
// Warm the user cache — dialect-neutral, same call the SQL Server path makes
|
|
345
|
+
await UserCache.Instance.Refresh(provider);
|
|
333
346
|
|
|
334
347
|
// Run startup actions — same 'full' entry-point default as the SQL Server path
|
|
335
348
|
const sysUser = UserCache.Instance.GetSystemUser();
|
|
@@ -337,6 +350,10 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
337
350
|
const pgStartupMode = ResolveStartupMode({ configValue: configInfo.startup?.mode, defaultMode: 'full' });
|
|
338
351
|
await StartupManagerImport.Instance.Startup(false, sysUser || backupSysUser, provider, { mode: pgStartupMode.mode });
|
|
339
352
|
|
|
353
|
+
// Both provider sources have now had their turn — config/env at module load, metadata via
|
|
354
|
+
// AuthProviderEngine's startup hook — so "no providers at all" is finally a meaningful check.
|
|
355
|
+
validateAuthProvidersRegistered();
|
|
356
|
+
|
|
340
357
|
// Monkey-patch SQLServerDataProvider.ExecuteSQLWithPool to support PostgreSQL
|
|
341
358
|
// Generated resolvers call this static method with bracket-quoted SQL.
|
|
342
359
|
// When the pool is our PG-compat wrapper, translate and execute via pg.Pool.
|
|
@@ -487,11 +504,16 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
487
504
|
startupLog.LogIf('verbose', 'Read-only Connection Pool has been initialized.');
|
|
488
505
|
}
|
|
489
506
|
|
|
490
|
-
|
|
507
|
+
// cacheRefreshInterval is configured in ms; checkRefreshIntervalSeconds declares seconds — see providerConfigUnits.ts
|
|
508
|
+
const config = new SQLServerProviderConfigData(pool, mj_core_schema, MetadataCacheRefreshIntervalSeconds(cacheRefreshInterval));
|
|
491
509
|
// MJAPI is a long-running server, so entry-point default is 'full' engine pre-warm;
|
|
492
510
|
// MJ_STARTUP_MODE / mj.config.cjs startup.mode can override per the shared precedence chain
|
|
493
511
|
const startupMode = ResolveStartupMode({ configValue: configInfo.startup?.mode, defaultMode: 'full' });
|
|
494
512
|
await setupSQLServerClient(config, { mode: startupMode.mode });
|
|
513
|
+
|
|
514
|
+
// See the note on the PostgreSQL path above: this is the first point at which both the
|
|
515
|
+
// config/env providers and the metadata catalog have been registered.
|
|
516
|
+
validateAuthProvidersRegistered();
|
|
495
517
|
lap('Metadata + Provider Setup', tPhase);
|
|
496
518
|
startupLog.BeginPhase('Initializing data provider');
|
|
497
519
|
const md = new Metadata(); // global-provider-ok: bootstrap
|
|
@@ -522,7 +544,8 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
522
544
|
await codegenPool.connect();
|
|
523
545
|
|
|
524
546
|
const { RuntimeSchemaManager } = await import('@memberjunction/schema-engine');
|
|
525
|
-
|
|
547
|
+
// Same ms→seconds seam as the main provider config above — see providerConfigUnits.ts
|
|
548
|
+
const codegenConfig = new SQLServerProviderConfigData(codegenPool, mj_core_schema, MetadataCacheRefreshIntervalSeconds(cacheRefreshInterval));
|
|
526
549
|
const codegenProvider = new SQLServerDataProvider();
|
|
527
550
|
await codegenProvider.Config(codegenConfig);
|
|
528
551
|
RuntimeSchemaManager.Instance.SetDDLProvider(codegenProvider);
|
|
@@ -833,6 +856,14 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
833
856
|
})
|
|
834
857
|
);
|
|
835
858
|
|
|
859
|
+
// Give Runtime Schema Update runs the same durable, tailable event stream as syncs and connector
|
|
860
|
+
// builds. `IntegrationRunKind` has always had an 'RSU' kind and RUN_KIND_TO_TOPIC has always
|
|
861
|
+
// mapped it to an 'RSU' channel, but nothing published to it — the only live signal was polling
|
|
862
|
+
// RuntimeSchemaUpdateStatus, which reports the current step and keeps no history, and which goes
|
|
863
|
+
// silent entirely across the API restart the pipeline performs on itself. Registered AFTER the
|
|
864
|
+
// publish hook above so the first RSU event also reaches live subscribers.
|
|
865
|
+
RegisterRSUProgressBridge();
|
|
866
|
+
|
|
836
867
|
// Global listener: broadcast CACHE_INVALIDATION to all browser clients whenever
|
|
837
868
|
// ANY BaseEntity save/delete occurs on this server — regardless of whether it
|
|
838
869
|
// originated from a GraphQL mutation or internal server-side code (agents, actions,
|
|
@@ -858,23 +889,73 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
858
889
|
lap('Resolver + Middleware Discovery', tServe);
|
|
859
890
|
tServe = startupLog.BeginPhase('Building GraphQL schema');
|
|
860
891
|
|
|
892
|
+
// ── Scale-runtime instrumentation (fix #1 profiling) ─────────────────────────
|
|
893
|
+
// Split the previously-monolithic "Schema Build" phase into its three real
|
|
894
|
+
// sub-steps so we can see which one dominates at high entity counts, and capture
|
|
895
|
+
// the type-graphql metadata cardinality (the O(entities×fields) signal). Guarded
|
|
896
|
+
// by MJ_SCHEMA_PROFILE, and emits ONE explicit console line (independent of the
|
|
897
|
+
// startup logger's level, and NOT via EndPhase, so the "schema" summary token and
|
|
898
|
+
// its total math stay clean). No-op in normal deployments.
|
|
899
|
+
const schemaProfile = process.env.MJ_SCHEMA_PROFILE === '1';
|
|
900
|
+
let objectTypeCount = -1, fieldCount = -1;
|
|
901
|
+
if (schemaProfile) {
|
|
902
|
+
try {
|
|
903
|
+
const meta = getMetadataStorage();
|
|
904
|
+
// Read BEFORE buildSchemaSync — buildSchemaSync's internal build() resets these arrays.
|
|
905
|
+
objectTypeCount = meta.objectTypes.length;
|
|
906
|
+
fieldCount = meta.fields.length;
|
|
907
|
+
} catch {
|
|
908
|
+
/* metadata cardinality is best-effort; leave sentinels */
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// Surgical CPU profile of ONLY buildSchemaSync (behind MJ_SCHEMA_CPUPROF=1), so we can see
|
|
913
|
+
// whether the ~66s at scale is uniform per-field work (cache is the only fix) or a patchable
|
|
914
|
+
// hotspot in type-graphql's generator. Deterministic flush (writes before serve continues) —
|
|
915
|
+
// no dependency on --cpu-prof surviving a process kill.
|
|
916
|
+
const cpuProf = process.env.MJ_SCHEMA_CPUPROF === '1';
|
|
917
|
+
let profSession: InspectorSession | undefined;
|
|
918
|
+
if (cpuProf) {
|
|
919
|
+
profSession = new InspectorSession();
|
|
920
|
+
profSession.connect();
|
|
921
|
+
await new Promise<void>((res, rej) => profSession!.post('Profiler.enable', (e) => (e ? rej(e) : res())));
|
|
922
|
+
await new Promise<void>((res, rej) => profSession!.post('Profiler.start', (e) => (e ? rej(e) : res())));
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
const tBuild = performance.now();
|
|
926
|
+
const builtSchema = buildSchemaSync({
|
|
927
|
+
resolvers: allResolvers,
|
|
928
|
+
validate: false,
|
|
929
|
+
scalarsMap: [{ type: Date, scalar: GraphQLTimestamp }],
|
|
930
|
+
emitSchemaFile: websiteRunFromPackage !== 1,
|
|
931
|
+
pubSub,
|
|
932
|
+
globalMiddlewares: [variablesLoggingMiddleware],
|
|
933
|
+
});
|
|
934
|
+
const buildMs = performance.now() - tBuild;
|
|
935
|
+
|
|
936
|
+
if (cpuProf && profSession) {
|
|
937
|
+
const profile = await new Promise<unknown>((res, rej) =>
|
|
938
|
+
profSession!.post('Profiler.stop', (e, r) => (e ? rej(e) : res((r as { profile: unknown }).profile)))
|
|
939
|
+
);
|
|
940
|
+
const outPath = `/tmp/mjapi_schema_build_${process.pid}.cpuprofile`;
|
|
941
|
+
writeFileSync(outPath, JSON.stringify(profile));
|
|
942
|
+
profSession.disconnect();
|
|
943
|
+
// eslint-disable-next-line no-console
|
|
944
|
+
console.log(`[SCHEMA-CPUPROF] wrote ${outPath} (buildSchemaSync=${buildMs.toFixed(0)}ms)`);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
const tMerge = performance.now();
|
|
861
948
|
let schema = mergeSchemas({
|
|
862
|
-
schemas: [
|
|
863
|
-
buildSchemaSync({
|
|
864
|
-
resolvers: allResolvers,
|
|
865
|
-
validate: false,
|
|
866
|
-
scalarsMap: [{ type: Date, scalar: GraphQLTimestamp }],
|
|
867
|
-
emitSchemaFile: websiteRunFromPackage !== 1,
|
|
868
|
-
pubSub,
|
|
869
|
-
globalMiddlewares: [variablesLoggingMiddleware],
|
|
870
|
-
}),
|
|
871
|
-
],
|
|
949
|
+
schemas: [builtSchema],
|
|
872
950
|
typeDefs: [requireSystemUserDirective.typeDefs, publicDirective.typeDefs],
|
|
873
951
|
});
|
|
952
|
+
const mergeMs = performance.now() - tMerge;
|
|
874
953
|
|
|
875
954
|
// Verbose-mode-only diagnostic: name custom-resolver args that aren't metadata-bound
|
|
876
955
|
// and aren't @NoLog-marked. No-op in default config (logVariables=false).
|
|
877
956
|
auditResolversForUndecoratedArgs();
|
|
957
|
+
|
|
958
|
+
const tTransform = performance.now();
|
|
878
959
|
schema = requireSystemUserDirective.transformer(schema);
|
|
879
960
|
schema = publicDirective.transformer(schema);
|
|
880
961
|
|
|
@@ -882,6 +963,17 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
882
963
|
for (const transformer of mwSchemaTransformers) {
|
|
883
964
|
schema = transformer(schema);
|
|
884
965
|
}
|
|
966
|
+
const transformMs = performance.now() - tTransform;
|
|
967
|
+
|
|
968
|
+
if (schemaProfile) {
|
|
969
|
+
const typeMapSize = Object.keys(schema.getTypeMap()).length;
|
|
970
|
+
// eslint-disable-next-line no-console
|
|
971
|
+
console.log(
|
|
972
|
+
`[SCHEMA-PROFILE] resolvers=${allResolvers.length} objectTypes=${objectTypeCount} fields=${fieldCount} ` +
|
|
973
|
+
`typeMap=${typeMapSize} | buildSchemaSync=${buildMs.toFixed(0)}ms mergeSchemas=${mergeMs.toFixed(0)}ms ` +
|
|
974
|
+
`transformers=${transformMs.toFixed(0)}ms`
|
|
975
|
+
);
|
|
976
|
+
}
|
|
885
977
|
|
|
886
978
|
lap('Schema Build', tServe);
|
|
887
979
|
tServe = startupLog.BeginPhase('Starting HTTP server');
|
|
@@ -1044,7 +1136,9 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
1044
1136
|
const { callbackRouter, authenticatedRouter } = createOAuthCallbackHandler({
|
|
1045
1137
|
publicUrl: oauthPublicUrl,
|
|
1046
1138
|
successRedirectUrl: `${oauthPublicUrl}/oauth/success`,
|
|
1047
|
-
errorRedirectUrl: `${oauthPublicUrl}/oauth/error
|
|
1139
|
+
errorRedirectUrl: `${oauthPublicUrl}/oauth/error`,
|
|
1140
|
+
// Constrains where a caller-supplied frontendReturnUrl may point (open-redirect guard).
|
|
1141
|
+
allowedFrontendOrigins: configInfo.cors?.allowedOrigins ?? ['*']
|
|
1048
1142
|
});
|
|
1049
1143
|
oauthAuthenticatedRouter = authenticatedRouter;
|
|
1050
1144
|
|
|
@@ -1193,6 +1287,14 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
1193
1287
|
res.status(allHealthy ? 200 : 503).json({ extensions: results });
|
|
1194
1288
|
});
|
|
1195
1289
|
|
|
1290
|
+
// ─── Public authentication-provider catalog (PUBLIC, before auth mw) ──────
|
|
1291
|
+
// The browser needs the provider list BEFORE it holds a token, so this is necessarily
|
|
1292
|
+
// unauthenticated and must mount ahead of the auth middleware. It publishes only the
|
|
1293
|
+
// non-secret allow-list (see AuthProviderEngine.GetPublicCatalog) — the same values a
|
|
1294
|
+
// single-provider SPA already compiled into its bundle.
|
|
1295
|
+
app.use(AUTH_CATALOG_MOUNT_PATH, cors<cors.CorsRequest>(), createAuthProviderCatalogRouter());
|
|
1296
|
+
startupLog.LogIf('verbose', `[Auth] Public provider catalog registered at ${AUTH_CATALOG_MOUNT_PATH}/providers`);
|
|
1297
|
+
|
|
1196
1298
|
// ─── Unified auth middleware (replaces both REST authMiddleware and contextFunction auth) ─────
|
|
1197
1299
|
app.use(createUnifiedAuthMiddleware(dataSources));
|
|
1198
1300
|
|
|
@@ -1291,6 +1393,20 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
1291
1393
|
}
|
|
1292
1394
|
}
|
|
1293
1395
|
|
|
1396
|
+
// Initialize and start the integration sync worker if enabled (PR 1 item 8).
|
|
1397
|
+
// Off by default — deployments that don't opt in keep running syncs inline.
|
|
1398
|
+
let integrationSyncWorker: IntegrationSyncWorkerService | null = null;
|
|
1399
|
+
if (configInfo.integrationSyncWorker?.enabled) {
|
|
1400
|
+
try {
|
|
1401
|
+
integrationSyncWorker = new IntegrationSyncWorkerService(configInfo.integrationSyncWorker);
|
|
1402
|
+
await integrationSyncWorker.Initialize();
|
|
1403
|
+
integrationSyncWorker.Start();
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
console.error('❌ Failed to start integration sync worker:', error);
|
|
1406
|
+
// Don't throw — an unavailable worker must not prevent the API from serving
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1294
1410
|
// Data hooks are now registered via BaseServerMiddleware classes above
|
|
1295
1411
|
// (e.g., MJTenantFilterMiddleware registers PreRunView and PreSave hooks).
|
|
1296
1412
|
// No config-bag hook registration needed.
|
|
@@ -1350,8 +1466,28 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
1350
1466
|
// submitted graph — submission would be durable and inert, which is strictly worse than the old
|
|
1351
1467
|
// client-driven path it replaced. Gated on SQL Server because the provider factory mints
|
|
1352
1468
|
// SQLServerDataProvider; the PG branch lands with PG parity. Self-registers with ShutdownRegistry.
|
|
1469
|
+
//
|
|
1470
|
+
// `MJ_DISABLE_TASK_GRAPH_DISPATCHER=1` suppresses it, for the one case where a second dispatcher
|
|
1471
|
+
// is actively harmful: the integration suite's task-graph bundle drives its OWN dispatcher against
|
|
1472
|
+
// a stub runner and asserts exactly-once execution. A dispatcher claims from the whole table, not
|
|
1473
|
+
// from "its own" graphs, so a server sharing that database races the suite for every claim and
|
|
1474
|
+
// executes the suite's tasks with the real agent runner. The bundle then reports tasks that never
|
|
1475
|
+
// ran and graphs that settled to the wrong status — symptoms that read as engine defects and cost
|
|
1476
|
+
// a release cycle to trace back to here. The suite still needs MJAPI up for its client-transport
|
|
1477
|
+
// members, so "stop the server" is not the remedy; this is.
|
|
1353
1478
|
const taskGraphPool = dataSources[0]?.dataSource;
|
|
1354
|
-
|
|
1479
|
+
const taskGraphDispatcherDisabled = process.env.MJ_DISABLE_TASK_GRAPH_DISPATCHER === '1';
|
|
1480
|
+
if (taskGraphDispatcherDisabled) {
|
|
1481
|
+
// AND REFUSE SUBMISSIONS, not just execution (R3-11). The durable submitter registers through
|
|
1482
|
+
// the generated manifest unconditionally, so without this the host went on ACCEPTING graphs it
|
|
1483
|
+
// had no intention of running: the agent submitted, promised the user a follow-up, and parked
|
|
1484
|
+
// its run `Paused` — with the graph `Pending` and the run parked forever, no per-submission
|
|
1485
|
+
// diagnostics anywhere, and the stale graph executing hours later if anyone unset the flag.
|
|
1486
|
+
// The entity-action seam already had this treatment (its submitter registers inside
|
|
1487
|
+
// StartTaskGraphDispatcher); this gives the agent seam the same.
|
|
1488
|
+
SuppressTaskGraphSubmission('MJ_DISABLE_TASK_GRAPH_DISPATCHER=1 is set on this host');
|
|
1489
|
+
LogStatus('[TaskGraphDispatcher] Disabled by MJ_DISABLE_TASK_GRAPH_DISPATCHER=1 — this process will neither accept nor execute task graphs.');
|
|
1490
|
+
} else if (resumeUser && taskGraphPool instanceof sql.ConnectionPool) {
|
|
1355
1491
|
StartTaskGraphDispatcher(taskGraphPool, resumeUser)
|
|
1356
1492
|
.catch(err => console.warn(`[TaskGraphDispatcher] Startup failed: ${err}`));
|
|
1357
1493
|
}
|
|
@@ -1397,6 +1533,17 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
1397
1533
|
}
|
|
1398
1534
|
}
|
|
1399
1535
|
|
|
1536
|
+
// Stop the integration sync worker's polling. In-flight runs finish on their own —
|
|
1537
|
+
// their leases are heartbeat-renewed, and killing them here would only strand rows.
|
|
1538
|
+
if (integrationSyncWorker?.IsRunning) {
|
|
1539
|
+
try {
|
|
1540
|
+
integrationSyncWorker.Stop();
|
|
1541
|
+
console.log(`✅ Integration sync worker stopped (${integrationSyncWorker.InFlightCount} run(s) still in flight)`);
|
|
1542
|
+
} catch (error) {
|
|
1543
|
+
console.error('❌ Error stopping integration sync worker:', error);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1400
1547
|
// Drain anything self-registered with ShutdownRegistry — QueueManager,
|
|
1401
1548
|
// future engines/services with timers/intervals/listeners. Each is
|
|
1402
1549
|
// responsible for being idempotent and not throwing.
|
|
@@ -1435,15 +1582,32 @@ export const serve = async (resolverPaths: Array<string>, app: Application = cre
|
|
|
1435
1582
|
});
|
|
1436
1583
|
};
|
|
1437
1584
|
|
|
1585
|
+
/**
|
|
1586
|
+
* Age at which an unprocessed `MJ: RSU Pending Works` row is reported as stranded.
|
|
1587
|
+
* A row older than this survived at least one full restart cycle without being completed.
|
|
1588
|
+
*/
|
|
1589
|
+
const RSU_PENDING_WORK_STALE_MINUTES = 30;
|
|
1590
|
+
|
|
1438
1591
|
/**
|
|
1439
1592
|
* Process pending RSU work left from a pre-restart Apply All.
|
|
1440
|
-
* Reads
|
|
1593
|
+
* Reads the durable `MJ: RSU Pending Works` queue, creates entity maps + field maps,
|
|
1594
|
+
* starts sync, and marks each row Completed only AFTER its work actually succeeded —
|
|
1595
|
+
* so a crash mid-processing leaves the row Pending and re-processable on the next boot.
|
|
1441
1596
|
*/
|
|
1442
1597
|
async function processRSUPendingWork(): Promise<void> {
|
|
1443
1598
|
// Dynamic import — schema-engine is not yet published to npm, only exists as a workspace package
|
|
1444
1599
|
const { RuntimeSchemaManager } = await import('@memberjunction/schema-engine');
|
|
1445
1600
|
const rsm = RuntimeSchemaManager.Instance;
|
|
1446
|
-
|
|
1601
|
+
|
|
1602
|
+
// Get system user for server-side operations — needed to read the queue itself
|
|
1603
|
+
const systemUser = UserCache.Instance.Users.find(u => u.Type?.trim().toLowerCase() === 'owner') ?? UserCache.Instance.Users[0];
|
|
1604
|
+
if (!systemUser) {
|
|
1605
|
+
console.warn(`[RSU] No system user found — cannot process pending work`);
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
// Rows older than this were left behind by an earlier process and are surfaced as stale.
|
|
1610
|
+
const pendingItems = await rsm.ReadPendingWork(systemUser, RSU_PENDING_WORK_STALE_MINUTES);
|
|
1447
1611
|
if (pendingItems.length === 0) return;
|
|
1448
1612
|
|
|
1449
1613
|
console.log(`[RSU] Processing ${pendingItems.length} pending work item(s) from pre-restart...`);
|
|
@@ -1451,15 +1615,11 @@ async function processRSUPendingWork(): Promise<void> {
|
|
|
1451
1615
|
// Wait a moment for metadata to be fully loaded
|
|
1452
1616
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
1453
1617
|
|
|
1454
|
-
for (const
|
|
1618
|
+
for (const pending of pendingItems) {
|
|
1619
|
+
const pendingWorkID = pending.ID;
|
|
1620
|
+
const item = pending.Work;
|
|
1455
1621
|
try {
|
|
1456
1622
|
const md = new Metadata(); // global-provider-ok: server startup recovery — runs once before any per-request context exists
|
|
1457
|
-
// Get system user for server-side operations
|
|
1458
|
-
const systemUser = UserCache.Instance.Users.find(u => u.Type?.trim().toLowerCase() === 'owner') ?? UserCache.Instance.Users[0];
|
|
1459
|
-
if (!systemUser) {
|
|
1460
|
-
console.warn(`[RSU] No system user found, skipping pending work for ${item.CompanyIntegrationID}`);
|
|
1461
|
-
continue;
|
|
1462
|
-
}
|
|
1463
1623
|
|
|
1464
1624
|
await Metadata.Provider.Refresh(); // global-provider-ok: server startup recovery — one-shot global cache refresh
|
|
1465
1625
|
|
|
@@ -1472,6 +1632,7 @@ async function processRSUPendingWork(): Promise<void> {
|
|
|
1472
1632
|
}, systemUser);
|
|
1473
1633
|
const companyIntegration = ciResult.Results[0];
|
|
1474
1634
|
if (!companyIntegration) {
|
|
1635
|
+
await rsm.FailPendingWork(pendingWorkID, `CompanyIntegration ${item.CompanyIntegrationID} not found`, systemUser);
|
|
1475
1636
|
console.warn(`[RSU] CompanyIntegration ${item.CompanyIntegrationID} not found`);
|
|
1476
1637
|
continue;
|
|
1477
1638
|
}
|
|
@@ -1484,11 +1645,13 @@ async function processRSUPendingWork(): Promise<void> {
|
|
|
1484
1645
|
}, systemUser);
|
|
1485
1646
|
const integrationEntity = integrationResult.Results[0];
|
|
1486
1647
|
if (!integrationEntity) {
|
|
1648
|
+
await rsm.FailPendingWork(pendingWorkID, `Integration entity for ${integrationName} not found`, systemUser);
|
|
1487
1649
|
console.warn(`[RSU] Integration entity for ${integrationName} not found`);
|
|
1488
1650
|
continue;
|
|
1489
1651
|
}
|
|
1490
1652
|
const connector = ConnectorFactory.Resolve(integrationEntity);
|
|
1491
1653
|
if (!connector) {
|
|
1654
|
+
await rsm.FailPendingWork(pendingWorkID, `Connector for ${integrationName} not found`, systemUser);
|
|
1492
1655
|
console.warn(`[RSU] Connector for ${integrationName} not found`);
|
|
1493
1656
|
continue;
|
|
1494
1657
|
}
|
|
@@ -1713,8 +1876,13 @@ async function processRSUPendingWork(): Promise<void> {
|
|
|
1713
1876
|
console.warn(`[RSU] Schedule creation failed: ${schedErr}`);
|
|
1714
1877
|
}
|
|
1715
1878
|
}
|
|
1879
|
+
|
|
1880
|
+
// Only NOW is the work durably done — close the row out.
|
|
1881
|
+
await rsm.CompletePendingWork(pendingWorkID, systemUser);
|
|
1716
1882
|
} catch (err) {
|
|
1717
|
-
|
|
1883
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1884
|
+
console.error(`[RSU] Failed to process pending work for ${item.CompanyIntegrationID}: ${message}`);
|
|
1885
|
+
await rsm.FailPendingWork(pendingWorkID, message, systemUser);
|
|
1718
1886
|
}
|
|
1719
1887
|
}
|
|
1720
1888
|
|
|
@@ -1745,31 +1913,6 @@ function createMSSQLCompatPool(pgPool: import('pg').Pool): sql.ConnectionPool {
|
|
|
1745
1913
|
return wrapper as unknown as sql.ConnectionPool;
|
|
1746
1914
|
}
|
|
1747
1915
|
|
|
1748
|
-
/**
|
|
1749
|
-
* Refreshes the UserCache using PostgreSQL queries instead of MSSQL.
|
|
1750
|
-
* This mirrors the logic in UserCache.Refresh() but uses pg.Pool.
|
|
1751
|
-
*/
|
|
1752
|
-
async function refreshUserCacheFromPG(pgPool: import('pg').Pool, coreSchema: string): Promise<void> {
|
|
1753
|
-
const { UserInfo } = await import('@memberjunction/core');
|
|
1754
|
-
const uResult = await pgPool.query(`SELECT * FROM ${coreSchema}."vwUsers"`);
|
|
1755
|
-
const rResult = await pgPool.query(`SELECT * FROM ${coreSchema}."vwUserRoles"`);
|
|
1756
|
-
const users = uResult.rows;
|
|
1757
|
-
const roles = rResult.rows;
|
|
1758
|
-
|
|
1759
|
-
if (users) {
|
|
1760
|
-
const userInfos = users.map((user: Record<string, unknown>) => {
|
|
1761
|
-
const userWithRoles = {
|
|
1762
|
-
...user,
|
|
1763
|
-
UserRoles: roles.filter((role: Record<string, unknown>) => UUIDsEqual(role.UserID as string, user.ID as string)),
|
|
1764
|
-
};
|
|
1765
|
-
return new UserInfo(Metadata.Provider, userWithRoles); // global-provider-ok: bootstrap (UserCache initialization)
|
|
1766
|
-
});
|
|
1767
|
-
// Access the UserCache internals to set users
|
|
1768
|
-
const cache = UserCache.Instance;
|
|
1769
|
-
(cache as unknown as Record<string, unknown>)['_users'] = userInfos;
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
|
|
1773
1916
|
/**
|
|
1774
1917
|
* Translates SQL Server bracket-quoted identifiers to PostgreSQL double-quoted identifiers.
|
|
1775
1918
|
* Converts [schema].[table] to "schema"."table" and handles common T-SQL patterns.
|