@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.
Files changed (261) hide show
  1. package/LICENSE +180 -4
  2. package/dist/auth/AuthProviderCatalogRouter.d.ts +31 -0
  3. package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -0
  4. package/dist/auth/AuthProviderCatalogRouter.js +69 -0
  5. package/dist/auth/AuthProviderCatalogRouter.js.map +1 -0
  6. package/dist/auth/AuthProviderEngine.d.ts +96 -0
  7. package/dist/auth/AuthProviderEngine.d.ts.map +1 -0
  8. package/dist/auth/AuthProviderEngine.js +245 -0
  9. package/dist/auth/AuthProviderEngine.js.map +1 -0
  10. package/dist/auth/exampleNewUserSubClass.js +1 -1
  11. package/dist/auth/exampleNewUserSubClass.js.map +1 -1
  12. package/dist/auth/index.d.ts +11 -0
  13. package/dist/auth/index.d.ts.map +1 -1
  14. package/dist/auth/index.js +65 -18
  15. package/dist/auth/index.js.map +1 -1
  16. package/dist/auth/initializeProviders.d.ts +64 -1
  17. package/dist/auth/initializeProviders.d.ts.map +1 -1
  18. package/dist/auth/initializeProviders.js +117 -5
  19. package/dist/auth/initializeProviders.js.map +1 -1
  20. package/dist/auth/magicLink/MagicLinkService.js +1 -1
  21. package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
  22. package/dist/auth/newUsers.js +1 -1
  23. package/dist/auth/newUsers.js.map +1 -1
  24. package/dist/config.d.ts +89 -0
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +52 -35
  27. package/dist/config.js.map +1 -1
  28. package/dist/context.js +2 -2
  29. package/dist/context.js.map +1 -1
  30. package/dist/generated/generated.d.ts +540 -1595
  31. package/dist/generated/generated.d.ts.map +1 -1
  32. package/dist/generated/generated.js +2755 -16857
  33. package/dist/generated/generated.js.map +1 -1
  34. package/dist/generic/ResolverBase.d.ts +20 -4
  35. package/dist/generic/ResolverBase.d.ts.map +1 -1
  36. package/dist/generic/ResolverBase.js +58 -21
  37. package/dist/generic/ResolverBase.js.map +1 -1
  38. package/dist/generic/RunViewResolver.d.ts +4 -0
  39. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  40. package/dist/generic/RunViewResolver.js +31 -0
  41. package/dist/generic/RunViewResolver.js.map +1 -1
  42. package/dist/index.d.ts +3 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +183 -54
  45. package/dist/index.js.map +1 -1
  46. package/dist/integration/RSUProgressBridge.d.ts +83 -0
  47. package/dist/integration/RSUProgressBridge.d.ts.map +1 -0
  48. package/dist/integration/RSUProgressBridge.js +230 -0
  49. package/dist/integration/RSUProgressBridge.js.map +1 -0
  50. package/dist/integration/SchemaRefreshLaunch.d.ts +52 -0
  51. package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -0
  52. package/dist/integration/SchemaRefreshLaunch.js +50 -0
  53. package/dist/integration/SchemaRefreshLaunch.js.map +1 -0
  54. package/dist/logging/secretRedactor.d.ts +9 -0
  55. package/dist/logging/secretRedactor.d.ts.map +1 -1
  56. package/dist/logging/secretRedactor.js +39 -0
  57. package/dist/logging/secretRedactor.js.map +1 -1
  58. package/dist/middleware/BaseServerMiddleware.d.ts +5 -0
  59. package/dist/middleware/BaseServerMiddleware.d.ts.map +1 -1
  60. package/dist/middleware/BaseServerMiddleware.js +5 -0
  61. package/dist/middleware/BaseServerMiddleware.js.map +1 -1
  62. package/dist/providerConfigUnits.d.ts +20 -0
  63. package/dist/providerConfigUnits.d.ts.map +1 -0
  64. package/dist/providerConfigUnits.js +22 -0
  65. package/dist/providerConfigUnits.js.map +1 -0
  66. package/dist/realtimeWidget/WidgetSessionService.js +1 -1
  67. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
  68. package/dist/realtimeWidget/widgetGuestElevation.js +1 -1
  69. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  70. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  71. package/dist/resolvers/ActionResolver.js +12 -0
  72. package/dist/resolvers/ActionResolver.js.map +1 -1
  73. package/dist/resolvers/ComponentRegistryResolver.js +1 -1
  74. package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
  75. package/dist/resolvers/EntityPermissionResolver.js +1 -1
  76. package/dist/resolvers/EntityPermissionResolver.js.map +1 -1
  77. package/dist/resolvers/FileResolver.d.ts +34 -4
  78. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  79. package/dist/resolvers/FileResolver.js +218 -28
  80. package/dist/resolvers/FileResolver.js.map +1 -1
  81. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +85 -3
  82. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  83. package/dist/resolvers/IntegrationDiscoveryResolver.js +302 -82
  84. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  85. package/dist/resolvers/PotentialDuplicateRecordResolver.js +1 -1
  86. package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
  87. package/dist/resolvers/QueryResolver.d.ts +5 -4
  88. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  89. package/dist/resolvers/QueryResolver.js +29 -14
  90. package/dist/resolvers/QueryResolver.js.map +1 -1
  91. package/dist/resolvers/QuerySystemUserResolver.d.ts +12 -3
  92. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  93. package/dist/resolvers/QuerySystemUserResolver.js +33 -14
  94. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  95. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +10 -0
  96. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  97. package/dist/resolvers/RealtimeClientSessionResolver.js +5 -0
  98. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  99. package/dist/resolvers/RunAIAgentResolver.d.ts +3 -1
  100. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  101. package/dist/resolvers/RunAIAgentResolver.js +20 -7
  102. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  103. package/dist/resolvers/SearchEntitiesResolver.js +1 -1
  104. package/dist/resolvers/SearchEntitiesResolver.js.map +1 -1
  105. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  106. package/dist/resolvers/SqlLoggingConfigResolver.js +1 -1
  107. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  108. package/dist/resolvers/SyncRolesUsersResolver.js +2 -2
  109. package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
  110. package/dist/resolvers/TaskGraphFrameResolver.d.ts +18 -0
  111. package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
  112. package/dist/resolvers/TaskGraphFrameResolver.js +75 -0
  113. package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
  114. package/dist/resolvers/UserFavoriteResolver.js +1 -1
  115. package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
  116. package/dist/resolvers/UserResolver.d.ts +19 -17
  117. package/dist/resolvers/UserResolver.d.ts.map +1 -1
  118. package/dist/resolvers/UserResolver.js +66 -67
  119. package/dist/resolvers/UserResolver.js.map +1 -1
  120. package/dist/resolvers/currentUserRoles.d.ts +19 -0
  121. package/dist/resolvers/currentUserRoles.d.ts.map +1 -0
  122. package/dist/resolvers/currentUserRoles.js +36 -0
  123. package/dist/resolvers/currentUserRoles.js.map +1 -0
  124. package/dist/rest/MediaAccessKeys.d.ts +17 -0
  125. package/dist/rest/MediaAccessKeys.d.ts.map +1 -1
  126. package/dist/rest/MediaAccessKeys.js +42 -1
  127. package/dist/rest/MediaAccessKeys.js.map +1 -1
  128. package/dist/rest/MediaStreamHandler.d.ts +3 -2
  129. package/dist/rest/MediaStreamHandler.d.ts.map +1 -1
  130. package/dist/rest/MediaStreamHandler.js +83 -2
  131. package/dist/rest/MediaStreamHandler.js.map +1 -1
  132. package/dist/rest/OAuthCallbackHandler.d.ts +49 -1
  133. package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
  134. package/dist/rest/OAuthCallbackHandler.js +130 -44
  135. package/dist/rest/OAuthCallbackHandler.js.map +1 -1
  136. package/dist/rest/SignatureWebhookHandler.js +1 -1
  137. package/dist/rest/SignatureWebhookHandler.js.map +1 -1
  138. package/dist/rest/UploadTokenManager.d.ts +90 -0
  139. package/dist/rest/UploadTokenManager.d.ts.map +1 -0
  140. package/dist/rest/UploadTokenManager.js +156 -0
  141. package/dist/rest/UploadTokenManager.js.map +1 -0
  142. package/dist/services/DurableEntityActionTaskSubmitter.d.ts +26 -0
  143. package/dist/services/DurableEntityActionTaskSubmitter.d.ts.map +1 -0
  144. package/dist/services/DurableEntityActionTaskSubmitter.js +55 -0
  145. package/dist/services/DurableEntityActionTaskSubmitter.js.map +1 -0
  146. package/dist/services/IntegrationSyncWorkerService.d.ts +48 -0
  147. package/dist/services/IntegrationSyncWorkerService.d.ts.map +1 -0
  148. package/dist/services/IntegrationSyncWorkerService.js +132 -0
  149. package/dist/services/IntegrationSyncWorkerService.js.map +1 -0
  150. package/dist/services/ScheduledJobsService.js +1 -1
  151. package/dist/services/ScheduledJobsService.js.map +1 -1
  152. package/dist/services/StartTaskGraphDispatcher.d.ts +0 -10
  153. package/dist/services/StartTaskGraphDispatcher.d.ts.map +1 -1
  154. package/dist/services/StartTaskGraphDispatcher.js +37 -2
  155. package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
  156. package/dist/services/TaskGraphActionRunner.d.ts +34 -0
  157. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -0
  158. package/dist/services/TaskGraphActionRunner.js +95 -0
  159. package/dist/services/TaskGraphActionRunner.js.map +1 -0
  160. package/dist/services/TaskGraphAgentRunner.d.ts +20 -0
  161. package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
  162. package/dist/services/TaskGraphAgentRunner.js +53 -0
  163. package/dist/services/TaskGraphAgentRunner.js.map +1 -1
  164. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  165. package/dist/services/TaskGraphContinuationDeliverer.js +12 -1
  166. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  167. package/dist/services/TaskGraphPromptRunner.d.ts +31 -0
  168. package/dist/services/TaskGraphPromptRunner.d.ts.map +1 -0
  169. package/dist/services/TaskGraphPromptRunner.js +134 -0
  170. package/dist/services/TaskGraphPromptRunner.js.map +1 -0
  171. package/dist/telephony/RingCentralTelephonyService.js +1 -1
  172. package/dist/telephony/RingCentralTelephonyService.js.map +1 -1
  173. package/dist/telephony/TwilioTelephonyRouter.js +1 -1
  174. package/dist/telephony/TwilioTelephonyRouter.js.map +1 -1
  175. package/dist/telephony/VonageTelephonyRouter.js +1 -1
  176. package/dist/telephony/VonageTelephonyRouter.js.map +1 -1
  177. package/dist/types.d.ts +6 -0
  178. package/dist/types.d.ts.map +1 -1
  179. package/dist/types.js.map +1 -1
  180. package/package.json +91 -91
  181. package/src/__tests__/APIKeyScopeAuth.test.ts +475 -0
  182. package/src/__tests__/AuthProviderEngine.test.ts +278 -0
  183. package/src/__tests__/EntityCRUDHandler.test.ts +378 -0
  184. package/src/__tests__/IntegrationSyncWorkerService.test.ts +275 -0
  185. package/src/__tests__/OAuthCallbackHandler.openRedirect.test.ts +117 -0
  186. package/src/__tests__/OAuthCallbackHandler.xss.test.ts +4 -1
  187. package/src/__tests__/RESTEndpointHandler.test.ts +672 -0
  188. package/src/__tests__/RSUProgressBridge.test.ts +250 -0
  189. package/src/__tests__/RealtimeBridgeResolver.test.ts +10 -2
  190. package/src/__tests__/RealtimeClientSessionResolver.test.ts +1 -1
  191. package/src/__tests__/ResolverBase.frozenRecordMapping.test.ts +133 -0
  192. package/src/__tests__/ResolverBase.transportMapping.test.ts +289 -0
  193. package/src/__tests__/SchemaRefreshLaunch.test.ts +114 -0
  194. package/src/__tests__/SessionManager.test.ts +1 -1
  195. package/src/__tests__/UserResolver.currentUser.test.ts +87 -0
  196. package/src/__tests__/ViewOperationsHandler.test.ts +277 -0
  197. package/src/__tests__/WidgetSessionService.test.ts +1 -1
  198. package/src/__tests__/config-units.test.ts +74 -0
  199. package/src/__tests__/databaseAbstraction.test.ts +1 -1
  200. package/src/__tests__/initializeProviders.refresh.test.ts +146 -0
  201. package/src/__tests__/magicLinkService.provisionLog.test.ts +1 -1
  202. package/src/__tests__/mjapi-bootstrap.test.ts +0 -6
  203. package/src/__tests__/newUsers.test.ts +726 -0
  204. package/src/__tests__/resolverBase.rls.test.ts +3 -0
  205. package/src/__tests__/secretRedactor.failOpen.test.ts +135 -0
  206. package/src/__tests__/uploadTokenManager.test.ts +159 -0
  207. package/src/__tests__/widgetGuestElevation.test.ts +1 -1
  208. package/src/auth/AuthProviderCatalogRouter.ts +76 -0
  209. package/src/auth/AuthProviderEngine.ts +253 -0
  210. package/src/auth/exampleNewUserSubClass.ts +1 -1
  211. package/src/auth/index.ts +69 -21
  212. package/src/auth/initializeProviders.ts +128 -7
  213. package/src/auth/magicLink/MagicLinkService.ts +1 -1
  214. package/src/auth/newUsers.ts +1 -1
  215. package/src/config.ts +55 -36
  216. package/src/context.ts +2 -2
  217. package/src/generated/generated.ts +2038 -10529
  218. package/src/generic/ResolverBase.ts +63 -21
  219. package/src/generic/RunViewResolver.ts +31 -0
  220. package/src/index.ts +199 -56
  221. package/src/integration/RSUProgressBridge.ts +248 -0
  222. package/src/integration/SchemaRefreshLaunch.ts +77 -0
  223. package/src/logging/secretRedactor.ts +43 -0
  224. package/src/middleware/BaseServerMiddleware.ts +5 -0
  225. package/src/providerConfigUnits.ts +21 -0
  226. package/src/realtimeWidget/WidgetSessionService.ts +1 -1
  227. package/src/realtimeWidget/widgetGuestElevation.ts +1 -1
  228. package/src/resolvers/ActionResolver.ts +13 -0
  229. package/src/resolvers/ComponentRegistryResolver.ts +1 -1
  230. package/src/resolvers/EntityPermissionResolver.ts +1 -1
  231. package/src/resolvers/FileResolver.ts +200 -40
  232. package/src/resolvers/IntegrationDiscoveryResolver.ts +328 -70
  233. package/src/resolvers/PotentialDuplicateRecordResolver.ts +1 -1
  234. package/src/resolvers/QueryResolver.ts +25 -11
  235. package/src/resolvers/QuerySystemUserResolver.ts +28 -13
  236. package/src/resolvers/RealtimeClientSessionResolver.ts +13 -0
  237. package/src/resolvers/RunAIAgentResolver.ts +21 -6
  238. package/src/resolvers/SearchEntitiesResolver.ts +1 -1
  239. package/src/resolvers/SqlLoggingConfigResolver.ts +1 -2
  240. package/src/resolvers/SyncRolesUsersResolver.ts +2 -2
  241. package/src/resolvers/TaskGraphFrameResolver.ts +67 -0
  242. package/src/resolvers/UserFavoriteResolver.ts +1 -1
  243. package/src/resolvers/UserResolver.ts +99 -60
  244. package/src/resolvers/currentUserRoles.ts +47 -0
  245. package/src/rest/MediaAccessKeys.ts +47 -1
  246. package/src/rest/MediaStreamHandler.ts +98 -3
  247. package/src/rest/OAuthCallbackHandler.ts +150 -42
  248. package/src/rest/SignatureWebhookHandler.ts +1 -1
  249. package/src/rest/UploadTokenManager.ts +211 -0
  250. package/src/services/DurableEntityActionTaskSubmitter.ts +78 -0
  251. package/src/services/IntegrationSyncWorkerService.ts +141 -0
  252. package/src/services/ScheduledJobsService.ts +1 -1
  253. package/src/services/StartTaskGraphDispatcher.ts +38 -1
  254. package/src/services/TaskGraphActionRunner.ts +99 -0
  255. package/src/services/TaskGraphAgentRunner.ts +58 -1
  256. package/src/services/TaskGraphContinuationDeliverer.ts +11 -1
  257. package/src/services/TaskGraphPromptRunner.ts +144 -0
  258. package/src/telephony/RingCentralTelephonyService.ts +1 -1
  259. package/src/telephony/TwilioTelephonyRouter.ts +1 -1
  260. package/src/telephony/VonageTelephonyRouter.ts +1 -1
  261. 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, UserCache } from '@memberjunction/sqlserver-dataprovider';
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
- // Refresh user cache using PostgreSQL
332
- await refreshUserCacheFromPG(pgPool, mj_core_schema);
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
- const config = new SQLServerProviderConfigData(pool, mj_core_schema, cacheRefreshInterval / 1000); // convert ms to seconds (checkRefreshIntervalSeconds)
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
- const codegenConfig = new SQLServerProviderConfigData(codegenPool, mj_core_schema, cacheRefreshInterval / 1000); // convert ms to seconds (checkRefreshIntervalSeconds)
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
- if (resumeUser && taskGraphPool instanceof sql.ConnectionPool) {
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 pending work files, creates entity maps + field maps, starts sync.
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
- const pendingItems = await rsm.ReadAndClearPendingWork();
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 item of pendingItems) {
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
- console.error(`[RSU] Failed to process pending work for ${item.CompanyIntegrationID}: ${err}`);
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.