@opengeni/api-router 0.30.1 → 1.0.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 (436) hide show
  1. package/dist/access-grant-rls.d.ts +3 -0
  2. package/dist/admission-trace.d.ts +8 -0
  3. package/dist/api-websocket.d.ts +18 -0
  4. package/dist/app.d.ts +50 -2
  5. package/dist/app.js +12 -1
  6. package/dist/artifact-catalog-cursor.d.ts +27 -0
  7. package/dist/auth/managed-auth-attempt-context.d.ts +10 -0
  8. package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
  9. package/dist/auth/managed-auth-session-adapter.d.ts +6 -0
  10. package/dist/auth/managed-auth.d.ts +102 -3
  11. package/dist/auth/managed-email.d.ts +29 -0
  12. package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
  13. package/dist/auth/new-signups-gate.d.ts +23 -0
  14. package/dist/auth/organization-user-setup.d.ts +80 -0
  15. package/dist/auth/signup-funnel-metrics.d.ts +44 -0
  16. package/dist/browser-controller-authority.d.ts +1 -61
  17. package/dist/browser-ephemeral.d.ts +5 -0
  18. package/dist/browser-state-authority.d.ts +1 -27
  19. package/dist/chunk-6TZ5LG3O.js +123948 -0
  20. package/dist/chunk-6TZ5LG3O.js.map +1 -0
  21. package/dist/chunk-OGQDXVXY.js +18 -0
  22. package/dist/chunk-OGQDXVXY.js.map +1 -0
  23. package/dist/claude-subscription-account-conflicts.d.ts +1 -0
  24. package/dist/claude-subscription-account-usage.d.ts +39 -0
  25. package/dist/claude-subscription-oauth.d.ts +25 -0
  26. package/dist/claude-subscription-profile.d.ts +9 -0
  27. package/dist/claude-subscription-usage.d.ts +44 -0
  28. package/dist/claude-workspace-connection.d.ts +15 -0
  29. package/dist/codemode.d.ts +32 -1
  30. package/dist/company-brain-okf.d.ts +24 -0
  31. package/dist/connected-machine-computer-access.d.ts +11 -0
  32. package/dist/connection-ownership.d.ts +54 -0
  33. package/dist/controller-data-plane.d.ts +32 -0
  34. package/dist/editable-artifact-office-import.d.ts +7 -4
  35. package/dist/editable-artifact-source-session.d.ts +3 -0
  36. package/dist/editable-artifact-websocket.d.ts +10 -18
  37. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  38. package/dist/fatal-process-boundary.d.ts +25 -0
  39. package/dist/github-access.d.ts +31 -2
  40. package/dist/http/acting-person.d.ts +24 -0
  41. package/dist/http/api-contract-compat.d.ts +19 -0
  42. package/dist/http/api-error.d.ts +27 -1
  43. package/dist/http/cors.d.ts +17 -0
  44. package/dist/http/deprecation.d.ts +42 -0
  45. package/dist/http/interaction-control-error.d.ts +13 -0
  46. package/dist/http/keyed-admission.d.ts +12 -0
  47. package/dist/http/local-browser-boundary.d.ts +72 -0
  48. package/dist/http/metrics-listener.d.ts +22 -0
  49. package/dist/http/path-identifier.d.ts +17 -0
  50. package/dist/http/registered-route-label.d.ts +16 -0
  51. package/dist/http/request-body.d.ts +27 -0
  52. package/dist/http/request-source.d.ts +52 -0
  53. package/dist/http/sse.d.ts +17 -6
  54. package/dist/http/unmatched-route.d.ts +18 -0
  55. package/dist/http/user-content.d.ts +36 -0
  56. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  57. package/dist/index.d.ts +10 -3
  58. package/dist/index.js +1129 -166
  59. package/dist/index.js.map +1 -1
  60. package/dist/integration-endpoint-test.d.ts +20 -0
  61. package/dist/integrations/api-integrations.d.ts +2 -2
  62. package/dist/integrations/atlassian.d.ts +29 -3
  63. package/dist/integrations/connect-authority.d.ts +1 -0
  64. package/dist/integrations/connect-callback-return.d.ts +6 -0
  65. package/dist/integrations/fiken.d.ts +16 -2
  66. package/dist/integrations/github-app-connect.d.ts +47 -0
  67. package/dist/integrations/github-installation-proof.d.ts +3 -0
  68. package/dist/integrations/github-lens-connect.d.ts +116 -0
  69. package/dist/integrations/github-skill-source.d.ts +1 -5
  70. package/dist/integrations/google-drive.d.ts +25 -0
  71. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  72. package/dist/integrations/marketplace-plugin.d.ts +2691 -0
  73. package/dist/integrations/oauth-client.d.ts +178 -18
  74. package/dist/integrations/oauth-profiles.d.ts +222 -0
  75. package/dist/integrations/oauth-return-path.d.ts +1 -0
  76. package/dist/integrations/personal-github-repositories.d.ts +84 -0
  77. package/dist/integrations/personal-github.d.ts +42 -0
  78. package/dist/integrations/pr-review-provider.d.ts +22 -0
  79. package/dist/integrations/provider-oauth.d.ts +19 -1
  80. package/dist/integrations/slack-app-home.d.ts +24 -0
  81. package/dist/integrations/slack-bot.d.ts +367 -12
  82. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  83. package/dist/integrations/slack-install.d.ts +20 -0
  84. package/dist/integrations/slack-interactions.d.ts +113 -10
  85. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  86. package/dist/integrations/slack-routing.d.ts +120 -0
  87. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  88. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  89. package/dist/integrations/social-oauth.d.ts +7 -0
  90. package/dist/interaction-agent-access.d.ts +15 -0
  91. package/dist/interaction-frame-proxy.d.ts +68 -0
  92. package/dist/interaction-metrics.d.ts +2 -0
  93. package/dist/mcp/action-catalog-types.d.ts +9 -0
  94. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  95. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  96. package/dist/mcp/child-read-evidence.d.ts +9 -0
  97. package/dist/mcp/command-read.d.ts +24 -0
  98. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  99. package/dist/mcp/contract-input.d.ts +11 -0
  100. package/dist/mcp/documents.d.ts +7 -5
  101. package/dist/mcp/files.d.ts +2 -2
  102. package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
  103. package/dist/mcp/knowledge-entries.d.ts +5 -0
  104. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  105. package/dist/mcp/receipts.d.ts +9 -0
  106. package/dist/mcp/request-abort.d.ts +19 -0
  107. package/dist/mcp/scheduled-task-input.d.ts +1189 -0
  108. package/dist/mcp/scheduled-task-view.d.ts +22 -4
  109. package/dist/mcp/server.d.ts +255 -3
  110. package/dist/mcp/session-event-view.d.ts +94 -0
  111. package/dist/mcp/session-view.d.ts +66 -2
  112. package/dist/mcp/session-wait.d.ts +174 -0
  113. package/dist/mcp-oauth.d.ts +52 -0
  114. package/dist/model-catalog.d.ts +11 -31
  115. package/dist/observability.d.ts +3 -1
  116. package/dist/organization-mcp.d.ts +52 -0
  117. package/dist/organization-recovery-notifications.d.ts +41 -0
  118. package/dist/routes/analytics-consent.d.ts +26 -0
  119. package/dist/routes/api-integrations.d.ts +25 -0
  120. package/dist/routes/api-keys.d.ts +17 -0
  121. package/dist/routes/artifact-catalog.d.ts +6 -0
  122. package/dist/routes/automations.d.ts +19 -0
  123. package/dist/routes/billing.d.ts +49 -0
  124. package/dist/routes/browser-sessions.d.ts +71 -3
  125. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  126. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  127. package/dist/routes/client-errors.d.ts +146 -0
  128. package/dist/routes/codex.d.ts +76 -2
  129. package/dist/routes/company-brain.d.ts +3 -0
  130. package/dist/routes/company-profile.d.ts +2 -1
  131. package/dist/routes/computer-sessions.d.ts +14 -0
  132. package/dist/routes/connect.d.ts +5 -0
  133. package/dist/routes/editable-artifacts.d.ts +2 -0
  134. package/dist/routes/external-identity-links.d.ts +6 -0
  135. package/dist/routes/feedback.d.ts +3 -0
  136. package/dist/routes/files.d.ts +4 -0
  137. package/dist/routes/github-browser-pages.d.ts +12 -0
  138. package/dist/routes/github.d.ts +2 -0
  139. package/dist/routes/insights-response-cache.d.ts +10 -0
  140. package/dist/routes/insights-usage.d.ts +12 -0
  141. package/dist/routes/insights.d.ts +30 -1
  142. package/dist/routes/knowledge.d.ts +3 -0
  143. package/dist/routes/managed-auth-session-sets.d.ts +26 -0
  144. package/dist/routes/managed-onboarding.d.ts +29 -0
  145. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  146. package/dist/routes/model-connection-access.d.ts +3 -0
  147. package/dist/routes/organization-integration-policy.d.ts +3 -0
  148. package/dist/routes/organization-integrations.d.ts +6 -0
  149. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  150. package/dist/routes/organization-model-providers.d.ts +3 -0
  151. package/dist/routes/organization-recovery.d.ts +19 -0
  152. package/dist/routes/organization-service-accounts.d.ts +3 -0
  153. package/dist/routes/organization-sessions.d.ts +26 -0
  154. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  155. package/dist/routes/personal-github.d.ts +3 -0
  156. package/dist/routes/pr-review-github.d.ts +3 -0
  157. package/dist/routes/pr-review.d.ts +3 -0
  158. package/dist/routes/session-artifact-associations.d.ts +4 -0
  159. package/dist/routes/session-history-imports.d.ts +9 -0
  160. package/dist/routes/sessions.d.ts +44 -6
  161. package/dist/routes/skill-content.d.ts +4 -0
  162. package/dist/routes/skill-install-authority.d.ts +6 -0
  163. package/dist/routes/subscription-account-pools.d.ts +34 -0
  164. package/dist/routes/subscription-pool-access.d.ts +16 -0
  165. package/dist/routes/supergrok.d.ts +6 -1
  166. package/dist/routes/usage-allowances.d.ts +12 -0
  167. package/dist/routes/user-resource-authorities.d.ts +3 -0
  168. package/dist/routes/workspace-artifacts.d.ts +2 -1
  169. package/dist/routes/workspace-capture.d.ts +10 -2
  170. package/dist/routes/workspace-integrations.d.ts +35 -0
  171. package/dist/routes/workspace-learning.d.ts +3 -0
  172. package/dist/routes/workspace-model-providers.d.ts +4 -0
  173. package/dist/routes/workspaces.d.ts +29 -0
  174. package/dist/sandbox/auth-callout.d.ts +8 -0
  175. package/dist/sandbox/channel-a.d.ts +19 -1
  176. package/dist/sandbox/connection-authority.d.ts +3 -0
  177. package/dist/sandbox/enrollment.d.ts +9 -1
  178. package/dist/sandbox/machines.d.ts +5 -2
  179. package/dist/sandbox/metrics-ingestion.d.ts +28 -20
  180. package/dist/sandbox/rematerialize.d.ts +2 -0
  181. package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
  182. package/dist/sandbox/viewer.d.ts +26 -1
  183. package/dist/sandbox-file-artifacts.d.ts +50 -0
  184. package/dist/scheduled-task-deletion.d.ts +13 -0
  185. package/dist/session-create-observability.d.ts +5 -0
  186. package/dist/session-event-view-MPS2OZD3.js +292 -0
  187. package/dist/session-event-view-MPS2OZD3.js.map +1 -0
  188. package/dist/site-session-origin.d.ts +13 -0
  189. package/dist/site-uploads.d.ts +41 -0
  190. package/dist/slack-reaction-files.d.ts +1 -1
  191. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  192. package/dist/temporal-schedule-sync.d.ts +26 -0
  193. package/dist/transcription/providers/xai-subscription.d.ts +1 -0
  194. package/dist/transcription/service.d.ts +2 -1
  195. package/dist/work-discovery-observability.d.ts +33 -0
  196. package/dist/workspace-artifact-content.d.ts +28 -0
  197. package/dist/workspace-artifact-provenance.d.ts +7 -0
  198. package/dist/workspace-delete-observability.d.ts +10 -0
  199. package/dist/workspace-deletion.d.ts +6 -0
  200. package/dist/workspace-state-projection.d.ts +3 -5
  201. package/dist/workspace-tool-gateway-observability.d.ts +17 -0
  202. package/dist/workspace-tool-gateway.d.ts +123 -0
  203. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  204. package/package.json +23 -19
  205. package/src/access-grant-rls.ts +75 -0
  206. package/src/admission-trace.ts +14 -0
  207. package/src/api-websocket.ts +23 -0
  208. package/src/app.ts +1974 -256
  209. package/src/artifact-catalog-cursor.ts +60 -0
  210. package/src/auth/managed-auth-attempt-context.ts +70 -0
  211. package/src/auth/managed-auth-rate-limits.ts +252 -0
  212. package/src/auth/managed-auth-session-adapter.ts +222 -0
  213. package/src/auth/managed-auth.ts +536 -60
  214. package/src/auth/managed-email.ts +174 -0
  215. package/src/auth/managed-sign-in-notifications.ts +81 -0
  216. package/src/auth/new-signups-gate.ts +49 -0
  217. package/src/auth/organization-user-setup.ts +307 -0
  218. package/src/auth/signup-funnel-metrics.ts +164 -0
  219. package/src/browser-controller-authority.ts +1 -186
  220. package/src/browser-ephemeral.ts +39 -0
  221. package/src/browser-state-authority.ts +1 -236
  222. package/src/claude-subscription-account-conflicts.ts +12 -0
  223. package/src/claude-subscription-account-usage.ts +48 -0
  224. package/src/claude-subscription-oauth.ts +362 -0
  225. package/src/claude-subscription-profile.ts +73 -0
  226. package/src/claude-subscription-usage.ts +97 -0
  227. package/src/claude-workspace-connection.ts +82 -0
  228. package/src/codemode.ts +194 -30
  229. package/src/codex-realtime.ts +8 -2
  230. package/src/company-brain-okf.ts +340 -0
  231. package/src/connected-machine-computer-access.ts +33 -0
  232. package/src/connection-ownership.ts +199 -0
  233. package/src/controller-data-plane.ts +81 -0
  234. package/src/editable-artifact-native-kernel.ts +26 -15
  235. package/src/editable-artifact-office-import.ts +77 -9
  236. package/src/editable-artifact-production.ts +23 -7
  237. package/src/editable-artifact-source-session.ts +123 -0
  238. package/src/editable-artifact-websocket.ts +27 -21
  239. package/src/editable-artifact-workspace-files.ts +31 -6
  240. package/src/fatal-process-boundary.ts +246 -0
  241. package/src/gateway-realtime.ts +1 -1
  242. package/src/github-access.ts +147 -5
  243. package/src/http/acting-person.ts +71 -0
  244. package/src/http/api-contract-compat.ts +49 -0
  245. package/src/http/api-error.ts +115 -1
  246. package/src/http/auth.ts +48 -0
  247. package/src/http/cors.ts +67 -0
  248. package/src/http/deprecation.ts +118 -0
  249. package/src/http/interaction-control-error.ts +164 -0
  250. package/src/http/keyed-admission.ts +29 -0
  251. package/src/http/local-browser-boundary.ts +343 -0
  252. package/src/http/metrics-listener.ts +57 -0
  253. package/src/http/path-identifier.ts +54 -0
  254. package/src/http/registered-route-label.ts +34 -0
  255. package/src/http/request-body.ts +127 -0
  256. package/src/http/request-source.ts +178 -0
  257. package/src/http/sse.ts +486 -132
  258. package/src/http/unmatched-route.ts +60 -0
  259. package/src/http/user-content.ts +158 -0
  260. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  261. package/src/index.ts +157 -52
  262. package/src/integration-endpoint-test.ts +291 -0
  263. package/src/integrations/api-integrations.ts +98 -11
  264. package/src/integrations/atlassian.ts +474 -136
  265. package/src/integrations/connect-authority.ts +2 -0
  266. package/src/integrations/connect-callback-return.ts +86 -0
  267. package/src/integrations/fiken.ts +354 -64
  268. package/src/integrations/github-app-connect.ts +435 -0
  269. package/src/integrations/github-installation-proof.ts +60 -0
  270. package/src/integrations/github-lens-connect.ts +76 -0
  271. package/src/integrations/github-skill-source.ts +2 -142
  272. package/src/integrations/google-drive.ts +820 -222
  273. package/src/integrations/integration-commit-authority.ts +69 -0
  274. package/src/integrations/marketplace-plugin.ts +48 -0
  275. package/src/integrations/oauth-client.ts +1356 -459
  276. package/src/integrations/oauth-profiles.ts +537 -0
  277. package/src/integrations/oauth-return-path.ts +18 -0
  278. package/src/integrations/personal-github-repositories.ts +674 -0
  279. package/src/integrations/personal-github.ts +825 -0
  280. package/src/integrations/pr-review-provider.ts +246 -0
  281. package/src/integrations/provider-oauth.ts +250 -22
  282. package/src/integrations/slack-app-home.ts +300 -0
  283. package/src/integrations/slack-bot.ts +963 -239
  284. package/src/integrations/slack-file-upload-flow.ts +147 -0
  285. package/src/integrations/slack-install.ts +83 -0
  286. package/src/integrations/slack-interactions.ts +3170 -474
  287. package/src/integrations/slack-mrkdwn.ts +193 -0
  288. package/src/integrations/slack-routing.ts +337 -0
  289. package/src/integrations/slack-session-defaults.ts +224 -0
  290. package/src/integrations/slack-task-file-upload.ts +323 -0
  291. package/src/integrations/social-oauth.ts +213 -15
  292. package/src/interaction-agent-access.ts +48 -0
  293. package/src/interaction-frame-proxy.ts +409 -0
  294. package/src/interaction-metrics.ts +30 -0
  295. package/src/mcp/action-catalog-types.ts +9 -0
  296. package/src/mcp/action-catalog.gen.ts +6696 -0
  297. package/src/mcp/capability-account-readiness.ts +17 -0
  298. package/src/mcp/child-read-evidence.ts +19 -0
  299. package/src/mcp/command-read.ts +109 -0
  300. package/src/mcp/company-profile-agent-admin.ts +198 -0
  301. package/src/mcp/contract-input.ts +141 -0
  302. package/src/mcp/documents.ts +65 -377
  303. package/src/mcp/editable-artifacts.ts +12 -6
  304. package/src/mcp/files.ts +80 -38
  305. package/src/mcp/first-party-tool-permissions.ts +305 -0
  306. package/src/mcp/knowledge-entries.ts +322 -0
  307. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  308. package/src/mcp/receipts.ts +34 -0
  309. package/src/mcp/request-abort.ts +44 -0
  310. package/src/mcp/scheduled-task-input.ts +76 -0
  311. package/src/mcp/scheduled-task-view.ts +44 -3
  312. package/src/mcp/server.ts +3030 -1267
  313. package/src/mcp/session-event-view.ts +383 -0
  314. package/src/mcp/session-view.ts +84 -3
  315. package/src/mcp/session-wait.ts +665 -0
  316. package/src/mcp-oauth.ts +1123 -0
  317. package/src/model-catalog.ts +91 -333
  318. package/src/observability.ts +15 -1
  319. package/src/organization-mcp.ts +397 -0
  320. package/src/organization-recovery-notifications.ts +103 -0
  321. package/src/routes/analytics-consent.ts +123 -0
  322. package/src/routes/api-integrations.ts +364 -74
  323. package/src/routes/api-keys.ts +336 -10
  324. package/src/routes/artifact-catalog.ts +279 -0
  325. package/src/routes/automations.ts +768 -0
  326. package/src/routes/billing.ts +461 -46
  327. package/src/routes/browser-sessions.ts +839 -131
  328. package/src/routes/canonical-human-identities.ts +90 -14
  329. package/src/routes/capabilities.ts +107 -6
  330. package/src/routes/channels.ts +20 -3
  331. package/src/routes/claude-subscription-accounts.ts +334 -0
  332. package/src/routes/claude-subscription-oauth.ts +142 -0
  333. package/src/routes/client-errors.ts +362 -0
  334. package/src/routes/codex.ts +833 -116
  335. package/src/routes/company-brain.ts +322 -0
  336. package/src/routes/company-profile.ts +65 -1
  337. package/src/routes/computer-sessions.ts +557 -106
  338. package/src/routes/connect.ts +1938 -0
  339. package/src/routes/connections.ts +1040 -349
  340. package/src/routes/documents.ts +488 -287
  341. package/src/routes/editable-artifacts.ts +79 -9
  342. package/src/routes/enrollments.ts +135 -39
  343. package/src/routes/environments.ts +154 -58
  344. package/src/routes/external-identity-links.ts +201 -0
  345. package/src/routes/feedback.ts +113 -0
  346. package/src/routes/files.ts +337 -39
  347. package/src/routes/github-browser-pages.ts +162 -0
  348. package/src/routes/github.ts +446 -144
  349. package/src/routes/insights-response-cache.ts +83 -0
  350. package/src/routes/insights-usage.ts +345 -0
  351. package/src/routes/insights.ts +153 -19
  352. package/src/routes/install.ts +133 -38
  353. package/src/routes/integration-facets.ts +107 -33
  354. package/src/routes/interaction-resources.ts +30 -3
  355. package/src/routes/knowledge.ts +488 -0
  356. package/src/routes/machines.ts +313 -15
  357. package/src/routes/managed-auth-session-sets.ts +1218 -0
  358. package/src/routes/managed-onboarding.ts +337 -0
  359. package/src/routes/managed-sign-in-methods.ts +433 -0
  360. package/src/routes/memory-slack-publications.ts +3 -2
  361. package/src/routes/model-connection-access.ts +208 -0
  362. package/src/routes/organization-integration-policy.ts +116 -0
  363. package/src/routes/organization-integrations.ts +326 -0
  364. package/src/routes/organization-mcp-connections.ts +178 -0
  365. package/src/routes/organization-memberships.ts +1019 -27
  366. package/src/routes/organization-model-providers.ts +293 -0
  367. package/src/routes/organization-recovery.ts +325 -0
  368. package/src/routes/organization-service-accounts.ts +128 -0
  369. package/src/routes/organization-sessions.ts +350 -0
  370. package/src/routes/personal-github-git-broker.ts +785 -0
  371. package/src/routes/personal-github.ts +370 -0
  372. package/src/routes/plugins.ts +251 -22
  373. package/src/routes/pr-review-github.ts +881 -0
  374. package/src/routes/pr-review.ts +622 -0
  375. package/src/routes/preference-registry.ts +12 -93
  376. package/src/routes/rigs.ts +167 -50
  377. package/src/routes/scheduled-tasks.ts +346 -41
  378. package/src/routes/session-artifact-associations.ts +87 -0
  379. package/src/routes/session-history-imports.ts +280 -0
  380. package/src/routes/sessions.ts +2306 -264
  381. package/src/routes/skill-content.ts +297 -0
  382. package/src/routes/skill-install-authority.ts +64 -0
  383. package/src/routes/skills.ts +62 -9
  384. package/src/routes/social.ts +46 -18
  385. package/src/routes/subscription-account-pools.ts +436 -0
  386. package/src/routes/subscription-pool-access.ts +126 -0
  387. package/src/routes/supergrok.ts +219 -303
  388. package/src/routes/transcription-recordings.ts +38 -3
  389. package/src/routes/transcriptions.ts +4 -0
  390. package/src/routes/usage-allowances.ts +378 -0
  391. package/src/routes/user-resource-authorities.ts +138 -0
  392. package/src/routes/video-generation.ts +14 -10
  393. package/src/routes/workspace-artifacts.ts +275 -69
  394. package/src/routes/workspace-capture.ts +21 -0
  395. package/src/routes/workspace-integrations.ts +576 -0
  396. package/src/routes/workspace-learning.ts +159 -0
  397. package/src/routes/workspace-model-providers.ts +148 -0
  398. package/src/routes/workspace-state.ts +38 -25
  399. package/src/routes/workspaces.ts +1004 -127
  400. package/src/sandbox/auth-callout.ts +96 -19
  401. package/src/sandbox/channel-a.ts +323 -24
  402. package/src/sandbox/connection-authority.ts +3 -0
  403. package/src/sandbox/enrollment.ts +81 -6
  404. package/src/sandbox/machines.ts +218 -76
  405. package/src/sandbox/metrics-ingestion.ts +411 -62
  406. package/src/sandbox/rematerialize.ts +121 -19
  407. package/src/sandbox/session-attach-variable-sets.ts +131 -0
  408. package/src/sandbox/viewer.ts +280 -25
  409. package/src/sandbox-file-artifacts.ts +413 -0
  410. package/src/scheduled-task-deletion.ts +138 -0
  411. package/src/session-create-observability.ts +46 -0
  412. package/src/session-realtime-context.ts +6 -3
  413. package/src/site-session-origin.ts +48 -0
  414. package/src/site-uploads.ts +224 -0
  415. package/src/slack-reaction-files.ts +16 -5
  416. package/src/temporal-schedule-cleanup.ts +13 -0
  417. package/src/temporal-schedule-sync.ts +74 -0
  418. package/src/transcription/providers/codex-subscription.ts +2 -0
  419. package/src/transcription/providers/openai.ts +1 -0
  420. package/src/transcription/providers/xai-subscription.ts +49 -3
  421. package/src/transcription/segmenter.ts +8 -2
  422. package/src/transcription/service.ts +43 -6
  423. package/src/work-discovery-observability.ts +121 -0
  424. package/src/workspace-artifact-content.ts +144 -0
  425. package/src/workspace-artifact-provenance.ts +104 -0
  426. package/src/workspace-delete-observability.ts +75 -0
  427. package/src/workspace-deletion.ts +73 -0
  428. package/src/workspace-state-projection.ts +18 -148
  429. package/src/workspace-tool-gateway-observability.ts +100 -0
  430. package/src/workspace-tool-gateway.ts +870 -0
  431. package/src/workspace-webhook-dispatch.ts +190 -0
  432. package/src/xai-subscription-auth.ts +9 -2
  433. package/dist/chunk-2PQMSRCB.js +0 -49759
  434. package/dist/chunk-2PQMSRCB.js.map +0 -1
  435. package/dist/routes/packs.d.ts +0 -3
  436. package/src/routes/packs.ts +0 -729
