@rudderhq/server 0.6.1 → 0.6.2-canary.0

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 (298) hide show
  1. package/dist/bundled-plugins/plugin-linear/dist/worker.js +112 -4
  2. package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +2 -2
  3. package/dist/routes/access-onboarding.helpers.d.ts +0 -6
  4. package/dist/routes/access-onboarding.helpers.d.ts.map +1 -1
  5. package/dist/routes/access-onboarding.helpers.js +0 -7
  6. package/dist/routes/access-onboarding.helpers.js.map +1 -1
  7. package/dist/routes/access.d.ts +1 -1
  8. package/dist/routes/access.d.ts.map +1 -1
  9. package/dist/routes/access.js +2 -7
  10. package/dist/routes/access.js.map +1 -1
  11. package/dist/routes/agents.d.ts.map +1 -1
  12. package/dist/routes/agents.js +24 -49
  13. package/dist/routes/agents.js.map +1 -1
  14. package/dist/routes/agents.management-routes.d.ts.map +1 -1
  15. package/dist/routes/agents.management-routes.js +0 -1
  16. package/dist/routes/agents.management-routes.js.map +1 -1
  17. package/dist/routes/chats.d.ts.map +1 -1
  18. package/dist/routes/chats.js +77 -62
  19. package/dist/routes/chats.js.map +1 -1
  20. package/dist/routes/chats.preflight.d.ts +56 -0
  21. package/dist/routes/chats.preflight.d.ts.map +1 -0
  22. package/dist/routes/chats.preflight.js +72 -0
  23. package/dist/routes/chats.preflight.js.map +1 -0
  24. package/dist/routes/chats.runtime-controls.d.ts +62 -0
  25. package/dist/routes/chats.runtime-controls.d.ts.map +1 -0
  26. package/dist/routes/chats.runtime-controls.js +51 -0
  27. package/dist/routes/chats.runtime-controls.js.map +1 -0
  28. package/dist/routes/chats.stream-routes.d.ts.map +1 -1
  29. package/dist/routes/chats.stream-routes.js +22 -38
  30. package/dist/routes/chats.stream-routes.js.map +1 -1
  31. package/dist/routes/chats.stream-support.d.ts +6 -0
  32. package/dist/routes/chats.stream-support.d.ts.map +1 -1
  33. package/dist/routes/chats.stream-support.js.map +1 -1
  34. package/dist/routes/chats.user-state-routes.d.ts +3 -0
  35. package/dist/routes/chats.user-state-routes.d.ts.map +1 -0
  36. package/dist/routes/chats.user-state-routes.js +40 -0
  37. package/dist/routes/chats.user-state-routes.js.map +1 -0
  38. package/dist/routes/costs.d.ts.map +1 -1
  39. package/dist/routes/costs.js +11 -1
  40. package/dist/routes/costs.js.map +1 -1
  41. package/dist/routes/managed-mcp-agent-bindings.d.ts +1 -1
  42. package/dist/routes/managed-mcp-agent-bindings.d.ts.map +1 -1
  43. package/dist/routes/managed-mcp-agent-bindings.js +4 -0
  44. package/dist/routes/managed-mcp-agent-bindings.js.map +1 -1
  45. package/dist/routes/managed-mcp-connections.d.ts.map +1 -1
  46. package/dist/routes/managed-mcp-connections.js +33 -21
  47. package/dist/routes/managed-mcp-connections.js.map +1 -1
  48. package/dist/services/agent-run-context.d.ts.map +1 -1
  49. package/dist/services/agent-run-context.js +5 -1
  50. package/dist/services/agent-run-context.js.map +1 -1
  51. package/dist/services/agents.d.ts +5 -25
  52. package/dist/services/agents.d.ts.map +1 -1
  53. package/dist/services/agents.js +0 -72
  54. package/dist/services/agents.js.map +1 -1
  55. package/dist/services/approvals.d.ts.map +1 -1
  56. package/dist/services/approvals.js +0 -1
  57. package/dist/services/approvals.js.map +1 -1
  58. package/dist/services/chat-assistant.annotations.d.ts.map +1 -1
  59. package/dist/services/chat-assistant.annotations.js +3 -0
  60. package/dist/services/chat-assistant.annotations.js.map +1 -1
  61. package/dist/services/chat-assistant.d.ts +7 -0
  62. package/dist/services/chat-assistant.d.ts.map +1 -1
  63. package/dist/services/chat-assistant.helpers.d.ts +7 -0
  64. package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
  65. package/dist/services/chat-assistant.helpers.js +23 -3
  66. package/dist/services/chat-assistant.helpers.js.map +1 -1
  67. package/dist/services/chat-assistant.js +61 -4
  68. package/dist/services/chat-assistant.js.map +1 -1
  69. package/dist/services/chat-assistant.proposal-validation.d.ts +10 -0
  70. package/dist/services/chat-assistant.proposal-validation.d.ts.map +1 -0
  71. package/dist/services/chat-assistant.proposal-validation.js +65 -0
  72. package/dist/services/chat-assistant.proposal-validation.js.map +1 -0
  73. package/dist/services/chat-assistant.runtime-batch.d.ts +1 -1
  74. package/dist/services/chat-assistant.runtime-batch.d.ts.map +1 -1
  75. package/dist/services/chat-assistant.runtime-batch.js +6 -1
  76. package/dist/services/chat-assistant.runtime-batch.js.map +1 -1
  77. package/dist/services/chat-assistant.runtime-overrides.d.ts +6 -0
  78. package/dist/services/chat-assistant.runtime-overrides.d.ts.map +1 -0
  79. package/dist/services/chat-assistant.runtime-overrides.js +81 -0
  80. package/dist/services/chat-assistant.runtime-overrides.js.map +1 -0
  81. package/dist/services/chat-generation-protocol.d.ts.map +1 -1
  82. package/dist/services/chat-generation-protocol.js +2 -1
  83. package/dist/services/chat-generation-protocol.js.map +1 -1
  84. package/dist/services/chat-generation-protocol.test.js +89 -0
  85. package/dist/services/chat-generation-protocol.test.js.map +1 -1
  86. package/dist/services/chat-queued-message-materialization.d.ts +2 -0
  87. package/dist/services/chat-queued-message-materialization.d.ts.map +1 -1
  88. package/dist/services/chat-queued-message-materialization.js +12 -1
  89. package/dist/services/chat-queued-message-materialization.js.map +1 -1
  90. package/dist/services/chat-work-manifest.d.ts.map +1 -1
  91. package/dist/services/chat-work-manifest.js +189 -4
  92. package/dist/services/chat-work-manifest.js.map +1 -1
  93. package/dist/services/chats.create.d.ts +6 -0
  94. package/dist/services/chats.create.d.ts.map +1 -1
  95. package/dist/services/chats.create.js +10 -1
  96. package/dist/services/chats.create.js.map +1 -1
  97. package/dist/services/chats.d.ts +105 -10
  98. package/dist/services/chats.d.ts.map +1 -1
  99. package/dist/services/chats.helpers.d.ts +3 -1
  100. package/dist/services/chats.helpers.d.ts.map +1 -1
  101. package/dist/services/chats.helpers.js +4 -3
  102. package/dist/services/chats.helpers.js.map +1 -1
  103. package/dist/services/chats.js +21 -111
  104. package/dist/services/chats.js.map +1 -1
  105. package/dist/services/chats.queued-message-create.d.ts +20 -0
  106. package/dist/services/chats.queued-message-create.d.ts.map +1 -0
  107. package/dist/services/chats.queued-message-create.js +127 -0
  108. package/dist/services/chats.queued-message-create.js.map +1 -0
  109. package/dist/services/chats.runtime-controls.d.ts +53 -0
  110. package/dist/services/chats.runtime-controls.d.ts.map +1 -0
  111. package/dist/services/chats.runtime-controls.js +64 -0
  112. package/dist/services/chats.runtime-controls.js.map +1 -0
  113. package/dist/services/costs.d.ts +4 -2
  114. package/dist/services/costs.d.ts.map +1 -1
  115. package/dist/services/costs.js +59 -23
  116. package/dist/services/costs.js.map +1 -1
  117. package/dist/services/knowledge-portability/organization-portability.core.d.ts +0 -3
  118. package/dist/services/knowledge-portability/organization-portability.core.d.ts.map +1 -1
  119. package/dist/services/knowledge-portability/organization-portability.core.js +0 -44
  120. package/dist/services/knowledge-portability/organization-portability.core.js.map +1 -1
  121. package/dist/services/knowledge-portability/organization-portability.export.d.ts.map +1 -1
  122. package/dist/services/knowledge-portability/organization-portability.export.js +1 -20
  123. package/dist/services/knowledge-portability/organization-portability.export.js.map +1 -1
  124. package/dist/services/knowledge-portability/organization-portability.files.d.ts +1 -3
  125. package/dist/services/knowledge-portability/organization-portability.files.d.ts.map +1 -1
  126. package/dist/services/knowledge-portability/organization-portability.files.js +1 -26
  127. package/dist/services/knowledge-portability/organization-portability.files.js.map +1 -1
  128. package/dist/services/knowledge-portability/organization-portability.import.d.ts.map +1 -1
  129. package/dist/services/knowledge-portability/organization-portability.import.js +0 -19
  130. package/dist/services/knowledge-portability/organization-portability.import.js.map +1 -1
  131. package/dist/services/knowledge-portability/organization-portability.package.d.ts.map +1 -1
  132. package/dist/services/knowledge-portability/organization-portability.package.js +2 -1
  133. package/dist/services/knowledge-portability/organization-portability.package.js.map +1 -1
  134. package/dist/services/mcp/managed-bindings.d.ts +3 -1
  135. package/dist/services/mcp/managed-bindings.d.ts.map +1 -1
  136. package/dist/services/mcp/managed-bindings.js +254 -25
  137. package/dist/services/mcp/managed-bindings.js.map +1 -1
  138. package/dist/services/mcp/managed-connections.d.ts +4 -2
  139. package/dist/services/mcp/managed-connections.d.ts.map +1 -1
  140. package/dist/services/mcp/managed-connections.js +194 -22
  141. package/dist/services/mcp/managed-connections.js.map +1 -1
  142. package/dist/services/mcp/managed-runtime.d.ts +8 -3
  143. package/dist/services/mcp/managed-runtime.d.ts.map +1 -1
  144. package/dist/services/mcp/managed-runtime.js +175 -74
  145. package/dist/services/mcp/managed-runtime.js.map +1 -1
  146. package/dist/services/mcp/oauth-helpers.d.ts +53 -0
  147. package/dist/services/mcp/oauth-helpers.d.ts.map +1 -0
  148. package/dist/services/mcp/oauth-helpers.js +267 -0
  149. package/dist/services/mcp/oauth-helpers.js.map +1 -0
  150. package/dist/services/mcp/oauth.d.ts +13 -13
  151. package/dist/services/mcp/oauth.d.ts.map +1 -1
  152. package/dist/services/mcp/oauth.js +220 -307
  153. package/dist/services/mcp/oauth.js.map +1 -1
  154. package/dist/services/mcp/provider-registry.d.ts +1 -1
  155. package/dist/services/mcp/provider-registry.d.ts.map +1 -1
  156. package/dist/services/mcp/provider-registry.js +4 -6
  157. package/dist/services/mcp/provider-registry.js.map +1 -1
  158. package/dist/services/mcp/provider-registry.test.js +20 -8
  159. package/dist/services/mcp/provider-registry.test.js.map +1 -1
  160. package/dist/services/mcp/tool-discovery.d.ts +4 -0
  161. package/dist/services/mcp/tool-discovery.d.ts.map +1 -1
  162. package/dist/services/mcp/tool-discovery.js +29 -0
  163. package/dist/services/mcp/tool-discovery.js.map +1 -1
  164. package/dist/services/mcp/tool-discovery.test.js +34 -1
  165. package/dist/services/mcp/tool-discovery.test.js.map +1 -1
  166. package/dist/services/organization-export-readme.d.ts +0 -8
  167. package/dist/services/organization-export-readme.d.ts.map +1 -1
  168. package/dist/services/organization-export-readme.js +3 -43
  169. package/dist/services/organization-export-readme.js.map +1 -1
  170. package/dist/services/plugin-registry.d.ts +21 -21
  171. package/dist/services/postgres-json.d.ts +2 -0
  172. package/dist/services/postgres-json.d.ts.map +1 -0
  173. package/dist/services/postgres-json.js +33 -0
  174. package/dist/services/postgres-json.js.map +1 -0
  175. package/dist/services/postgres-json.test.d.ts +2 -0
  176. package/dist/services/postgres-json.test.d.ts.map +1 -0
  177. package/dist/services/postgres-json.test.js +25 -0
  178. package/dist/services/postgres-json.test.js.map +1 -0
  179. package/dist/services/run-events.d.ts.map +1 -1
  180. package/dist/services/run-events.js +6 -1
  181. package/dist/services/run-events.js.map +1 -1
  182. package/dist/services/runtime-kernel/heartbeat.core.d.ts +2 -2
  183. package/dist/services/runtime-kernel/heartbeat.d.ts +6 -3
  184. package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -1
  185. package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -1
  186. package/dist/services/runtime-kernel/heartbeat.execute.js +2 -0
  187. package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -1
  188. package/dist/services/runtime-kernel/heartbeat.js.map +1 -1
  189. package/dist/services/runtime-kernel/heartbeat.misc.d.ts +3 -0
  190. package/dist/services/runtime-kernel/heartbeat.misc.d.ts.map +1 -1
  191. package/dist/services/runtime-kernel/heartbeat.misc.js +16 -4
  192. package/dist/services/runtime-kernel/heartbeat.misc.js.map +1 -1
  193. package/dist/services/runtime-kernel/heartbeat.terminal.d.ts +8 -9
  194. package/dist/services/runtime-kernel/heartbeat.terminal.d.ts.map +1 -1
  195. package/dist/services/side-chats.d.ts +9 -0
  196. package/dist/services/side-chats.d.ts.map +1 -1
  197. package/dist/services/side-chats.js +18 -4
  198. package/dist/services/side-chats.js.map +1 -1
  199. package/package.json +14 -13
  200. package/resources/bundled-skills/rudder-docs/evals/trigger-evals.json +1 -1
  201. package/resources/bundled-skills/rudder-docs/references/agent-creation.md +1 -3
  202. package/resources/bundled-skills/rudder-docs/references/api-reference.md +3 -12
  203. package/resources/bundled-skills/rudder-docs/references/cli-reference.md +1 -1
  204. package/resources/bundled-skills/rudder-docs/references/operating-practices.md +2 -2
  205. package/skills/rudder-docs/evals/trigger-evals.json +1 -1
  206. package/skills/rudder-docs/references/agent-creation.md +1 -3
  207. package/skills/rudder-docs/references/api-reference.md +3 -12
  208. package/skills/rudder-docs/references/cli-reference.md +1 -1
  209. package/skills/rudder-docs/references/operating-practices.md +2 -2
  210. package/ui-dist/assets/{LibraryLiveSurface-C8ECMVFT.js → LibraryLiveSurface-CnZxAEHp.js} +1 -1
  211. package/ui-dist/assets/{abnfDiagram-VRR7QNED-BZHkBV8B.js → abnfDiagram-VRR7QNED-B208YmVN.js} +1 -1
  212. package/ui-dist/assets/{arc-DhnfBt9e.js → arc-_raxgt-X.js} +1 -1
  213. package/ui-dist/assets/{architectureDiagram-ZJ3FMSHR-BKHzH5qs.js → architectureDiagram-ZJ3FMSHR-y3eHT3Gk.js} +1 -1
  214. package/ui-dist/assets/{blockDiagram-677ZJIJ3--1g_r8lr.js → blockDiagram-677ZJIJ3-BT7LIBsS.js} +1 -1
  215. package/ui-dist/assets/{c4Diagram-LMCZKHZV-CnZQa_O3.js → c4Diagram-LMCZKHZV-w0r6PEZM.js} +1 -1
  216. package/ui-dist/assets/channel-NqK-mAXf.js +1 -0
  217. package/ui-dist/assets/{chunk-2Q5K7J3B-Cx1ETWPc.js → chunk-2Q5K7J3B-C3fuIoNI.js} +1 -1
  218. package/ui-dist/assets/{chunk-32BRIVSS-DwH6W0QD.js → chunk-32BRIVSS-DMb9Q2qh.js} +1 -1
  219. package/ui-dist/assets/{chunk-5VM5RSS4-DKjzajxX.js → chunk-5VM5RSS4-BqMkrxOv.js} +1 -1
  220. package/ui-dist/assets/{chunk-EX3LRPZG-DqPqTdiU.js → chunk-EX3LRPZG-D0uW7ZHY.js} +1 -1
  221. package/ui-dist/assets/{chunk-JWPE2WC7-BGZyFOPO.js → chunk-JWPE2WC7-_2Qhrxej.js} +1 -1
  222. package/ui-dist/assets/{chunk-MOJQB5TN-DWj-_Y-X.js → chunk-MOJQB5TN-Bx3r3XhP.js} +1 -1
  223. package/ui-dist/assets/{chunk-RYQCIY6F-Bp2OOi6q.js → chunk-RYQCIY6F-ryJ6ulQN.js} +1 -1
  224. package/ui-dist/assets/{chunk-V7JOEXUC-CxNGWU9-.js → chunk-V7JOEXUC-CpTtqgWd.js} +1 -1
  225. package/ui-dist/assets/{chunk-VR4S4FIN-rrwz8tGB.js → chunk-VR4S4FIN-C4qXyyxR.js} +1 -1
  226. package/ui-dist/assets/{chunk-XXDRQBXY-CuinF1_q.js → chunk-XXDRQBXY-CRPbq1d0.js} +1 -1
  227. package/ui-dist/assets/classDiagram-OUVF2IWQ-CRSBnWpX.js +1 -0
  228. package/ui-dist/assets/classDiagram-v2-EOCWNBFH-CRSBnWpX.js +1 -0
  229. package/ui-dist/assets/{cose-bilkent-JH36ORCC-BuP7WwKx.js → cose-bilkent-JH36ORCC-DClTXY3x.js} +1 -1
  230. package/ui-dist/assets/{cynefin-VYW2F7L2-Bdib4S1v.js → cynefin-VYW2F7L2-BqQy_6rq.js} +1 -1
  231. package/ui-dist/assets/{cynefinDiagram-TSTJHNR4-DuSsXSha.js → cynefinDiagram-TSTJHNR4-C_5uIlLF.js} +1 -1
  232. package/ui-dist/assets/{dagre-VKFMJZFB-Igot42Fe.js → dagre-VKFMJZFB-CvzApokN.js} +1 -1
  233. package/ui-dist/assets/{diagram-FQU43EPY-e8NWjImB.js → diagram-FQU43EPY-lsQoO58-.js} +1 -1
  234. package/ui-dist/assets/{diagram-G47NLZAW-BMQV4r9I.js → diagram-G47NLZAW-DJSeMnXd.js} +1 -1
  235. package/ui-dist/assets/{diagram-NH7WQ7WH-CPKOpfkM.js → diagram-NH7WQ7WH-Cfg6gXXN.js} +1 -1
  236. package/ui-dist/assets/{diagram-OA4YK3LP-C_fdlr3v.js → diagram-OA4YK3LP-DUS8ge-b.js} +1 -1
  237. package/ui-dist/assets/{diagram-WEI45ONY-Cu7lfxa2.js → diagram-WEI45ONY-Cp-l5tVI.js} +1 -1
  238. package/ui-dist/assets/{ebnfDiagram-CCIWWBDH-CN6-jt9d.js → ebnfDiagram-CCIWWBDH-BlRaFF_K.js} +1 -1
  239. package/ui-dist/assets/{erDiagram-Q63AITRT-D2z6C-we.js → erDiagram-Q63AITRT-BZwqidAe.js} +1 -1
  240. package/ui-dist/assets/{flowDiagram-23GEKE2U-CQlS5jRI.js → flowDiagram-23GEKE2U-BsfwK51N.js} +1 -1
  241. package/ui-dist/assets/{ganttDiagram-NO4QXBWP-BuuHqPc8.js → ganttDiagram-NO4QXBWP-D7rDtE9-.js} +1 -1
  242. package/ui-dist/assets/{gitGraphDiagram-IHSO6WYX-zmgrxxBX.js → gitGraphDiagram-IHSO6WYX-SI7fggdm.js} +1 -1
  243. package/ui-dist/assets/{graph-BJvZTk9a.js → graph-jB2l85dN.js} +1 -1
  244. package/ui-dist/assets/{index-D0VRM_9h.js → index-3UJgpZuo.js} +1 -1
  245. package/ui-dist/assets/{index-CLLpIiBV.js → index-BEtrDYuf.js} +1 -1
  246. package/ui-dist/assets/{index-HrYgeHT8.js → index-BXIRLNEz.js} +1 -1
  247. package/ui-dist/assets/{index-BkG5PUIN.js → index-BzZl24GX.js} +1 -1
  248. package/ui-dist/assets/{index-Cc-ewLqn.js → index-C2YHCs23.js} +1 -1
  249. package/ui-dist/assets/index-CFGCM2jL.css +1 -0
  250. package/ui-dist/assets/{index-DwCuHGmD.js → index-CMGFrbv8.js} +1 -1
  251. package/ui-dist/assets/{index-BUkyKZIq.js → index-CTAmMJYG.js} +1 -1
  252. package/ui-dist/assets/{index-DshvyEC6.js → index-CZoL7L4x.js} +1 -1
  253. package/ui-dist/assets/{index-DyfYslLG.js → index-C_i-wGZX.js} +1 -1
  254. package/ui-dist/assets/{index-B2ZiqwcG.js → index-CkjUvGSq.js} +1 -1
  255. package/ui-dist/assets/{index-8kxaiDPU.js → index-CuPTWos7.js} +1 -1
  256. package/ui-dist/assets/{index-B0Kc4Reu.js → index-D8o_GAok.js} +1 -1
  257. package/ui-dist/assets/{index-B-_jOiYM.js → index-DMFCHg9M.js} +1 -1
  258. package/ui-dist/assets/{index-Be6_jEMJ.js → index-DR1WCr91.js} +1 -1
  259. package/ui-dist/assets/{index-CagHzH_y.js → index-DV8jlH7u.js} +1 -1
  260. package/ui-dist/assets/{index-BYiU3CbU.js → index-DaC9LwaF.js} +1 -1
  261. package/ui-dist/assets/{index--DAOoBdz.js → index-DrRmkklS.js} +539 -541
  262. package/ui-dist/assets/{index-BoJ3Lpc0.js → index-gRrC-1Ro.js} +1 -1
  263. package/ui-dist/assets/{infoDiagram-FWYZ7A6U-DcewEow-.js → infoDiagram-FWYZ7A6U-Dq_2Rg1m.js} +1 -1
  264. package/ui-dist/assets/{ishikawaDiagram-FXEZZL3T-DDA-hStd.js → ishikawaDiagram-FXEZZL3T-uyywLhOx.js} +1 -1
  265. package/ui-dist/assets/{journeyDiagram-5HDEW3XC-Di45AJjj.js → journeyDiagram-5HDEW3XC-BSdGAEe3.js} +1 -1
  266. package/ui-dist/assets/{kanban-definition-HUTT4EX6-BSCbVwWj.js → kanban-definition-HUTT4EX6-BeiytV3M.js} +1 -1
  267. package/ui-dist/assets/{layout-pITZAjqg.js → layout-kKtSz6Lw.js} +1 -1
  268. package/ui-dist/assets/{linear-Cu3rtYRt.js → linear-BNg7ltC5.js} +1 -1
  269. package/ui-dist/assets/{map-DYuY604Q.js → map-rBM_jVzN.js} +1 -1
  270. package/ui-dist/assets/{mermaid.core-DDOr0JGp.js → mermaid.core-B0lX_I1S.js} +4 -4
  271. package/ui-dist/assets/{mindmap-definition-LN4V7U3C-D7XVVo_g.js → mindmap-definition-LN4V7U3C-6WrmM-3d.js} +1 -1
  272. package/ui-dist/assets/{pegDiagram-2B236MQR-BC1GaeL3.js → pegDiagram-2B236MQR-BJ0lR6j8.js} +1 -1
  273. package/ui-dist/assets/{pieDiagram-ENE6RG2P-dEClB4rW.js → pieDiagram-ENE6RG2P-Ch-KedEq.js} +1 -1
  274. package/ui-dist/assets/{quadrantDiagram-ABIIQ3AL-DYEEk2Me.js → quadrantDiagram-ABIIQ3AL-BLnrHtbN.js} +1 -1
  275. package/ui-dist/assets/{railroadDiagram-RFXS5EU6-DNsj-q9g.js → railroadDiagram-RFXS5EU6-u0KJZK8C.js} +1 -1
  276. package/ui-dist/assets/{requirementDiagram-TGXJPOKE-BmkJ6fzV.js → requirementDiagram-TGXJPOKE-C1MzHKp-.js} +1 -1
  277. package/ui-dist/assets/{sankeyDiagram-HTMAVEWB-BsOkjZzG.js → sankeyDiagram-HTMAVEWB-UIufCGDd.js} +1 -1
  278. package/ui-dist/assets/{sequenceDiagram-DBY2YBRQ-Bi3Z-JjU.js → sequenceDiagram-DBY2YBRQ-Cv8Fb7zZ.js} +1 -1
  279. package/ui-dist/assets/{sizeCapture-X5ZJPWSS-BL5Nebl1.js → sizeCapture-X5ZJPWSS-9U-7wwO3.js} +1 -1
  280. package/ui-dist/assets/{stateDiagram-2N3HPSRC-Cq_vKfyy.js → stateDiagram-2N3HPSRC-BEOjkPpv.js} +1 -1
  281. package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-BBO_VsOI.js +1 -0
  282. package/ui-dist/assets/{swimlanes-5IMT3BWC-2J5KFUSB.js → swimlanes-5IMT3BWC-BEwruQnI.js} +2 -2
  283. package/ui-dist/assets/swimlanesDiagram-G3AALYLV-DjAl9cJv.js +8 -0
  284. package/ui-dist/assets/{timeline-definition-FHXFAJF6-D1ICgYtA.js → timeline-definition-FHXFAJF6-CfWC6EYo.js} +1 -1
  285. package/ui-dist/assets/{vennDiagram-L72KCM5P-D0Pe93oZ.js → vennDiagram-L72KCM5P-B2BPrj_n.js} +1 -1
  286. package/ui-dist/assets/{wardleyDiagram-EHGQE667-B7cKDg_l.js → wardleyDiagram-EHGQE667-Cx2wmgRm.js} +1 -1
  287. package/ui-dist/assets/{xychartDiagram-FW5EYKEG-CpD2ZP52.js → xychartDiagram-FW5EYKEG-Due4dZhR.js} +1 -1
  288. package/ui-dist/index.html +2 -2
  289. package/dist/routes/org-chart-svg.d.ts +0 -25
  290. package/dist/routes/org-chart-svg.d.ts.map +0 -1
  291. package/dist/routes/org-chart-svg.js +0 -652
  292. package/dist/routes/org-chart-svg.js.map +0 -1
  293. package/ui-dist/assets/channel-DAg8UTDO.js +0 -1
  294. package/ui-dist/assets/classDiagram-OUVF2IWQ-BDDhIQB_.js +0 -1
  295. package/ui-dist/assets/classDiagram-v2-EOCWNBFH-BDDhIQB_.js +0 -1
  296. package/ui-dist/assets/index-BnZ6czsu.css +0 -1
  297. package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-BUOXYIgQ.js +0 -1
  298. package/ui-dist/assets/swimlanesDiagram-G3AALYLV-BCURODlK.js +0 -8
