@memberjunction/server 6.2.0-edge.4 → 6.2.0-edge.5

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 (287) hide show
  1. package/README.md +20 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/agentSessions/SessionJanitor.d.ts +91 -30
  4. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  5. package/dist/agentSessions/SessionJanitor.js +311 -81
  6. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  7. package/dist/agentSessions/SessionManager.d.ts +5 -1
  8. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  9. package/dist/agentSessions/SessionManager.js +13 -1
  10. package/dist/agentSessions/SessionManager.js.map +1 -1
  11. package/dist/apiRoot.d.ts +32 -0
  12. package/dist/apiRoot.d.ts.map +1 -0
  13. package/dist/apiRoot.js +67 -0
  14. package/dist/apiRoot.js.map +1 -0
  15. package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
  16. package/dist/auth/AuthProviderCatalogRouter.js +25 -0
  17. package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
  18. package/dist/auth/LoginScreenEngine.d.ts +22 -0
  19. package/dist/auth/LoginScreenEngine.d.ts.map +1 -0
  20. package/dist/auth/LoginScreenEngine.js +57 -0
  21. package/dist/auth/LoginScreenEngine.js.map +1 -0
  22. package/dist/auth/index.d.ts +1 -0
  23. package/dist/auth/index.d.ts.map +1 -1
  24. package/dist/auth/index.js +1 -0
  25. package/dist/auth/index.js.map +1 -1
  26. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  27. package/dist/auth/magicLink/MagicLinkRouter.js +3 -2
  28. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  29. package/dist/config.d.ts +136 -22
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +43 -4
  32. package/dist/config.js.map +1 -1
  33. package/dist/coreRoutes.d.ts +29 -0
  34. package/dist/coreRoutes.d.ts.map +1 -0
  35. package/dist/coreRoutes.js +142 -0
  36. package/dist/coreRoutes.js.map +1 -0
  37. package/dist/generated/graphql-schemas/__mj.d.ts +369 -3
  38. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  39. package/dist/generated/graphql-schemas/__mj.js +1750 -7
  40. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  41. package/dist/generic/CacheInvalidationResolver.d.ts +43 -8
  42. package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
  43. package/dist/generic/CacheInvalidationResolver.js +59 -19
  44. package/dist/generic/CacheInvalidationResolver.js.map +1 -1
  45. package/dist/generic/PushStatusResolver.js +1 -1
  46. package/dist/generic/PushStatusResolver.js.map +1 -1
  47. package/dist/generic/ResolverBase.d.ts +103 -44
  48. package/dist/generic/ResolverBase.d.ts.map +1 -1
  49. package/dist/generic/ResolverBase.js +264 -305
  50. package/dist/generic/ResolverBase.js.map +1 -1
  51. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  52. package/dist/generic/RunViewResolver.js +12 -0
  53. package/dist/generic/RunViewResolver.js.map +1 -1
  54. package/dist/globalCors.d.ts +33 -0
  55. package/dist/globalCors.d.ts.map +1 -0
  56. package/dist/globalCors.js +58 -0
  57. package/dist/globalCors.js.map +1 -0
  58. package/dist/index.d.ts +11 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +112 -160
  61. package/dist/index.js.map +1 -1
  62. package/dist/multiTenancy/index.d.ts.map +1 -1
  63. package/dist/multiTenancy/index.js +22 -2
  64. package/dist/multiTenancy/index.js.map +1 -1
  65. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -1
  66. package/dist/realtimeSessions/RealtimeSessionVerificationService.js +2 -1
  67. package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -1
  68. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -1
  69. package/dist/realtimeSessions/RealtimeVerifyRouter.js +2 -1
  70. package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -1
  71. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts +100 -0
  72. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts.map +1 -0
  73. package/dist/realtimeSessions/RecordingAssemblyScheduler.js +173 -0
  74. package/dist/realtimeSessions/RecordingAssemblyScheduler.js.map +1 -0
  75. package/dist/realtimeSessions/index.d.ts +2 -0
  76. package/dist/realtimeSessions/index.d.ts.map +1 -1
  77. package/dist/realtimeSessions/index.js +2 -0
  78. package/dist/realtimeSessions/index.js.map +1 -1
  79. package/dist/realtimeSessions/ownedRealtimeSession.d.ts +30 -0
  80. package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
  81. package/dist/realtimeSessions/ownedRealtimeSession.js +47 -0
  82. package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
  83. package/dist/realtimeSessions/sessionAccess.d.ts +6 -0
  84. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
  85. package/dist/realtimeSessions/sessionAccess.js +7 -3
  86. package/dist/realtimeSessions/sessionAccess.js.map +1 -1
  87. package/dist/resolvers/ArtifactFileResolver.d.ts +5 -1
  88. package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -1
  89. package/dist/resolvers/ArtifactFileResolver.js +9 -7
  90. package/dist/resolvers/ArtifactFileResolver.js.map +1 -1
  91. package/dist/resolvers/ConversationRunEventsResolver.d.ts +8 -4
  92. package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
  93. package/dist/resolvers/ConversationRunEventsResolver.js +6 -6
  94. package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
  95. package/dist/resolvers/DatasetResolver.d.ts +24 -3
  96. package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
  97. package/dist/resolvers/DatasetResolver.js +57 -8
  98. package/dist/resolvers/DatasetResolver.js.map +1 -1
  99. package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -1
  100. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  101. package/dist/resolvers/EntityRecordNameResolver.js +3 -2
  102. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  103. package/dist/resolvers/FetchEntityVectorsResolver.d.ts +18 -3
  104. package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
  105. package/dist/resolvers/FetchEntityVectorsResolver.js +100 -35
  106. package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
  107. package/dist/resolvers/FileResolver.d.ts +82 -11
  108. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  109. package/dist/resolvers/FileResolver.js +279 -101
  110. package/dist/resolvers/FileResolver.js.map +1 -1
  111. package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
  112. package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
  113. package/dist/resolvers/GetDataContextDataResolver.js +117 -38
  114. package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
  115. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  116. package/dist/resolvers/GetDataResolver.js +6 -3
  117. package/dist/resolvers/GetDataResolver.js.map +1 -1
  118. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  119. package/dist/resolvers/IntegrationDiscoveryResolver.js +4 -2
  120. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  121. package/dist/resolvers/QueryResolver.d.ts +2 -0
  122. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  123. package/dist/resolvers/QueryResolver.js +13 -0
  124. package/dist/resolvers/QueryResolver.js.map +1 -1
  125. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +2 -8
  126. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  127. package/dist/resolvers/RealtimeClientSessionResolver.js +10 -26
  128. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  129. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  130. package/dist/resolvers/RunAIAgentResolver.js +35 -6
  131. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  132. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts +12 -1
  133. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts.map +1 -1
  134. package/dist/resolvers/SearchKnowledgeStreamResolver.js +15 -2
  135. package/dist/resolvers/SearchKnowledgeStreamResolver.js.map +1 -1
  136. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  137. package/dist/resolvers/SqlLoggingConfigResolver.js +2 -3
  138. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  139. package/dist/resolvers/TaskGraphFrameResolver.d.ts +2 -1
  140. package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
  141. package/dist/resolvers/TaskGraphFrameResolver.js +28 -1
  142. package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
  143. package/dist/resolvers/TestQuerySQLResolver.d.ts +24 -0
  144. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  145. package/dist/resolvers/TestQuerySQLResolver.js +65 -13
  146. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  147. package/dist/resolvers/TransactionGroupResolver.d.ts +19 -2
  148. package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
  149. package/dist/resolvers/TransactionGroupResolver.js +102 -24
  150. package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
  151. package/dist/resolvers/agent-run-data-guard.d.ts +31 -0
  152. package/dist/resolvers/agent-run-data-guard.d.ts.map +1 -0
  153. package/dist/resolvers/agent-run-data-guard.js +72 -0
  154. package/dist/resolvers/agent-run-data-guard.js.map +1 -0
  155. package/dist/rest/RealtimeRecordingHandler.d.ts +49 -0
  156. package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -0
  157. package/dist/rest/RealtimeRecordingHandler.js +383 -0
  158. package/dist/rest/RealtimeRecordingHandler.js.map +1 -0
  159. package/dist/rest/ViewOperationsHandler.d.ts +3 -1
  160. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  161. package/dist/rest/ViewOperationsHandler.js +21 -12
  162. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  163. package/dist/rest/setupRESTEndpoints.d.ts +6 -0
  164. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
  165. package/dist/rest/setupRESTEndpoints.js +6 -0
  166. package/dist/rest/setupRESTEndpoints.js.map +1 -1
  167. package/dist/serverExtensionReservedRoots.d.ts +12 -10
  168. package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
  169. package/dist/serverExtensionReservedRoots.js +14 -17
  170. package/dist/serverExtensionReservedRoots.js.map +1 -1
  171. package/dist/services/MJStorageBlobStore.d.ts +8 -1
  172. package/dist/services/MJStorageBlobStore.d.ts.map +1 -1
  173. package/dist/services/MJStorageBlobStore.js +25 -19
  174. package/dist/services/MJStorageBlobStore.js.map +1 -1
  175. package/dist/services/StartTaskGraphDispatcher.js +2 -2
  176. package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
  177. package/dist/services/TaskGraphActionRunner.d.ts +5 -3
  178. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  179. package/dist/services/TaskGraphActionRunner.js +27 -5
  180. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  181. package/dist/services/TaskGraphAgentRunner.d.ts +14 -2
  182. package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
  183. package/dist/services/TaskGraphAgentRunner.js +157 -9
  184. package/dist/services/TaskGraphAgentRunner.js.map +1 -1
  185. package/dist/services/TaskGraphContinuationDeliverer.d.ts +54 -2
  186. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  187. package/dist/services/TaskGraphContinuationDeliverer.js +598 -15
  188. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  189. package/dist/sharedCache.d.ts.map +1 -1
  190. package/dist/sharedCache.js +3 -0
  191. package/dist/sharedCache.js.map +1 -1
  192. package/package.json +99 -98
  193. package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
  194. package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
  195. package/src/__tests__/FetchEntityVectorsResolver.test.ts +163 -15
  196. package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
  197. package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
  198. package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
  199. package/src/__tests__/LoginScreenEngine.test.ts +86 -0
  200. package/src/__tests__/MJStorageBlobStore.storageGate.test.ts +63 -0
  201. package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
  202. package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
  203. package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
  204. package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
  205. package/src/__tests__/ResolverBase.clientOldValues.test.ts +209 -6
  206. package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
  207. package/src/__tests__/RunAIAgentResolver.branch.test.ts +1 -0
  208. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +5 -3
  209. package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +258 -0
  210. package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
  211. package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
  212. package/src/__tests__/SessionJanitor.test.ts +365 -10
  213. package/src/__tests__/SessionManager.test.ts +27 -0
  214. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
  215. package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
  216. package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +356 -22
  217. package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
  218. package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
  219. package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
  220. package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
  221. package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
  222. package/src/__tests__/agent-run-data-guard.test.ts +130 -0
  223. package/src/__tests__/apiRootBoot.test.ts +202 -0
  224. package/src/__tests__/cacheInvalidationRecordData.test.ts +64 -0
  225. package/src/__tests__/conversationRunEvents.test.ts +56 -14
  226. package/src/__tests__/globalCors.test.ts +217 -0
  227. package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
  228. package/src/__tests__/multiTenancy.security.test.ts +51 -0
  229. package/src/__tests__/multiTenancy.test.ts +1 -1
  230. package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
  231. package/src/__tests__/pushStatusResolver.filter.test.ts +7 -0
  232. package/src/__tests__/realtimeRecordingHandler.test.ts +652 -0
  233. package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
  234. package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -98
  235. package/src/__tests__/sharedCache.test.ts +5 -3
  236. package/src/agentSessions/SessionJanitor.ts +369 -93
  237. package/src/agentSessions/SessionManager.ts +13 -1
  238. package/src/apiRoot.ts +78 -0
  239. package/src/auth/AuthProviderCatalogRouter.ts +26 -0
  240. package/src/auth/LoginScreenEngine.ts +50 -0
  241. package/src/auth/index.ts +1 -0
  242. package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
  243. package/src/config.ts +46 -5
  244. package/src/coreRoutes.ts +166 -0
  245. package/src/generated/graphql-schemas/__mj.ts +1273 -10
  246. package/src/generic/CacheInvalidationResolver.ts +73 -18
  247. package/src/generic/PushStatusResolver.ts +1 -1
  248. package/src/generic/ResolverBase.ts +304 -325
  249. package/src/generic/RunViewResolver.ts +17 -0
  250. package/src/globalCors.ts +71 -0
  251. package/src/index.ts +116 -174
  252. package/src/multiTenancy/index.ts +24 -2
  253. package/src/realtimeSessions/RealtimeSessionVerificationService.ts +2 -1
  254. package/src/realtimeSessions/RealtimeVerifyRouter.ts +2 -1
  255. package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
  256. package/src/realtimeSessions/index.ts +2 -0
  257. package/src/realtimeSessions/ownedRealtimeSession.ts +55 -0
  258. package/src/realtimeSessions/sessionAccess.ts +7 -3
  259. package/src/resolvers/ArtifactFileResolver.ts +9 -8
  260. package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
  261. package/src/resolvers/DatasetResolver.ts +70 -10
  262. package/src/resolvers/EntityRecordNameResolver.ts +3 -2
  263. package/src/resolvers/FetchEntityVectorsResolver.ts +121 -39
  264. package/src/resolvers/FileResolver.ts +321 -106
  265. package/src/resolvers/GetDataContextDataResolver.ts +139 -41
  266. package/src/resolvers/GetDataResolver.ts +6 -3
  267. package/src/resolvers/IntegrationDiscoveryResolver.ts +4 -2
  268. package/src/resolvers/QueryResolver.ts +11 -0
  269. package/src/resolvers/RealtimeClientSessionResolver.ts +10 -33
  270. package/src/resolvers/RunAIAgentResolver.ts +39 -4
  271. package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
  272. package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
  273. package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
  274. package/src/resolvers/TestQuerySQLResolver.ts +68 -13
  275. package/src/resolvers/TransactionGroupResolver.ts +131 -27
  276. package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
  277. package/src/resolvers/agent-run-data-guard.ts +89 -0
  278. package/src/rest/RealtimeRecordingHandler.ts +464 -0
  279. package/src/rest/ViewOperationsHandler.ts +29 -13
  280. package/src/rest/setupRESTEndpoints.ts +6 -0
  281. package/src/serverExtensionReservedRoots.ts +14 -17
  282. package/src/services/MJStorageBlobStore.ts +31 -30
  283. package/src/services/StartTaskGraphDispatcher.ts +2 -2
  284. package/src/services/TaskGraphActionRunner.ts +25 -5
  285. package/src/services/TaskGraphAgentRunner.ts +188 -11
  286. package/src/services/TaskGraphContinuationDeliverer.ts +704 -14
  287. package/src/sharedCache.ts +3 -0