@@ -0,0 +1,116 @@
1
+ import { UpdateOrganizationIntegrationPolicyRequest } from "@opengeni/contracts";
2
+ import {
3
+ accountScopedApiKeyWorkspaceAuthority,
4
+ organizationIntegrationCatalog,
5
+ requireAccessContext,
6
+ requireCanonicalLocalAccountAdministrator,
7
+ type ApiRouteDeps,
8
+ } from "@opengeni/core";
9
+ import {
10
+ getOrganizationIntegrationPolicy,
11
+ updateOrganizationIntegrationPolicy,
12
+ } from "@opengeni/db/organization-integration-policy";
13
+ import { nestedPostgresSqlState } from "@opengeni/db";
14
+ import type { Context, Hono } from "hono";
15
+ import { HTTPException } from "hono/http-exception";
16
+ import { z } from "zod";
17
+ import { agentActingAsPerson } from "../http/acting-person";
18
+ import { requireSameOriginBrowserMutation } from "./codex";
19
+ import { managedCookieHuman } from "./supergrok";
20
+
21
+ /** The database rechecks current organization membership/key authority at commit. */
22
+ async function authorizeAdministration(
23
+ context: Context,
24
+ deps: ApiRouteDeps,
25
+ accountId: string,
26
+ mutation: boolean,
27
+ ): Promise<{ accountId: string; subjectId: string }> {
28
+ const access = await requireAccessContext(context, deps);
29
+ const service = accountScopedApiKeyWorkspaceAuthority(access);
30
+ if (service) {
31
+ if (service.accountId !== accountId || !service.permissions.includes("workspace:admin")) {
32
+ throw new HTTPException(403, { message: "Organization administration required" });
33
+ }
34
+ return { accountId, subjectId: access.subjectId };
35
+ }
36
+ if (deps.settings.productAccessMode === "local") {
37
+ const local = await requireCanonicalLocalAccountAdministrator(context, deps, accountId);
38
+ if (mutation) requireSameOriginBrowserMutation(context, deps);
39
+ return { accountId, subjectId: local.subjectId };
40
+ }
41
+ const human =
42
+ agentActingAsPerson(context, accountId, mutation ? "account:admin" : "account:read") ??
43
+ (await managedCookieHuman(context, deps));
44
+ if (!human || human.subjectId !== access.subjectId) {
45
+ throw new HTTPException(403, { message: "Organization administration required" });
46
+ }
47
+ if (mutation) requireSameOriginBrowserMutation(context, deps);
48
+ return { accountId, subjectId: human.subjectId };
49
+ }
50
+
51
+ async function policyResponse<T>(readOrWrite: () => Promise<T>): Promise<T> {
52
+ try {
53
+ return await readOrWrite();
54
+ } catch (error) {
55
+ if (error instanceof HTTPException) throw error;
56
+ const state = nestedPostgresSqlState(error);
57
+ if (state === "42501") {
58
+ throw new HTTPException(403, { message: "Organization administration required" });
59
+ }
60
+ if (state === "40001" || state === "23505") {
61
+ throw new HTTPException(409, {
62
+ message: "Integration policy changed; refresh before saving",
63
+ });
64
+ }
65
+ if (state === "22023") {
66
+ throw new HTTPException(422, { message: "Invalid integration policy" });
67
+ }
68
+ throw new HTTPException(503, { message: "Integration policy is temporarily unavailable" });
69
+ }
70
+ }
71
+
72
+ export function registerOrganizationIntegrationPolicyRoutes(app: Hono, deps: ApiRouteDeps): void {
73
+ const path = "/v1/organizations/:organizationId/integration-policy";
74
+ const organizationId = (context: Context) => {
75
+ const parsed = z.string().uuid().safeParse(context.req.param("organizationId"));
76
+ if (!parsed.success) throw new HTTPException(422, { message: "Invalid organization identity" });
77
+ return parsed.data.toLowerCase();
78
+ };
79
+ app.get(`${path}/catalog`, async (context) => {
80
+ const accountId = organizationId(context);
81
+ // The same live administration check as policy reads, including workspace-free service access.
82
+ await policyResponse(() =>
83
+ getOrganizationIntegrationPolicy(deps.db, { accountId }, () =>
84
+ authorizeAdministration(context, deps, accountId, false),
85
+ ),
86
+ );
87
+ context.header("cache-control", "private, no-store");
88
+ return context.json(organizationIntegrationCatalog());
89
+ });
90
+ app.get(path, async (context) => {
91
+ context.header("cache-control", "private, no-store");
92
+ const accountId = organizationId(context);
93
+ return context.json(
94
+ await policyResponse(() =>
95
+ getOrganizationIntegrationPolicy(deps.db, { accountId }, () =>
96
+ authorizeAdministration(context, deps, accountId, false),
97
+ ),
98
+ ),
99
+ );
100
+ });
101
+ app.put(path, async (context) => {
102
+ context.header("cache-control", "private, no-store");
103
+ const accountId = organizationId(context);
104
+ const parsed = UpdateOrganizationIntegrationPolicyRequest.safeParse(
105
+ await context.req.json().catch(() => null),
106
+ );
107
+ if (!parsed.success) throw new HTTPException(422, { message: "Invalid integration policy" });
108
+ return context.json(
109
+ await policyResponse(() =>
110
+ updateOrganizationIntegrationPolicy(deps.db, { accountId }, parsed.data, () =>
111
+ authorizeAdministration(context, deps, accountId, true),
112
+ ),
113
+ ),
114
+ );
115
+ });
116
+ }
@@ -0,0 +1,326 @@
1
+ import {
2
+ CreateOrganizationWebhookRequest,
3
+ CreateOrganizationWebhookResponse,
4
+ GetOrganizationCredentialProviderResponse,
5
+ ListOrganizationWebhookDeliveriesResponse,
6
+ ListOrganizationWebhooksResponse,
7
+ OrganizationCredentialProvider,
8
+ OrganizationWebhook,
9
+ PutOrganizationCredentialProviderRequest,
10
+ PutOrganizationCredentialProviderResponse,
11
+ RotateOrganizationCredentialProviderSecretResponse,
12
+ RotateOrganizationWebhookSecretResponse,
13
+ UpdateOrganizationWebhookRequest,
14
+ type AccessContext,
15
+ } from "@opengeni/contracts";
16
+ import {
17
+ accountScopedApiKeyWorkspaceAuthority,
18
+ accessGrantAuthorizationFromContext,
19
+ requireAccountAdminAuthorizationStamp,
20
+ requireAccessContext,
21
+ requireCanonicalLocalAccountAdministrator,
22
+ type AccessGrantAuthorization,
23
+ type ApiRouteDeps,
24
+ isVerifiedDelegatedHumanAuthorization,
25
+ } from "@opengeni/core";
26
+ import {
27
+ createOrganizationWebhook,
28
+ deleteOrganizationCredentialProvider,
29
+ deleteOrganizationWebhook,
30
+ encryptEnvironmentValue,
31
+ getOrganizationCredentialProvider,
32
+ getOrganizationWebhook,
33
+ listOrganizationWebhookDeliveries,
34
+ listOrganizationWebhooks,
35
+ OrganizationWebhookLimitError,
36
+ redeliverOrganizationWebhookDelivery,
37
+ rotateOrganizationCredentialProviderSecret,
38
+ rotateOrganizationWebhookSecret,
39
+ updateOrganizationWebhook,
40
+ upsertOrganizationCredentialProvider,
41
+ withCredentialProviderConfigurationLock,
42
+ type OrganizationCredentialProviderRow,
43
+ type OrganizationWebhookRow,
44
+ } from "@opengeni/db";
45
+ import type { Context, Hono } from "hono";
46
+ import { HTTPException } from "hono/http-exception";
47
+ import { z } from "zod";
48
+ import { organizationApiKeyAccess, requireOrganizationApiKeyControlPermission } from "./api-keys";
49
+ import { requireSameOriginBrowserMutation } from "./codex";
50
+ import {
51
+ integrationBody as body,
52
+ integrationDeliveryProjection as deliveryProjection,
53
+ integrationProviderFields,
54
+ integrationRouteConfiguration,
55
+ integrationWebhookFields,
56
+ isIntegrationAgent,
57
+ newIntegrationSecret,
58
+ } from "./workspace-integrations";
59
+
60
+ /** Account administrators or verified full-access organization keys; never workspace keys. */
61
+ export function requireOrganizationIntegrationAdmin(
62
+ context: AccessContext,
63
+ organizationId: string,
64
+ authorization?: AccessGrantAuthorization,
65
+ ): string {
66
+ if (context.workspaceGrants.some(isIntegrationAgent)) {
67
+ throw new HTTPException(403, {
68
+ message: "Agent attempts cannot manage organization integrations",
69
+ });
70
+ }
71
+ const grant = context.accountGrants.find(
72
+ (candidate) =>
73
+ candidate.accountId === organizationId && candidate.subjectId === context.subjectId,
74
+ );
75
+ if (!grant) {
76
+ throw new HTTPException(403, { message: "missing permission: account:admin" });
77
+ }
78
+ if (context.subjectId.startsWith("api_key:")) {
79
+ requireOrganizationApiKeyControlPermission(context, organizationId);
80
+ const authority = accountScopedApiKeyWorkspaceAuthority(context);
81
+ if (
82
+ !authority ||
83
+ authority.accountId !== organizationId ||
84
+ organizationApiKeyAccess(authority.permissions) !== "full"
85
+ ) {
86
+ throw new HTTPException(403, { message: "organization API key authority required" });
87
+ }
88
+ } else {
89
+ if (!grant.permissions.includes("account:admin"))
90
+ throw new HTTPException(403, { message: "missing permission: account:admin" });
91
+ if (
92
+ !authorization ||
93
+ !(
94
+ authorization.canonicalManagedHumanSession ||
95
+ authorization.canonicalLocalHumanSession ||
96
+ isVerifiedDelegatedHumanAuthorization(authorization)
97
+ ) ||
98
+ authorization.grant.accountId !== organizationId ||
99
+ authorization.authenticatedSubjectId !== context.subjectId ||
100
+ context.workspaceGrants.some((candidate) => candidate.metadata?.delegated === true)
101
+ ) {
102
+ throw new HTTPException(403, { message: "Canonical organization administrator required" });
103
+ }
104
+ requireAccountAdminAuthorizationStamp(authorization);
105
+ }
106
+ return grant.subjectId;
107
+ }
108
+
109
+ function providerProjection(
110
+ row: OrganizationCredentialProviderRow,
111
+ ): OrganizationCredentialProvider {
112
+ return OrganizationCredentialProvider.parse({
113
+ ...integrationProviderFields(row),
114
+ organizationId: row.accountId,
115
+ workspaceFilter: row.workspaceFilter,
116
+ });
117
+ }
118
+ function webhookProjection(row: OrganizationWebhookRow): OrganizationWebhook {
119
+ return OrganizationWebhook.parse({
120
+ ...integrationWebhookFields(row),
121
+ organizationId: row.accountId,
122
+ workspaceFilter: row.workspaceFilter,
123
+ });
124
+ }
125
+
126
+ export function registerOrganizationIntegrationRoutes(app: Hono, deps: ApiRouteDeps): void {
127
+ const scope = async (c: Context) => {
128
+ const id = z.string().uuid().safeParse(c.req.param("organizationId"));
129
+ if (!id.success) throw new HTTPException(422, { message: "invalid organization id" });
130
+ const context = await requireAccessContext(c, deps);
131
+ const accountId = id.data.toLowerCase();
132
+ let authorization: AccessGrantAuthorization | undefined;
133
+ if (!accountScopedApiKeyWorkspaceAuthority(context)) {
134
+ if (deps.settings.productAccessMode === "local") {
135
+ authorization = (await requireCanonicalLocalAccountAdministrator(c, deps, accountId))
136
+ .authorization;
137
+ } else {
138
+ const grant = context.workspaceGrants.find(
139
+ (candidate) => candidate.accountId === accountId,
140
+ );
141
+ if (grant) authorization = accessGrantAuthorizationFromContext(context, grant);
142
+ }
143
+ }
144
+ const subjectId = requireOrganizationIntegrationAdmin(context, accountId, authorization);
145
+ if (!accountScopedApiKeyWorkspaceAuthority(context) && !["GET", "HEAD"].includes(c.req.method))
146
+ requireSameOriginBrowserMutation(c, deps);
147
+ c.header("cache-control", "private, no-store");
148
+ return { accountId, subjectId };
149
+ };
150
+ const { requireKey, requireDeployableUrl: requireUrl } = integrationRouteConfiguration(
151
+ deps,
152
+ "organization",
153
+ );
154
+ const encrypted = (secret: string): string => encryptEnvironmentValue(requireKey(), secret);
155
+ const webhookId = (c: Context): string => {
156
+ const id = z.string().uuid().safeParse(c.req.param("webhookId"));
157
+ if (!id.success) throw new HTTPException(404, { message: "Webhook not found" });
158
+ return id.data;
159
+ };
160
+ const base = "/v1/organizations/:organizationId";
161
+ app.get(`${base}/credential-provider`, async (c) => {
162
+ const target = await scope(c);
163
+ const row = await getOrganizationCredentialProvider(deps.db, target);
164
+ return c.json(
165
+ GetOrganizationCredentialProviderResponse.parse({
166
+ provider: row ? providerProjection(row) : null,
167
+ }),
168
+ );
169
+ });
170
+ app.put(`${base}/credential-provider`, async (c) => {
171
+ const target = await scope(c);
172
+ const request = await body(c, PutOrganizationCredentialProviderRequest, 422);
173
+ requireUrl(request.url);
174
+ const {
175
+ row: providerRow,
176
+ secret: signingSecret,
177
+ created,
178
+ } = await withCredentialProviderConfigurationLock(deps.db, target, async (tx) => {
179
+ const existing = await getOrganizationCredentialProvider(tx, target);
180
+ const secret = existing ? undefined : newIntegrationSecret("ogcp");
181
+ const row = await upsertOrganizationCredentialProvider(tx, {
182
+ accountId: target.accountId,
183
+ url: request.url,
184
+ enabled: request.enabled ?? true,
185
+ timeoutMs: request.timeoutMs ?? 10_000,
186
+ workspaceFilter: request.workspaceFilter,
187
+ createdBySubjectId: target.subjectId,
188
+ ...(secret ? { secretEncrypted: encrypted(secret) } : {}),
189
+ });
190
+ return { row, secret, created: !existing };
191
+ });
192
+ return c.json(
193
+ PutOrganizationCredentialProviderResponse.parse({
194
+ provider: providerProjection(providerRow),
195
+ ...(signingSecret ? { secret: signingSecret } : {}),
196
+ }),
197
+ created ? 201 : 200,
198
+ );
199
+ });
200
+ app.delete(`${base}/credential-provider`, async (c) => {
201
+ await deleteOrganizationCredentialProvider(deps.db, await scope(c));
202
+ return c.body(null, 204);
203
+ });
204
+ app.post(`${base}/credential-provider/rotate-secret`, async (c) => {
205
+ const target = await scope(c);
206
+ const secret = newIntegrationSecret("ogcp");
207
+ const row = await rotateOrganizationCredentialProviderSecret(deps.db, {
208
+ ...target,
209
+ secretEncrypted: encrypted(secret),
210
+ });
211
+ if (!row) throw new HTTPException(404, { message: "Credential provider not found" });
212
+ return c.json(
213
+ RotateOrganizationCredentialProviderSecretResponse.parse({
214
+ provider: providerProjection(row),
215
+ secret,
216
+ }),
217
+ );
218
+ });
219
+ app.get(`${base}/webhooks`, async (c) => {
220
+ const rows = await listOrganizationWebhooks(deps.db, await scope(c));
221
+ return c.json(
222
+ ListOrganizationWebhooksResponse.parse({ webhooks: rows.map(webhookProjection) }),
223
+ );
224
+ });
225
+ app.post(`${base}/webhooks`, async (c) => {
226
+ const target = await scope(c);
227
+ const request = await body(c, CreateOrganizationWebhookRequest, 422);
228
+ requireUrl(request.url);
229
+ const secret = newIntegrationSecret("whsec");
230
+ try {
231
+ const row = await createOrganizationWebhook(deps.db, {
232
+ accountId: target.accountId,
233
+ url: request.url,
234
+ secretEncrypted: encrypted(secret),
235
+ eventTypes: request.eventTypes,
236
+ enabled: request.enabled ?? true,
237
+ description: request.description ?? null,
238
+ workspaceFilter: request.workspaceFilter,
239
+ createdBySubjectId: target.subjectId,
240
+ });
241
+ return c.json(
242
+ CreateOrganizationWebhookResponse.parse({ webhook: webhookProjection(row), secret }),
243
+ 201,
244
+ );
245
+ } catch (error) {
246
+ if (error instanceof OrganizationWebhookLimitError)
247
+ throw new HTTPException(409, { message: error.message });
248
+ throw error;
249
+ }
250
+ });
251
+ app.get(`${base}/webhooks/:webhookId`, async (c) => {
252
+ const target = await scope(c);
253
+ const row = await getOrganizationWebhook(deps.db, {
254
+ accountId: target.accountId,
255
+ webhookId: webhookId(c),
256
+ });
257
+ if (!row) throw new HTTPException(404, { message: "Webhook not found" });
258
+ return c.json(webhookProjection(row));
259
+ });
260
+ app.patch(`${base}/webhooks/:webhookId`, async (c) => {
261
+ const target = await scope(c);
262
+ const request = await body(c, UpdateOrganizationWebhookRequest, 422);
263
+ if (request.url) requireUrl(request.url);
264
+ const row = await updateOrganizationWebhook(deps.db, {
265
+ accountId: target.accountId,
266
+ webhookId: webhookId(c),
267
+ ...(request.url !== undefined ? { url: request.url } : {}),
268
+ ...(request.eventTypes !== undefined ? { eventTypes: request.eventTypes } : {}),
269
+ ...(request.enabled !== undefined ? { enabled: request.enabled } : {}),
270
+ ...(request.description !== undefined ? { description: request.description } : {}),
271
+ ...(request.workspaceFilter !== undefined
272
+ ? { workspaceFilter: request.workspaceFilter }
273
+ : {}),
274
+ });
275
+ if (!row) throw new HTTPException(404, { message: "Webhook not found" });
276
+ return c.json(webhookProjection(row));
277
+ });
278
+ app.delete(`${base}/webhooks/:webhookId`, async (c) => {
279
+ const target = await scope(c);
280
+ if (!(await deleteOrganizationWebhook(deps.db, { ...target, webhookId: webhookId(c) }))) {
281
+ throw new HTTPException(404, { message: "Webhook not found" });
282
+ }
283
+ return c.body(null, 204);
284
+ });
285
+ app.post(`${base}/webhooks/:webhookId/rotate-secret`, async (c) => {
286
+ const target = await scope(c);
287
+ const secret = newIntegrationSecret("whsec");
288
+ const row = await rotateOrganizationWebhookSecret(deps.db, {
289
+ ...target,
290
+ webhookId: webhookId(c),
291
+ secretEncrypted: encrypted(secret),
292
+ });
293
+ if (!row) throw new HTTPException(404, { message: "Webhook not found" });
294
+ return c.json(
295
+ RotateOrganizationWebhookSecretResponse.parse({
296
+ webhook: webhookProjection(row),
297
+ secret,
298
+ }),
299
+ );
300
+ });
301
+ app.get(`${base}/webhooks/:webhookId/deliveries`, async (c) => {
302
+ const target = { ...(await scope(c)), webhookId: webhookId(c) };
303
+ if (!(await getOrganizationWebhook(deps.db, target)))
304
+ throw new HTTPException(404, { message: "Webhook not found" });
305
+ const limit = z.coerce.number().int().min(1).max(200).catch(50).parse(c.req.query("limit"));
306
+ const rows = await listOrganizationWebhookDeliveries(deps.db, { ...target, limit });
307
+ return c.json(
308
+ ListOrganizationWebhookDeliveriesResponse.parse({ deliveries: rows.map(deliveryProjection) }),
309
+ );
310
+ });
311
+ app.post(`${base}/webhooks/:webhookId/deliveries/:deliveryId/redeliver`, async (c) => {
312
+ const target = await scope(c);
313
+ const id = z.string().uuid().safeParse(c.req.param("deliveryId"));
314
+ if (!id.success) throw new HTTPException(404, { message: "Delivery not found" });
315
+ const row = await redeliverOrganizationWebhookDelivery(deps.db, {
316
+ ...target,
317
+ webhookId: webhookId(c),
318
+ deliveryId: id.data,
319
+ });
320
+ if (!row)
321
+ throw new HTTPException(409, {
322
+ message: "Only a delivered or failed delivery can be redelivered",
323
+ });
324
+ return c.json(deliveryProjection(row));
325
+ });
326
+ }
@@ -0,0 +1,178 @@
1
+ import { OrganizationAccessPolicy, type AccessContext } from "@opengeni/contracts";
2
+ import {
3
+ getManagedUserProfilesByIds,
4
+ getWorkspace,
5
+ listOrganizationMcpConnections,
6
+ revokeOrganizationMcpConnection,
7
+ updateOrganizationMcpConnectionAccess,
8
+ type OrganizationMcpConnection,
9
+ } from "@opengeni/db";
10
+ import { hasPermission, requireAccessContext, type ApiRouteDeps } from "@opengeni/core";
11
+ import type { Context, Hono } from "hono";
12
+ import { HTTPException } from "hono/http-exception";
13
+ import { requireNotAgent } from "../http/acting-person";
14
+ import { z } from "zod";
15
+
16
+ import { requireSameOriginBrowserMutation } from "./codex";
17
+
18
+ /* ----------------------------------------------------------------------------
19
+ Connected agents: outside MCP clients people signed in to the organization
20
+ server with. Everyone sees and manages their own; owners and admins see and
21
+ can disconnect everyone's. Only the person who connected an agent changes
22
+ what it can do, and only from the browser: an agent can never widen its own
23
+ access through these routes.
24
+ -------------------------------------------------------------------------- */
25
+
26
+ const UpdateBody = z.object({ access: OrganizationAccessPolicy }).strict();
27
+
28
+ export function registerOrganizationMcpConnectionRoutes(app: Hono, deps: ApiRouteDeps): void {
29
+ app.get("/v1/organizations/:organizationId/mcp-connections", async (c) => {
30
+ const { context, organizationId, admin } = await requireOrganizationPerson(c, deps);
31
+ const connections = await listOrganizationMcpConnections(deps.db, {
32
+ accountId: organizationId,
33
+ ...(admin ? {} : { subjectId: context.subjectId }),
34
+ });
35
+ c.header("cache-control", "no-store");
36
+ return c.json({
37
+ connections: await projectConnections(deps, connections),
38
+ canManageAll: admin,
39
+ });
40
+ });
41
+
42
+ app.patch("/v1/organizations/:organizationId/mcp-connections/:connectionId", async (c) => {
43
+ requireSameOriginBrowserMutation(c, deps);
44
+ const { context, organizationId } = await requireOrganizationPerson(c, deps);
45
+ const connection = await requireConnection(deps, organizationId, c.req.param("connectionId"));
46
+ if (connection.subjectId !== context.subjectId) {
47
+ throw new HTTPException(403, {
48
+ message: "Only the person who connected this agent can change what it can do.",
49
+ });
50
+ }
51
+ const parsed = UpdateBody.safeParse(await c.req.json().catch(() => null));
52
+ if (!parsed.success) throw new HTTPException(400, { message: "invalid access setting" });
53
+ const access = parsed.data.access;
54
+ if (access.workspaceScope.kind === "selected") {
55
+ for (const workspaceId of access.workspaceScope.workspaceIds) {
56
+ const workspace = await getWorkspace(deps.db, workspaceId);
57
+ if (workspace?.accountId !== organizationId) {
58
+ throw new HTTPException(400, {
59
+ message: "a selected workspace is not in this organization",
60
+ });
61
+ }
62
+ }
63
+ }
64
+ await updateOrganizationMcpConnectionAccess(deps.db, {
65
+ accountId: organizationId,
66
+ connectionId: connection.id,
67
+ organizationAccess: access,
68
+ });
69
+ const [updated] = await projectConnections(
70
+ deps,
71
+ await listOrganizationMcpConnections(deps.db, {
72
+ accountId: organizationId,
73
+ connectionId: connection.id,
74
+ }),
75
+ );
76
+ if (!updated) throw new HTTPException(404, { message: "connected agent not found" });
77
+ return c.json(updated);
78
+ });
79
+
80
+ app.delete("/v1/organizations/:organizationId/mcp-connections/:connectionId", async (c) => {
81
+ requireSameOriginBrowserMutation(c, deps);
82
+ const { context, organizationId, admin } = await requireOrganizationPerson(c, deps);
83
+ const connection = await requireConnection(deps, organizationId, c.req.param("connectionId"));
84
+ if (connection.subjectId !== context.subjectId && !admin) {
85
+ throw new HTTPException(403, {
86
+ message: "Only the person who connected this agent, or an admin, can disconnect it.",
87
+ });
88
+ }
89
+ await revokeOrganizationMcpConnection(deps.db, {
90
+ accountId: organizationId,
91
+ connectionId: connection.id,
92
+ });
93
+ return c.body(null, 204);
94
+ });
95
+ }
96
+
97
+ /** A member of the organization, signed in in this browser. Keys and agents are refused. */
98
+ async function requireOrganizationPerson(
99
+ c: Context,
100
+ deps: ApiRouteDeps,
101
+ ): Promise<{ context: AccessContext; organizationId: string; admin: boolean }> {
102
+ requireNotAgent(c, "Managing connected agents");
103
+ if (
104
+ deps.settings.productAccessMode !== "managed" ||
105
+ !c.req.header("cookie") ||
106
+ c.req.header("authorization")
107
+ ) {
108
+ throw new HTTPException(403, {
109
+ message: "Manage connected agents in the Opengeni app in your browser.",
110
+ });
111
+ }
112
+ const context = await requireAccessContext(c, deps);
113
+ const organizationId = c.req.param("organizationId") ?? "";
114
+ const grant = context.accountGrants.find((each) => each.accountId === organizationId);
115
+ if (context.mode !== "managed" || !context.subjectId.startsWith("user:") || !grant) {
116
+ throw new HTTPException(404, { message: "organization not found" });
117
+ }
118
+ return { context, organizationId, admin: hasPermission(grant.permissions, "account:admin") };
119
+ }
120
+
121
+ async function requireConnection(
122
+ deps: ApiRouteDeps,
123
+ organizationId: string,
124
+ connectionId: string,
125
+ ): Promise<OrganizationMcpConnection> {
126
+ if (!z.string().uuid().safeParse(connectionId).success) {
127
+ throw new HTTPException(404, { message: "connected agent not found" });
128
+ }
129
+ const [connection] = await listOrganizationMcpConnections(deps.db, {
130
+ accountId: organizationId,
131
+ connectionId,
132
+ });
133
+ if (!connection) throw new HTTPException(404, { message: "connected agent not found" });
134
+ return connection;
135
+ }
136
+
137
+ async function projectConnections(deps: ApiRouteDeps, connections: OrganizationMcpConnection[]) {
138
+ const userIds = connections
139
+ .map((connection) => connection.subjectId)
140
+ .filter((subjectId) => subjectId.startsWith("user:"))
141
+ .map((subjectId) => subjectId.slice("user:".length));
142
+ const profiles = new Map(
143
+ (await getManagedUserProfilesByIds(deps.db, userIds)).map((profile) => [
144
+ `user:${profile.id}`,
145
+ profile,
146
+ ]),
147
+ );
148
+ return connections.map((connection) => {
149
+ const profile = profiles.get(connection.subjectId);
150
+ return {
151
+ id: connection.id,
152
+ clientName: connection.clientName ?? "MCP client",
153
+ clientHost: clientHost(connection.redirectUris),
154
+ actor: "user" as const,
155
+ connectedBy: {
156
+ subjectId: connection.subjectId,
157
+ name: profile?.name?.trim() || profile?.email || "Someone",
158
+ },
159
+ policy: connection.organizationAccess,
160
+ createdAt: connection.connectedAt.toISOString(),
161
+ lastUsedAt: connection.lastUsedAt?.toISOString() ?? null,
162
+ expiresAt: connection.expiresAt.toISOString(),
163
+ revokedAt: null,
164
+ };
165
+ });
166
+ }
167
+
168
+ function clientHost(redirectUris: string[]): string | null {
169
+ for (const value of redirectUris) {
170
+ try {
171
+ const url = new URL(value);
172
+ return url.host || url.protocol.replace(/:$/u, "");
173
+ } catch {
174
+ continue;
175
+ }
176
+ }
177
+ return null;
178
+ }