@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
@@ -18,7 +18,7 @@ vi.mock('../config.js', () => ({
18
18
  },
19
19
  }));
20
20
 
21
- import { auditResolverList } from '../logging/bootAudit.js';
21
+ import { AuditResolverList } from '../logging/bootAudit.js';
22
22
  import type { AuditArgParam, AuditResolver } from '../logging/bootAudit.js';
23
23
  import { NoLog } from '../logging/NoLog.js';
24
24
 
@@ -37,12 +37,12 @@ function makeArgParam(opts: {
37
37
  type: Function;
38
38
  }): AuditArgParam {
39
39
  return {
40
- target: opts.target,
41
- methodName: opts.methodName,
42
- index: opts.index,
40
+ Target: opts.target,
41
+ MethodName: opts.methodName,
42
+ Index: opts.index,
43
43
  kind: 'arg',
44
44
  name: opts.name,
45
- getType: () => opts.type,
45
+ GetType: () => opts.type,
46
46
  };
47
47
  }
48
48
 
@@ -52,8 +52,8 @@ function makeResolver(opts: {
52
52
  params: AuditArgParam[];
53
53
  }): AuditResolver {
54
54
  return {
55
- target: opts.target,
56
- methodName: opts.methodName,
55
+ Target: opts.target,
56
+ MethodName: opts.methodName,
57
57
  params: opts.params,
58
58
  };
59
59
  }
@@ -93,7 +93,7 @@ describe('auditResolverList', () => {
93
93
  ],
94
94
  });
95
95
 
96
- auditResolverList([resolver]);
96
+ AuditResolverList([resolver]);
97
97
  expect(warnSpy).not.toHaveBeenCalled();
98
98
  });
99
99
 
@@ -117,7 +117,7 @@ describe('auditResolverList', () => {
117
117
  ],
118
118
  });
119
119
 
120
- auditResolverList([resolver]);
120
+ AuditResolverList([resolver]);
121
121
  expect(warnSpy).toHaveBeenCalledTimes(1);
122
122
  const message = warnSpy.mock.calls[0][0];
123
123
  expect(typeof message).toBe('string');
@@ -148,7 +148,7 @@ describe('auditResolverList', () => {
148
148
  ],
149
149
  });
150
150
 
151
- auditResolverList([resolver]);
151
+ AuditResolverList([resolver]);
152
152
  expect(warnSpy).not.toHaveBeenCalled();
153
153
  });
154
154
 
@@ -179,7 +179,7 @@ describe('auditResolverList', () => {
179
179
  ],
180
180
  });
181
181
 
182
- auditResolverList([resolver]);
182
+ AuditResolverList([resolver]);
183
183
  expect(warnSpy).toHaveBeenCalledTimes(1);
184
184
  const message = warnSpy.mock.calls[0][0];
185
185
  expect(message).toContain("'custom'");
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { buildBoundaryLogPayload } from '../logging/boundaryLogPayload.js';
2
+ import { BuildBoundaryLogPayload } from '../logging/boundaryLogPayload.js';
3
3
 
4
4
  /**
5
5
  * Guards the load-bearing #2638 fix: the always-on GraphQL boundary log line emits the
@@ -10,22 +10,22 @@ import { buildBoundaryLogPayload } from '../logging/boundaryLogPayload.js';
10
10
  */
11
11
  describe('buildBoundaryLogPayload', () => {
12
12
  it('returns operation name only', () => {
13
- expect(buildBoundaryLogPayload('CreateMJCredential')).toEqual({ operationName: 'CreateMJCredential' });
13
+ expect(BuildBoundaryLogPayload('CreateMJCredential')).toEqual({ operationName: 'CreateMJCredential' });
14
14
  });
15
15
 
16
16
  it('never includes a `variables` key', () => {
17
- const payload = buildBoundaryLogPayload('RunViewsWithCacheCheck');
17
+ const payload = BuildBoundaryLogPayload('RunViewsWithCacheCheck');
18
18
  expect('variables' in payload).toBe(false);
19
19
  });
20
20
 
21
21
  it('serialized form contains no value content — only the operation name', () => {
22
22
  // Even if someone passes a secret-shaped operation name, nothing but the name is emitted.
23
- const serialized = JSON.stringify(buildBoundaryLogPayload('SomeOp'));
23
+ const serialized = JSON.stringify(BuildBoundaryLogPayload('SomeOp'));
24
24
  expect(serialized).toBe('{"operationName":"SomeOp"}');
25
25
  });
26
26
 
27
27
  it('handles undefined operation name (non-named operations)', () => {
28
- expect(buildBoundaryLogPayload(undefined)).toEqual({ operationName: undefined });
29
- expect('variables' in buildBoundaryLogPayload(undefined)).toBe(false);
28
+ expect(BuildBoundaryLogPayload(undefined)).toEqual({ operationName: undefined });
29
+ expect('variables' in BuildBoundaryLogPayload(undefined)).toBe(false);
30
30
  });
31
31
  });