@@ -0,0 +1,66 @@
1
+ /**
2
+ * A host mj.config.cjs serverExtensions[] entry may be a partial OVERLAY of an extension an Open App
3
+ * package publishes: only DriverClass is required. The schema used to require RootPath and default
4
+ * Enabled to true, so `{ DriverClass, OwnsCORS: false }` failed config parsing at startup, and an
5
+ * overlay that omitted Enabled re-enabled an extension its package ships disabled. Completeness is
6
+ * checked after the merge instead.
7
+ */
8
+ import { describe, it, expect, vi } from 'vitest';
9
+
10
+ // config.ts evaluates `configInfo = LoadConfig()` at module load, and it rejects a configuration
11
+ // carrying no database credentials. Stubbing only the cosmiconfig search lets the module import so the
12
+ // REAL ServerExtensionSchema is under test (same pattern as newUserRolesDefault.test.ts).
13
+ vi.mock('cosmiconfig', () => ({
14
+ cosmiconfigSync: () => ({
15
+ search: () => ({
16
+ filepath: '/test/mj.config.cjs',
17
+ isEmpty: false,
18
+ config: { dbUsername: 'test-user', dbPassword: 'test-password', dbDatabase: 'test-db' },
19
+ }),
20
+ }),
21
+ }));
22
+
23
+ import { MergeServerExtensionConfigs, PrepareServerExtensionConfigs } from '@memberjunction/server-extensions-core';
24
+ import type { ServerExtensionConfig } from '@memberjunction/server-extensions-core';
25
+ import { ServerExtensionSchema } from '../config.js';
26
+
27
+ const published: ServerExtensionConfig = {
28
+ Enabled: true,
29
+ DriverClass: 'BallotEdge',
30
+ RootPath: '/vote',
31
+ OwnsCORS: true,
32
+ Settings: { RateLimitMax: 20 },
33
+ };
34
+
35
+ describe('host serverExtensions[] overlay schema', () => {
36
+ it('accepts an overlay that names only DriverClass and the fields it overrides', () => {
37
+ const parsed = ServerExtensionSchema.safeParse({ DriverClass: 'BallotEdge', OwnsCORS: false });
38
+ expect(parsed.success).toBe(true);
39
+ expect(parsed.success && parsed.data.RootPath).toBeUndefined();
40
+ expect(parsed.success && parsed.data.Enabled).toBeUndefined();
41
+ });
42
+
43
+ it('merges the overlay onto the published entry without losing RootPath or Enabled', () => {
44
+ const overlay = ServerExtensionSchema.parse({ DriverClass: 'BallotEdge', OwnsCORS: false, Settings: { RateLimitMax: 2000 } });
45
+ const [merged] = MergeServerExtensionConfigs([published], [overlay as ServerExtensionConfig]);
46
+ expect(merged).toMatchObject({ DriverClass: 'BallotEdge', RootPath: '/vote', Enabled: true, OwnsCORS: false });
47
+ expect(merged.Settings).toEqual({ RateLimitMax: 2000 });
48
+ });
49
+
50
+ it('does not re-enable an extension the package ships disabled', () => {
51
+ const overlay = ServerExtensionSchema.parse({ DriverClass: 'BallotEdge', Settings: { RateLimitMax: 5 } });
52
+ const [merged] = MergeServerExtensionConfigs([{ ...published, Enabled: false }], [overlay as ServerExtensionConfig]);
53
+ expect(merged.Enabled).toBe(false);
54
+ });
55
+
56
+ it('still rejects a host-only entry without a RootPath, after the merge', () => {
57
+ const overlay = ServerExtensionSchema.parse({ DriverClass: 'NotPublishedAnywhere' });
58
+ const problems: string[] = [];
59
+ const prepared = PrepareServerExtensionConfigs(
60
+ MergeServerExtensionConfigs([published], [overlay as ServerExtensionConfig]),
61
+ { onInvalid: (message: string) => problems.push(message) },
62
+ );
63
+ expect(prepared.map(c => c.DriverClass)).toEqual(['BallotEdge']);
64
+ expect(problems.some(p => p.includes('NotPublishedAnywhere') && p.includes('RootPath is empty'))).toBe(true);
65
+ });
66
+ });
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Pins the reserved-root set passed into prepareServerExtensionConfigs.
3
- * A new public mount in index.ts / a drifted `*_MOUNT_PATH` constant is a
4
- * contract failure — this file reads those sources as text so it never loads
5
- * `config.ts`.
3
+ * A drifted `*_MOUNT_PATH` constant is a contract failure — this file reads those
4
+ * sources as text so it never loads `config.ts`. That every core mount is reserved
5
+ * is checked against the real mounts in apiRootBoot.test.ts.
6
6
  */
