@memberjunction/server 6.2.0-edge.0 → 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 (403) 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/index.d.ts +20 -1
  16. package/dist/auth/index.d.ts.map +1 -1
  17. package/dist/auth/index.js +20 -10
  18. package/dist/auth/index.js.map +1 -1
  19. package/dist/auth/initializeProviders.d.ts +8 -0
  20. package/dist/auth/initializeProviders.d.ts.map +1 -1
  21. package/dist/auth/initializeProviders.js +21 -5
  22. package/dist/auth/initializeProviders.js.map +1 -1
  23. package/dist/auth/magicLink/MagicLinkRouter.d.ts +9 -0
  24. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  25. package/dist/auth/magicLink/MagicLinkRouter.js +22 -10
  26. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  27. package/dist/auth/magicLink/MagicLinkService.d.ts +17 -15
  28. package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
  29. package/dist/auth/magicLink/MagicLinkService.js +65 -51
  30. package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
  31. package/dist/auth/magicLink/index.d.ts +2 -2
  32. package/dist/auth/magicLink/index.d.ts.map +1 -1
  33. package/dist/auth/magicLink/index.js +2 -2
  34. package/dist/auth/magicLink/index.js.map +1 -1
  35. package/dist/auth/magicLink/magicLinkCore.d.ts +54 -33
  36. package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -1
  37. package/dist/auth/magicLink/magicLinkCore.js +61 -61
  38. package/dist/auth/magicLink/magicLinkCore.js.map +1 -1
  39. package/dist/auth/magicLink/redeemLanding.d.ts +4 -0
  40. package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
  41. package/dist/auth/magicLink/redeemLanding.js +12 -4
  42. package/dist/auth/magicLink/redeemLanding.js.map +1 -1
  43. package/dist/auth/magicLink/types.d.ts +4 -4
  44. package/dist/auth/principals.d.ts +2 -0
  45. package/dist/auth/principals.d.ts.map +1 -1
  46. package/dist/auth/principals.js +6 -2
  47. package/dist/auth/principals.js.map +1 -1
  48. package/dist/cache.d.ts +2 -0
  49. package/dist/cache.d.ts.map +1 -1
  50. package/dist/cache.js +3 -1
  51. package/dist/cache.js.map +1 -1
  52. package/dist/config.d.ts +346 -2
  53. package/dist/config.d.ts.map +1 -1
  54. package/dist/config.js +34 -4
  55. package/dist/config.js.map +1 -1
  56. package/dist/context.d.ts +20 -0
  57. package/dist/context.d.ts.map +1 -1
  58. package/dist/context.js +27 -19
  59. package/dist/context.js.map +1 -1
  60. package/dist/directives/Public.d.ts +2 -0
  61. package/dist/directives/Public.d.ts.map +1 -1
  62. package/dist/directives/Public.js +3 -1
  63. package/dist/directives/Public.js.map +1 -1
  64. package/dist/directives/RequireSystemUser.d.ts +2 -0
  65. package/dist/directives/RequireSystemUser.d.ts.map +1 -1
  66. package/dist/directives/RequireSystemUser.js +3 -1
  67. package/dist/directives/RequireSystemUser.js.map +1 -1
  68. package/dist/generated/graphql-schemas/__mj.d.ts +11 -0
  69. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  70. package/dist/generated/graphql-schemas/__mj.js +48 -0
  71. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  72. package/dist/generic/CacheInvalidationResolver.d.ts +94 -4
  73. package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
  74. package/dist/generic/CacheInvalidationResolver.js +122 -3
  75. package/dist/generic/CacheInvalidationResolver.js.map +1 -1
  76. package/dist/generic/DeleteOptionsInput.d.ts +8 -1
  77. package/dist/generic/DeleteOptionsInput.d.ts.map +1 -1
  78. package/dist/generic/DeleteOptionsInput.js +1 -1
  79. package/dist/generic/DeleteOptionsInput.js.map +1 -1
  80. package/dist/generic/FireAndForgetHeartbeat.d.ts +3 -1
  81. package/dist/generic/FireAndForgetHeartbeat.d.ts.map +1 -1
  82. package/dist/generic/FireAndForgetHeartbeat.js +8 -4
  83. package/dist/generic/FireAndForgetHeartbeat.js.map +1 -1
  84. package/dist/generic/PushStatusResolver.d.ts +10 -1
  85. package/dist/generic/PushStatusResolver.d.ts.map +1 -1
  86. package/dist/generic/PushStatusResolver.js +11 -3
  87. package/dist/generic/PushStatusResolver.js.map +1 -1
  88. package/dist/generic/ResolverBase.d.ts +5 -1
  89. package/dist/generic/ResolverBase.d.ts.map +1 -1
  90. package/dist/generic/ResolverBase.js +15 -8
  91. package/dist/generic/ResolverBase.js.map +1 -1
  92. package/dist/index.d.ts +6 -0
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +30 -9
  95. package/dist/index.js.map +1 -1
  96. package/dist/integration/CustomColumnPromoter.d.ts +2 -0
  97. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  98. package/dist/integration/CustomColumnPromoter.js +5 -1
  99. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  100. package/dist/integration/EntityMapLifecycle.d.ts +4 -0
  101. package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
  102. package/dist/integration/EntityMapLifecycle.js +10 -2
  103. package/dist/integration/EntityMapLifecycle.js.map +1 -1
  104. package/dist/logging/NoLog.d.ts +4 -0
  105. package/dist/logging/NoLog.d.ts.map +1 -1
  106. package/dist/logging/NoLog.js +10 -2
  107. package/dist/logging/NoLog.js.map +1 -1
  108. package/dist/logging/StartupLogger.d.ts +2 -0
  109. package/dist/logging/StartupLogger.d.ts.map +1 -1
  110. package/dist/logging/StartupLogger.js +5 -1
  111. package/dist/logging/StartupLogger.js.map +1 -1
  112. package/dist/logging/bootAudit.d.ts +11 -7
  113. package/dist/logging/bootAudit.d.ts.map +1 -1
  114. package/dist/logging/bootAudit.js +15 -7
  115. package/dist/logging/bootAudit.js.map +1 -1
  116. package/dist/logging/boundaryLogPayload.d.ts +4 -0
  117. package/dist/logging/boundaryLogPayload.d.ts.map +1 -1
  118. package/dist/logging/boundaryLogPayload.js +5 -1
  119. package/dist/logging/boundaryLogPayload.js.map +1 -1
  120. package/dist/logging/secretRedactor.d.ts +2 -0
  121. package/dist/logging/secretRedactor.d.ts.map +1 -1
  122. package/dist/logging/secretRedactor.js +8 -4
  123. package/dist/logging/secretRedactor.js.map +1 -1
  124. package/dist/logging/shortenForLog.d.ts +2 -0
  125. package/dist/logging/shortenForLog.d.ts.map +1 -1
  126. package/dist/logging/shortenForLog.js +7 -3
  127. package/dist/logging/shortenForLog.js.map +1 -1
  128. package/dist/logging/variablesLoggingMiddleware.d.ts +2 -0
  129. package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
  130. package/dist/logging/variablesLoggingMiddleware.js +8 -6
  131. package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
  132. package/dist/metadataRefreshSignal.d.ts +19 -0
  133. package/dist/metadataRefreshSignal.d.ts.map +1 -0
  134. package/dist/metadataRefreshSignal.js +45 -0
  135. package/dist/metadataRefreshSignal.js.map +1 -0
  136. package/dist/middleware/MJTenantFilterMiddleware.js +4 -4
  137. package/dist/multiTenancy/index.d.ts +8 -0
  138. package/dist/multiTenancy/index.d.ts.map +1 -1
  139. package/dist/multiTenancy/index.js +21 -5
  140. package/dist/multiTenancy/index.js.map +1 -1
  141. package/dist/realtimeWidget/WidgetRouter.d.ts +5 -0
  142. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
  143. package/dist/realtimeWidget/WidgetRouter.js +14 -10
  144. package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
  145. package/dist/realtimeWidget/WidgetSessionService.d.ts +6 -6
  146. package/dist/realtimeWidget/WidgetSessionService.js +27 -27
  147. package/dist/realtimeWidget/host-identity.d.ts +5 -1
  148. package/dist/realtimeWidget/host-identity.d.ts.map +1 -1
  149. package/dist/realtimeWidget/host-identity.js +11 -3
  150. package/dist/realtimeWidget/host-identity.js.map +1 -1
  151. package/dist/realtimeWidget/index.d.ts +2 -2
  152. package/dist/realtimeWidget/index.d.ts.map +1 -1
  153. package/dist/realtimeWidget/index.js +2 -2
  154. package/dist/realtimeWidget/index.js.map +1 -1
  155. package/dist/realtimeWidget/visitorIdentity.d.ts +21 -1
  156. package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
  157. package/dist/realtimeWidget/visitorIdentity.js +16 -4
  158. package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
  159. package/dist/realtimeWidget/widgetCore.d.ts +48 -0
  160. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
  161. package/dist/realtimeWidget/widgetCore.js +38 -10
  162. package/dist/realtimeWidget/widgetCore.js.map +1 -1
  163. package/dist/realtimeWidget/widgetGuestElevation.d.ts +10 -6
  164. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
  165. package/dist/realtimeWidget/widgetGuestElevation.js +14 -6
  166. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  167. package/dist/resolvers/AdhocQueryResolver.js +3 -3
  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/RealtimeBridgeResolver.js +3 -3
  185. package/dist/resolvers/RealtimeClientSessionResolver.js +3 -3
  186. package/dist/resolvers/RemoteBrowserActionResolver.js +5 -5
  187. package/dist/resolvers/RunAIAgentResolver.d.ts +10 -4
  188. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  189. package/dist/resolvers/RunAIAgentResolver.js +69 -38
  190. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  191. package/dist/resolvers/RunAIPromptResolver.d.ts +1 -1
  192. package/dist/resolvers/RunAIPromptResolver.js +2 -2
  193. package/dist/resolvers/RunTestResolver.js +5 -5
  194. package/dist/resolvers/SqlLoggingConfigResolver.d.ts +8 -4
  195. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  196. package/dist/resolvers/SqlLoggingConfigResolver.js +5 -5
  197. package/dist/resolvers/TaskGraphFrameResolver.d.ts +8 -1
  198. package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
  199. package/dist/resolvers/TaskGraphFrameResolver.js +6 -2
  200. package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
  201. package/dist/resolvers/adhoc-query-helpers.d.ts +6 -0
  202. package/dist/resolvers/adhoc-query-helpers.d.ts.map +1 -1
  203. package/dist/resolvers/adhoc-query-helpers.js +10 -2
  204. package/dist/resolvers/adhoc-query-helpers.js.map +1 -1
  205. package/dist/resolvers/artifact-routing.d.ts +8 -8
  206. package/dist/resolvers/artifact-routing.js +2 -2
  207. package/dist/resolvers/artifact-routing.js.map +1 -1
  208. package/dist/resolvers/meetingRecordingRegistration.d.ts +10 -2
  209. package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
  210. package/dist/resolvers/meetingRecordingRegistration.js +24 -8
  211. package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
  212. package/dist/resolvers/peaksSidecar.d.ts +4 -0
  213. package/dist/resolvers/peaksSidecar.d.ts.map +1 -1
  214. package/dist/resolvers/peaksSidecar.js +10 -2
  215. package/dist/resolvers/peaksSidecar.js.map +1 -1
  216. package/dist/rest/EntityCRUDHandler.d.ts +28 -0
  217. package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
  218. package/dist/rest/EntityCRUDHandler.js +20 -4
  219. package/dist/rest/EntityCRUDHandler.js.map +1 -1
  220. package/dist/rest/MediaStreamHandler.d.ts +2 -0
  221. package/dist/rest/MediaStreamHandler.d.ts.map +1 -1
  222. package/dist/rest/MediaStreamHandler.js +10 -6
  223. package/dist/rest/MediaStreamHandler.js.map +1 -1
  224. package/dist/rest/OAuthCallbackHandler.d.ts +9 -0
  225. package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
  226. package/dist/rest/OAuthCallbackHandler.js +15 -3
  227. package/dist/rest/OAuthCallbackHandler.js.map +1 -1
  228. package/dist/rest/RESTEndpointHandler.d.ts +6 -4
  229. package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
  230. package/dist/rest/RESTEndpointHandler.js +15 -11
  231. package/dist/rest/RESTEndpointHandler.js.map +1 -1
  232. package/dist/rest/RealtimeSdpBrokerHandler.d.ts +5 -1
  233. package/dist/rest/RealtimeSdpBrokerHandler.d.ts.map +1 -1
  234. package/dist/rest/RealtimeSdpBrokerHandler.js +12 -4
  235. package/dist/rest/RealtimeSdpBrokerHandler.js.map +1 -1
  236. package/dist/rest/SignatureWebhookHandler.d.ts +2 -0
  237. package/dist/rest/SignatureWebhookHandler.d.ts.map +1 -1
  238. package/dist/rest/SignatureWebhookHandler.js +5 -1
  239. package/dist/rest/SignatureWebhookHandler.js.map +1 -1
  240. package/dist/rest/UploadTokenManager.d.ts +24 -8
  241. package/dist/rest/UploadTokenManager.d.ts.map +1 -1
  242. package/dist/rest/UploadTokenManager.js +53 -21
  243. package/dist/rest/UploadTokenManager.js.map +1 -1
  244. package/dist/rest/ViewOperationsHandler.d.ts +20 -0
  245. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  246. package/dist/rest/ViewOperationsHandler.js +20 -4
  247. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  248. package/dist/rest/mediaRange.d.ts +4 -0
  249. package/dist/rest/mediaRange.d.ts.map +1 -1
  250. package/dist/rest/mediaRange.js +10 -2
  251. package/dist/rest/mediaRange.js.map +1 -1
  252. package/dist/rest/setupRESTEndpoints.d.ts +4 -0
  253. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
  254. package/dist/rest/setupRESTEndpoints.js +13 -7
  255. package/dist/rest/setupRESTEndpoints.js.map +1 -1
  256. package/dist/serverExtensionReservedRoots.d.ts +2 -0
  257. package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
  258. package/dist/serverExtensionReservedRoots.js +5 -1
  259. package/dist/serverExtensionReservedRoots.js.map +1 -1
  260. package/dist/services/TaskGraphActionRunner.d.ts +13 -8
  261. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  262. package/dist/services/TaskGraphActionRunner.js +16 -15
  263. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  264. package/dist/types.d.ts +2 -0
  265. package/dist/types.d.ts.map +1 -1
  266. package/dist/types.js +7 -3
  267. package/dist/types.js.map +1 -1
  268. package/dist/util.d.ts +6 -0
  269. package/dist/util.d.ts.map +1 -1
  270. package/dist/util.js +13 -5
  271. package/dist/util.js.map +1 -1
  272. package/package.json +92 -92
  273. package/src/__tests__/DeleteOptionsInput.wireShape.test.ts +62 -0
  274. package/src/__tests__/FileResolverPeaks.test.ts +13 -13
  275. package/src/__tests__/ListOperationsResolver.test.ts +17 -17
  276. package/src/__tests__/MediaStreamHandler.test.ts +28 -28
  277. package/src/__tests__/NoLog.test.ts +11 -11
  278. package/src/__tests__/PrimaryKeyAlwaysMapped.test.ts +10 -10
  279. package/src/__tests__/RESTEndpointHandler.test.ts +14 -14
  280. package/src/__tests__/RealtimeBridgeResolver.test.ts +4 -2
  281. package/src/__tests__/RealtimeSdpBrokerHandler.test.ts +6 -6
  282. package/src/__tests__/RefreshAdoptsNewColumns.test.ts +8 -8
  283. package/src/__tests__/RemoteBrowserGoalEngine.test.ts +18 -18
  284. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +228 -0
  285. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +129 -0
  286. package/src/__tests__/TaskGraphFrameResolver.test.ts +2 -2
  287. package/src/__tests__/WidgetSessionService.test.ts +8 -4
  288. package/src/__tests__/adhoc-query-helpers.test.ts +21 -21
  289. package/src/__tests__/bootAudit.test.ts +11 -11
  290. package/src/__tests__/boundaryLogPayload.test.ts +6 -6
  291. package/src/__tests__/cacheInvalidationRecordData.test.ts +177 -0
  292. package/src/__tests__/databaseAbstraction.test.ts +12 -6
  293. package/src/__tests__/getDataTokenRedaction.test.ts +7 -7
  294. package/src/__tests__/initializeProviders.refresh.test.ts +4 -4
  295. package/src/__tests__/magicLink.test.ts +73 -134
  296. package/src/__tests__/magicLinkService.consume.test.ts +224 -0
  297. package/src/__tests__/meetingRecordingRegistration.test.ts +12 -12
  298. package/src/__tests__/metadataRefreshSignal.test.ts +78 -0
  299. package/src/__tests__/multiTenancy.security.test.ts +40 -40
  300. package/src/__tests__/multiTenancy.test.ts +18 -18
  301. package/src/__tests__/newUsers.test.ts +24 -23
  302. package/src/__tests__/principals.test.ts +22 -22
  303. package/src/__tests__/pushStatusResolver.filter.test.ts +8 -8
  304. package/src/__tests__/secretRedactor.failOpen.test.ts +12 -12
  305. package/src/__tests__/secretRedactor.test.ts +12 -12
  306. package/src/__tests__/serverExtensionReservedRoots.test.ts +7 -7
  307. package/src/__tests__/subscriptionRedaction.test.ts +5 -5
  308. package/src/__tests__/unifiedAuth.test.ts +15 -9
  309. package/src/__tests__/visitorIdentity.resolve.test.ts +6 -6
  310. package/src/__tests__/widget.test.ts +45 -45
  311. package/src/__tests__/widgetGuestElevation.test.ts +7 -7
  312. package/src/__tests__/widgetHostIdentity.test.ts +14 -14
  313. package/src/agentSessions/ReturningVisitorRecap.ts +12 -1
  314. package/src/agentSessions/SessionManager.ts +2 -2
  315. package/src/agentSessions/remoteBrowserGoalEngine.ts +30 -5
  316. package/src/auth/AuthProviderCatalogRouter.ts +6 -1
  317. package/src/auth/__tests__/backward-compatibility.test.ts +3 -3
  318. package/src/auth/index.ts +43 -28
  319. package/src/auth/initializeProviders.ts +25 -5
  320. package/src/auth/magicLink/MagicLinkRouter.ts +28 -10
  321. package/src/auth/magicLink/MagicLinkService.ts +71 -52
  322. package/src/auth/magicLink/index.ts +7 -7
  323. package/src/auth/magicLink/magicLinkCore.ts +96 -64
  324. package/src/auth/magicLink/redeemLanding.ts +14 -4
  325. package/src/auth/magicLink/types.ts +54 -54
  326. package/src/auth/newUsers.ts +1 -1
  327. package/src/auth/principals.ts +11 -2
  328. package/src/cache.ts +4 -1
  329. package/src/config.ts +37 -4
  330. package/src/context.ts +37 -24
  331. package/src/directives/Public.ts +4 -1
  332. package/src/directives/RequireSystemUser.ts +4 -1
  333. package/src/generated/graphql-schemas/__mj.ts +37 -0
  334. package/src/generic/CacheInvalidationResolver.ts +148 -4
  335. package/src/generic/DeleteOptionsInput.ts +9 -2
  336. package/src/generic/FireAndForgetHeartbeat.ts +19 -14
  337. package/src/generic/PushStatusResolver.ts +21 -7
  338. package/src/generic/ResolverBase.ts +16 -8
  339. package/src/generic/RunViewResolver.ts +22 -22
  340. package/src/generic/__tests__/FireAndForgetHeartbeat.test.ts +7 -7
  341. package/src/index.ts +35 -9
  342. package/src/integration/CustomColumnPromoter.ts +6 -1
  343. package/src/integration/EntityMapLifecycle.ts +20 -2
  344. package/src/logging/NoLog.ts +16 -2
  345. package/src/logging/StartupLogger.ts +6 -1
  346. package/src/logging/bootAudit.ts +26 -16
  347. package/src/logging/boundaryLogPayload.ts +8 -1
  348. package/src/logging/secretRedactor.ts +14 -9
  349. package/src/logging/shortenForLog.ts +8 -3
  350. package/src/logging/variablesLoggingMiddleware.ts +9 -6
  351. package/src/metadataRefreshSignal.ts +45 -0
  352. package/src/middleware/MJTenantFilterMiddleware.ts +4 -4
  353. package/src/multiTenancy/index.ts +29 -5
  354. package/src/realtimeWidget/WidgetRouter.ts +15 -10
  355. package/src/realtimeWidget/WidgetSessionService.ts +76 -76
  356. package/src/realtimeWidget/host-identity.ts +24 -10
  357. package/src/realtimeWidget/index.ts +3 -3
  358. package/src/realtimeWidget/visitorIdentity.ts +39 -8
  359. package/src/realtimeWidget/widgetCore.ts +75 -10
  360. package/src/realtimeWidget/widgetGuestElevation.ts +25 -12
  361. package/src/resolvers/AdhocQueryResolver.ts +3 -3
  362. package/src/resolvers/AgentSessionResolver.ts +3 -3
  363. package/src/resolvers/ColorResolver.ts +6 -6
  364. package/src/resolvers/ComponentRegistryResolver.ts +36 -36
  365. package/src/resolvers/EntityCommunicationsResolver.ts +4 -4
  366. package/src/resolvers/ExecuteRemoteOperationResolver.ts +9 -9
  367. package/src/resolvers/FileResolver.ts +42 -42
  368. package/src/resolvers/GeoResolver.ts +4 -4
  369. package/src/resolvers/GetDataResolver.ts +50 -15
  370. package/src/resolvers/IntegrationDiscoveryResolver.ts +2 -2
  371. package/src/resolvers/ListOperationsResolver.ts +78 -28
  372. package/src/resolvers/MCPResolver.ts +30 -15
  373. package/src/resolvers/QueryResolver.ts +13 -13
  374. package/src/resolvers/RealtimeBridgeResolver.ts +3 -3
  375. package/src/resolvers/RealtimeClientSessionResolver.ts +3 -3
  376. package/src/resolvers/RemoteBrowserActionResolver.ts +5 -5
  377. package/src/resolvers/RunAIAgentResolver.ts +113 -72
  378. package/src/resolvers/RunAIPromptResolver.ts +22 -22
  379. package/src/resolvers/RunTemplateResolver.ts +4 -4
  380. package/src/resolvers/RunTestResolver.ts +25 -25
  381. package/src/resolvers/SqlLoggingConfigResolver.ts +56 -56
  382. package/src/resolvers/TaskGraphFrameResolver.ts +37 -28
  383. package/src/resolvers/TelemetryResolver.ts +79 -79
  384. package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +40 -38
  385. package/src/resolvers/__tests__/artifact-routing.test.ts +23 -23
  386. package/src/resolvers/adhoc-query-helpers.ts +19 -2
  387. package/src/resolvers/artifact-routing.ts +19 -19
  388. package/src/resolvers/meetingRecordingRegistration.ts +44 -10
  389. package/src/resolvers/peaksSidecar.ts +12 -2
  390. package/src/rest/EntityCRUDHandler.ts +24 -4
  391. package/src/rest/MediaStreamHandler.ts +11 -6
  392. package/src/rest/OAuthCallbackHandler.ts +25 -7
  393. package/src/rest/RESTEndpointHandler.ts +20 -15
  394. package/src/rest/RealtimeSdpBrokerHandler.ts +14 -4
  395. package/src/rest/SignatureWebhookHandler.ts +6 -1
  396. package/src/rest/UploadTokenManager.ts +66 -30
  397. package/src/rest/ViewOperationsHandler.ts +24 -4
  398. package/src/rest/mediaRange.ts +16 -6
  399. package/src/rest/setupRESTEndpoints.ts +24 -12
  400. package/src/serverExtensionReservedRoots.ts +6 -1
  401. package/src/services/TaskGraphActionRunner.ts +16 -15
  402. package/src/types.ts +21 -16
  403. package/src/util.ts +16 -6