@@ -66,11 +66,16 @@ vi.mock('mssql', () => {
66
66
  // We must also mock the auth module and its transitive deps so that importing
67
67
  // individual source files does not trigger type-graphql or reflect-metadata.
68
68
  vi.mock('../auth/index', () => ({
69
- getSigningKeys: vi.fn(),
70
- getSystemUser: vi.fn(),
71
- getValidationOptions: vi.fn(),
72
- verifyUserRecord: vi.fn(),
73
- extractUserInfoFromPayload: vi.fn(),
69
+ GetSigningKeys: vi.fn(),
70
+ get getSigningKeys() { return this.GetSigningKeys; },
71
+ GetSystemUser: vi.fn(),
72
+ get getSystemUser() { return this.GetSystemUser; },
73
+ GetValidationOptions: vi.fn(),
74
+ get getValidationOptions() { return this.GetValidationOptions; },
75
+ VerifyUserRecord: vi.fn(),
76
+ get verifyUserRecord() { return this.VerifyUserRecord; },
77
+ ExtractUserInfoFromPayload: vi.fn(),
78
+ get extractUserInfoFromPayload() { return this.ExtractUserInfoFromPayload; },
74
79
  TokenExpiredError: class TokenExpiredError extends Error {},
75
80
  AuthProviderFactory: { getInstance: vi.fn(() => ({ getByIssuer: vi.fn() })) },
76
81
  IAuthProvider: {},
@@ -82,7 +87,8 @@ vi.mock('../auth/AuthProviderFactory', () => ({
82
87
  }));
83
88
 
84
89
  vi.mock('../cache', () => ({
85
- authCache: new Map(),
90
+ AuthCache: new Map(),
91
+ get authCache() { return this.AuthCache; },
86
92
  }));
87
93
 
88
94
  vi.mock('@memberjunction/core', () => ({
@@ -1,8 +1,8 @@
1
1
  import 'reflect-metadata';
2
2
  import { describe, it, expect } from 'vitest';
3
3
  import type { IMetadataProvider } from '@memberjunction/core';
4
- import { redactArg } from '../logging/secretRedactor.js';
5
- import { NoLog, getNoLogFields } from '../logging/NoLog.js';
4
+ import { RedactArg } from '../logging/secretRedactor.js';
5
+ import { NoLog, GetNoLogFields } from '../logging/NoLog.js';
6
6
 
7
7
  /**
8
8
  * Test 4 (unit form): the `@NoLog`-decorated `Token` field on GetDataInputType is redacted
@@ -27,7 +27,7 @@ describe('Test 4: GetData Token redaction via field-level @NoLog', () => {
27
27
  const provider = { Entities: [] } as unknown as IMetadataProvider;
28
28
 
29
29
  it('getNoLogFields picks up the Token field mark', () => {
30
- const fields = getNoLogFields(GetDataInputType);
30
+ const fields = GetNoLogFields(GetDataInputType);
31
31
  expect(fields.has('Token')).toBe(true);
32
32
  expect(fields.has('Queries')).toBe(false);
33
33
  });
@@ -40,12 +40,12 @@ describe('Test 4: GetData Token redaction via field-level @NoLog', () => {
40
40
  Entities: [{ ClassName: 'Something', EncryptedFields: [] }],
41
41
  } as unknown as IMetadataProvider;
42
42
 
43
- const result = redactArg({
43
+ const result = RedactArg({
44
44
  inputTypeName: 'GetDataInput', // not entity-bound — regex won't match
45
45
  rawValue: { Token: 'FAKE_SYSTEM_TOKEN_DO_NOT_USE', Queries: ['SELECT 1', 'SELECT 2'] },
46
46
  provider: providerWithEntities,
47
47
  noLogParameter: false,
48
- noLogFields: getNoLogFields(GetDataInputType),
48
+ noLogFields: GetNoLogFields(GetDataInputType),
49
49
  });
50
50
 
51
51
  expect(result).toEqual({ Token: '<redacted>', Queries: ['SELECT 1', 'SELECT 2'] });
@@ -58,7 +58,7 @@ describe('Test 4: GetData Token redaction via field-level @NoLog', () => {
58
58
  Entities: [{ ClassName: 'GetDataThing', EncryptedFields: [] }],
59
59
  } as unknown as IMetadataProvider;
60
60
 
61
- const result = redactArg({
61
+ const result = RedactArg({
62
62
  inputTypeName: 'CreateGetDataThingInput',
63
63
  rawValue: { Token: 'FAKE_SYSTEM_TOKEN_DO_NOT_USE', Queries: ['SELECT 1'] },
64
64
  provider: providerWithEntity,
@@ -72,7 +72,7 @@ describe('Test 4: GetData Token redaction via field-level @NoLog', () => {
72
72
 
73
73
  it('parameter-level @NoLog masks the entire arg regardless of shape', () => {
74
74
  // If Token were a top-level @Arg with @NoLog (parameter form), noLogParameter=true masks it whole.
75
- const result = redactArg({
75
+ const result = RedactArg({
76
76
  inputTypeName: 'String',
77
77
  rawValue: 'FAKE_SYSTEM_TOKEN_DO_NOT_USE',
78
78
  provider,
@@ -78,7 +78,7 @@ vi.mock('@memberjunction/core', () => {
78
78
  });
79
79
 
80
80
  import { AuthProviderEngine } from '../auth/AuthProviderEngine.js';
81
- import { refreshAuthProviders } from '../auth/initializeProviders.js';
81
+ import { RefreshAuthProviders } from '../auth/initializeProviders.js';
82
82
 
83
83
  /** Minimal stand-in for a generated MJAuthenticationProviderEntity row. */
84
84
  function metadataRow(name: string, driverClass: string) {
@@ -106,7 +106,7 @@ beforeEach(() => {
106
106
 
107
107
  describe('refreshAuthProviders', () => {
108
108
  it('re-registers the config-declared providers after clearing, so a refresh cannot lock config-path users out', async () => {
109
- await refreshAuthProviders();
109
+ await RefreshAuthProviders();
110
110
 
111
111
  expect(clearMock).toHaveBeenCalledTimes(1);
112
112
  expect(createProviderMock).toHaveBeenCalledWith(expect.objectContaining({ name: 'config-okta' }));
@@ -124,7 +124,7 @@ describe('refreshAuthProviders', () => {
124
124
  });
125
125
 
126
126
  try {
127
- await expect(refreshAuthProviders()).rejects.toThrow('PermissionConstrainedError');
127
+ await expect(RefreshAuthProviders()).rejects.toThrow('PermissionConstrainedError');
128
128
  expect(clearMock).not.toHaveBeenCalled();
129
129
  expect(registerMock).not.toHaveBeenCalled();
130
130
  } finally {
@@ -135,7 +135,7 @@ describe('refreshAuthProviders', () => {
135
135
  it('layers the metadata rows on top of the config-declared providers, in that order', async () => {
136
136
  (AuthProviderEngine.Instance as unknown as { _providers: unknown[] })._providers = [metadataRow('Catalog WorkOS', 'workos')];
137
137
 
138
- const count = await refreshAuthProviders();
138
+ const count = await RefreshAuthProviders();
139
139
 
140
140
  expect(count).toBe(1);
141
141
  expect(registerMock).toHaveBeenCalledTimes(2);
@@ -2,30 +2,30 @@ import { describe, it, expect } from 'vitest';
2
2
  import jwt from 'jsonwebtoken';
3
3
  import { createPublicKey, type JsonWebKey } from 'node:crypto';
4
4
  import {
5
- generateRawToken,
6
- hashToken,
7
- evaluateInvite,
8
- buildSessionClaims,
9
- buildConsumeInviteSQL,
10
- canIssueInvites,
11
- isRoleGrantable,
12
- unionScopes,
5
+ GenerateRawToken,
6
+ HashToken,
7
+ EvaluateInvite,
8
+ BuildSessionClaims,
9
+ BuildConsumeInvitePostgresSQL,
10
+ CanIssueInvites,
11
+ IsRoleGrantable,
12
+ UnionScopes,
13
13
  MAGIC_LINK_TOKEN_PREFIX,
14
14
  } from '../auth/magicLink/magicLinkCore.js';
15
- import { buildRedeemLandingHtml, escapeHtml } from '../auth/magicLink/redeemLanding.js';
15
+ import { BuildRedeemLandingHtml, EscapeHtml } from '../auth/magicLink/redeemLanding.js';
16
16
  import { MagicLinkKeyManager } from '../auth/magicLink/MagicLinkKeys.js';
17
17
 
18
18
  describe('magic-link core', () => {
19
19
  describe('generateRawToken', () => {
20
20
  it('prefixes tokens and uses 32 bytes of hex entropy', () => {
21
- const t = generateRawToken();
21
+ const t = GenerateRawToken();
22
22
  expect(t.startsWith(MAGIC_LINK_TOKEN_PREFIX)).toBe(true);
23
23
  const body = t.slice(MAGIC_LINK_TOKEN_PREFIX.length);
24
24
  expect(body).toMatch(/^[0-9a-f]{64}$/);
25
25
  });
26
26
 
27
27
  it('produces unique tokens', () => {
28
- const set = new Set(Array.from({ length: 100 }, () => generateRawToken()));
28
+ const set = new Set(Array.from({ length: 100 }, () => GenerateRawToken()));
29
29
  expect(set.size).toBe(100);
30
30
  });
31
31
  });
@@ -33,15 +33,15 @@ describe('magic-link core', () => {
33
33
  describe('hashToken', () => {
34
34
  it('is deterministic and base64url-encoded sha256 (43 chars, URL-safe alphabet)', () => {
35
35
  const raw = 'mj_ml_abc';
36
- expect(hashToken(raw)).toBe(hashToken(raw));
36
+ expect(HashToken(raw)).toBe(HashToken(raw));
37
37
  // base64url of 32 bytes = 43 chars, no padding, only [A-Za-z0-9_-]
38
- expect(hashToken(raw)).toMatch(/^[A-Za-z0-9_-]{43}$/);
38
+ expect(HashToken(raw)).toMatch(/^[A-Za-z0-9_-]{43}$/);
39
39
  });
40
40
 
41
41
  it('differs for different inputs and never equals the raw token', () => {
42
- const raw = generateRawToken();
43
- expect(hashToken(raw)).not.toBe(hashToken(generateRawToken()));
44
- expect(hashToken(raw)).not.toBe(raw);
42
+ const raw = GenerateRawToken();
43
+ expect(HashToken(raw)).not.toBe(HashToken(GenerateRawToken()));
44
+ expect(HashToken(raw)).not.toBe(raw);
45
45
  });
46
46
  });
47
47
 
@@ -51,37 +51,37 @@ describe('magic-link core', () => {
51
51
  const past = new Date(now - 3600_000);
52
52
 
53
53
  it('accepts an active, unexpired, unused invite', () => {
54
- expect(evaluateInvite({ Status: 'Active', ExpiresAt: future, MaxUses: 1, UseCount: 0 }, now)).toEqual({ ok: true });
54
+ expect(EvaluateInvite({ Status: 'Active', ExpiresAt: future, MaxUses: 1, UseCount: 0 }, now)).toEqual({ ok: true });
55
55
  });
56
56
 
57
57
  it('rejects revoked invites first', () => {
58
- expect(evaluateInvite({ Status: 'Revoked', ExpiresAt: future, MaxUses: 1, UseCount: 0 }, now)).toEqual({ ok: false, errorCode: 'revoked' });
58
+ expect(EvaluateInvite({ Status: 'Revoked', ExpiresAt: future, MaxUses: 1, UseCount: 0 }, now)).toEqual({ ok: false, errorCode: 'revoked' });
59
59
  });
60
60
 
61
61
  it('rejects expired invites', () => {
62
- expect(evaluateInvite({ Status: 'Active', ExpiresAt: past, MaxUses: 1, UseCount: 0 }, now)).toEqual({ ok: false, errorCode: 'expired' });
62
+ expect(EvaluateInvite({ Status: 'Active', ExpiresAt: past, MaxUses: 1, UseCount: 0 }, now)).toEqual({ ok: false, errorCode: 'expired' });
63
63
  });
64
64
 
65
65
  it('rejects consumed invites (by status)', () => {
66
- expect(evaluateInvite({ Status: 'Consumed', ExpiresAt: future, MaxUses: 1, UseCount: 1 }, now)).toEqual({ ok: false, errorCode: 'consumed' });
66
+ expect(EvaluateInvite({ Status: 'Consumed', ExpiresAt: future, MaxUses: 1, UseCount: 1 }, now)).toEqual({ ok: false, errorCode: 'consumed' });
67
67
  });
68
68
 
69
69
  it('rejects when use count reaches max', () => {
70
- expect(evaluateInvite({ Status: 'Active', ExpiresAt: future, MaxUses: 3, UseCount: 3 }, now)).toEqual({ ok: false, errorCode: 'consumed' });
70
+ expect(EvaluateInvite({ Status: 'Active', ExpiresAt: future, MaxUses: 3, UseCount: 3 }, now)).toEqual({ ok: false, errorCode: 'consumed' });
71
71
  });
72
72
 
73
73
  it('allows multi-use invites that still have uses left', () => {
74
- expect(evaluateInvite({ Status: 'Active', ExpiresAt: future, MaxUses: 3, UseCount: 2 }, now)).toEqual({ ok: true });
74
+ expect(EvaluateInvite({ Status: 'Active', ExpiresAt: future, MaxUses: 3, UseCount: 2 }, now)).toEqual({ ok: true });
75
75
  });
76
76
 
77
77
  it('rejects unknown statuses as invalid', () => {
78
- expect(evaluateInvite({ Status: 'Pending', ExpiresAt: future, MaxUses: 1, UseCount: 0 }, now)).toEqual({ ok: false, errorCode: 'invalid' });
78
+ expect(EvaluateInvite({ Status: 'Pending', ExpiresAt: future, MaxUses: 1, UseCount: 0 }, now)).toEqual({ ok: false, errorCode: 'invalid' });
79
79
  });
80
80
  });
81
81
 
82
82
  describe('buildSessionClaims', () => {
83
83
  it('scopes the token to exactly the given app and role and marks it magic-link', () => {
84
- const claims = buildSessionClaims({
84
+ const claims = BuildSessionClaims({
85
85
  issuer: 'http://localhost:4051',
86
86
  audience: 'mj-magic-link',
87
87
  inviteId: 'INVITE-1',
@@ -103,7 +103,7 @@ describe('magic-link core', () => {
103
103
  });
104
104
 
105
105
  it('carries mj_invited_by when an inviter is supplied (attribution claim)', () => {
106
- const claims = buildSessionClaims({
106
+ const claims = BuildSessionClaims({
107
107
  issuer: 'i', audience: 'a', inviteId: 'INVITE-1', email: 'e@x.com',
108
108
  applicationId: 'APP-1', roleName: 'Magic Link Baseline',
109
109
  invitedByUserId: 'USER-42', nowSeconds: 1000, ttlSeconds: 3600,
@@ -112,7 +112,7 @@ describe('magic-link core', () => {
112
112
  });
113
113
 
114
114
  it('omits mj_invited_by when no inviter is supplied', () => {
115
- const claims = buildSessionClaims({
115
+ const claims = BuildSessionClaims({
116
116
  issuer: 'i', audience: 'a', inviteId: 'INVITE-1', email: 'e@x.com',
117
117
  applicationId: 'APP-1', roleName: 'Magic Link Baseline',
118
118
  nowSeconds: 1000, ttlSeconds: 3600,
@@ -121,7 +121,7 @@ describe('magic-link core', () => {
121
121
  });
122
122
 
123
123
  it('always emits a single-entry mj_scopes for the current link', () => {
124
- const claims = buildSessionClaims({
124
+ const claims = BuildSessionClaims({
125
125
  issuer: 'i', audience: 'a', inviteId: 'INVITE-1', email: 'e@x.com',
126
126
  applicationId: 'APP-1', roleName: 'Magic Link Baseline', nowSeconds: 1000, ttlSeconds: 3600,
127
127
  });
@@ -129,7 +129,7 @@ describe('magic-link core', () => {
129
129
  });
130
130
 
131
131
  it('marks anonymous sessions and carries the per-session id + prior-scope union', () => {
132
- const claims = buildSessionClaims({
132
+ const claims = BuildSessionClaims({
133
133
  issuer: 'i', audience: 'a', inviteId: 'INVITE-2', email: 'anon@x',
134
134
  applicationId: 'APP-2', roleName: 'Guest', anonymous: true, sessionId: 'SID-9',
135
135
  priorScopes: [{ inviteId: 'INVITE-1', appId: 'APP-1', role: 'Guest' }],
@@ -142,7 +142,7 @@ describe('magic-link core', () => {
142
142
  });
143
143
 
144
144
  it('does NOT mark mj_anon for email sessions', () => {
145
- const claims = buildSessionClaims({
145
+ const claims = BuildSessionClaims({
146
146
  issuer: 'i', audience: 'a', inviteId: 'INVITE-1', email: 'e@x.com',
147
147
  applicationId: 'APP-1', roleName: 'Magic Link Baseline', nowSeconds: 1000, ttlSeconds: 3600,
148
148
  });
@@ -155,84 +155,26 @@ describe('magic-link core', () => {
155
155
  const b = { inviteId: 'I2', appId: 'A2', role: 'R' };
156
156
 
157
157
  it('appends a new scope entry', () => {
158
- expect(unionScopes([a], b)).toEqual([a, b]);
158
+ expect(UnionScopes([a], b)).toEqual([a, b]);
159
159
  });
160
160
 
161
161
  it('is idempotent by inviteId — re-redeeming the same link never accretes a duplicate', () => {
162
- expect(unionScopes([a, b], { inviteId: 'I1', appId: 'A1', role: 'R' })).toEqual([a, b]);
162
+ expect(UnionScopes([a, b], { inviteId: 'I1', appId: 'A1', role: 'R' })).toEqual([a, b]);
163
163
  });
164
164
 
165
165
  it('handles an empty/undefined prior union', () => {
166
- expect(unionScopes(undefined, a)).toEqual([a]);
167
- expect(unionScopes([], a)).toEqual([a]);
166
+ expect(UnionScopes(undefined, a)).toEqual([a]);
167
+ expect(UnionScopes([], a)).toEqual([a]);
168
168
  });
169
169
  });
170
170
 
171
- describe('buildConsumeInviteSQL', () => {
172
- const table = '[__mj].[MagicLinkInvite]';
173
- const sql = buildConsumeInviteSQL(table);
174
-
175
- it('targets the supplied qualified table', () => {
176
- expect(sql).toContain(`UPDATE ${table} `);
177
- });
178
-
179
- it('increments UseCount', () => {
180
- expect(sql).toContain('UseCount = UseCount + 1');
181
- });
182
-
183
- it('stamps ConsumedAt only the first time (COALESCE preserves an existing value)', () => {
184
- expect(sql).toContain('ConsumedAt = COALESCE(ConsumedAt, SYSUTCDATETIME())');
185
- });
186
-
187
- it('flips Status to Consumed exactly when the last use is taken', () => {
188
- expect(sql).toContain("Status = CASE WHEN UseCount + 1 >= MaxUses THEN 'Consumed' ELSE Status END");
189
- });
190
-
191
- it('returns the affected row via OUTPUT INTO a table var so the caller can detect a win (exactly one row)', () => {
192
- // Must be OUTPUT ... INTO, not a bare OUTPUT: SQL Server forbids a bare
193
- // OUTPUT clause on a table with enabled triggers, and CodeGen adds an
194
- // __mj_UpdatedAt trigger to every MJ table. Regression guard for that bug.
195
- expect(sql).toContain('OUTPUT INSERTED.ID INTO @consumed');
196
- expect(sql).not.toMatch(/OUTPUT INSERTED\.ID(?!\s+INTO)/);
197
- expect(sql).toContain('SELECT ID FROM @consumed');
198
- });
199
-
200
- it('guards atomically on Active + not-exhausted + not-expired — this IS the single-use gate', () => {
201
- const where = sql.slice(sql.indexOf('WHERE'));
202
- expect(where).toContain("Status = 'Active'");
203
- expect(where).toContain('UseCount < MaxUses');
204
- expect(where).toContain('ExpiresAt > SYSUTCDATETIME()');
205
- });
206
-
207
- it('binds the invite ID as a parameter, never interpolated (injection-safe)', () => {
208
- expect(sql).toContain('ID = @p0');
209
- // The id must not be string-interpolated with quotes around a value.
210
- expect(sql).not.toMatch(/ID = '/);
211
- });
212
-
213
- it('is a self-contained batch: declare table var, update-with-output, select', () => {
214
- // Intentionally a 3-statement batch (the OUTPUT-INTO requirement). The ID is
215
- // still parameterized, so the batch carries no interpolated user input.
216
- expect(sql).toContain('DECLARE @consumed TABLE (ID UNIQUEIDENTIFIER)');
217
- expect(sql.match(/;/g)?.length).toBe(3);
218
- expect(sql.trim().endsWith(';')).toBe(true);
219
- });
220
-
221
- it('rejects a non-whitelisted table identifier (defense-in-depth against injection)', () => {
222
- // Only bracket-quoted [schema].[table] of word chars is accepted, even though
223
- // the caller derives the table from EntityInfo and never from user input.
224
- expect(() => buildConsumeInviteSQL('__mj.MagicLinkInvite')).toThrow();
225
- expect(() => buildConsumeInviteSQL('[__mj].[MagicLinkInvite]; DROP TABLE x;--')).toThrow();
226
- expect(() => buildConsumeInviteSQL('[__mj].[Magic Link]')).toThrow();
227
- expect(() => buildConsumeInviteSQL(table)).not.toThrow();
228
- });
229
- });
230
-
231
- describe('buildConsumeInviteSQL (postgresql dialect)', () => {
232
- // PG uses `schema.table` (unquoted — PostgreSQLDataProvider.ExecuteSQL auto-quotes
233
- // the PascalCase identifiers). SS uses the bracket-quoted `[schema].[table]` form.
171
+ describe('BuildConsumeInvitePostgresSQL', () => {
172
+ // PostgreSQL only: SQL Server consumes through spConsumeMagicLinkInvite (#4753), but PG has no
173
+ // such function and its runtime roles hold table DML, so PG keeps this direct guarded UPDATE.
174
+ // PG uses `schema.table` unquoted — PostgreSQLDataProvider.ExecuteSQL auto-quotes the
175
+ // PascalCase identifiers.
234
176
  const pgTable = '__mj.MagicLinkInvite';
235
- const pgSql = buildConsumeInviteSQL(pgTable, 'postgresql');
177
+ const pgSql = BuildConsumeInvitePostgresSQL(pgTable);
236
178
 
237
179
  it('targets the supplied unquoted schema.table', () => {
238
180
  expect(pgSql).toContain(`UPDATE ${pgTable} `);
@@ -246,63 +188,60 @@ describe('magic-link core', () => {
246
188
 
247
189
  it('binds the invite ID as PG positional param $1, not T-SQL @p0 (injection-safe)', () => {
248
190
  expect(pgSql).toContain('ID = $1');
249
- expect(pgSql).not.toContain('@p0');
250
- expect(pgSql).not.toMatch(/@/); // no T-SQL @-anything survives on PG
191
+ expect(pgSql).not.toMatch(/@/);
251
192
  expect(pgSql).not.toMatch(/ID = '/);
252
193
  });
253
194
 
254
195
  it('uses PG timestamp expressions, not T-SQL SYSUTCDATETIME()', () => {
255
196
  expect(pgSql).not.toContain('SYSUTCDATETIME');
256
- expect(pgSql).toContain("(now() AT TIME ZONE 'utc')");
257
197
  expect(pgSql).toContain("ConsumedAt = COALESCE(ConsumedAt, (now() AT TIME ZONE 'utc'))");
258
198
  });
259
199
 
260
- it('guards atomically on Active + not-exhausted + not-expired (same predicate as SS)', () => {
200
+ it('guards atomically on Active + not-exhausted + not-expired (same predicate as spConsumeMagicLinkInvite)', () => {
261
201
  const where = pgSql.slice(pgSql.indexOf('WHERE'));
262
202
  expect(where).toContain("Status = 'Active'");
263
203
  expect(where).toContain('UseCount < MaxUses');
264
204
  expect(where).toContain("ExpiresAt > (now() AT TIME ZONE 'utc')");
265
205
  });
266
206
 
267
- it('increments UseCount and flips Status on the last use (same semantics as SS)', () => {
207
+ it('increments UseCount and flips Status on the last use (same semantics as spConsumeMagicLinkInvite)', () => {
268
208
  expect(pgSql).toContain('UseCount = UseCount + 1');
269
209
  expect(pgSql).toContain("Status = CASE WHEN UseCount + 1 >= MaxUses THEN 'Consumed' ELSE Status END");
270
210
  });
271
211
 
272
- it('rejects a non-whitelisted PG table identifier (defense-in-depth against injection)', () => {
273
- // Bracket-quoted (SS) form is not a valid PG identifier here.
274
- expect(() => buildConsumeInviteSQL('[__mj].[MagicLinkInvite]', 'postgresql')).toThrow();
275
- expect(() => buildConsumeInviteSQL('__mj.MagicLinkInvite; DROP TABLE x;--', 'postgresql')).toThrow();
276
- expect(() => buildConsumeInviteSQL('__mj.Magic Link', 'postgresql')).toThrow();
277
- expect(() => buildConsumeInviteSQL(pgTable, 'postgresql')).not.toThrow();
212
+ it('rejects a non-whitelisted table identifier (defense-in-depth against injection)', () => {
213
+ expect(() => BuildConsumeInvitePostgresSQL('[__mj].[MagicLinkInvite]')).toThrow();
214
+ expect(() => BuildConsumeInvitePostgresSQL('__mj.MagicLinkInvite; DROP TABLE x;--')).toThrow();
215
+ expect(() => BuildConsumeInvitePostgresSQL('__mj.Magic Link')).toThrow();
216
+ expect(() => BuildConsumeInvitePostgresSQL(pgTable)).not.toThrow();
278
217
  });
279
218
  });
280
219
 
281
220
  describe('canIssueInvites', () => {
282
221
  it('always allows Owners, regardless of issuer-role config (case/space-insensitive)', () => {
283
- expect(canIssueInvites('Owner', [], [])).toBe(true);
284
- expect(canIssueInvites(' owner ', [], [])).toBe(true);
222
+ expect(CanIssueInvites('Owner', [], [])).toBe(true);
223
+ expect(CanIssueInvites(' owner ', [], [])).toBe(true);
285
224
  });
286
225
 
287
226
  it('Owner-only by default: a non-Owner with no configured issuer roles is denied', () => {
288
- expect(canIssueInvites('User', ['Developer', 'Magic Link Baseline'], [])).toBe(false);
227
+ expect(CanIssueInvites('User', ['Developer', 'Magic Link Baseline'], [])).toBe(false);
289
228
  });
290
229
 
291
230
  it('denies an external user holding the restricted role (the escalation we are blocking)', () => {
292
231
  // restricted role is never an issuer role, so this stays false even if someone
293
232
  // mistakenly leaves issuerRoleNames empty
294
- expect(canIssueInvites('User', ['Magic Link Baseline'], [])).toBe(false);
233
+ expect(CanIssueInvites('User', ['Magic Link Baseline'], [])).toBe(false);
295
234
  });
296
235
 
297
236
  it('allows a non-Owner only when one of their roles is a configured issuer role', () => {
298
- expect(canIssueInvites('User', ['Sales Admin'], ['Sales Admin'])).toBe(true);
299
- expect(canIssueInvites('User', ['sales admin'], ['Sales Admin'])).toBe(true); // case-insensitive
300
- expect(canIssueInvites('User', ['Marketing'], ['Sales Admin'])).toBe(false);
237
+ expect(CanIssueInvites('User', ['Sales Admin'], ['Sales Admin'])).toBe(true);
238
+ expect(CanIssueInvites('User', ['sales admin'], ['Sales Admin'])).toBe(true); // case-insensitive
239
+ expect(CanIssueInvites('User', ['Marketing'], ['Sales Admin'])).toBe(false);
301
240
  });
302
241
 
303
242
  it('handles null/undefined type and empty role lists safely', () => {
304
- expect(canIssueInvites(null, [], ['X'])).toBe(false);
305
- expect(canIssueInvites(undefined, ['X'], ['X'])).toBe(true);
243
+ expect(CanIssueInvites(null, [], ['X'])).toBe(false);
244
+ expect(CanIssueInvites(undefined, ['X'], ['X'])).toBe(true);
306
245
  });
307
246
  });
308
247
 
@@ -310,41 +249,41 @@ describe('magic-link core', () => {
310
249
  const restricted = 'Magic Link Baseline';
311
250
 
312
251
  it('always allows the restricted role (case/space-insensitive)', () => {
313
- expect(isRoleGrantable('Magic Link Baseline', restricted, [])).toBe(true);
314
- expect(isRoleGrantable(' magic link baseline ', restricted, [])).toBe(true);
252
+ expect(IsRoleGrantable('Magic Link Baseline', restricted, [])).toBe(true);
253
+ expect(IsRoleGrantable(' magic link baseline ', restricted, [])).toBe(true);
315
254
  });
316
255
 
317
256
  it('rejects a privileged role by default — blocks roleId=Owner escalation', () => {
318
- expect(isRoleGrantable('Owner', restricted, [])).toBe(false);
319
- expect(isRoleGrantable('Administrator', restricted, [])).toBe(false);
257
+ expect(IsRoleGrantable('Owner', restricted, [])).toBe(false);
258
+ expect(IsRoleGrantable('Administrator', restricted, [])).toBe(false);
320
259
  });
321
260
 
322
261
  it('allows additional roles only when explicitly opted in', () => {
323
- expect(isRoleGrantable('Read Only Guest', restricted, ['Read Only Guest'])).toBe(true);
324
- expect(isRoleGrantable('read only guest', restricted, ['Read Only Guest'])).toBe(true);
325
- expect(isRoleGrantable('Owner', restricted, ['Read Only Guest'])).toBe(false);
262
+ expect(IsRoleGrantable('Read Only Guest', restricted, ['Read Only Guest'])).toBe(true);
263
+ expect(IsRoleGrantable('read only guest', restricted, ['Read Only Guest'])).toBe(true);
264
+ expect(IsRoleGrantable('Owner', restricted, ['Read Only Guest'])).toBe(false);
326
265
  });
327
266
 
328
267
  it('rejects empty/null role names', () => {
329
- expect(isRoleGrantable('', restricted, [])).toBe(false);
330
- expect(isRoleGrantable(null, restricted, [])).toBe(false);
268
+ expect(IsRoleGrantable('', restricted, [])).toBe(false);
269
+ expect(IsRoleGrantable(null, restricted, [])).toBe(false);
331
270
  });
332
271
  });
333
272
 
334
273
  describe('escapeHtml', () => {
335
274
  it('escapes the five significant HTML characters', () => {
336
- expect(escapeHtml(`<>&"'`)).toBe('&lt;&gt;&amp;&quot;&#39;');
275
+ expect(EscapeHtml(`<>&"'`)).toBe('&lt;&gt;&amp;&quot;&#39;');
337
276
  });
338
277
 
339
278
  it('leaves a normal magic-link token untouched', () => {
340
- const t = generateRawToken();
341
- expect(escapeHtml(t)).toBe(t);
279
+ const t = GenerateRawToken();
280
+ expect(EscapeHtml(t)).toBe(t);
342
281
  });
343
282
  });
344
283
 
345
284
  describe('buildRedeemLandingHtml', () => {
346
- const token = generateRawToken();
347
- const html = buildRedeemLandingHtml(token, '/magic-link/redeem');
285
+ const token = GenerateRawToken();
286
+ const html = BuildRedeemLandingHtml(token, '/magic-link/redeem');
348
287
 
349
288
  it('renders a POST form to the redeem path (GET stays side-effect-free)', () => {
350
289
  expect(html).toContain('method="POST"');
@@ -365,7 +304,7 @@ describe('magic-link core', () => {
365
304
  });
366
305
 
367
306
  it('escapes a token containing HTML metacharacters into the form value', () => {
368
- const evil = buildRedeemLandingHtml('a"><script>x</script>', '/magic-link/redeem');
307
+ const evil = BuildRedeemLandingHtml('a"><script>x</script>', '/magic-link/redeem');
369
308
  expect(evil).not.toContain('<script>x</script>');
370
309
  expect(evil).toContain('&lt;script&gt;');
371
310
  });
@@ -377,7 +316,7 @@ describe('MagicLinkKeyManager', () => {
377
316
  const km = MagicLinkKeyManager.Instance;
378
317
  km.Initialize(); // ephemeral keypair
379
318
 
380
- const claims = buildSessionClaims({
319
+ const claims = BuildSessionClaims({
381
320
  issuer: 'http://localhost:4051',
382
321
  audience: 'mj-magic-link',
383
322
  inviteId: 'INVITE-1',
@@ -414,7 +353,7 @@ describe('MagicLinkKeyManager', () => {
414
353
  it('rejects a tampered token', () => {
415
354
  const km = MagicLinkKeyManager.Instance;
416
355
  km.Initialize();
417
- const claims = buildSessionClaims({
356
+ const claims = BuildSessionClaims({
418
357
  issuer: 'http://localhost:4051',
419
358
  audience: 'mj-magic-link',
420
359
  inviteId: 'INVITE-2',