@@ -1,27 +1,26 @@
1
1
  import { auth, OAuthError, OAuthErrorCode, } from "@modelcontextprotocol/client";
2
- import { activityLog, instanceUserRoles, mcpConnections, mcpOAuthGrants, mcpOAuthSessions, organizationMemberships, organizationSecrets, organizationSecretVersions, } from "@rudderhq/db";
2
+ import { activityLog, agentCustomIntegrationBindings, instanceUserRoles, mcpConnections, mcpOAuthGrants, mcpOAuthSessions, organizationMemberships, organizationSecrets, organizationSecretVersions, } from "@rudderhq/db";
3
3
  import { MCP_OAUTH_SESSION_TTL_MS, mcpOAuthCallbackSchema, mcpScopeSelectionSchema, } from "@rudderhq/shared";
4
4
  import { and, asc, eq, gt, inArray, isNull, lte, sql, } from "drizzle-orm";
5
5
  import { createHash, randomBytes, randomUUID, } from "node:crypto";
6
6
  import { HttpError, notFound, unprocessable } from "../../errors.js";
7
7
  import { getSecretProvider } from "../../secrets/provider-registry.js";
8
8
  import { lockManagedMcpOAuthAuthorizer } from "./authorizer-lock.js";
9
- import { createManagedMcpClient, resolveMcpHttpCredentials, } from "./managed-client.js";
9
+ import { accessToken, defaultDiscoverProviderScope, defaultValidateProviderTools, MAX_SCOPE_OPTIONS, oauthActivityValues, oauthRevocationEndpoint, parseOAuthMaterial, safeScopeOption, tokenExpiry, tokenScopes } from "./oauth-helpers.js";
10
10
  import { PersistentMcpOAuthClientProvider, resolveMcpOAuthRedirectUri, } from "./oauth-provider.js";