@@ -43,8 +43,8 @@ vi.mock('@memberjunction/core-entities', async (importOriginal) => {
43
43
  });
44
44
 
45
45
  import {
46
- registerMeetingRecordingFile,
47
- resolveMeetingConversation,
46
+ RegisterMeetingRecordingFile,
47
+ ResolveMeetingConversation,
48
48
  type MeetingRecordingEgressResult,
49
49
  } from '../resolvers/meetingRecordingRegistration';
50
50
 
@@ -124,7 +124,7 @@ describe('registerMeetingRecordingFile', () => {
124
124
  .mockResolvedValueOnce({ Success: true, Results: [{ ID: 'conv-existing' }] });
125
125
 
126
126
  const { provider, created } = makeProvider();
127
- const result = await registerMeetingRecordingFile(egress, user, provider);
127
+ const result = await RegisterMeetingRecordingFile(egress, user, provider);
128
128
 
129
129
  expect(result.Success).toBe(true);
130
130
  expect(result.RecordingFileID).toBe('file-123');
@@ -153,7 +153,7 @@ describe('registerMeetingRecordingFile', () => {
153
153
  it('prefers matching the conversation by EgressID when present', async () => {
154
154
  runViewMock.mockResolvedValueOnce({ Success: true, Results: [{ ID: 'conv-by-egress' }] });
155
155
  const { provider } = makeProvider();
156
- const result = await registerMeetingRecordingFile(egress, user, provider);
156
+ const result = await RegisterMeetingRecordingFile(egress, user, provider);
157
157
  expect(result.ConversationID).toBe('conv-by-egress');
158
158
  // Only the EgressID lookup ran (no fall-through to room-name lookup).
159
159
  expect(runViewMock).toHaveBeenCalledTimes(1);
@@ -162,7 +162,7 @@ describe('registerMeetingRecordingFile', () => {
162
162
  it('creates a Meeting-Room Conversation when none exists', async () => {
163
163
  runViewMock.mockResolvedValue({ Success: true, Results: [] }); // neither lookup matches
164
164
  const { provider, created } = makeProvider();
165
- const result = await registerMeetingRecordingFile(egress, user, provider);
165
+ const result = await RegisterMeetingRecordingFile(egress, user, provider);
166
166
  expect(result.Success).toBe(true);
167
167
  const conv = created.conversation[0];
168
168
  expect(conv.fields.Type).toBe('Meeting Room');
@@ -173,7 +173,7 @@ describe('registerMeetingRecordingFile', () => {
173
173
  it('returns a graceful failure when the storage provider is not configured', async () => {
174
174
  delete process.env.MJ_MEETING_RECORDING_STORAGE_PROVIDER;
175
175
  const { provider } = makeProvider();
176
- const result = await registerMeetingRecordingFile(egress, user, provider);
176
+ const result = await RegisterMeetingRecordingFile(egress, user, provider);
177
177
  expect(result.Success).toBe(false);
178
178
  expect(result.ErrorMessage).toMatch(/MJ_MEETING_RECORDING_STORAGE_PROVIDER/);
179
179
  expect(result.RecordingFileID).toBeUndefined();
@@ -182,14 +182,14 @@ describe('registerMeetingRecordingFile', () => {
182
182
  it('returns a graceful failure when no account is linked to the configured provider', async () => {
183
183
  storage.accountsByProvider = new Map(); // no accounts for prov-sink
184
184
  const { provider } = makeProvider();
185
- const result = await registerMeetingRecordingFile(egress, user, provider);
185
+ const result = await RegisterMeetingRecordingFile(egress, user, provider);
186
186
  expect(result.Success).toBe(false);
187
187
  expect(result.ErrorMessage).toMatch(/No active MJStorage account/i);
188
188
  });
189
189
 
190
190
  it('returns a graceful failure when the egress has no output yet', async () => {
191
191
  const { provider } = makeProvider();
192
- const result = await registerMeetingRecordingFile({ ...egress, OutputLocation: undefined }, user, provider);
192
+ const result = await RegisterMeetingRecordingFile({ ...egress, OutputLocation: undefined }, user, provider);
193
193
  expect(result.Success).toBe(false);
194
194
  expect(result.ErrorMessage).toMatch(/no output/i);
195
195
  });
@@ -204,7 +204,7 @@ describe('registerMeetingRecordingFile', () => {
204
204
  runViewMock.mockResolvedValueOnce({ Success: true, Results: [{ ID: 'conv-1' }] });
205
205
 
206
206
  const { provider, created } = makeProvider();
207
- const result = await registerMeetingRecordingFile(egress, user, provider);
207
+ const result = await RegisterMeetingRecordingFile(egress, user, provider);
208
208
 
209
209
  expect(result.Success).toBe(true);
210
210
  // Bytes were read from the sink and uploaded into the canonical provider.
@@ -221,7 +221,7 @@ describe('registerMeetingRecordingFile', () => {
221
221
  process.env.MJ_MEETING_RECORDING_CANONICAL_STORAGE_PROVIDER = 'prov-sink'; // same as sink
222
222
  runViewMock.mockResolvedValueOnce({ Success: true, Results: [{ ID: 'conv-1' }] });
223
223
  const { provider, created } = makeProvider();
224
- const result = await registerMeetingRecordingFile(egress, user, provider);
224
+ const result = await RegisterMeetingRecordingFile(egress, user, provider);
225
225
  expect(result.Success).toBe(true);
226
226
  expect(storage.getObject).not.toHaveBeenCalled();
227
227
  expect(created.file[0].fields.ProviderID).toBe('prov-sink');
@@ -231,7 +231,7 @@ describe('registerMeetingRecordingFile', () => {
231
231
  it('fails gracefully (no throw) when the Files row save fails', async () => {
232
232
  runViewMock.mockResolvedValueOnce({ Success: true, Results: [{ ID: 'conv-1' }] });
233
233
  const { provider } = makeProvider({ fileSaveOk: false });
234
- const result = await registerMeetingRecordingFile(egress, user, provider);
234
+ const result = await RegisterMeetingRecordingFile(egress, user, provider);
235
235
  expect(result.Success).toBe(false);
236
236
  expect(result.ErrorMessage).toMatch(/Files row/i);
237
237
  });
@@ -241,7 +241,7 @@ describe('resolveMeetingConversation', () => {
241
241
  it('falls back to creating a conversation when neither lookup matches', async () => {
242
242
  runViewMock.mockResolvedValue({ Success: true, Results: [] });
243
243
  const { provider, created } = makeProvider();
244
- const id = await resolveMeetingConversation(egress, user, provider);
244
+ const id = await ResolveMeetingConversation(egress, user, provider);
245
245
  expect(id).toBe('conv-new');
246
246
  expect(created.conversation).toHaveLength(1);
247
247
  });
@@ -0,0 +1,78 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+
3
+ /**
4
+ * Tests for the SIGHUP operator control that hard-reloads metadata in a running MJAPI.
5
+ * What matters: a signal triggers exactly one refresh, a burst of signals does not stack
6
+ * reloads, and a failing refresh never rejects out of a process signal listener.
7
+ */
8
+
9
+ const { logStatusMock, logErrorMock } = vi.hoisted(() => ({
10
+ logStatusMock: vi.fn(),
11
+ logErrorMock: vi.fn()
12
+ }));
13
+
14
+ vi.mock('@memberjunction/core', () => ({
15
+ LogStatus: logStatusMock,
16
+ LogError: logErrorMock
17
+ }));
18
+
19
+ import { CreateMetadataRefreshSignalHandler, METADATA_REFRESH_SIGNAL } from '../metadataRefreshSignal.js';
20
+
21
+ describe('CreateMetadataRefreshSignalHandler', () => {
22
+ beforeEach(() => {
23
+ logStatusMock.mockReset();
24
+ logErrorMock.mockReset();
25
+ });
26
+
27
+ it('uses SIGHUP, not SIGUSR1 (reserved by the Node inspector)', () => {
28
+ expect(METADATA_REFRESH_SIGNAL).toBe('SIGHUP');
29
+ });
30
+
31
+ it('runs the refresh once per signal', async () => {
32
+ const refresh = vi.fn(async () => true);
33
+ const handler = CreateMetadataRefreshSignalHandler(refresh);
34
+
35
+ await handler();
36
+ await handler();
37
+
38
+ expect(refresh).toHaveBeenCalledTimes(2);
39
+ expect(logErrorMock).not.toHaveBeenCalled();
40
+ });
41
+
42
+ it('ignores a signal that arrives while a refresh is still running', async () => {
43
+ let finish: (ok: boolean) => void = () => {};
44
+ const refresh = vi.fn(async () => true)
45
+ .mockImplementationOnce(() => new Promise<boolean>((resolve) => { finish = resolve; }));
46
+ const handler = CreateMetadataRefreshSignalHandler(refresh);
47
+
48
+ const first = handler();
49
+ await handler(); // arrives mid-refresh
50
+ finish(true);
51
+ await first;
52
+
53
+ expect(refresh).toHaveBeenCalledTimes(1);
54
+ expect(logStatusMock).toHaveBeenCalledWith(expect.stringContaining('already running'));
55
+
56
+ await handler(); // in-flight flag cleared after completion
57
+ expect(refresh).toHaveBeenCalledTimes(2);
58
+ });
59
+
60
+ it('logs, does not reject, and re-arms when the refresh throws', async () => {
61
+ const refresh = vi.fn(async (): Promise<boolean> => { throw new Error('db down'); });
62
+ const handler = CreateMetadataRefreshSignalHandler(refresh);
63
+
64
+ await expect(handler()).resolves.toBeUndefined();
65
+ expect(logErrorMock).toHaveBeenCalledTimes(1);
66
+
67
+ await handler();
68
+ expect(refresh).toHaveBeenCalledTimes(2);
69
+ });
70
+
71
+ it('logs an error when the refresh reports failure', async () => {
72
+ const handler = CreateMetadataRefreshSignalHandler(async () => false);
73
+
74
+ await handler();
75
+
76
+ expect(logErrorMock).toHaveBeenCalledWith(expect.stringContaining('reported failure'));
77
+ });
78
+ });
@@ -7,11 +7,11 @@
7
7
  */
8
8
  import { describe, it, expect, vi } from 'vitest';
9
9
  import {
10
- createTenantPreRunViewHook,
11
- createTenantPreSaveHook,
12
- createTenantMiddleware,
10
+ CreateTenantPreRunViewHook,
11
+ CreateTenantPreSaveHook,
12
+ CreateTenantMiddleware,
13
13
  IsValidTenantId,
14
- attachTenantContext,
14
+ AttachTenantContext,
15
15
  } from '../multiTenancy/index.js';
16
16
  import type { MultiTenancyConfig } from '../config.js';
17
17
  import { Metadata } from '@memberjunction/core';
@@ -76,7 +76,7 @@ function makeConfig(overrides: Partial<MultiTenancyConfig> = {}): MultiTenancyCo
76
76
  };
77
77
  }
78
78
 
79
- type MockUser = Parameters<ReturnType<typeof createTenantPreRunViewHook>>[1];
79
+ type MockUser = Parameters<ReturnType<typeof CreateTenantPreRunViewHook>>[1];
80
80
 
81
81
  function makeUser(tenantId?: string, roles: string[] = []): MockUser {
82
82
  return {
@@ -91,7 +91,7 @@ function makeUser(tenantId?: string, roles: string[] = []): MockUser {
91
91
  describe('Multi-Tenancy Security Edge Cases', () => {
92
92
  describe('SQL injection in tenant ID', () => {
93
93
  it('should escape quotes so an injection attempt stays INSIDE the string literal', () => {
94
- const hook = createTenantPreRunViewHook(makeConfig());
94
+ const hook = CreateTenantPreRunViewHook(makeConfig());
95
95
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
96
96
  const user = makeUser("' OR 1=1 --");
97
97
 
@@ -105,7 +105,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
105
105
  });
106
106
 
107
107
  it('should escape quotes in a UNION attack payload', () => {
108
- const hook = createTenantPreRunViewHook(makeConfig());
108
+ const hook = CreateTenantPreRunViewHook(makeConfig());
109
109
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
110
110
  const user = makeUser("' UNION SELECT * FROM Users --");
111
111
 
@@ -115,7 +115,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
115
115
  });
116
116
 
117
117
  it('should escape quotes in a stacked-statement payload', () => {
118
- const hook = createTenantPreRunViewHook(makeConfig());
118
+ const hook = CreateTenantPreRunViewHook(makeConfig());
119
119
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
120
120
  const user = makeUser("abc'; DROP TABLE Customers; --");
121
121
 
@@ -177,19 +177,19 @@ describe('Multi-Tenancy Security Edge Cases', () => {
177
177
 
178
178
  it('throws on an invalid tenant id instead of attaching it', () => {
179
179
  const user = makePlainUser();
180
- expect(() => attachTenantContext(user, "x' OR '1'='1", 'header')).toThrow(/Invalid tenant identifier/);
180
+ expect(() => AttachTenantContext(user, "x' OR '1'='1", 'header')).toThrow(/Invalid tenant identifier/);
181
181
  expect(user.TenantContext).toBeUndefined();
182
182
  });
183
183
 
184
184
  it('throws on empty and oversized tenant ids', () => {
185
185
  const user = makePlainUser();
186
- expect(() => attachTenantContext(user, '', 'custom')).toThrow(/Invalid tenant identifier/);
187
- expect(() => attachTenantContext(user, 'a'.repeat(129), 'custom')).toThrow(/Invalid tenant identifier/);
186
+ expect(() => AttachTenantContext(user, '', 'custom')).toThrow(/Invalid tenant identifier/);
187
+ expect(() => AttachTenantContext(user, 'a'.repeat(129), 'custom')).toThrow(/Invalid tenant identifier/);
188
188
  });
189
189
 
190
190
  it('attaches a valid tenant id with the given source', () => {
191
191
  const user = makePlainUser();
192
- attachTenantContext(user, 'tenant_1.a-b', 'linkedEntity');
192
+ AttachTenantContext(user, 'tenant_1.a-b', 'linkedEntity');
193
193
  expect(user.TenantContext).toEqual<TenantContext>({ TenantID: 'tenant_1.a-b', Source: 'linkedEntity' });
194
194
  });
195
195
  });
@@ -198,7 +198,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
198
198
 
199
199
  describe('tenant column must resolve to a stored field', () => {
200
200
  it('produces an escaped-value predicate with a quoted identifier for a valid setup', () => {
201
- const hook = createTenantPreRunViewHook(makeConfig());
201
+ const hook = CreateTenantPreRunViewHook(makeConfig());
202
202
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
203
203
  const user = makeUser("t'1"); // legal only via non-header sources; must still be escaped
204
204
 
@@ -207,7 +207,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
207
207
  });
208
208
 
209
209
  it('throws when the configured tenant column does not exist on the entity', () => {
210
- const hook = createTenantPreRunViewHook(makeConfig({ defaultTenantColumn: 'NoSuchColumn' }));
210
+ const hook = CreateTenantPreRunViewHook(makeConfig({ defaultTenantColumn: 'NoSuchColumn' }));
211
211
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
212
212
  const user = makeUser('tenant-1');
213
213
 
@@ -215,7 +215,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
215
215
  });
216
216
 
217
217
  it('throws when the tenant column resolves only to a VIRTUAL field', () => {
218
- const hook = createTenantPreRunViewHook(makeConfig({ defaultTenantColumn: 'OrganizationName' }));
218
+ const hook = CreateTenantPreRunViewHook(makeConfig({ defaultTenantColumn: 'OrganizationName' }));
219
219
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
220
220
  const user = makeUser('tenant-1');
221
221
 
@@ -223,7 +223,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
223
223
  });
224
224
 
225
225
  it('throws when an entityColumnMappings override points at a nonexistent column', () => {
226
- const hook = createTenantPreRunViewHook(makeConfig({
226
+ const hook = CreateTenantPreRunViewHook(makeConfig({
227
227
  entityColumnMappings: { 'Customers': "Bad]Column" },
228
228
  }));
229
229
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
@@ -237,7 +237,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
237
237
  // @ts-expect-error — simulating the no-provider-available case
238
238
  Metadata.Provider = undefined;
239
239
  try {
240
- const hook = createTenantPreRunViewHook(makeConfig());
240
+ const hook = CreateTenantPreRunViewHook(makeConfig());
241
241
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
242
242
  const user = makeUser('tenant-1');
243
243
 
@@ -255,7 +255,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
255
255
 
256
256
  describe('Tenant ID boundary values', () => {
257
257
  it('should not filter when tenant ID is empty string (falsy)', () => {
258
- const hook = createTenantPreRunViewHook(makeConfig());
258
+ const hook = CreateTenantPreRunViewHook(makeConfig());
259
259
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
260
260
  // Empty string is falsy → makeUser sets TenantContext = undefined
261
261
  // This matches createTenantMiddleware behavior: `if (tenantId)` skips empty strings
@@ -267,7 +267,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
267
267
 
268
268
  it('should handle very long tenant ID', () => {
269
269
  const longId = 'a'.repeat(1000);
270
- const hook = createTenantPreRunViewHook(makeConfig());
270
+ const hook = CreateTenantPreRunViewHook(makeConfig());
271
271
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
272
272
  const user = makeUser(longId);
273
273
 
@@ -277,7 +277,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
277
277
 
278
278
  it('should handle UUID tenant ID (standard format)', () => {
279
279
  const uuid = '550e8400-e29b-41d4-a716-446655440000';
280
- const hook = createTenantPreRunViewHook(makeConfig());
280
+ const hook = CreateTenantPreRunViewHook(makeConfig());
281
281
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
282
282
  const user = makeUser(uuid);
283
283
 
@@ -286,7 +286,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
286
286
  });
287
287
 
288
288
  it('should handle tenant ID with special characters', () => {
289
- const hook = createTenantPreRunViewHook(makeConfig());
289
+ const hook = CreateTenantPreRunViewHook(makeConfig());
290
290
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
291
291
  const user = makeUser('tenant<script>alert(1)</script>');
292
292
 
@@ -299,7 +299,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
299
299
 
300
300
  describe('Admin role matching', () => {
301
301
  it('should be case-insensitive for admin role matching', () => {
302
- const hook = createTenantPreRunViewHook(makeConfig({ adminRoles: ['Admin'] }));
302
+ const hook = CreateTenantPreRunViewHook(makeConfig({ adminRoles: ['Admin'] }));
303
303
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
304
304
 
305
305
  // User role is 'admin' (lowercase), config has 'Admin'
@@ -309,7 +309,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
309
309
  });
310
310
 
311
311
  it('should handle whitespace in role names', () => {
312
- const hook = createTenantPreRunViewHook(makeConfig({ adminRoles: [' Admin '] }));
312
+ const hook = CreateTenantPreRunViewHook(makeConfig({ adminRoles: [' Admin '] }));
313
313
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
314
314
 
315
315
  const user = makeUser('tenant-1', ['Admin']);
@@ -318,7 +318,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
318
318
  });
319
319
 
320
320
  it('should not bypass for non-admin roles', () => {
321
- const hook = createTenantPreRunViewHook(makeConfig({ adminRoles: ['Admin'] }));
321
+ const hook = CreateTenantPreRunViewHook(makeConfig({ adminRoles: ['Admin'] }));
322
322
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
323
323
 
324
324
  const user = makeUser('tenant-1', ['User', 'Editor']);
@@ -327,7 +327,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
327
327
  });
328
328
 
329
329
  it('should handle user with empty roles array', () => {
330
- const hook = createTenantPreRunViewHook(makeConfig());
330
+ const hook = CreateTenantPreRunViewHook(makeConfig());
331
331
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
332
332
 
333
333
  const user = makeUser('tenant-1', []);
@@ -340,7 +340,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
340
340
 
341
341
  describe('Entity name matching', () => {
342
342
  it('should be case-insensitive for entity names in allowlist', () => {
343
- const hook = createTenantPreRunViewHook(makeConfig({
343
+ const hook = CreateTenantPreRunViewHook(makeConfig({
344
344
  scopingStrategy: 'allowlist',
345
345
  scopedEntities: ['customers'],
346
346
  }));
@@ -352,7 +352,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
352
352
  });
353
353
 
354
354
  it('should handle whitespace in entity names', () => {
355
- const hook = createTenantPreRunViewHook(makeConfig({
355
+ const hook = CreateTenantPreRunViewHook(makeConfig({
356
356
  scopingStrategy: 'allowlist',
357
357
  scopedEntities: [' Customers '],
358
358
  }));
@@ -364,7 +364,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
364
364
  });
365
365
 
366
366
  it('should not filter when EntityName is missing from params', () => {
367
- const hook = createTenantPreRunViewHook(makeConfig());
367
+ const hook = CreateTenantPreRunViewHook(makeConfig());
368
368
  const params = { ExtraFilter: '' } as RunViewParams;
369
369
  const user = makeUser('tenant-1');
370
370
 
@@ -377,7 +377,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
377
377
 
378
378
  describe('createTenantMiddleware', () => {
379
379
  it('should skip tenant resolution when no userPayload on request', () => {
380
- const middleware = createTenantMiddleware(makeConfig());
380
+ const middleware = CreateTenantMiddleware(makeConfig());
381
381
  const req = { headers: { 'x-tenant-id': 'tenant-1' } } as unknown as Parameters<typeof middleware>[0];
382
382
  const res = {} as Parameters<typeof middleware>[1];
383
383
  const next = vi.fn();
@@ -388,7 +388,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
388
388
  });
389
389
 
390
390
  it('should attach TenantContext to a CLONED userRecord when userPayload and header are present', () => {
391
- const middleware = createTenantMiddleware(makeConfig());
391
+ const middleware = CreateTenantMiddleware(makeConfig());
392
392
  const userRecord = { ID: 'u1' } as Record<string, unknown>;
393
393
  const userPayload = { userRecord, email: 'test@test.com', sessionId: 's1' };
394
394
  const req = {
@@ -414,7 +414,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
414
414
  });
415
415
 
416
416
  it('should reject an invalid tenant header with 400 and never attach or continue', () => {
417
- const middleware = createTenantMiddleware(makeConfig());
417
+ const middleware = CreateTenantMiddleware(makeConfig());
418
418
  const userRecord = { ID: 'u1' } as Record<string, unknown>;
419
419
  const userPayload = { userRecord, email: 'test@test.com', sessionId: 's1' };
420
420
  const req = {
@@ -437,7 +437,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
437
437
  });
438
438
 
439
439
  it('should handle case-insensitive header name', () => {
440
- const middleware = createTenantMiddleware(makeConfig({ tenantHeader: 'X-Tenant-ID' }));
440
+ const middleware = CreateTenantMiddleware(makeConfig({ tenantHeader: 'X-Tenant-ID' }));
441
441
  const userRecord = { ID: 'u1' } as Record<string, unknown>;
442
442
  const userPayload = { userRecord, email: 'test@test.com', sessionId: 's1' };
443
443
  const req = {
@@ -457,7 +457,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
457
457
  });
458
458
 
459
459
  it('should not set TenantContext when header is missing', () => {
460
- const middleware = createTenantMiddleware(makeConfig());
460
+ const middleware = CreateTenantMiddleware(makeConfig());
461
461
  const userRecord = { ID: 'u1' } as Record<string, unknown>;
462
462
  const req = {
463
463
  headers: {},
@@ -472,7 +472,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
472
472
  });
473
473
 
474
474
  it('should reject a repeated header (array value) with 400 rather than guessing which value applies', () => {
475
- const middleware = createTenantMiddleware(makeConfig());
475
+ const middleware = CreateTenantMiddleware(makeConfig());
476
476
  const userRecord = { ID: 'u1' } as Record<string, unknown>;
477
477
  const userPayload = { userRecord, email: 'test@test.com', sessionId: 's1' };
478
478
  const req = {
@@ -494,7 +494,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
494
494
  });
495
495
 
496
496
  it('two concurrent requests for the same shared user with different headers do not cross-contaminate', () => {
497
- const middleware = createTenantMiddleware(makeConfig());
497
+ const middleware = CreateTenantMiddleware(makeConfig());
498
498
  const sharedUserRecord = { ID: 'u1', UserRoles: [] } as unknown as Record<string, unknown>;
499
499
 
500
500
  const reqA = {
@@ -527,11 +527,11 @@ describe('Multi-Tenancy Security Edge Cases', () => {
527
527
  IsSaved: isSaved,
528
528
  Get: vi.fn((col: string) => col === 'OrganizationID' ? tenantValue : null),
529
529
  Set: vi.fn(),
530
- } as unknown as Parameters<ReturnType<typeof createTenantPreSaveHook>>[0];
530
+ } as unknown as Parameters<ReturnType<typeof CreateTenantPreSaveHook>>[0];
531
531
  }
532
532
 
533
533
  it('should reject save with SQL injection in entity tenant column', () => {
534
- const hook = createTenantPreSaveHook(makeConfig());
534
+ const hook = CreateTenantPreSaveHook(makeConfig());
535
535
  const entity = makeEntity('Customers', "' OR 1=1 --", true);
536
536
  const user = makeUser('tenant-abc');
537
537
 
@@ -541,13 +541,13 @@ describe('Multi-Tenancy Security Edge Cases', () => {
541
541
  });
542
542
 
543
543
  it('should auto-assign tenant for new record even when entity has no EntityInfo', () => {
544
- const hook = createTenantPreSaveHook(makeConfig());
544
+ const hook = CreateTenantPreSaveHook(makeConfig());
545
545
  const entity = {
546
546
  EntityInfo: undefined,
547
547
  IsSaved: false,
548
548
  Get: vi.fn(() => null),
549
549
  Set: vi.fn(),
550
- } as unknown as Parameters<ReturnType<typeof createTenantPreSaveHook>>[0];
550
+ } as unknown as Parameters<ReturnType<typeof CreateTenantPreSaveHook>>[0];
551
551
  const user = makeUser('tenant-abc');
552
552
 
553
553
  // No EntityInfo → no entity name → not scoped → allow
@@ -556,7 +556,7 @@ describe('Multi-Tenancy Security Edge Cases', () => {
556
556
  });
557
557
 
558
558
  it('should handle null contextUser gracefully', () => {
559
- const hook = createTenantPreSaveHook(makeConfig());
559
+ const hook = CreateTenantPreSaveHook(makeConfig());
560
560
  const entity = makeEntity('Customers', 'tenant-abc', true);
561
561
 
562
562
  const result = hook(entity, undefined);
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { createTenantPreRunViewHook, createTenantPreSaveHook } from '../multiTenancy/index.js';
2
+ import { CreateTenantPreRunViewHook, CreateTenantPreSaveHook } from '../multiTenancy/index.js';
3
3
  import type { MultiTenancyConfig } from '../config.js';
4
4
  import type { RunViewParams } from '@memberjunction/core';
5
5
 
@@ -66,13 +66,13 @@ function makeUser(tenantId?: string, roles: string[] = []) {
66
66
  ID: 'user-1',
67
67
  TenantContext: tenantId ? { TenantID: tenantId, Source: 'header' as const } : undefined,
68
68
  UserRoles: roles.map(r => ({ Role: r, RoleID: `role-${r}`, UserID: 'user-1' })),
69
- } as Parameters<ReturnType<typeof createTenantPreRunViewHook>>[1];
69
+ } as Parameters<ReturnType<typeof CreateTenantPreRunViewHook>>[1];
70
70
  }
71
71
 
72
72
  describe('Multi-Tenancy Hooks', () => {
73
73
  describe('createTenantPreRunViewHook', () => {
74
74
  it('should inject tenant filter for scoped entity', () => {
75
- const hook = createTenantPreRunViewHook(makeConfig());
75
+ const hook = CreateTenantPreRunViewHook(makeConfig());
76
76
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
77
77
  const user = makeUser('tenant-abc');
78
78
 
@@ -81,7 +81,7 @@ describe('Multi-Tenancy Hooks', () => {
81
81
  });
82
82
 
83
83
  it('should AND with existing filter', () => {
84
- const hook = createTenantPreRunViewHook(makeConfig());
84
+ const hook = CreateTenantPreRunViewHook(makeConfig());
85
85
  const params = { EntityName: 'Customers', ExtraFilter: "Status = 'Active'" } as RunViewParams;
86
86
  const user = makeUser('tenant-abc');
87
87
 
@@ -92,7 +92,7 @@ describe('Multi-Tenancy Hooks', () => {
92
92
  });
93
93
 
94
94
  it('should skip core __mj entities when autoExcludeCoreEntities is true', () => {
95
- const hook = createTenantPreRunViewHook(makeConfig());
95
+ const hook = CreateTenantPreRunViewHook(makeConfig());
96
96
  const params = { EntityName: 'AI Models', ExtraFilter: '' } as RunViewParams;
97
97
  const user = makeUser('tenant-abc');
98
98
 
@@ -101,7 +101,7 @@ describe('Multi-Tenancy Hooks', () => {
101
101
  });
102
102
 
103
103
  it('should not filter when user has no TenantContext', () => {
104
- const hook = createTenantPreRunViewHook(makeConfig());
104
+ const hook = CreateTenantPreRunViewHook(makeConfig());
105
105
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
106
106
  const user = makeUser(undefined);
107
107
 
@@ -110,7 +110,7 @@ describe('Multi-Tenancy Hooks', () => {
110
110
  });
111
111
 
112
112
  it('should bypass filtering for admin users', () => {
113
- const hook = createTenantPreRunViewHook(makeConfig());
113
+ const hook = CreateTenantPreRunViewHook(makeConfig());
114
114
  const params = { EntityName: 'Customers', ExtraFilter: '' } as RunViewParams;
115
115
  const user = makeUser('tenant-abc', ['Admin']);
116
116
 
@@ -119,7 +119,7 @@ describe('Multi-Tenancy Hooks', () => {
119
119
  });
120
120
 
121
121
  it('should use entity column mapping override', () => {
122
- const hook = createTenantPreRunViewHook(makeConfig({
122
+ const hook = CreateTenantPreRunViewHook(makeConfig({
123
123
  entityColumnMappings: { 'Orders': 'TenantID' },
124
124
  }));
125
125
  const params = { EntityName: 'Orders', ExtraFilter: '' } as RunViewParams;
@@ -130,7 +130,7 @@ describe('Multi-Tenancy Hooks', () => {
130
130
  });
131
131
 
132
132
  it('should respect allowlist scoping strategy', () => {
133
- const hook = createTenantPreRunViewHook(makeConfig({
133
+ const hook = CreateTenantPreRunViewHook(makeConfig({
134
134
  scopingStrategy: 'allowlist',
135
135
  scopedEntities: ['Customers'],
136
136
  }));
@@ -148,7 +148,7 @@ describe('Multi-Tenancy Hooks', () => {
148
148
  });
149
149
 
150
150
  it('should respect denylist scoping strategy', () => {
151
- const hook = createTenantPreRunViewHook(makeConfig({
151
+ const hook = CreateTenantPreRunViewHook(makeConfig({
152
152
  scopingStrategy: 'denylist',
153
153
  scopedEntities: ['Orders'],
154
154
  }));
@@ -173,11 +173,11 @@ describe('Multi-Tenancy Hooks', () => {
173
173
  IsSaved: isSaved,
174
174
  Get: vi.fn((col: string) => col === 'OrganizationID' ? tenantValue : null),
175
175
  Set: vi.fn(),
176
- } as unknown as Parameters<ReturnType<typeof createTenantPreSaveHook>>[0];
176
+ } as unknown as Parameters<ReturnType<typeof CreateTenantPreSaveHook>>[0];
177
177
  }
178
178
 
179
179
  it('should allow save when tenant matches', () => {
180
- const hook = createTenantPreSaveHook(makeConfig());
180
+ const hook = CreateTenantPreSaveHook(makeConfig());
181
181
  const entity = makeEntity('Customers', 'tenant-abc', true);
182
182
  const user = makeUser('tenant-abc');
183
183
 
@@ -186,7 +186,7 @@ describe('Multi-Tenancy Hooks', () => {
186
186
  });
187
187
 
188
188
  it('should reject save in strict mode when tenant mismatches', () => {
189
- const hook = createTenantPreSaveHook(makeConfig());
189
+ const hook = CreateTenantPreSaveHook(makeConfig());
190
190
  const entity = makeEntity('Customers', 'tenant-other', true);
191
191
  const user = makeUser('tenant-abc');
192
192
 
@@ -197,7 +197,7 @@ describe('Multi-Tenancy Hooks', () => {
197
197
 
198
198
  it('should warn but allow in log mode when tenant mismatches', () => {
199
199
  const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
200
- const hook = createTenantPreSaveHook(makeConfig({ writeProtection: 'log' }));
200
+ const hook = CreateTenantPreSaveHook(makeConfig({ writeProtection: 'log' }));
201
201
  const entity = makeEntity('Customers', 'tenant-other', true);
202
202
  const user = makeUser('tenant-abc');
203
203
 
@@ -208,7 +208,7 @@ describe('Multi-Tenancy Hooks', () => {
208
208
  });
209
209
 
210
210
  it('should allow when writeProtection is off', () => {
211
- const hook = createTenantPreSaveHook(makeConfig({ writeProtection: 'off' }));
211
+ const hook = CreateTenantPreSaveHook(makeConfig({ writeProtection: 'off' }));
212
212
  const entity = makeEntity('Customers', 'tenant-other', true);
213
213
  const user = makeUser('tenant-abc');
214
214
 
@@ -217,7 +217,7 @@ describe('Multi-Tenancy Hooks', () => {
217
217
  });
218
218
 
219
219
  it('should auto-assign tenant for new records without tenant value', () => {
220
- const hook = createTenantPreSaveHook(makeConfig());
220
+ const hook = CreateTenantPreSaveHook(makeConfig());
221
221
  const entity = makeEntity('Customers', null, false);
222
222
  const user = makeUser('tenant-abc');
223
223
 
@@ -227,7 +227,7 @@ describe('Multi-Tenancy Hooks', () => {
227
227
  });
228
228
 
229
229
  it('should bypass validation for admin users', () => {
230
- const hook = createTenantPreSaveHook(makeConfig());
230
+ const hook = CreateTenantPreSaveHook(makeConfig());
231
231
  const entity = makeEntity('Customers', 'tenant-other', true);
232
232
  const user = makeUser('tenant-abc', ['Admin']);
233
233
 
@@ -236,7 +236,7 @@ describe('Multi-Tenancy Hooks', () => {
236
236
  });
237
237
 
238
238
  it('should skip core __mj entities', () => {
239
- const hook = createTenantPreSaveHook(makeConfig());
239
+ const hook = CreateTenantPreSaveHook(makeConfig());
240
240
  const entity = makeEntity('AI Models', 'any-tenant', true);
241
241
  const user = makeUser('tenant-abc');
242
242