7
7
  import { describe, it, expect } from 'vitest';
8
8
  import { readFileSync } from 'node:fs';
@@ -26,11 +26,6 @@ function exportedStringConst(relativeFile: string, name: string): string {
26
26
  return match[1];
27
27
  }
28
28
 
29
- function indexContainsLiteralPath(path: string): boolean {
30
- const src = readFileSync(join(SRC, 'index.ts'), 'utf8');
31
- return src.includes(`'${path}'`) || src.includes(`\`${path}\``) || src.includes(path.replace(/^\//, ''));
32
- }
33
-
34
29
  describe('coreReservedServerExtensionRoots', () => {
35
30
  it('stays in lockstep with exported *_MOUNT_PATH constants', () => {
36
31
  expect(CORE_CONSTANT_RESERVED_SERVER_EXTENSION_ROOTS).toEqual([
@@ -40,92 +35,11 @@ describe('coreReservedServerExtensionRoots', () => {
40
35
  ]);
41
36
  });
42
37
 
43
- it('includes the literal pre-auth paths serve() registers without a constant', () => {
44
- const indexSrc = readFileSync(join(SRC, 'index.ts'), 'utf8');
45
- for (const path of CORE_STATIC_RESERVED_SERVER_EXTENSION_ROOTS) {
46
- if (path === '/health') {
47
- expect(indexSrc, `${path} missing from serve()`).toContain("'/health/extensions'");
48
- } else if (path === '/realtime') {
49
- expect(indexSrc, `${path} missing from serve()`).toMatch(/REALTIME_SDP_EXCHANGE_PATH|'\/realtime'/);
50
- } else if (path === '/realtime-proxy') {
51
- expect(indexSrc, `${path} missing from serve()`).toContain('/realtime-proxy');
52
- } else {
53
- expect(indexSrc, `${path} missing from serve()`).toContain(`'${path}'`);
54
- }
55
- }
56
- expect(indexContainsLiteralPath('/healthcheck')).toBe(true);
57
- });
58
-
59
- it('structurally guarantees every pre-auth app.use / app.get / app.post mount in index.ts is reserved', () => {
60
- const indexSrc = readFileSync(join(SRC, 'index.ts'), 'utf8');
61
- const authMiddlewareIndex = indexSrc.indexOf('app.use(CreateUnifiedAuthMiddleware');
62
- expect(authMiddlewareIndex).toBeGreaterThan(0);
63
- const preAuthSrc = indexSrc.substring(0, authMiddlewareIndex);
64
-
65
- const mountRegex = /app\.(?:use|get|post)\s*\(\s*([^,\s)]+)/g;
66
- const reservedRoots = CoreReservedServerExtensionRoots('/');
67
-
68
- // Explicit allowlist of known non-path middleware mounts (e.g. app.use(mw), app.use(cors()), app.use(compression(...)))
69
- const knownNonPathTokens = [
70
- 'cors',
71
- 'express.',
72
- 'compression',
73
- 'cookieParser',
74
- 'CreateUnifiedAuthMiddleware',
75
- 'mw',
76
- ];
77
- const isKnownNonPath = (t: string): boolean =>
78
- knownNonPathTokens.some(k => t === k || t.startsWith(k));
79
-
80
- // Strip single-line and multi-line comments so comments like `app.use(...)` are not treated as code
81
- const cleanPreAuthSrc = preAuthSrc.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
82
-
83
- let match: RegExpExecArray | null;
84
- const mountedTokens: string[] = [];
85
- while ((match = mountRegex.exec(cleanPreAuthSrc)) !== null) {
86
- mountedTokens.push(match[1].trim());
87
- }
88
-
89
- expect(mountedTokens.length).toBeGreaterThan(0);
90
-
91
- const knownConstants: Record<string, string> = {
92
- REALTIME_SDP_EXCHANGE_PATH: '/realtime',
93
- // Public verify-link routes for realtime identity verification; under the reserved '/realtime' root.
94
- REALTIME_VERIFY_MOUNT_PATH: '/realtime/verify',
95
- MAGIC_LINK_MOUNT_PATH: '/magic-link',
96
- WIDGET_MOUNT_PATH: '/widget',
97
- AUTH_CATALOG_MOUNT_PATH: '/auth',
98
- };
99
-
100
- for (const token of mountedTokens) {
101
- const isLiteralPath = token.startsWith("'") || token.startsWith('"') || token.startsWith('`');
102
- const isPathConstant = /^[A-Z0-9_]+_PATH$/.test(token) || token in knownConstants;
103
- if (!isLiteralPath && !isPathConstant) {
104
- if (isKnownNonPath(token)) {
105
- continue;
106
- }
107
- throw new Error(`Unrecognized pre-auth mount argument '${token}' in index.ts. If this is a non-path middleware, add it to knownNonPathTokens; if it is a route, reserve its prefix or map its constant.`);
108
- }
109
-
110
- let pathPrefix: string;
111
- if (isLiteralPath) {
112
- pathPrefix = token.slice(1, -1);
113
- } else if (token in knownConstants) {
114
- pathPrefix = knownConstants[token];
115
- } else {
116
- throw new Error(`Unrecognized pre-auth mount constant '${token}' in index.ts. If this is a new pre-auth route, map its constant or reserve its prefix.`);
117
- }
118
-
119
- const isCovered = reservedRoots.some(root => pathPrefix === root || pathPrefix.startsWith(`${root}/`));
120
- expect(isCovered, `Pre-auth mount '${pathPrefix}' (from token '${token}') must be covered by reserved roots`).toBe(true);
121
- }
122
- });
123
-
124
- it('includes graphqlRootPath and every core mount', () => {
125
- const roots = CoreReservedServerExtensionRoots('/api');
38
+ it('includes every core mount, and no longer graphqlRootPath', () => {
39
+ const roots = CoreReservedServerExtensionRoots();
40
+ expect(roots).not.toContain('/api');
126
41
  expect(roots).toEqual(
127
42
  expect.arrayContaining([
128
- '/api',
129
43
  '/auth',
130
44
  '/magic-link',
131
45
  '/widget',
@@ -141,7 +55,7 @@ describe('coreReservedServerExtensionRoots', () => {
141
55
  });
142
56
 
143
57
  it('closes the F-M2 bypasses: cased /auth and sibling /healthcheck', () => {
144
- const extra = CoreReservedServerExtensionRoots('/');
58
+ const extra = CoreReservedServerExtensionRoots();
145
59
  expect(validateServerExtensionRootPath('/Auth', extra)).toMatch(/reserved prefix/);
146
60
  expect(validateServerExtensionRootPath('/healthcheck', extra)).toMatch(/reserved prefix/);
147
61
  expect(validateServerExtensionRootPath('/Healthcheck', extra)).toMatch(/reserved prefix/);
@@ -157,10 +71,9 @@ describe('coreReservedServerExtensionRoots', () => {
157
71
  expect(validateServerExtensionRootPath('/meetings/teams', extra)).toBeNull();
158
72
  });
159
73
 
160
- it('reserves a non-default graphqlRootPath and its nested paths', () => {
161
- const extra = CoreReservedServerExtensionRoots('/api');
162
- expect(validateServerExtensionRootPath('/api', extra)).toMatch(/reserved prefix/);
163
- expect(validateServerExtensionRootPath('/api/graphql', extra)).toMatch(/reserved prefix/);
164
- expect(validateServerExtensionRootPath('/apiv2', extra)).toBeNull();
74
+ it('lets extensions sit under the GraphQL path (#5674): RootPaths are relative to MJAPI_BASE_PATH', () => {
75
+ const extra = CoreReservedServerExtensionRoots();
76
+ expect(validateServerExtensionRootPath('/api', extra)).toBeNull();
77
+ expect(validateServerExtensionRootPath('/forms', extra)).toBeNull();
165
78
  });
166
79
  });
@@ -45,7 +45,7 @@ import { RedisLocalStorageProvider } from '@memberjunction/redis-provider';
45
45
  import type { CacheSettingsConfig } from '../config.js';
46
46
 
47
47
  function settings(overrides: Partial<CacheSettingsConfig>): CacheSettingsConfig {
48
- return { maxMemoryMB: 150, maxPercentOfCachePerEntity: 50, defaultTTLSeconds: 0, evictionSweepIntervalSeconds: 300, verboseLogging: false, engineSweepIntervalSeconds: 300, ...overrides };
48
+ return { maxMemoryMB: 150, maxPercentOfCachePerEntity: 50, maxEntryPercentOfCache: 'auto', defaultTTLSeconds: 0, evictionSweepIntervalSeconds: 300, verboseLogging: false, engineSweepIntervalSeconds: 300, ...overrides };
49
49
  }
50
50
 
51
51
  function event(overrides: Partial<CacheChangedEvent>): CacheChangedEvent {
@@ -117,9 +117,11 @@ describe('shared cache configuration', () => {
117
117
  });
118
118
 
119
119
  it('maps cacheSettings onto LocalCacheManager settings', () => {
120
- expect(CacheManagerConfigFromSettings(settings({ maxMemoryMB: 10, maxPercentOfCachePerEntity: 20, defaultTTLSeconds: 5, evictionSweepIntervalSeconds: 7, verboseLogging: true })))
121
- .toEqual({ maxSizeBytes: 10 * 1024 * 1024, maxPercentOfCachePerEntity: 20, defaultTTLMs: 5000, evictionSweepIntervalMs: 7000, verboseLogging: true });
120
+ expect(CacheManagerConfigFromSettings(settings({ maxMemoryMB: 10, maxPercentOfCachePerEntity: 20, maxEntryPercentOfCache: 40, defaultTTLSeconds: 5, evictionSweepIntervalSeconds: 7, verboseLogging: true })))
121
+ .toEqual({ maxSizeBytes: 10 * 1024 * 1024, maxPercentOfCachePerEntity: 20, maxEntryPercentOfCache: 40, defaultTTLMs: 5000, evictionSweepIntervalMs: 7000, verboseLogging: true });
122
122
  expect(CacheManagerConfigFromSettings(undefined).maxSizeBytes).toBe(150 * 1024 * 1024);
123
+ // The per-entry ceiling reaches the cache, and an unset one is derived rather than a fixed fraction.
124
+ expect(CacheManagerConfigFromSettings(undefined).maxEntryPercentOfCache).toBe('auto');
123
125
  });
124
126
 
125
127
  it('starts the engine sweep at the configured interval, off when 0', () => {