@memberjunction/server 6.1.4 → 6.2.0-edge.1

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