@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,870 @@
1
+ import { isVerifiedDelegatedHumanAuthorization, knowledgeContextForGateway } from "@opengeni/core";
2
+ import { createHash, randomBytes } from "node:crypto";
3
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
5
+ import { withSiteSessionOrigin } from "@opengeni/core";
6
+ import { resolveSiteSessionOrigin } from "./site-session-origin";
7
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
9
+ import {
10
+ CallToolRequestSchema,
11
+ ListToolsRequestSchema,
12
+ type CallToolResult,
13
+ } from "@modelcontextprotocol/sdk/types.js";
14
+ import { CODEX_CLIENT_VERSION } from "@opengeni/codex";
15
+ import { IntegrationInvocationError } from "@opengeni/capabilities";
16
+ import type { Settings } from "@opengeni/config";
17
+ import {
18
+ FIRST_PARTY_MCP_TOOL_NAMES,
19
+ ToolGatewayCallRequest,
20
+ ToolGatewayCallResponse,
21
+ ToolGatewayApprovalRequest,
22
+ ToolGatewayApprovalResponse,
23
+ ToolGatewayDeclarationsResponse,
24
+ type AccessGrant,
25
+ type ToolGatewayCatalog,
26
+ type ToolGatewayIdentity,
27
+ type ToolRef,
28
+ } from "@opengeni/contracts";
29
+ import {
30
+ availableMcpAccountBindings,
31
+ buildApiIntegrationMcpServers,
32
+ expandApiIntegrationAccountRoutes,
33
+ expandMcpAccountRoutes,
34
+ hasPermission,
35
+ externalActorContinuationForAuthorization,
36
+ isVerifiedOrganizationServiceAuthorization,
37
+ externalContinuationCommitAuthorizer,
38
+ requireResolvedAccessGrantAuthorization,
39
+ resolveCodexAppsCredentialIdForRun,
40
+ resolveWorkspaceCatalogSettings,
41
+ settingsWithEnabledCapabilityMcpServers,
42
+ type AccessGrantAuthorization,
43
+ type ApiRouteDeps,
44
+ } from "@opengeni/core";
45
+ import {
46
+ buildCodexTokenResolver,
47
+ buildConnectionTokenResolver,
48
+ buildSlackApiRateLimiter,
49
+ lockActiveExternalOrganizationKeyAuthority,
50
+ withAccountRls,
51
+ requireWorkspace,
52
+ withCodexAppsRequestAuthorization,
53
+ consumeToolGatewayApproval,
54
+ getWorkspaceArtifactContentRef,
55
+ issueToolGatewayApproval,
56
+ ToolGatewayApprovalOperationStartedError,
57
+ ToolGatewayApprovalRateLimitError,
58
+ WorkspaceArtifactNotFoundError,
59
+ type ApiIntegrationRuntime,
60
+ } from "@opengeni/db";
61
+ import {
62
+ type LocalMcpServerRegistration,
63
+ type PreparedWorkspaceToolGatewayTools,
64
+ type ResolveConnectionCredentialInput,
65
+ type ResolveConnectionCredentialResult,
66
+ prepareWorkspaceToolGatewayTools,
67
+ } from "@opengeni/runtime/workspace-tool-gateway";
68
+ import {
69
+ ToolGatewayApprovalRequiredError,
70
+ ToolGatewayCatalogStaleError,
71
+ ToolGatewayInputValidationError,
72
+ ToolGatewayToolNotFoundError,
73
+ digestCanonicalJson,
74
+ generateToolGatewayDeclarations,
75
+ type PreparedToolGatewayCall,
76
+ type ToolGatewayDefinition,
77
+ } from "@opengeni/tool-gateway";
78
+ import { HTTPException } from "hono/http-exception";
79
+
80
+ import { ApiHttpError } from "./http/api-error";
81
+ import { buildDocumentsMcpServer } from "./mcp/documents";
82
+ import { buildFilesMcpServer } from "./mcp/files";
83
+ import { buildOpenGeniMcpServer } from "./mcp/server";
84
+ import { startWorkspaceToolGatewayObservation } from "./workspace-tool-gateway-observability";
85
+ import type { Observability } from "@opengeni/observability";
86
+
87
+ export type PreparedWorkspaceToolGateway = Pick<
88
+ PreparedWorkspaceToolGatewayTools,
89
+ "toolGateway" | "toolGatewayCatalog" | "close"
90
+ > & {
91
+ toolGateway: NonNullable<PreparedWorkspaceToolGatewayTools["toolGateway"]>;
92
+ toolGatewayCatalog: NonNullable<PreparedWorkspaceToolGatewayTools["toolGatewayCatalog"]>;
93
+ reauthorize?: () => Promise<void>;
94
+ };
95
+
96
+ type WorkspaceSiteToolContext = {
97
+ siteArtifactId: string;
98
+ siteVersionId: string;
99
+ identity: { serverId: string; toolName: string };
100
+ };
101
+
102
+ type AuthorizeWorkspaceSiteTool = (
103
+ db: ApiRouteDeps["db"],
104
+ grant: AccessGrant,
105
+ context: WorkspaceSiteToolContext,
106
+ ) => Promise<void>;
107
+
108
+ export function grantUsesAttemptScopedMcp(grant: AccessGrant): boolean {
109
+ return (
110
+ grant.principalKind === "agent_attempt" ||
111
+ grant.metadata?.delegated === true ||
112
+ typeof grant.metadata?.sessionId === "string"
113
+ );
114
+ }
115
+
116
+ export function requireWorkspaceToolGatewayGrant(grant: AccessGrant): void {
117
+ if (
118
+ grantUsesAttemptScopedMcp(grant) ||
119
+ (grant.principalKind !== undefined && grant.principalKind !== "human_session")
120
+ ) {
121
+ throw new HTTPException(403, { message: "current-human tool access required" });
122
+ }
123
+ }
124
+
125
+ export function requireWorkspaceToolGatewayAuthorization(
126
+ authorization: AccessGrantAuthorization,
127
+ ): AccessGrant {
128
+ const grant = requireResolvedAccessGrantAuthorization(
129
+ authorization,
130
+ authorization.grant.workspaceId,
131
+ );
132
+ if (isVerifiedOrganizationServiceAuthorization(authorization)) {
133
+ if (grantUsesAttemptScopedMcp(grant))
134
+ throw new HTTPException(403, {
135
+ message: "service tool access cannot carry attempt authority",
136
+ });
137
+ return grant;
138
+ }
139
+ requireWorkspaceToolGatewayGrant(grant);
140
+ if (
141
+ !authorization.canonicalManagedHumanSession &&
142
+ !authorization.canonicalLocalHumanSession &&
143
+ !isVerifiedDelegatedHumanAuthorization(authorization) &&
144
+ !externalActorContinuationForAuthorization(authorization)
145
+ ) {
146
+ throw new HTTPException(403, { message: "current-human tool access required" });
147
+ }
148
+ return grant;
149
+ }
150
+
151
+ export async function prepareWorkspaceToolGateway(
152
+ routeDeps: ApiRouteDeps,
153
+ authorization: AccessGrantAuthorization,
154
+ ): Promise<PreparedWorkspaceToolGateway> {
155
+ const grant = requireWorkspaceToolGatewayAuthorization(authorization);
156
+ const external = externalActorContinuationForAuthorization(authorization);
157
+ const reauthorizeExternal = externalContinuationCommitAuthorizer(authorization);
158
+ const service = isVerifiedOrganizationServiceAuthorization(authorization);
159
+ const scope = {
160
+ accountId: grant.accountId,
161
+ workspaceId: grant.workspaceId,
162
+ subjectId: grant.subjectId,
163
+ };
164
+ const permissions = [...grant.permissions];
165
+ const reauthorize =
166
+ external || service
167
+ ? async () => {
168
+ await withAccountRls(routeDeps.db, scope.accountId, async (tx) => {
169
+ if (reauthorizeExternal) await reauthorizeExternal(tx);
170
+ else {
171
+ const live = await lockActiveExternalOrganizationKeyAuthority(
172
+ tx,
173
+ scope.accountId,
174
+ scope.subjectId.slice("api_key:".length),
175
+ scope.workspaceId,
176
+ );
177
+ const workspace = await requireWorkspace(tx, scope.workspaceId);
178
+ if (
179
+ !live ||
180
+ permissions.some(
181
+ (permission) => !hasPermission(live.permissions, permission, live.permissionMode),
182
+ ) ||
183
+ workspace.accountId !== scope.accountId ||
184
+ workspace.kind !== "shared"
185
+ )
186
+ throw new HTTPException(403, { message: "service gateway authority changed" });
187
+ }
188
+ });
189
+ }
190
+ : undefined;
191
+ await reauthorize?.();
192
+ const prepared = await prepareWorkspaceToolGatewayForGrantInternal(
193
+ routeDeps,
194
+ grant,
195
+ undefined,
196
+ reauthorize,
197
+ );
198
+ try {
199
+ await reauthorize?.();
200
+ } catch (error) {
201
+ await prepared.close();
202
+ throw error;
203
+ }
204
+ return { ...prepared, ...(reauthorize ? { reauthorize } : {}) };
205
+ }
206
+
207
+ export async function prepareMcpOAuthWorkspaceToolGateway(
208
+ routeDeps: ApiRouteDeps,
209
+ grant: AccessGrant,
210
+ allowedIdentities: readonly { serverId: string; toolName: string }[],
211
+ ): Promise<PreparedWorkspaceToolGateway> {
212
+ if (grant.metadata?.mcpOAuth !== true || grant.principalKind !== "human_session") {
213
+ throw new HTTPException(403, { message: "MCP OAuth authority is invalid" });
214
+ }
215
+ return await prepareWorkspaceToolGatewayForGrant(routeDeps, grant, allowedIdentities);
216
+ }
217
+
218
+ export async function prepareWorkspaceToolGatewayForGrant(
219
+ routeDeps: ApiRouteDeps,
220
+ grant: AccessGrant,
221
+ allowedIdentities?: readonly { serverId: string; toolName: string }[],
222
+ ): Promise<PreparedWorkspaceToolGateway> {
223
+ return await prepareWorkspaceToolGatewayForGrantInternal(routeDeps, grant, allowedIdentities);
224
+ }
225
+
226
+ /** Keep live caller authority independent of native connection acquisition and refresh. */
227
+ export function withWorkspaceConnectionAuthorization(
228
+ resolve: ReturnType<typeof buildConnectionTokenResolver>,
229
+ reauthorize?: () => Promise<void>,
230
+ ): ReturnType<typeof buildConnectionTokenResolver> {
231
+ if (!reauthorize) return resolve;
232
+ return async (input) => {
233
+ await reauthorize();
234
+ const result = await resolve(input);
235
+ await reauthorize();
236
+ if (result.status !== "ok") return result;
237
+ return {
238
+ ...result,
239
+ authorizeProviderRequest: async () => {
240
+ try {
241
+ await reauthorize();
242
+ return result.authorizeProviderRequest ? await result.authorizeProviderRequest() : true;
243
+ } catch {
244
+ return false;
245
+ }
246
+ },
247
+ };
248
+ };
249
+ }
250
+
251
+ async function prepareWorkspaceToolGatewayForGrantInternal(
252
+ routeDeps: ApiRouteDeps,
253
+ grant: AccessGrant,
254
+ allowedIdentities?: readonly { serverId: string; toolName: string }[],
255
+ reauthorize?: () => Promise<void>,
256
+ ): Promise<PreparedWorkspaceToolGateway> {
257
+ const catalogSourceSettings = routeDeps.catalogSourceSettings ?? routeDeps.settings;
258
+ const resolvedCatalog = await resolveWorkspaceCatalogSettings(
259
+ routeDeps.db,
260
+ catalogSourceSettings,
261
+ {
262
+ accountId: grant.accountId,
263
+ workspaceId: grant.workspaceId,
264
+ },
265
+ );
266
+ let integrations: readonly ApiIntegrationRuntime[] = [];
267
+ const settings = await settingsWithEnabledCapabilityMcpServers(
268
+ routeDeps.db,
269
+ grant.workspaceId,
270
+ resolvedCatalog.settings,
271
+ {
272
+ subjectId: grant.subjectId,
273
+ onResolvedApiIntegrations: (resolved) => {
274
+ integrations = resolved;
275
+ },
276
+ },
277
+ );
278
+ // Transport admission has already verified the current caller. A service
279
+ // receives workspace accounts only; human transports use their exact subject.
280
+ const accountBindings = await availableMcpAccountBindings({
281
+ db: routeDeps.db,
282
+ accountId: grant.accountId,
283
+ workspaceId: grant.workspaceId,
284
+ settings,
285
+ tools: allGatewayToolRefs(settings),
286
+ source:
287
+ grant.principalKind === "service" || grant.principalKind === "api_key"
288
+ ? { kind: "none" }
289
+ : { kind: "subject", accountId: grant.accountId, subjectId: grant.subjectId },
290
+ });
291
+ const accountRoutes = expandMcpAccountRoutes({
292
+ settings,
293
+ tools: allGatewayToolRefs(settings),
294
+ bindings: accountBindings,
295
+ });
296
+ // OAuth/Site identities are account-qualified. Intersect only after expansion;
297
+ // canonical connector IDs are never aliases for an account's execution route.
298
+ const gatewaySettings = workspaceToolGatewaySettingsForGrant(
299
+ accountRoutes.settings,
300
+ grant,
301
+ allowedIdentities,
302
+ );
303
+ const gatewayServerIds = new Set(gatewaySettings.mcpServers.map((server) => server.id));
304
+ const deps = { ...routeDeps, catalogSourceSettings, settings: gatewaySettings };
305
+ const resolveConnection = withWorkspaceConnectionAuthorization(
306
+ buildConnectionTokenResolver(routeDeps.db, gatewaySettings),
307
+ reauthorize,
308
+ );
309
+ const resolveCredential = async (
310
+ input: ResolveConnectionCredentialInput,
311
+ ): Promise<ResolveConnectionCredentialResult> =>
312
+ await resolveConnection({
313
+ ...input,
314
+ ...(input.connectionRef.subjectScope === "subject" ? { subjectId: grant.subjectId } : {}),
315
+ });
316
+ const firstPartyServers = await Promise.all([
317
+ ...(gatewayServerIds.has("opengeni")
318
+ ? [inMemoryMcpRegistration("opengeni", buildOpenGeniMcpServer(deps, grant))]
319
+ : []),
320
+ ...(gatewayServerIds.has("files")
321
+ ? [inMemoryMcpRegistration("files", buildFilesMcpServer(deps, grant))]
322
+ : []),
323
+ ...(gatewayServerIds.has("docs") && hasPermission(grant.permissions, "documents:search")
324
+ ? [
325
+ inMemoryMcpRegistration(
326
+ "docs",
327
+ buildDocumentsMcpServer(
328
+ routeDeps.db,
329
+ grant.accountId,
330
+ grant.workspaceId,
331
+ routeDeps.getDocumentServices(),
332
+ {
333
+ knowledge: await knowledgeContextForGateway(routeDeps, grant),
334
+ settings: gatewaySettings,
335
+ },
336
+ ),
337
+ ),
338
+ ]
339
+ : []),
340
+ ]);
341
+ const apiIntegrationServers = buildApiIntegrationMcpServers({
342
+ settings: gatewaySettings,
343
+ integrations: expandApiIntegrationAccountRoutes({
344
+ integrations,
345
+ bindings: accountBindings,
346
+ tools: allGatewayToolRefs(gatewaySettings),
347
+ }),
348
+ authority: {
349
+ accountId: grant.accountId,
350
+ workspaceId: grant.workspaceId,
351
+ initiatingSubjectId: grant.subjectId,
352
+ },
353
+ resolveCredential: async (input) =>
354
+ await resolveConnection({
355
+ ...input,
356
+ ...(input.connectionRef.subjectScope === "subject" ? { subjectId: grant.subjectId } : {}),
357
+ }),
358
+ });
359
+ const codexAppsCredentialId = gatewayServerIds.has("codex_apps")
360
+ ? await resolveCodexAppsCredentialIdForRun(routeDeps.db, grant.workspaceId)
361
+ : null;
362
+ const codexAppsAuth = codexAppsCredentialId
363
+ ? (() => {
364
+ const resolver = buildCodexTokenResolver(
365
+ routeDeps.db,
366
+ settings,
367
+ grant.workspaceId,
368
+ codexAppsCredentialId,
369
+ );
370
+ return {
371
+ clientVersion: CODEX_CLIENT_VERSION,
372
+ withAuthorization: async <T>(
373
+ use: (token: { accessToken: string; chatgptAccountId: string | null }) => Promise<T>,
374
+ ): Promise<T> =>
375
+ await resolver.getToken().then(
376
+ async (token) =>
377
+ await withCodexAppsRequestAuthorization(
378
+ routeDeps.db,
379
+ {
380
+ workspaceId: grant.workspaceId,
381
+ credentialId: codexAppsCredentialId,
382
+ },
383
+ async () => await use(token),
384
+ ),
385
+ ),
386
+ };
387
+ })()
388
+ : undefined;
389
+ const localMcpServers = [...firstPartyServers, ...apiIntegrationServers];
390
+ const prepared = await prepareWorkspaceToolGatewayTools(
391
+ gatewaySettings,
392
+ allGatewayToolRefs(gatewaySettings),
393
+ {
394
+ accountId: grant.accountId,
395
+ workspaceId: grant.workspaceId,
396
+ subjectId: grant.subjectId,
397
+ credentialSubjectId: grant.subjectId,
398
+ mcpAccountLabels: accountRoutes.accountLabels,
399
+ resolveCredential,
400
+ slackRateLimit: buildSlackApiRateLimiter(routeDeps.db, gatewaySettings),
401
+ localMcpServers,
402
+ ...(codexAppsAuth ? { codexAppsAuth } : {}),
403
+ workspaceToolGateway: {
404
+ requireApproval: (entry, _caller, context) =>
405
+ entry.approval === "human" && context.transportMeta?.approvalConfirmed !== true,
406
+ filterDefinition: workspaceToolGatewayDefinitionFilter(gatewaySettings, allowedIdentities),
407
+ },
408
+ },
409
+ );
410
+ if (!prepared.toolGateway || !prepared.toolGatewayCatalog) {
411
+ await prepared.close().catch(() => undefined);
412
+ throw new Error("workspace tool gateway preparation did not produce a gateway");
413
+ }
414
+ return {
415
+ toolGateway: prepared.toolGateway,
416
+ toolGatewayCatalog: prepared.toolGatewayCatalog,
417
+ close: prepared.close,
418
+ };
419
+ }
420
+
421
+ export function workspaceToolGatewayDefinitionFilter(
422
+ settings: Pick<Settings, "allowedFirstPartyMcpTools">,
423
+ allowedIdentities?: readonly ToolGatewayIdentity[],
424
+ ): (definition: ToolGatewayDefinition) => boolean {
425
+ const allowedFirstPartyTools: ReadonlySet<string> = new Set(
426
+ settings.allowedFirstPartyMcpTools ?? FIRST_PARTY_MCP_TOOL_NAMES,
427
+ );
428
+ const frozenIdentityKeys = allowedIdentities
429
+ ? new Set(allowedIdentities.map(workspaceToolGatewayIdentityKey))
430
+ : null;
431
+ return (definition) => {
432
+ if (
433
+ definition.identity.serverId === "opengeni" &&
434
+ !allowedFirstPartyTools.has(definition.identity.toolName)
435
+ ) {
436
+ return false;
437
+ }
438
+ if (
439
+ definition.approval === "human" &&
440
+ definition.requiresProviderPreflight === true &&
441
+ !definition.preflightCall
442
+ ) {
443
+ return false;
444
+ }
445
+ return frozenIdentityKeys?.has(workspaceToolGatewayIdentityKey(definition.identity)) ?? true;
446
+ };
447
+ }
448
+
449
+ function workspaceToolGatewayIdentityKey(identity: ToolGatewayIdentity): string {
450
+ return JSON.stringify([identity.serverId, identity.toolName]);
451
+ }
452
+
453
+ export function workspaceToolGatewaySettingsForGrant(
454
+ settings: Settings,
455
+ grant: AccessGrant,
456
+ allowedIdentities?: readonly { serverId: string; toolName: string }[],
457
+ ): Settings {
458
+ const allowedServerIds = allowedIdentities
459
+ ? new Set(allowedIdentities.map((identity) => identity.serverId))
460
+ : null;
461
+ return {
462
+ ...settings,
463
+ mcpServers: settings.mcpServers.filter((server) => {
464
+ if (allowedServerIds && !allowedServerIds.has(server.id)) return false;
465
+ if (server.id === "docs" && !hasPermission(grant.permissions, "documents:search")) {
466
+ return false;
467
+ }
468
+ if (server.id === "files" && !hasPermission(grant.permissions, "files:read")) return false;
469
+ return true;
470
+ }),
471
+ };
472
+ }
473
+
474
+ export function buildWorkspaceToolGatewayMcpServer(
475
+ prepared: PreparedWorkspaceToolGateway,
476
+ grant: AccessGrant,
477
+ observability?: Observability,
478
+ ): Server {
479
+ const callableEntries = prepared.toolGatewayCatalog.entries.filter(
480
+ (entry) => entry.approval !== "human",
481
+ );
482
+ const server = new Server(
483
+ { name: "opengeni-tool-gateway", version: "1.0.0" },
484
+ { capabilities: { tools: {} } },
485
+ );
486
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
487
+ await prepared.reauthorize?.();
488
+ return {
489
+ tools: callableEntries.map((entry) => ({
490
+ name: entry.modelName,
491
+ ...(entry.title ? { title: entry.title } : {}),
492
+ ...(entry.description ? { description: entry.description } : {}),
493
+ inputSchema: entry.inputSchema,
494
+ ...(entry.outputSchema ? { outputSchema: entry.outputSchema } : {}),
495
+ ...(entry.annotations ? { annotations: entry.annotations } : {}),
496
+ ...(entry.icons ? { icons: entry.icons } : {}),
497
+ _meta: {
498
+ "opengeni/identity": entry.identity,
499
+ "opengeni/path": entry.codemodePath,
500
+ "opengeni/source": entry.source,
501
+ "opengeni/approval": entry.approval,
502
+ "opengeni/catalogDigest": prepared.toolGatewayCatalog.digest,
503
+ },
504
+ })),
505
+ };
506
+ });
507
+ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
508
+ const entry = callableEntries.find((candidate) => candidate.modelName === request.params.name);
509
+ if (!entry) throw new ToolGatewayToolNotFoundError();
510
+ const observation = startWorkspaceToolGatewayObservation(observability, {
511
+ adapter: "mcp",
512
+ operation: "call",
513
+ source: entry.source,
514
+ });
515
+ try {
516
+ await prepared.reauthorize?.();
517
+ const call = await prepared.toolGateway.prepareCall(
518
+ {
519
+ operationId: crypto.randomUUID(),
520
+ catalogDigest: prepared.toolGatewayCatalog.digest,
521
+ identity: entry.identity,
522
+ arguments: request.params.arguments ?? {},
523
+ caller: { kind: "mcp", subjectId: grant.subjectId },
524
+ },
525
+ { signal: extra.signal },
526
+ );
527
+ await prepared.reauthorize?.();
528
+ const result = (await call.execute()) as CallToolResult;
529
+ observation.end(result.isError ? "tool_error" : "ok");
530
+ return result;
531
+ } catch (error) {
532
+ observation.end(workspaceToolGatewayOutcome(error));
533
+ throw error;
534
+ }
535
+ });
536
+ return server;
537
+ }
538
+
539
+ export async function callWorkspaceToolGateway(
540
+ prepared: PreparedWorkspaceToolGateway,
541
+ grant: AccessGrant,
542
+ input: unknown,
543
+ db?: ApiRouteDeps["db"],
544
+ consumeApproval: typeof consumeToolGatewayApproval = consumeToolGatewayApproval,
545
+ observability?: Observability,
546
+ authorizeSiteTool: AuthorizeWorkspaceSiteTool = requireWorkspaceSiteToolAuthorization,
547
+ resolveOrigin: typeof resolveSiteSessionOrigin = resolveSiteSessionOrigin,
548
+ ) {
549
+ const request = ToolGatewayCallRequest.parse(input);
550
+ const operationId = request.operationId ?? crypto.randomUUID();
551
+ const entry = prepared.toolGatewayCatalog.entries.find(
552
+ (candidate) =>
553
+ candidate.identity.serverId === request.identity.serverId &&
554
+ candidate.identity.toolName === request.identity.toolName,
555
+ );
556
+ const observation = startWorkspaceToolGatewayObservation(observability, {
557
+ adapter: "http",
558
+ operation: "call",
559
+ source: entry?.source ?? "aggregate",
560
+ });
561
+ try {
562
+ const siteContext =
563
+ request.siteArtifactId && request.siteVersionId
564
+ ? {
565
+ siteArtifactId: request.siteArtifactId,
566
+ siteVersionId: request.siteVersionId,
567
+ identity: request.identity,
568
+ }
569
+ : null;
570
+ await prepared.reauthorize?.();
571
+ if (siteContext) {
572
+ if (!db) throw new HTTPException(503, { message: "site_tool_authorization_unavailable" });
573
+ await authorizeSiteTool(db, grant, siteContext);
574
+ }
575
+ // Approval is adapter-owned. Prepare provisionally so provider preflight can
576
+ // run, then require the ordinary single-use capability before execution.
577
+ const transportMeta: Record<string, unknown> = { approvalConfirmed: true };
578
+ const preparedCall = await prepared.toolGateway.prepareCall(
579
+ {
580
+ operationId,
581
+ catalogDigest: request.catalogDigest,
582
+ identity: request.identity,
583
+ arguments: request.arguments,
584
+ caller: { kind: "http", subjectId: grant.subjectId },
585
+ },
586
+ { transportMeta },
587
+ );
588
+ await prepared.reauthorize?.();
589
+ let approvalConfirmed = false;
590
+ const approvalRequired = preparedCall.entry.approval === "human";
591
+ if (approvalRequired && request.approvalToken && db) {
592
+ approvalConfirmed = await consumeApproval(db, {
593
+ tokenHash: hashOpaqueValue(request.approvalToken),
594
+ accountId: grant.accountId,
595
+ workspaceId: grant.workspaceId,
596
+ subjectId: grant.subjectId,
597
+ operationId,
598
+ catalogDigest: request.catalogDigest,
599
+ identity: request.identity,
600
+ argumentsDigest: digestCanonicalJson(request.arguments),
601
+ approvalAuthorityDigest: preparedCall.approvalAuthorityDigest,
602
+ });
603
+ }
604
+ if (approvalRequired && !approvalConfirmed) {
605
+ throw new HTTPException(409, { message: "tool_gateway_approval_required" });
606
+ }
607
+ transportMeta.approvalConfirmed = approvalConfirmed;
608
+ const origin =
609
+ siteContext && db
610
+ ? await resolveOrigin(
611
+ db,
612
+ grant.workspaceId,
613
+ siteContext.siteArtifactId,
614
+ siteContext.siteVersionId,
615
+ )
616
+ : null;
617
+ await prepared.reauthorize?.();
618
+ const result = await (origin
619
+ ? withSiteSessionOrigin(origin, () => preparedCall.execute())
620
+ : preparedCall.execute());
621
+ observation.end(result.isError ? "tool_error" : "ok");
622
+ return ToolGatewayCallResponse.parse({
623
+ operationId,
624
+ catalogDigest: prepared.toolGatewayCatalog.digest,
625
+ result,
626
+ });
627
+ } catch (error) {
628
+ observation.end(workspaceToolGatewayOutcome(error));
629
+ throwWorkspaceToolGatewayHttpError(error);
630
+ }
631
+ }
632
+
633
+ export async function approveWorkspaceToolGatewayCall(
634
+ prepared: PreparedWorkspaceToolGateway,
635
+ grant: AccessGrant,
636
+ db: ApiRouteDeps["db"],
637
+ input: unknown,
638
+ issueApproval: typeof issueToolGatewayApproval = issueToolGatewayApproval,
639
+ observability?: Observability,
640
+ ) {
641
+ const request = ToolGatewayApprovalRequest.parse(input);
642
+ let preparedCall: PreparedToolGatewayCall;
643
+ try {
644
+ await prepared.reauthorize?.();
645
+ preparedCall = await prepared.toolGateway.prepareCall(
646
+ {
647
+ operationId: request.operationId,
648
+ catalogDigest: request.catalogDigest,
649
+ identity: request.identity,
650
+ arguments: request.arguments,
651
+ caller: { kind: "http", subjectId: grant.subjectId },
652
+ },
653
+ { transportMeta: { approvalConfirmed: true } },
654
+ );
655
+ } catch (error) {
656
+ throwWorkspaceToolGatewayHttpError(error);
657
+ }
658
+ if (preparedCall.entry.approval !== "human") {
659
+ throw new HTTPException(422, { message: "tool_does_not_require_human_approval" });
660
+ }
661
+ const observation = startWorkspaceToolGatewayObservation(observability, {
662
+ adapter: "http",
663
+ operation: "approval",
664
+ source: preparedCall.entry.source,
665
+ });
666
+ const approvalToken = `ogta_${randomBytes(32).toString("base64url")}`;
667
+ const expiresAt = new Date(Date.now() + 5 * 60_000);
668
+ try {
669
+ await prepared.reauthorize?.();
670
+ await issueApproval(db, {
671
+ tokenHash: hashOpaqueValue(approvalToken),
672
+ accountId: grant.accountId,
673
+ workspaceId: grant.workspaceId,
674
+ subjectId: grant.subjectId,
675
+ operationId: request.operationId,
676
+ catalogDigest: request.catalogDigest,
677
+ identity: request.identity,
678
+ argumentsDigest: digestCanonicalJson(request.arguments),
679
+ approvalAuthorityDigest: preparedCall.approvalAuthorityDigest,
680
+ expiresAt,
681
+ });
682
+ } catch (error) {
683
+ if (error instanceof ToolGatewayApprovalRateLimitError) {
684
+ observation.end("rate_limited");
685
+ throw new HTTPException(429, { message: "tool_approval_rate_limited", cause: error });
686
+ }
687
+ if (error instanceof ToolGatewayApprovalOperationStartedError) {
688
+ observation.end("failed");
689
+ throw new ApiHttpError(409, {
690
+ code: "conflict",
691
+ message:
692
+ "This tool operation may already have started and cannot be approved again. Reconcile its outcome before creating a new operation.",
693
+ retryable: false,
694
+ outcomeUnknown: true,
695
+ details: {
696
+ code: "tool_gateway_operation_already_started",
697
+ operationId: request.operationId,
698
+ },
699
+ });
700
+ }
701
+ observation.end("failed");
702
+ throw error;
703
+ }
704
+ observation.end("ok");
705
+ return ToolGatewayApprovalResponse.parse({
706
+ operationId: request.operationId,
707
+ catalogDigest: request.catalogDigest,
708
+ identity: preparedCall.entry.identity,
709
+ approvalToken,
710
+ expiresAt: expiresAt.toISOString(),
711
+ });
712
+ }
713
+
714
+ function catalogStaleHttpError(): ApiHttpError {
715
+ return new ApiHttpError(409, {
716
+ code: "conflict",
717
+ message: "The workspace tool catalog changed; retry with the current catalog.",
718
+ retryable: true,
719
+ details: { code: "catalog_stale" },
720
+ });
721
+ }
722
+
723
+ function throwWorkspaceToolGatewayHttpError(error: unknown): never {
724
+ if (error instanceof ToolGatewayCatalogStaleError) {
725
+ throw catalogStaleHttpError();
726
+ }
727
+ if (error instanceof ToolGatewayToolNotFoundError) {
728
+ throw new HTTPException(404, { message: error.code, cause: error });
729
+ }
730
+ if (error instanceof ToolGatewayInputValidationError) {
731
+ // The same value-free summary the model sees: which properties are missing
732
+ // or mistyped, never the submitted argument values.
733
+ throw new ApiHttpError(422, {
734
+ code: "validation_failed",
735
+ message: error.message,
736
+ retryable: false,
737
+ details: {
738
+ code: error.code,
739
+ issues: error.issues,
740
+ omittedIssueCount: error.omittedIssueCount,
741
+ },
742
+ });
743
+ }
744
+ if (error instanceof ToolGatewayApprovalRequiredError) {
745
+ throw new HTTPException(409, { message: error.code, cause: error });
746
+ }
747
+ if (error instanceof IntegrationInvocationError && error.outcome === "unknown") {
748
+ throw new ApiHttpError(502, {
749
+ code: "upstream_unavailable",
750
+ message:
751
+ "The integration call ended without a confirmed provider result. Inspect the external system before retrying.",
752
+ retryable: false,
753
+ outcomeUnknown: true,
754
+ details: { code: "tool_outcome_unknown", providerCode: error.code },
755
+ });
756
+ }
757
+ throw error;
758
+ }
759
+
760
+ export async function requireWorkspaceSiteToolAuthorization(
761
+ db: ApiRouteDeps["db"],
762
+ grant: AccessGrant,
763
+ context: WorkspaceSiteToolContext,
764
+ resolveVersion = getWorkspaceArtifactContentRef,
765
+ ): Promise<void> {
766
+ try {
767
+ const { status, version } = await resolveVersion(
768
+ db,
769
+ grant.workspaceId,
770
+ context.siteArtifactId,
771
+ context.siteVersionId,
772
+ );
773
+ const requested = version.requestedTools.some(
774
+ (identity) =>
775
+ identity.serverId === context.identity.serverId &&
776
+ identity.toolName === context.identity.toolName,
777
+ );
778
+ if (status !== "active" || version.id !== context.siteVersionId || !requested) {
779
+ throw new HTTPException(403, { message: "site_tool_not_authorized" });
780
+ }
781
+ } catch (error) {
782
+ if (error instanceof WorkspaceArtifactNotFoundError) {
783
+ throw new HTTPException(403, { message: "site_tool_not_authorized" });
784
+ }
785
+ throw error;
786
+ }
787
+ }
788
+
789
+ function hashOpaqueValue(value: string): string {
790
+ return createHash("sha256").update(value, "utf8").digest("hex");
791
+ }
792
+
793
+ function workspaceToolGatewayOutcome(error: unknown) {
794
+ if (error instanceof ToolGatewayApprovalRequiredError) return "approval_required" as const;
795
+ if (error instanceof ToolGatewayCatalogStaleError) return "catalog_stale" as const;
796
+ if (error instanceof ToolGatewayInputValidationError) return "invalid_input" as const;
797
+ if (error instanceof ToolGatewayToolNotFoundError) return "not_found" as const;
798
+ return "failed" as const;
799
+ }
800
+
801
+ function allGatewayToolRefs(settings: Settings): ToolRef[] {
802
+ return settings.mcpServers.map((server) => ({
803
+ kind: "mcp" as const,
804
+ id: server.id,
805
+ ...(server.connectionRef ? { optional: true } : {}),
806
+ }));
807
+ }
808
+
809
+ async function inMemoryMcpRegistration(
810
+ id: string,
811
+ server: McpServer,
812
+ ): Promise<LocalMcpServerRegistration> {
813
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
814
+ const client = new Client({ name: `opengeni-tool-gateway-${id}`, version: "1.0.0" });
815
+ let connected = false;
816
+ let closed = false;
817
+ type RuntimeMcpServer = LocalMcpServerRegistration["server"];
818
+ type RuntimeMcpTools = Awaited<ReturnType<RuntimeMcpServer["listTools"]>>;
819
+ type RuntimeMcpCallResult = Awaited<ReturnType<NonNullable<RuntimeMcpServer["callToolResult"]>>>;
820
+ return {
821
+ id,
822
+ server: {
823
+ name: `opengeni-tool-gateway-local:${id}`,
824
+ cacheToolsList: false,
825
+ connect: async () => {
826
+ if (closed) throw new Error(`Local MCP server ${id} is closed`);
827
+ if (connected) return;
828
+ await server.connect(serverTransport);
829
+ await client.connect(clientTransport);
830
+ connected = true;
831
+ },
832
+ close: async () => {
833
+ if (closed) return;
834
+ closed = true;
835
+ await Promise.allSettled([client.close(), server.close()]);
836
+ },
837
+ listTools: async () => (await client.listTools()).tools as unknown as RuntimeMcpTools,
838
+ callTool: async (toolName, args, _meta, options) =>
839
+ (
840
+ (await client.callTool(
841
+ { name: toolName, arguments: args ?? {} },
842
+ undefined,
843
+ options?.signal ? { signal: options.signal } : undefined,
844
+ )) as CallToolResult
845
+ ).content,
846
+ callToolResult: async (toolName, args, _meta, options) =>
847
+ (await client.callTool(
848
+ { name: toolName, arguments: args ?? {} },
849
+ undefined,
850
+ options?.signal ? { signal: options.signal } : undefined,
851
+ )) as unknown as RuntimeMcpCallResult,
852
+ invalidateToolsCache: async () => undefined,
853
+ },
854
+ };
855
+ }
856
+
857
+ export function toolGatewayCatalogResponse(catalog: ToolGatewayCatalog): ToolGatewayCatalog {
858
+ return catalog;
859
+ }
860
+
861
+ export function workspaceToolGatewayDeclarations(
862
+ prepared: PreparedWorkspaceToolGateway,
863
+ ): ToolGatewayDeclarationsResponse {
864
+ const moduleSpecifier = "@opengeni/sdk";
865
+ return ToolGatewayDeclarationsResponse.parse({
866
+ catalogDigest: prepared.toolGatewayCatalog.digest,
867
+ moduleSpecifier,
868
+ source: generateToolGatewayDeclarations(prepared.toolGatewayCatalog, { moduleSpecifier }),
869
+ });
870
+ }