11
11
  import { createSecureMcpFetch } from "./pinned-fetch.js";
12
12
  import { MCP_CURATED_OAUTH_ORIGINS, MCP_PROVIDER_REGISTRY, resolveCuratedMcpEndpoint, } from "./provider-registry.js";
13
13
  import { resolveMcpHttpTarget } from "./security-policy.js";
14
+ export { parseProviderWorkspaceScope } from "./oauth-helpers.js";
14
15
  function createOAuthAuthorizationSnapshot(connection) {
15
16
  if (connection.provider === "custom") {
16
17
  throw unprocessable("Managed MCP OAuth only supports curated providers");
17
18
  }
18
- const serverUrl = connection.provider === "supabase"
19
- ? MCP_PROVIDER_REGISTRY.supabase.endpoint
20
- : resolveCuratedMcpEndpoint({
21
- provider: connection.provider,
22
- accessMode: connection.accessMode,
23
- externalScope: connection.externalScope,
24
- }).href;
19
+ const serverUrl = resolveCuratedMcpEndpoint({
20
+ provider: connection.provider,
21
+ accessMode: connection.accessMode,
22
+ externalScope: connection.externalScope,
23
+ }).href;
25
24
  return {
26
25
  serverUrl,
27
26
  ...(connection.provider === "linear" && connection.accessMode === "read_only"
@@ -30,6 +29,13 @@ function createOAuthAuthorizationSnapshot(connection) {
30
29
  accessMode: connection.accessMode,
31
30
  };
32
31
  }
32
+ function isSupabaseAccountUpgradeCandidate(connection) {
33
+ return connection.provider === "supabase"
34
+ && connection.scopeMode === "account"
35
+ && connection.externalScope === null
36
+ && connection.canonicalState === "superseded"
37
+ && connection.supersededByConnectionId !== null;
38
+ }
33
39
  function readOAuthAuthorizationSnapshot(statusMetadata, connection) {
34
40
  const value = statusMetadata.authorization;
35
41
  if (isRecord(value)
@@ -118,237 +124,6 @@ function publicConnection(row) {
118
124
  updatedAt: row.updatedAt,
119
125
  };
120
126
  }
121
- function oauthActivityValues(input) {
122
- return {
123
- orgId: input.orgId,
124
- actorType: input.actorUserId ? "user" : "system",
125
- actorId: input.actorUserId ?? "system",
126
- action: input.action,
127
- entityType: "mcp_connection",
128
- entityId: input.connectionId,
129
- details: input.details,
130
- };
131
- }
132
- function tokenExpiry(tokens, now = new Date()) {
133
- if (typeof tokens?.expires_in !== "number" || !Number.isFinite(tokens.expires_in))
134
- return null;
135
- return new Date(now.getTime() + Math.max(0, tokens.expires_in) * 1_000);
136
- }
137
- function tokenScopes(tokens) {
138
- return typeof tokens?.scope === "string"
139
- ? Array.from(new Set(tokens.scope.split(/\s+/u).filter(Boolean)))
140
- : [];
141
- }
142
- function accessToken(material) {
143
- const value = material.tokens?.access_token;
144
- if (!value)
145
- throw unprocessable("Managed MCP OAuth credentials are unavailable");
146
- return value;
147
- }
148
- function oauthRevocationEndpoint(material) {
149
- const metadata = material?.discoveryState?.authorizationServerMetadata;
150
- return isRecord(metadata) && typeof metadata.revocation_endpoint === "string"
151
- ? metadata.revocation_endpoint
152
- : null;
153
- }
154
- const SAFE_SCOPE_METADATA_KEYS = new Set([
155
- "region",
156
- "scopeKind",
157
- "status",
158
- "workspaceName",
159
- "workspace_name",
160
- "organizationName",
161
- "organization_name",
162
- ]);
163
- const MAX_SCOPE_OPTIONS = 500;
164
- const MAX_SCOPE_METADATA_BYTES = 4_096;
165
- function safeScopeMetadata(value) {
166
- const output = {};
167
- for (const [key, raw] of Object.entries(value)) {
168
- if (!SAFE_SCOPE_METADATA_KEYS.has(key))
169
- continue;
170
- const safeValue = typeof raw === "string"
171
- ? raw.slice(0, 512)
172
- : typeof raw === "number" && Number.isFinite(raw)
173
- ? raw
174
- : typeof raw === "boolean"
175
- ? raw
176
- : undefined;
177
- if (safeValue === undefined)
178
- continue;
179
- const candidate = { ...output, [key]: safeValue };
180
- if (Buffer.byteLength(JSON.stringify(candidate), "utf8") > MAX_SCOPE_METADATA_BYTES) {
181
- continue;
182
- }
183
- output[key] = safeValue;
184
- }
185
- return output;
186
- }
187
- function safeScopeOption(value) {
188
- return {
189
- id: value.id.trim().slice(0, 512),
190
- displayName: value.displayName.trim().slice(0, 240),
191
- metadata: isRecord(value.metadata) ? safeScopeMetadata(value.metadata) : {},
192
- };
193
- }
194
- function sanitizeScopeOptions(values) {
195
- const output = [];
196
- const seen = new Set();
197
- for (const value of values) {
198
- const safe = safeScopeOption(value);
199
- if (!safe.id || !safe.displayName || seen.has(safe.id))
200
- continue;
201
- seen.add(safe.id);
202
- output.push(safe);
203
- if (output.length === MAX_SCOPE_OPTIONS)
204
- break;
205
- }
206
- return output;
207
- }
208
- function parseToolJson(result) {
209
- for (const content of result.content ?? []) {
210
- if (content.type !== "text")
211
- continue;
212
- try {
213
- return JSON.parse(content.text);
214
- }
215
- catch {
216
- // Ignore non-JSON provider prose; onboarding never persists it.
217
- }
218
- }
219
- return undefined;
220
- }
221
- function asProviderScope(value, keys) {
222
- if (!isRecord(value))
223
- return null;
224
- const id = keys.id.map((key) => value[key])
225
- .find((item) => typeof item === "string" && item.length > 0);
226
- if (!id)
227
- return null;
228
- const displayName = keys.name.map((key) => value[key])
229
- .find((item) => typeof item === "string" && item.length > 0) ?? id;
230
- const metadata = Object.fromEntries(["region", "status", "workspaceName", "workspace_name", "organizationName"]
231
- .flatMap((key) => value[key] === undefined ? [] : [[key, value[key]]]));
232
- return safeScopeOption({ id, displayName, metadata });
233
- }
234
- function providerScopeContainer(provider, value) {
235
- const definition = MCP_PROVIDER_REGISTRY[provider].scopeIdentity;
236
- const candidates = [
237
- ...definition.containers.map((key) => value[key]),
238
- ];
239
- const user = value.user;
240
- if (provider === "linear" && isRecord(user)) {
241
- candidates.push(...definition.containers.map((key) => user[key]));
242
- }
243
- const bot = value.bot;
244
- if (provider === "notion" && isRecord(bot)) {
245
- candidates.push(...definition.containers.map((key) => bot[key]));
246
- }
247
- const self = value.self;
248
- if (provider === "notion" && isRecord(self)) {
249
- candidates.push(...definition.containers.map((key) => self[key]));
250
- }
251
- return candidates.find(isRecord) ?? null;
252
- }
253
- /**
254
- * Official identity tools return an actor plus an explicit workspace or
255
- * organization. The actor id is never a valid Rudder connection scope.
256
- */
257
- export function parseProviderWorkspaceScope(provider, value) {
258
- if (!isRecord(value))
259
- return null;
260
- const container = providerScopeContainer(provider, value);
261
- if (container) {
262
- return asProviderScope(container, {
263
- id: ["workspace_id", "workspaceId", "organization_id", "organizationId", "id"],
264
- name: [
265
- "workspace_name",
266
- "workspaceName",
267
- "organization_name",
268
- "organizationName",
269
- "name",
270
- ],
271
- });
272
- }
273
- if (provider === "linear"
274
- && typeof value.id === "string"
275
- && value.id.length > 0
276
- && Array.isArray(value.teams)
277
- && value.teams.some((team) => isRecord(team) && typeof team.id === "string")) {
278
- const authorizationName = typeof value.name === "string" && value.name.length > 0
279
- ? `${value.name}'s Linear authorization`
280
- : "Linear authorization";
281
- const opaqueSubjectId = createHash("sha256")
282
- .update(`linear-authorization-subject:${value.id}`)
283
- .digest("hex")
284
- .slice(0, 24);
285
- return safeScopeOption({
286
- id: `linear-authorization-subject-${opaqueSubjectId}`,
287
- displayName: authorizationName,
288
- metadata: {
289
- scopeKind: "authorization_subject",
290
- },
291
- });
292
- }
293
- const nested = provider === "notion" && isRecord(value.bot) ? value.bot : value;
294
- return asProviderScope(nested, {
295
- id: ["workspace_id", "workspaceId", "organization_id", "organizationId"],
296
- name: [
297
- "workspace_name",
298
- "workspaceName",
299
- "organization_name",
300
- "organizationName",
301
- ],
302
- });
303
- }
304
- async function defaultDiscoverProviderScope(input) {
305
- const curatedOrigin = new URL(MCP_PROVIDER_REGISTRY[input.provider].endpoint).origin;
306
- const client = await createManagedMcpClient({
307
- transport: "streamable_http",
308
- url: input.endpoint,
309
- credentials: resolveMcpHttpCredentials({ bearerToken: accessToken(input.material) }),
310
- network: {
311
- allowedOrigins: input.allowlists.httpOrigins,
312
- curatedOrigin,
313
- lookup: input.dnsLookup,
314
- },
315
- startupTimeoutMs: input.connection.startupTimeoutMs,
316
- toolTimeoutMs: input.connection.toolTimeoutMs,
317
- });
318
- try {
319
- if (input.provider === "supabase") {
320
- const parsed = parseToolJson(await client.callTool("list_projects", {}));
321
- const rawProjects = Array.isArray(parsed)
322
- ? parsed
323
- : isRecord(parsed) && Array.isArray(parsed.projects)
324
- ? parsed.projects
325
- : [];
326
- const options = rawProjects
327
- .map((project) => asProviderScope(project, {
328
- id: ["ref", "id", "project_ref"],
329
- name: ["name", "display_name", "ref", "id"],
330
- }))
331
- .filter((option) => Boolean(option));
332
- return { options };
333
- }
334
- const identity = MCP_PROVIDER_REGISTRY[input.provider].scopeIdentity;
335
- if (!identity)
336
- throw new Error("Provider did not define workspace identity discovery");
337
- const tools = await client.discoverTools();
338
- const identityTool = identity.toolNames.find((name) => (tools.some((tool) => tool.name === name)));
339
- if (!identityTool) {
340
- throw new Error("Provider did not expose a safe workspace identity tool");
341
- }
342
- const parsed = parseToolJson(await client.callTool(identityTool, identity.arguments));
343
- const selected = parseProviderWorkspaceScope(input.provider, parsed);
344
- if (!selected)
345
- throw new Error("Provider workspace identity was invalid");
346
- return { options: [], selected };
347
- }
348
- finally {
349
- await client.close();
350
- }
351
- }
352
127
  async function prepareOAuthSecret(connectionName, kind, material) {
353
128
  const id = randomUUID();
354
129
  const prepared = await getSecretProvider("local_encrypted").createVersion({
@@ -383,17 +158,6 @@ async function insertOAuthSecret(tx, input) {
383
158
  createdByUserId: input.actorUserId ?? null,
384
159
  });
385
160
  }
386
- function parseOAuthMaterial(value) {
387
- try {
388
- const parsed = JSON.parse(value);
389
- if (!isRecord(parsed))
390
- throw new Error("invalid");
391
- return parsed;
392
- }
393
- catch {
394
- throw unprocessable("Managed MCP OAuth credentials are unavailable");
395
- }
396
- }
397
161
  export function managedMcpOAuthService(db, options) {
398
162
  const grantRefreshSingleFlights = new Map();
399
163
  const runAuth = options.oauthAuth ?? auth;
@@ -471,8 +235,8 @@ export function managedMcpOAuthService(db, options) {
471
235
  .for("share")
472
236
  .then((rows) => rows[0] ?? null));
473
237
  }
474
- async function requireUsableGrant(orgId, connectionId) {
475
- const outcome = await db.transaction(async (tx) => {
238
+ async function requireUsableGrant(orgId, connectionId, executor) {
239
+ const validate = async (tx) => {
476
240
  const connection = await tx.select().from(mcpConnections)
477
241
  .where(and(eq(mcpConnections.orgId, orgId), eq(mcpConnections.id, connectionId)))
478
242
  .for("update")
@@ -493,7 +257,10 @@ export function managedMcpOAuthService(db, options) {
493
257
  return { kind: "invalid_authorizer" };
494
258
  }
495
259
  return { kind: "usable", grant };
496
- });
260
+ };
261
+ const outcome = executor
262
+ ? await validate(executor)
263
+ : await db.transaction(validate);
497
264
  if (outcome.kind === "invalid_authorizer") {
498
265
  throw unprocessable("Managed MCP OAuth authorization must be reconnected by an owner");
499
266
  }
@@ -557,6 +324,25 @@ export function managedMcpOAuthService(db, options) {
557
324
  dnsLookup: options.dnsLookup,
558
325
  });
559
326
  }
327
+ async function validateProviderTools(input) {
328
+ if (options.validateProviderTools) {
329
+ await options.validateProviderTools({
330
+ provider: input.connection.provider,
331
+ connection: input.connection,
332
+ material: input.material,
333
+ endpoint: input.endpoint,
334
+ });
335
+ return;
336
+ }
337
+ await defaultValidateProviderTools({
338
+ provider: input.connection.provider,
339
+ connection: input.connection,
340
+ material: input.material,
341
+ endpoint: input.endpoint,
342
+ allowlists: options.allowlists,
343
+ dnsLookup: options.dnsLookup,
344
+ });
345
+ }
560
346
  async function bestEffortRevokeMaterial(material, timeoutMs) {
561
347
  const revocationEndpoint = oauthRevocationEndpoint(material);
562
348
  const tokens = material?.tokens;
@@ -668,14 +454,24 @@ export function managedMcpOAuthService(db, options) {
668
454
  }
669
455
  return cleaned;
670
456
  }
671
- async function start(orgId, connectionId, actor) {
457
+ async function start(orgId, connectionId, actor, request = {}) {
672
458
  await cleanupExpiredSessions(orgId);
673
459
  const connection = await findConnection(orgId, connectionId);
674
460
  assertCurated(connection);
461
+ if (connection.canonicalState !== "canonical"
462
+ && !isSupabaseAccountUpgradeCandidate(connection)) {
463
+ throw unprocessable("Superseded MCP connections cannot start authorization");
464
+ }
675
465
  if (options.deploymentMode === "authenticated"
676
466
  && !actor.userId) {
677
467
  throw unprocessable("Managed MCP OAuth requires an authenticated authorizing user");
678
468
  }
469
+ if (request.requestedAccessMode
470
+ && (!["supabase", "linear"].includes(connection.provider)
471
+ || connection.status !== "active"
472
+ || !connection.enabled)) {
473
+ throw unprocessable("Managed MCP access changes require an active Supabase or Linear connection");
474
+ }
679
475
  let redirectUri;
680
476
  try {
681
477
  redirectUri = resolveMcpOAuthRedirectUri({
@@ -697,7 +493,12 @@ export function managedMcpOAuthService(db, options) {
697
493
  material = structuredClone(next);
698
494
  },
699
495
  });
700
- const authorization = createOAuthAuthorizationSnapshot(connection);
496
+ const authorization = createOAuthAuthorizationSnapshot({
497
+ ...connection,
498
+ ...(request.requestedAccessMode
499
+ ? { accessMode: request.requestedAccessMode }
500
+ : {}),
501
+ });
701
502
  const result = await runAuth(provider, {
702
503
  serverUrl: authorization.serverUrl,
703
504
  scope: authorization.scope,
@@ -726,27 +527,30 @@ export function managedMcpOAuthService(db, options) {
726
527
  if (!locked)
727
528
  throw notFound("MCP connection not found");
728
529
  assertCurated(locked);
530
+ if (isSupabaseAccountUpgradeCandidate(locked)) {
531
+ const legacy = await tx.select().from(mcpConnections)
532
+ .where(and(eq(mcpConnections.orgId, orgId), eq(mcpConnections.id, locked.supersededByConnectionId), eq(mcpConnections.provider, "supabase"), eq(mcpConnections.scopeMode, "legacy_project"), eq(mcpConnections.canonicalState, "canonical")))
533
+ .for("share")
534
+ .then((rows) => rows[0] ?? null);
535
+ if (!legacy) {
536
+ throw unprocessable("Supabase account upgrade is no longer available");
537
+ }
538
+ }
729
539
  if (locked.lifecycleRevision !== connection.lifecycleRevision) {
730
540
  throw unprocessable("Managed MCP OAuth connection changed; start authorization again");
731
541
  }
542
+ if (request.requestedAccessMode
543
+ && locked.accessMode !== connection.accessMode) {
544
+ throw unprocessable("Managed MCP access changed; start authorization again");
545
+ }
732
546
  const priorGrant = await tx.select().from(mcpOAuthGrants)
733
547
  .where(and(eq(mcpOAuthGrants.orgId, orgId), eq(mcpOAuthGrants.connectionId, connectionId)))
734
548
  .for("update")
735
549
  .then((rows) => rows[0] ?? null);
736
- if (priorGrant?.status === "active") {
737
- await tx.update(mcpOAuthGrants).set({
738
- status: "needs_reauth",
739
- statusMetadata: { reason: "authorization_restarted" },
740
- credentialSecretId: null,
741
- refreshLeaseNonce: null,
742
- refreshLeaseExpiresAt: null,
743
- updatedAt: now,
744
- }).where(eq(mcpOAuthGrants.id, priorGrant.id));
745
- if (priorGrant.credentialSecretId) {
746
- await tx.delete(organizationSecrets)
747
- .where(eq(organizationSecrets.id, priorGrant.credentialSecretId));
748
- }
749
- }
550
+ const isCredentialReplacement = priorGrant?.status === "active"
551
+ && Boolean(priorGrant.credentialSecretId)
552
+ && locked.status === "active"
553
+ && locked.enabled;
750
554
  const replacedSessions = await tx.select({
751
555
  id: mcpOAuthSessions.id,
752
556
  credentialSecretId: mcpOAuthSessions.credentialSecretId,
@@ -779,11 +583,17 @@ export function managedMcpOAuthService(db, options) {
779
583
  credentialSecretId: sessionSecret.id,
780
584
  redirectUri,
781
585
  status: "authorizing",
782
- statusMetadata: { authorization },
586
+ statusMetadata: {
587
+ authorization,
588
+ reauthorization: isCredentialReplacement,
589
+ ...(request.requestedAccessMode
590
+ ? { pendingAccessMode: request.requestedAccessMode }
591
+ : {}),
592
+ },
783
593
  expiresAt,
784
594
  });
785
595
  await tx.update(mcpConnections).set({
786
- status: "authorizing",
596
+ status: isCredentialReplacement ? "active" : "authorizing",
787
597
  enabled: true,
788
598
  disabledAt: null,
789
599
  revokedAt: null,
@@ -822,7 +632,8 @@ export function managedMcpOAuthService(db, options) {
822
632
  if (!connection)
823
633
  return null;
824
634
  assertCurated(connection);
825
- if (connection.status !== "authorizing")
635
+ if (connection.canonicalState !== "canonical"
636
+ && !isSupabaseAccountUpgradeCandidate(connection))
826
637
  return null;
827
638
  const lockedSession = await tx.select().from(mcpOAuthSessions)
828
639
  .where(and(eq(mcpOAuthSessions.id, session.id), eq(mcpOAuthSessions.stateHash, stateHash)))
@@ -831,6 +642,11 @@ export function managedMcpOAuthService(db, options) {
831
642
  if (!lockedSession || lockedSession.status !== "authorizing" || lockedSession.consumedAt) {
832
643
  return null;
833
644
  }
645
+ const isCredentialReplacement = lockedSession.statusMetadata.reauthorization === true;
646
+ if (connection.status !== "authorizing"
647
+ && !(isCredentialReplacement && connection.status === "active" && connection.enabled)) {
648
+ return null;
649
+ }
834
650
  if (lockedSession.expiresAt <= now) {
835
651
  await tx.update(mcpOAuthSessions).set({
836
652
  consumedAt: now,
@@ -892,12 +708,29 @@ export function managedMcpOAuthService(db, options) {
892
708
  .where(and(eq(mcpConnections.orgId, callbackContext.session.orgId), eq(mcpConnections.id, callbackContext.connection.id)))
893
709
  .for("update")
894
710
  .then((rows) => rows[0] ?? null);
711
+ const isCredentialReplacement = callbackContext.session.statusMetadata.reauthorization === true
712
+ && locked?.status === "active"
713
+ && locked.enabled;
895
714
  if (!locked
896
- || locked.status !== "authorizing"
715
+ || (locked.status !== "authorizing"
716
+ && !isCredentialReplacement)
897
717
  || locked.lifecycleRevision !== callbackContext.connectionLifecycleRevision) {
898
718
  return;
899
719
  }
900
720
  const now = new Date();
721
+ if (isCredentialReplacement) {
722
+ await tx.insert(activityLog).values(oauthActivityValues({
723
+ orgId: callbackContext.session.orgId,
724
+ connectionId: locked.id,
725
+ action: inputFailure.action,
726
+ actorUserId: callbackContext.session.authorizingUserId,
727
+ details: {
728
+ reason: inputFailure.reason,
729
+ existingGrantPreserved: true,
730
+ },
731
+ }));
732
+ return;
733
+ }
901
734
  await tx.update(mcpConnections).set({
902
735
  status: inputFailure.status,
903
736
  ...(inputFailure.status === "needs_reauth"
@@ -932,8 +765,10 @@ export function managedMcpOAuthService(db, options) {
932
765
  throw unprocessable("Managed MCP OAuth authorization was not completed");
933
766
  }
934
767
  const authorization = readOAuthAuthorizationSnapshot(consumed.session.statusMetadata, consumed.connection);
935
- if (consumed.connection.provider === "linear"
936
- && authorization.accessMode !== consumed.connection.accessMode) {
768
+ const stagedAccessMode = consumed.session.statusMetadata.reauthorization === true
769
+ && consumed.session.statusMetadata.pendingAccessMode === authorization.accessMode;
770
+ if (authorization.accessMode !== consumed.connection.accessMode
771
+ && !stagedAccessMode) {
937
772
  await finishFailure({
938
773
  status: "needs_reauth",
939
774
  action: "mcp_oauth.authorization_failed",
@@ -981,11 +816,13 @@ export function managedMcpOAuthService(db, options) {
981
816
  if (authResult !== "AUTHORIZED" || !grantMaterial.tokens?.access_token) {
982
817
  throw unprocessable("Managed MCP OAuth token exchange failed");
983
818
  }
984
- scope = await discoverScope({
985
- connection: consumed.connection,
986
- material: grantMaterial,
987
- endpoint: authorization.serverUrl,
988
- });
819
+ scope = consumed.connection.provider === "supabase"
820
+ ? { options: [] }
821
+ : await discoverScope({
822
+ connection: consumed.connection,
823
+ material: grantMaterial,
824
+ endpoint: authorization.serverUrl,
825
+ });
989
826
  }
990
827
  catch (error) {
991
828
  await finishUnpersistedGrantFailure({
@@ -999,23 +836,31 @@ export function managedMcpOAuthService(db, options) {
999
836
  throw error;
1000
837
  throw unprocessable("Managed MCP OAuth authorization could not be completed");
1001
838
  }
1002
- const safeOptions = sanitizeScopeOptions(scope.options);
1003
839
  const selected = scope.selected ? safeScopeOption(scope.selected) : undefined;
1004
- if (consumed.connection.provider === "supabase" && safeOptions.length === 0) {
840
+ if (consumed.connection.provider !== "supabase" && !selected) {
1005
841
  await finishUnpersistedGrantFailure({
1006
842
  status: "error",
1007
843
  action: "mcp_oauth.authorization_failed",
1008
- reason: "no_selectable_projects",
844
+ reason: "workspace_identity_unavailable",
1009
845
  });
1010
- throw unprocessable("Supabase OAuth did not return any selectable projects");
846
+ throw unprocessable("Managed MCP OAuth did not identify a provider workspace");
1011
847
  }
1012
- if (consumed.connection.provider !== "supabase" && !selected) {
848
+ try {
849
+ await validateProviderTools({
850
+ connection: consumed.connection,
851
+ material: grantMaterial,
852
+ endpoint: authorization.serverUrl,
853
+ });
854
+ }
855
+ catch (error) {
1013
856
  await finishUnpersistedGrantFailure({
1014
- status: "error",
857
+ status: isInvalidGrantOAuthError(error) ? "needs_reauth" : "error",
1015
858
  action: "mcp_oauth.authorization_failed",
1016
- reason: "workspace_identity_unavailable",
859
+ reason: "tool_discovery_failed",
1017
860
  });
1018
- throw unprocessable("Managed MCP OAuth did not identify a provider workspace");
861
+ if (error instanceof HttpError)
862
+ throw error;
863
+ throw unprocessable("Managed MCP OAuth tool discovery could not be completed");
1019
864
  }
1020
865
  const outcome = await (async () => {
1021
866
  try {
@@ -1028,10 +873,23 @@ export function managedMcpOAuthService(db, options) {
1028
873
  .for("update")
1029
874
  .then((rows) => rows[0] ?? null);
1030
875
  if (!connection
1031
- || connection.status !== "authorizing"
876
+ || (connection.status !== "authorizing"
877
+ && !(consumed.session.statusMetadata.reauthorization === true
878
+ && connection.status === "active"
879
+ && connection.enabled))
1032
880
  || connection.lifecycleRevision !== consumed.connectionLifecycleRevision) {
1033
881
  return null;
1034
882
  }
883
+ const legacyUpgradeConnection = isSupabaseAccountUpgradeCandidate(connection)
884
+ ? await tx.select().from(mcpConnections)
885
+ .where(and(eq(mcpConnections.orgId, connection.orgId), eq(mcpConnections.id, connection.supersededByConnectionId), eq(mcpConnections.provider, "supabase"), eq(mcpConnections.scopeMode, "legacy_project"), eq(mcpConnections.canonicalState, "canonical")))
886
+ .for("update")
887
+ .then((rows) => rows[0] ?? null)
888
+ : null;
889
+ if (isSupabaseAccountUpgradeCandidate(connection)
890
+ && !legacyUpgradeConnection) {
891
+ return null;
892
+ }
1035
893
  const stillAuthorized = options.deploymentMode === "local_trusted"
1036
894
  && !consumed.session.authorizingUserId
1037
895
  ? true
@@ -1046,19 +904,27 @@ export function managedMcpOAuthService(db, options) {
1046
904
  .for("share")
1047
905
  .then((rows) => rows[0] ?? null));
1048
906
  if (!stillAuthorized) {
1049
- await tx.update(mcpConnections).set({
1050
- status: "needs_reauth",
1051
- enabled: false,
1052
- disabledAt: now,
1053
- lifecycleRevision: connection.lifecycleRevision + 1,
1054
- updatedAt: now,
1055
- }).where(eq(mcpConnections.id, connection.id));
907
+ const existingGrantPreserved = consumed.session.statusMetadata.reauthorization === true
908
+ && connection.status === "active"
909
+ && connection.enabled;
910
+ if (!existingGrantPreserved) {
911
+ await tx.update(mcpConnections).set({
912
+ status: "needs_reauth",
913
+ enabled: false,
914
+ disabledAt: now,
915
+ lifecycleRevision: connection.lifecycleRevision + 1,
916
+ updatedAt: now,
917
+ }).where(eq(mcpConnections.id, connection.id));
918
+ }
1056
919
  await tx.insert(activityLog).values(oauthActivityValues({
1057
920
  orgId: consumed.session.orgId,
1058
921
  connectionId: connection.id,
1059
922
  action: "mcp_oauth.authorization_rejected",
1060
923
  actorUserId: consumed.session.authorizingUserId,
1061
- details: { reason: "authorizer_no_longer_authorized" },
924
+ details: {
925
+ reason: "authorizer_no_longer_authorized",
926
+ existingGrantPreserved,
927
+ },
1062
928
  }));
1063
929
  return { kind: "reauth" };
1064
930
  }
@@ -1080,9 +946,6 @@ export function managedMcpOAuthService(db, options) {
1080
946
  status: "active",
1081
947
  statusMetadata: {
1082
948
  authorization,
1083
- ...(connection.provider === "supabase"
1084
- ? { scopeOptions: safeOptions }
1085
- : {}),
1086
949
  },
1087
950
  expiresAt: tokenExpiry(grantMaterial.tokens, now),
1088
951
  lastRefreshedAt: now,
@@ -1106,16 +969,62 @@ export function managedMcpOAuthService(db, options) {
1106
969
  await tx.delete(organizationSecrets)
1107
970
  .where(eq(organizationSecrets.id, existingGrant.credentialSecretId));
1108
971
  }
1109
- const status = connection.provider === "supabase" ? "selecting_scope" : "active";
972
+ const status = "active";
973
+ if (legacyUpgradeConnection) {
974
+ const legacyGrant = await tx.select().from(mcpOAuthGrants)
975
+ .where(and(eq(mcpOAuthGrants.orgId, connection.orgId), eq(mcpOAuthGrants.connectionId, legacyUpgradeConnection.id)))
976
+ .for("update")
977
+ .then((rows) => rows[0] ?? null);
978
+ await tx.update(mcpConnections).set({
979
+ canonicalState: "superseded",
980
+ supersededByConnectionId: connection.id,
981
+ status: "revoked",
982
+ enabled: false,
983
+ revokedAt: now,
984
+ lifecycleRevision: legacyUpgradeConnection.lifecycleRevision + 1,
985
+ revision: legacyUpgradeConnection.revision + 1,
986
+ updatedAt: now,
987
+ }).where(eq(mcpConnections.id, legacyUpgradeConnection.id));
988
+ await tx.update(agentCustomIntegrationBindings).set({
989
+ accessMode: "none",
990
+ policyRevision: sql `${agentCustomIntegrationBindings.policyRevision} + 1`,
991
+ updatedAt: now,
992
+ }).where(and(eq(agentCustomIntegrationBindings.orgId, connection.orgId), eq(agentCustomIntegrationBindings.connectionId, legacyUpgradeConnection.id)));
993
+ if (legacyGrant) {
994
+ await tx.update(mcpOAuthGrants).set({
995
+ status: "revoked",
996
+ credentialSecretId: null,
997
+ revokedAt: now,
998
+ updatedAt: now,
999
+ }).where(eq(mcpOAuthGrants.id, legacyGrant.id));
1000
+ if (legacyGrant.credentialSecretId) {
1001
+ await tx.delete(organizationSecrets)
1002
+ .where(eq(organizationSecrets.id, legacyGrant.credentialSecretId));
1003
+ }
1004
+ }
1005
+ }
1110
1006
  await tx.update(mcpConnections).set({
1111
1007
  status,
1112
- externalScope: selected?.id ?? null,
1113
- safeConfig: connection.provider === "supabase"
1114
- ? {}
1115
- : connection.safeConfig,
1008
+ accessMode: stagedAccessMode
1009
+ ? authorization.accessMode
1010
+ : connection.accessMode,
1011
+ externalScope: connection.provider === "supabase"
1012
+ ? legacyUpgradeConnection || connection.scopeMode === "account"
1013
+ ? null
1014
+ : connection.externalScope
1015
+ : selected?.id ?? null,
1016
+ scopeMode: legacyUpgradeConnection ? "account" : connection.scopeMode,
1017
+ safeConfig: legacyUpgradeConnection ? {} : connection.safeConfig,
1018
+ canonicalState: legacyUpgradeConnection
1019
+ ? "canonical"
1020
+ : connection.canonicalState,
1021
+ supersededByConnectionId: legacyUpgradeConnection
1022
+ ? null
1023
+ : connection.supersededByConnectionId,
1116
1024
  enabled: true,
1117
1025
  activatedAt: status === "active" ? connection.activatedAt ?? now : null,
1118
1026
  lifecycleRevision: connection.lifecycleRevision + 1,
1027
+ revision: connection.revision + 1,
1119
1028
  updatedAt: now,
1120
1029
  }).where(eq(mcpConnections.id, connection.id));
1121
1030
  await tx.insert(activityLog).values(oauthActivityValues({
@@ -1158,7 +1067,11 @@ export function managedMcpOAuthService(db, options) {
1158
1067
  throw unprocessable("Managed MCP OAuth must be reauthorized by an owner");
1159
1068
  }
1160
1069
  if (outcome.status === "active" && options.refreshConnectionTools) {
1161
- await options.refreshConnectionTools(outcome.orgId, outcome.connectionId, { userId: outcome.authorizingUserId, agentId: null });
1070
+ // The replacement grant was already validated before the atomic swap.
1071
+ // A transient second discovery must not turn a successfully swapped
1072
+ // connection into an outage. Keep the last known-safe catalog and let a
1073
+ // later refresh reconcile it.
1074
+ await options.refreshConnectionTools(outcome.orgId, outcome.connectionId, { userId: outcome.authorizingUserId, agentId: null }).catch(() => undefined);
1162
1075
  }
1163
1076
  return { connectionId: outcome.connectionId, status: outcome.status };
1164
1077
  }