@opengeni/api-router 0.30.3 → 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 (434) 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-source-session.d.ts +3 -0
  35. package/dist/editable-artifact-websocket.d.ts +10 -18
  36. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  37. package/dist/fatal-process-boundary.d.ts +25 -0
  38. package/dist/github-access.d.ts +31 -2
  39. package/dist/http/acting-person.d.ts +24 -0
  40. package/dist/http/api-contract-compat.d.ts +19 -0
  41. package/dist/http/api-error.d.ts +27 -1
  42. package/dist/http/cors.d.ts +17 -0
  43. package/dist/http/deprecation.d.ts +42 -0
  44. package/dist/http/interaction-control-error.d.ts +13 -0
  45. package/dist/http/keyed-admission.d.ts +12 -0
  46. package/dist/http/local-browser-boundary.d.ts +72 -0
  47. package/dist/http/metrics-listener.d.ts +22 -0
  48. package/dist/http/path-identifier.d.ts +17 -0
  49. package/dist/http/registered-route-label.d.ts +16 -0
  50. package/dist/http/request-body.d.ts +27 -0
  51. package/dist/http/request-source.d.ts +52 -0
  52. package/dist/http/sse.d.ts +17 -6
  53. package/dist/http/unmatched-route.d.ts +18 -0
  54. package/dist/http/user-content.d.ts +36 -0
  55. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  56. package/dist/index.d.ts +10 -3
  57. package/dist/index.js +1091 -162
  58. package/dist/index.js.map +1 -1
  59. package/dist/integration-endpoint-test.d.ts +20 -0
  60. package/dist/integrations/api-integrations.d.ts +2 -2
  61. package/dist/integrations/atlassian.d.ts +29 -3
  62. package/dist/integrations/connect-authority.d.ts +1 -0
  63. package/dist/integrations/connect-callback-return.d.ts +6 -0
  64. package/dist/integrations/fiken.d.ts +16 -2
  65. package/dist/integrations/github-app-connect.d.ts +47 -0
  66. package/dist/integrations/github-installation-proof.d.ts +3 -0
  67. package/dist/integrations/github-lens-connect.d.ts +116 -0
  68. package/dist/integrations/github-skill-source.d.ts +1 -5
  69. package/dist/integrations/google-drive.d.ts +24 -0
  70. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  71. package/dist/integrations/marketplace-plugin.d.ts +2691 -0
  72. package/dist/integrations/oauth-client.d.ts +178 -18
  73. package/dist/integrations/oauth-profiles.d.ts +222 -0
  74. package/dist/integrations/oauth-return-path.d.ts +1 -0
  75. package/dist/integrations/personal-github-repositories.d.ts +84 -0
  76. package/dist/integrations/personal-github.d.ts +42 -0
  77. package/dist/integrations/pr-review-provider.d.ts +22 -0
  78. package/dist/integrations/provider-oauth.d.ts +19 -1
  79. package/dist/integrations/slack-app-home.d.ts +24 -0
  80. package/dist/integrations/slack-bot.d.ts +367 -12
  81. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  82. package/dist/integrations/slack-install.d.ts +20 -0
  83. package/dist/integrations/slack-interactions.d.ts +107 -9
  84. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  85. package/dist/integrations/slack-routing.d.ts +120 -0
  86. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  87. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  88. package/dist/integrations/social-oauth.d.ts +7 -0
  89. package/dist/interaction-agent-access.d.ts +15 -0
  90. package/dist/interaction-frame-proxy.d.ts +68 -0
  91. package/dist/interaction-metrics.d.ts +2 -0
  92. package/dist/mcp/action-catalog-types.d.ts +9 -0
  93. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  94. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  95. package/dist/mcp/child-read-evidence.d.ts +9 -0
  96. package/dist/mcp/command-read.d.ts +24 -0
  97. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  98. package/dist/mcp/contract-input.d.ts +11 -0
  99. package/dist/mcp/documents.d.ts +7 -5
  100. package/dist/mcp/files.d.ts +2 -2
  101. package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
  102. package/dist/mcp/knowledge-entries.d.ts +5 -0
  103. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  104. package/dist/mcp/receipts.d.ts +9 -0
  105. package/dist/mcp/request-abort.d.ts +19 -0
  106. package/dist/mcp/scheduled-task-input.d.ts +1189 -0
  107. package/dist/mcp/scheduled-task-view.d.ts +22 -4
  108. package/dist/mcp/server.d.ts +255 -3
  109. package/dist/mcp/session-event-view.d.ts +94 -0
  110. package/dist/mcp/session-view.d.ts +66 -2
  111. package/dist/mcp/session-wait.d.ts +174 -0
  112. package/dist/mcp-oauth.d.ts +52 -0
  113. package/dist/model-catalog.d.ts +11 -31
  114. package/dist/observability.d.ts +3 -1
  115. package/dist/organization-mcp.d.ts +52 -0
  116. package/dist/organization-recovery-notifications.d.ts +41 -0
  117. package/dist/routes/analytics-consent.d.ts +26 -0
  118. package/dist/routes/api-integrations.d.ts +25 -0
  119. package/dist/routes/api-keys.d.ts +17 -0
  120. package/dist/routes/artifact-catalog.d.ts +6 -0
  121. package/dist/routes/automations.d.ts +19 -0
  122. package/dist/routes/billing.d.ts +49 -0
  123. package/dist/routes/browser-sessions.d.ts +59 -2
  124. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  125. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  126. package/dist/routes/client-errors.d.ts +146 -0
  127. package/dist/routes/codex.d.ts +76 -2
  128. package/dist/routes/company-brain.d.ts +3 -0
  129. package/dist/routes/company-profile.d.ts +2 -1
  130. package/dist/routes/computer-sessions.d.ts +14 -0
  131. package/dist/routes/connect.d.ts +5 -0
  132. package/dist/routes/editable-artifacts.d.ts +2 -0
  133. package/dist/routes/external-identity-links.d.ts +6 -0
  134. package/dist/routes/feedback.d.ts +3 -0
  135. package/dist/routes/github-browser-pages.d.ts +12 -0
  136. package/dist/routes/github.d.ts +2 -0
  137. package/dist/routes/insights-response-cache.d.ts +10 -0
  138. package/dist/routes/insights-usage.d.ts +12 -0
  139. package/dist/routes/insights.d.ts +30 -1
  140. package/dist/routes/knowledge.d.ts +3 -0
  141. package/dist/routes/managed-auth-session-sets.d.ts +26 -0
  142. package/dist/routes/managed-onboarding.d.ts +29 -0
  143. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  144. package/dist/routes/model-connection-access.d.ts +3 -0
  145. package/dist/routes/organization-integration-policy.d.ts +3 -0
  146. package/dist/routes/organization-integrations.d.ts +6 -0
  147. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  148. package/dist/routes/organization-model-providers.d.ts +3 -0
  149. package/dist/routes/organization-recovery.d.ts +19 -0
  150. package/dist/routes/organization-service-accounts.d.ts +3 -0
  151. package/dist/routes/organization-sessions.d.ts +26 -0
  152. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  153. package/dist/routes/personal-github.d.ts +3 -0
  154. package/dist/routes/pr-review-github.d.ts +3 -0
  155. package/dist/routes/pr-review.d.ts +3 -0
  156. package/dist/routes/session-artifact-associations.d.ts +4 -0
  157. package/dist/routes/session-history-imports.d.ts +9 -0
  158. package/dist/routes/sessions.d.ts +44 -6
  159. package/dist/routes/skill-content.d.ts +4 -0
  160. package/dist/routes/skill-install-authority.d.ts +6 -0
  161. package/dist/routes/subscription-account-pools.d.ts +34 -0
  162. package/dist/routes/subscription-pool-access.d.ts +16 -0
  163. package/dist/routes/supergrok.d.ts +6 -1
  164. package/dist/routes/usage-allowances.d.ts +12 -0
  165. package/dist/routes/user-resource-authorities.d.ts +3 -0
  166. package/dist/routes/workspace-artifacts.d.ts +2 -1
  167. package/dist/routes/workspace-capture.d.ts +10 -2
  168. package/dist/routes/workspace-integrations.d.ts +35 -0
  169. package/dist/routes/workspace-learning.d.ts +3 -0
  170. package/dist/routes/workspace-model-providers.d.ts +4 -0
  171. package/dist/routes/workspaces.d.ts +29 -0
  172. package/dist/sandbox/auth-callout.d.ts +8 -0
  173. package/dist/sandbox/channel-a.d.ts +19 -1
  174. package/dist/sandbox/connection-authority.d.ts +3 -0
  175. package/dist/sandbox/enrollment.d.ts +9 -1
  176. package/dist/sandbox/machines.d.ts +5 -2
  177. package/dist/sandbox/metrics-ingestion.d.ts +28 -20
  178. package/dist/sandbox/rematerialize.d.ts +2 -0
  179. package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
  180. package/dist/sandbox/viewer.d.ts +26 -1
  181. package/dist/sandbox-file-artifacts.d.ts +50 -0
  182. package/dist/scheduled-task-deletion.d.ts +13 -0
  183. package/dist/session-create-observability.d.ts +5 -0
  184. package/dist/session-event-view-MPS2OZD3.js +292 -0
  185. package/dist/session-event-view-MPS2OZD3.js.map +1 -0
  186. package/dist/site-session-origin.d.ts +13 -0
  187. package/dist/site-uploads.d.ts +41 -0
  188. package/dist/slack-reaction-files.d.ts +1 -1
  189. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  190. package/dist/temporal-schedule-sync.d.ts +26 -0
  191. package/dist/transcription/providers/xai-subscription.d.ts +1 -0
  192. package/dist/transcription/service.d.ts +2 -1
  193. package/dist/work-discovery-observability.d.ts +33 -0
  194. package/dist/workspace-artifact-content.d.ts +28 -0
  195. package/dist/workspace-artifact-provenance.d.ts +7 -0
  196. package/dist/workspace-delete-observability.d.ts +10 -0
  197. package/dist/workspace-deletion.d.ts +6 -0
  198. package/dist/workspace-state-projection.d.ts +3 -5
  199. package/dist/workspace-tool-gateway-observability.d.ts +17 -0
  200. package/dist/workspace-tool-gateway.d.ts +123 -0
  201. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  202. package/package.json +23 -19
  203. package/src/access-grant-rls.ts +75 -0
  204. package/src/admission-trace.ts +14 -0
  205. package/src/api-websocket.ts +23 -0
  206. package/src/app.ts +1967 -252
  207. package/src/artifact-catalog-cursor.ts +60 -0
  208. package/src/auth/managed-auth-attempt-context.ts +70 -0
  209. package/src/auth/managed-auth-rate-limits.ts +252 -0
  210. package/src/auth/managed-auth-session-adapter.ts +222 -0
  211. package/src/auth/managed-auth.ts +536 -60
  212. package/src/auth/managed-email.ts +174 -0
  213. package/src/auth/managed-sign-in-notifications.ts +81 -0
  214. package/src/auth/new-signups-gate.ts +49 -0
  215. package/src/auth/organization-user-setup.ts +307 -0
  216. package/src/auth/signup-funnel-metrics.ts +164 -0
  217. package/src/browser-controller-authority.ts +1 -186
  218. package/src/browser-ephemeral.ts +39 -0
  219. package/src/browser-state-authority.ts +1 -236
  220. package/src/claude-subscription-account-conflicts.ts +12 -0
  221. package/src/claude-subscription-account-usage.ts +48 -0
  222. package/src/claude-subscription-oauth.ts +362 -0
  223. package/src/claude-subscription-profile.ts +73 -0
  224. package/src/claude-subscription-usage.ts +97 -0
  225. package/src/claude-workspace-connection.ts +82 -0
  226. package/src/codemode.ts +194 -30
  227. package/src/codex-realtime.ts +8 -2
  228. package/src/company-brain-okf.ts +340 -0
  229. package/src/connected-machine-computer-access.ts +33 -0
  230. package/src/connection-ownership.ts +199 -0
  231. package/src/controller-data-plane.ts +81 -0
  232. package/src/editable-artifact-native-kernel.ts +26 -15
  233. package/src/editable-artifact-office-import.ts +28 -3
  234. package/src/editable-artifact-production.ts +23 -7
  235. package/src/editable-artifact-source-session.ts +123 -0
  236. package/src/editable-artifact-websocket.ts +27 -21
  237. package/src/editable-artifact-workspace-files.ts +31 -6
  238. package/src/fatal-process-boundary.ts +246 -0
  239. package/src/gateway-realtime.ts +1 -1
  240. package/src/github-access.ts +147 -5
  241. package/src/http/acting-person.ts +71 -0
  242. package/src/http/api-contract-compat.ts +49 -0
  243. package/src/http/api-error.ts +115 -1
  244. package/src/http/auth.ts +48 -0
  245. package/src/http/cors.ts +67 -0
  246. package/src/http/deprecation.ts +118 -0
  247. package/src/http/interaction-control-error.ts +164 -0
  248. package/src/http/keyed-admission.ts +29 -0
  249. package/src/http/local-browser-boundary.ts +343 -0
  250. package/src/http/metrics-listener.ts +57 -0
  251. package/src/http/path-identifier.ts +54 -0
  252. package/src/http/registered-route-label.ts +34 -0
  253. package/src/http/request-body.ts +127 -0
  254. package/src/http/request-source.ts +178 -0
  255. package/src/http/sse.ts +486 -132
  256. package/src/http/unmatched-route.ts +60 -0
  257. package/src/http/user-content.ts +158 -0
  258. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  259. package/src/index.ts +157 -52
  260. package/src/integration-endpoint-test.ts +291 -0
  261. package/src/integrations/api-integrations.ts +98 -11
  262. package/src/integrations/atlassian.ts +474 -136
  263. package/src/integrations/connect-authority.ts +2 -0
  264. package/src/integrations/connect-callback-return.ts +86 -0
  265. package/src/integrations/fiken.ts +354 -64
  266. package/src/integrations/github-app-connect.ts +435 -0
  267. package/src/integrations/github-installation-proof.ts +60 -0
  268. package/src/integrations/github-lens-connect.ts +76 -0
  269. package/src/integrations/github-skill-source.ts +2 -142
  270. package/src/integrations/google-drive.ts +717 -225
  271. package/src/integrations/integration-commit-authority.ts +69 -0
  272. package/src/integrations/marketplace-plugin.ts +48 -0
  273. package/src/integrations/oauth-client.ts +1356 -459
  274. package/src/integrations/oauth-profiles.ts +537 -0
  275. package/src/integrations/oauth-return-path.ts +18 -0
  276. package/src/integrations/personal-github-repositories.ts +674 -0
  277. package/src/integrations/personal-github.ts +825 -0
  278. package/src/integrations/pr-review-provider.ts +246 -0
  279. package/src/integrations/provider-oauth.ts +250 -22
  280. package/src/integrations/slack-app-home.ts +300 -0
  281. package/src/integrations/slack-bot.ts +963 -239
  282. package/src/integrations/slack-file-upload-flow.ts +147 -0
  283. package/src/integrations/slack-install.ts +83 -0
  284. package/src/integrations/slack-interactions.ts +3167 -474
  285. package/src/integrations/slack-mrkdwn.ts +193 -0
  286. package/src/integrations/slack-routing.ts +337 -0
  287. package/src/integrations/slack-session-defaults.ts +224 -0
  288. package/src/integrations/slack-task-file-upload.ts +323 -0
  289. package/src/integrations/social-oauth.ts +213 -15
  290. package/src/interaction-agent-access.ts +48 -0
  291. package/src/interaction-frame-proxy.ts +409 -0
  292. package/src/interaction-metrics.ts +30 -0
  293. package/src/mcp/action-catalog-types.ts +9 -0
  294. package/src/mcp/action-catalog.gen.ts +6696 -0
  295. package/src/mcp/capability-account-readiness.ts +17 -0
  296. package/src/mcp/child-read-evidence.ts +19 -0
  297. package/src/mcp/command-read.ts +109 -0
  298. package/src/mcp/company-profile-agent-admin.ts +198 -0
  299. package/src/mcp/contract-input.ts +141 -0
  300. package/src/mcp/documents.ts +65 -377
  301. package/src/mcp/editable-artifacts.ts +12 -6
  302. package/src/mcp/files.ts +80 -43
  303. package/src/mcp/first-party-tool-permissions.ts +305 -0
  304. package/src/mcp/knowledge-entries.ts +322 -0
  305. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  306. package/src/mcp/receipts.ts +34 -0
  307. package/src/mcp/request-abort.ts +44 -0
  308. package/src/mcp/scheduled-task-input.ts +76 -0
  309. package/src/mcp/scheduled-task-view.ts +44 -3
  310. package/src/mcp/server.ts +3030 -1267
  311. package/src/mcp/session-event-view.ts +383 -0
  312. package/src/mcp/session-view.ts +84 -3
  313. package/src/mcp/session-wait.ts +665 -0
  314. package/src/mcp-oauth.ts +1123 -0
  315. package/src/model-catalog.ts +91 -333
  316. package/src/observability.ts +15 -1
  317. package/src/organization-mcp.ts +397 -0
  318. package/src/organization-recovery-notifications.ts +103 -0
  319. package/src/routes/analytics-consent.ts +123 -0
  320. package/src/routes/api-integrations.ts +364 -74
  321. package/src/routes/api-keys.ts +336 -10
  322. package/src/routes/artifact-catalog.ts +279 -0
  323. package/src/routes/automations.ts +768 -0
  324. package/src/routes/billing.ts +461 -46
  325. package/src/routes/browser-sessions.ts +780 -112
  326. package/src/routes/canonical-human-identities.ts +90 -14
  327. package/src/routes/capabilities.ts +107 -6
  328. package/src/routes/channels.ts +20 -3
  329. package/src/routes/claude-subscription-accounts.ts +334 -0
  330. package/src/routes/claude-subscription-oauth.ts +142 -0
  331. package/src/routes/client-errors.ts +362 -0
  332. package/src/routes/codex.ts +833 -116
  333. package/src/routes/company-brain.ts +322 -0
  334. package/src/routes/company-profile.ts +65 -1
  335. package/src/routes/computer-sessions.ts +557 -106
  336. package/src/routes/connect.ts +1938 -0
  337. package/src/routes/connections.ts +1039 -349
  338. package/src/routes/documents.ts +488 -287
  339. package/src/routes/editable-artifacts.ts +79 -9
  340. package/src/routes/enrollments.ts +135 -39
  341. package/src/routes/environments.ts +154 -58
  342. package/src/routes/external-identity-links.ts +201 -0
  343. package/src/routes/feedback.ts +113 -0
  344. package/src/routes/files.ts +267 -33
  345. package/src/routes/github-browser-pages.ts +162 -0
  346. package/src/routes/github.ts +446 -144
  347. package/src/routes/insights-response-cache.ts +83 -0
  348. package/src/routes/insights-usage.ts +345 -0
  349. package/src/routes/insights.ts +153 -19
  350. package/src/routes/install.ts +133 -38
  351. package/src/routes/integration-facets.ts +107 -33
  352. package/src/routes/interaction-resources.ts +30 -3
  353. package/src/routes/knowledge.ts +488 -0
  354. package/src/routes/machines.ts +313 -15
  355. package/src/routes/managed-auth-session-sets.ts +1218 -0
  356. package/src/routes/managed-onboarding.ts +337 -0
  357. package/src/routes/managed-sign-in-methods.ts +433 -0
  358. package/src/routes/memory-slack-publications.ts +3 -2
  359. package/src/routes/model-connection-access.ts +208 -0
  360. package/src/routes/organization-integration-policy.ts +116 -0
  361. package/src/routes/organization-integrations.ts +326 -0
  362. package/src/routes/organization-mcp-connections.ts +178 -0
  363. package/src/routes/organization-memberships.ts +1019 -27
  364. package/src/routes/organization-model-providers.ts +293 -0
  365. package/src/routes/organization-recovery.ts +325 -0
  366. package/src/routes/organization-service-accounts.ts +128 -0
  367. package/src/routes/organization-sessions.ts +350 -0
  368. package/src/routes/personal-github-git-broker.ts +785 -0
  369. package/src/routes/personal-github.ts +370 -0
  370. package/src/routes/plugins.ts +251 -22
  371. package/src/routes/pr-review-github.ts +881 -0
  372. package/src/routes/pr-review.ts +622 -0
  373. package/src/routes/preference-registry.ts +12 -93
  374. package/src/routes/rigs.ts +167 -50
  375. package/src/routes/scheduled-tasks.ts +346 -41
  376. package/src/routes/session-artifact-associations.ts +87 -0
  377. package/src/routes/session-history-imports.ts +280 -0
  378. package/src/routes/sessions.ts +2306 -264
  379. package/src/routes/skill-content.ts +297 -0
  380. package/src/routes/skill-install-authority.ts +64 -0
  381. package/src/routes/skills.ts +62 -9
  382. package/src/routes/social.ts +46 -18
  383. package/src/routes/subscription-account-pools.ts +436 -0
  384. package/src/routes/subscription-pool-access.ts +126 -0
  385. package/src/routes/supergrok.ts +219 -303
  386. package/src/routes/transcription-recordings.ts +38 -3
  387. package/src/routes/transcriptions.ts +4 -0
  388. package/src/routes/usage-allowances.ts +378 -0
  389. package/src/routes/user-resource-authorities.ts +138 -0
  390. package/src/routes/video-generation.ts +14 -10
  391. package/src/routes/workspace-artifacts.ts +275 -69
  392. package/src/routes/workspace-capture.ts +21 -0
  393. package/src/routes/workspace-integrations.ts +576 -0
  394. package/src/routes/workspace-learning.ts +159 -0
  395. package/src/routes/workspace-model-providers.ts +148 -0
  396. package/src/routes/workspace-state.ts +38 -25
  397. package/src/routes/workspaces.ts +1004 -127
  398. package/src/sandbox/auth-callout.ts +96 -19
  399. package/src/sandbox/channel-a.ts +323 -24
  400. package/src/sandbox/connection-authority.ts +3 -0
  401. package/src/sandbox/enrollment.ts +81 -6
  402. package/src/sandbox/machines.ts +218 -76
  403. package/src/sandbox/metrics-ingestion.ts +411 -62
  404. package/src/sandbox/rematerialize.ts +121 -19
  405. package/src/sandbox/session-attach-variable-sets.ts +131 -0
  406. package/src/sandbox/viewer.ts +280 -25
  407. package/src/sandbox-file-artifacts.ts +413 -0
  408. package/src/scheduled-task-deletion.ts +138 -0
  409. package/src/session-create-observability.ts +46 -0
  410. package/src/session-realtime-context.ts +6 -3
  411. package/src/site-session-origin.ts +48 -0
  412. package/src/site-uploads.ts +224 -0
  413. package/src/slack-reaction-files.ts +16 -5
  414. package/src/temporal-schedule-cleanup.ts +13 -0
  415. package/src/temporal-schedule-sync.ts +74 -0
  416. package/src/transcription/providers/codex-subscription.ts +2 -0
  417. package/src/transcription/providers/openai.ts +1 -0
  418. package/src/transcription/providers/xai-subscription.ts +49 -3
  419. package/src/transcription/segmenter.ts +8 -2
  420. package/src/transcription/service.ts +43 -6
  421. package/src/work-discovery-observability.ts +121 -0
  422. package/src/workspace-artifact-content.ts +144 -0
  423. package/src/workspace-artifact-provenance.ts +104 -0
  424. package/src/workspace-delete-observability.ts +75 -0
  425. package/src/workspace-deletion.ts +73 -0
  426. package/src/workspace-state-projection.ts +18 -148
  427. package/src/workspace-tool-gateway-observability.ts +100 -0
  428. package/src/workspace-tool-gateway.ts +870 -0
  429. package/src/workspace-webhook-dispatch.ts +190 -0
  430. package/src/xai-subscription-auth.ts +9 -2
  431. package/dist/chunk-WCXHI3FF.js +0 -49920
  432. package/dist/chunk-WCXHI3FF.js.map +0 -1
  433. package/dist/routes/packs.d.ts +0 -3
  434. package/src/routes/packs.ts +0 -729
@@ -0,0 +1,433 @@
1
+ import {
2
+ ManagedSignInMethods,
3
+ ManagedSignInPasswordMutation,
4
+ ManagedSignInProviderMutation,
5
+ ManagedSignInMutationResponse,
6
+ } from "@opengeni/contracts/managed-sign-in-methods";
7
+ import type { ApiRouteDeps } from "@opengeni/core";
8
+ import {
9
+ requireCanonicalHumanRequestIdentity,
10
+ getManagedAuthRequestActorLeaseStamp,
11
+ markManagedAuthRequestActorTransitionApplied,
12
+ } from "@opengeni/core/canonical-human-identities";
13
+ import {
14
+ MANAGED_AUTH_SESSION_SET_COOKIE,
15
+ managedAuthSha256,
16
+ managedAuthSecretRequestDigest,
17
+ requireManagedAuthMutationAdmission,
18
+ } from "@opengeni/core/managed-auth-session-sets";
19
+ import { getManagedAuthSessionSetSnapshot } from "@opengeni/db/managed-auth-session-sets";
20
+ import { getCanonicalHumanIdentityProjection } from "@opengeni/db/canonical-human-identities";
21
+ import { sql } from "drizzle-orm";
22
+ import type { Context, Hono } from "hono";
23
+ import { getCookie } from "hono/cookie";
24
+ import { HTTPException } from "hono/http-exception";
25
+ import { z } from "zod";
26
+ import {
27
+ isolatedManagedAuthOAuthCallbackRequest,
28
+ hashManagedAuthPassword,
29
+ verifyManagedAuthPassword,
30
+ } from "../auth/managed-auth";
31
+ import { runManagedSignInConnect } from "../auth/managed-auth-attempt-context";
32
+ import { deliverManagedSignInNotification } from "../auth/managed-sign-in-notifications";
33
+ import { managedAuthSelectedProofHeaders } from "../auth/managed-auth-session-adapter";
34
+ import { scrubManagedAuthProviderResponse } from "./managed-auth-session-sets";
35
+
36
+ const ConnectState = z.object({
37
+ opengeniSignInMethod: z.object({
38
+ intentId: z.string().uuid(),
39
+ provider: z.enum(["google", "github"]),
40
+ }),
41
+ link: z.object({ userId: z.string().min(1), email: z.string().email() }),
42
+ callbackURL: z.string().url(),
43
+ errorURL: z.string().url(),
44
+ });
45
+ const ConnectIntent = z.object({
46
+ authUserId: z.string().min(1),
47
+ authSessionId: z.string().min(1),
48
+ expectedIdentityId: z.string().uuid(),
49
+ actorFence: z
50
+ .object({
51
+ authorityHash: z.string().regex(/^[0-9a-f]{64}$/),
52
+ actorEpoch: z.string().regex(/^[1-9][0-9]*$/),
53
+ requestId: z.string().uuid(),
54
+ })
55
+ .optional(),
56
+ });
57
+
58
+ async function rows<T>(deps: ApiRouteDeps, query: ReturnType<typeof sql>): Promise<T[]> {
59
+ const result = await deps.db.execute(query);
60
+ return (Array.isArray(result) ? result : (result as { rows: T[] }).rows) as T[];
61
+ }
62
+
63
+ async function identity(context: Context, deps: ApiRouteDeps) {
64
+ return requireCanonicalHumanRequestIdentity(context, {
65
+ db: deps.db,
66
+ managedAuth: deps.managedAuth,
67
+ managedAuthSessionAdapter: deps.managedAuthSessionAdapter,
68
+ managedAuthSessionSetMode: deps.settings.managedAuthSessionSetMode,
69
+ });
70
+ }
71
+
72
+ export async function admitManagedSignInMutation(context: Context, deps: ApiRouteDeps) {
73
+ const origin = deps.settings.publicBaseUrl ? new URL(deps.settings.publicBaseUrl).origin : null;
74
+ if (
75
+ !origin ||
76
+ context.req.header("origin") !== origin ||
77
+ context.req.header("sec-fetch-site") !== "same-origin" ||
78
+ context.req.header("content-type")?.split(";", 1)[0] !== "application/json"
79
+ ) {
80
+ throw new HTTPException(403, { message: "Same-origin browser mutation required" });
81
+ }
82
+ const authority = getCookie(context, MANAGED_AUTH_SESSION_SET_COOKIE);
83
+ if (deps.settings.managedAuthSessionSetMode !== "legacy" && authority) {
84
+ const snapshot = await getManagedAuthSessionSetSnapshot(deps.db, {
85
+ authorityHash: managedAuthSha256(authority),
86
+ mode: deps.settings.managedAuthSessionSetMode,
87
+ readOnly: true,
88
+ });
89
+ if (!snapshot) throw new HTTPException(401);
90
+ try {
91
+ requireManagedAuthMutationAdmission({
92
+ request: context.req.raw,
93
+ allowedOrigins: [origin],
94
+ authority,
95
+ signingSecret: deps.settings.betterAuthSecret!,
96
+ expectedGeneration: snapshot.projection.generation,
97
+ });
98
+ } catch {
99
+ throw new HTTPException(403, { message: "Browser session-set CSRF validation failed" });
100
+ }
101
+ }
102
+ }
103
+
104
+ function configured(deps: ApiRouteDeps, provider: "credential" | "google" | "github") {
105
+ return (
106
+ provider === "credential" ||
107
+ (provider === "google"
108
+ ? Boolean(
109
+ deps.settings.managedAuthGoogleClientId && deps.settings.managedAuthGoogleClientSecret,
110
+ )
111
+ : Boolean(
112
+ deps.settings.managedAuthGithubClientId && deps.settings.managedAuthGithubClientSecret,
113
+ ))
114
+ );
115
+ }
116
+
117
+ function mutationError(context: Context, error: unknown): Response {
118
+ let candidate: unknown = error;
119
+ for (
120
+ let depth = 0;
121
+ depth < 5 && candidate instanceof Error;
122
+ depth++, candidate = candidate.cause
123
+ ) {
124
+ const code = candidate.message.match(/SIGN_IN_METHOD_[A-Z_]+/)?.[0];
125
+ if (code)
126
+ return context.json(
127
+ { code, message: code.toLowerCase().replaceAll("_", " ") },
128
+ code.includes("CONFLICT") ||
129
+ code.includes("REUSED") ||
130
+ code.includes("CHANGED") ||
131
+ code.includes("COLLISION") ||
132
+ code.includes("ALREADY")
133
+ ? 409
134
+ : 403,
135
+ );
136
+ }
137
+ throw error;
138
+ }
139
+
140
+ export function registerManagedSignInMethodRoutes(app: Hono, deps: ApiRouteDeps): void {
141
+ const base = "/v1/auth/sign-in-methods";
142
+ app.use(`${base}*`, async (context, next) => {
143
+ context.header("cache-control", "no-store");
144
+ await next();
145
+ });
146
+ app.get(base, async (context) => {
147
+ const actor = await identity(context, deps);
148
+ const projection = await getCanonicalHumanIdentityProjection(deps.db, actor.authUserId);
149
+ const [user] = await rows<{ email: string; emailVerified: boolean; fresh: boolean }>(
150
+ deps,
151
+ sql`
152
+ select u.email, u.email_verified as "emailVerified", s.created_at > clock_timestamp()-interval '5 minutes' as fresh
153
+ from auth_users u join auth_sessions s on s.user_id=u.id where u.id=${actor.authUserId} and s.id=${actor.authSessionId}`,
154
+ );
155
+ if (!user) throw new HTTPException(401);
156
+ const accounts = await rows<{ provider: string; usable: boolean }>(
157
+ deps,
158
+ sql`
159
+ select provider_id as provider, (provider_id <> 'credential' or length(password)>0) as usable from auth_identities where user_id=${actor.authUserId}`,
160
+ );
161
+ const connected = (provider: string) =>
162
+ accounts.some((a) => a.provider === provider && a.usable) &&
163
+ projection.loginBindings.some((b) => b.providerId === provider && b.status === "active");
164
+ const count = (["credential", "google", "github"] as const).filter(
165
+ (p) => connected(p) && configured(deps, p),
166
+ ).length;
167
+ return context.json(
168
+ ManagedSignInMethods.parse({
169
+ ...user,
170
+ identityId: projection.activeIdentity.id,
171
+ identityRevision: projection.activeIdentity.identityRevision,
172
+ freshAuthenticationRequired: !user.fresh,
173
+ methods: (["credential", "google", "github"] as const).map((provider) => ({
174
+ provider,
175
+ connected: connected(provider),
176
+ available: configured(deps, provider),
177
+ canDisconnect:
178
+ provider !== "credential" &&
179
+ connected(provider) &&
180
+ count - (configured(deps, provider) ? 1 : 0) > 0,
181
+ implicitRelinkingSuppressed:
182
+ !connected(provider) &&
183
+ projection.loginBindings.some(
184
+ (b) => b.providerId === provider && b.status !== "active",
185
+ ),
186
+ })),
187
+ }),
188
+ );
189
+ });
190
+ for (const kind of ["connect", "disconnect", "password"] as const) {
191
+ app.post(`${base}/${kind}`, async (context) => {
192
+ await admitManagedSignInMutation(context, deps);
193
+ const actor = await identity(context, deps);
194
+ const actorFence = getManagedAuthRequestActorLeaseStamp(context.req.raw);
195
+ if (deps.settings.managedAuthSessionSetMode !== "legacy" && !actorFence)
196
+ throw new HTTPException(409, { message: "Managed actor fence required" });
197
+ const schema =
198
+ kind === "password" ? ManagedSignInPasswordMutation : ManagedSignInProviderMutation;
199
+ const parsed = schema.safeParse(await context.req.json().catch(() => null));
200
+ if (!parsed.success)
201
+ throw new HTTPException(422, { message: "Invalid sign-in method request" });
202
+ const body = parsed.data;
203
+ const currentIdentity = await getCanonicalHumanIdentityProjection(deps.db, actor.authUserId);
204
+ if (currentIdentity.activeIdentity.id !== body.expectedIdentityId)
205
+ return context.json(
206
+ {
207
+ code: "SIGN_IN_METHOD_IDENTITY_CHANGED",
208
+ message: "The signed-in account changed; reload security settings",
209
+ },
210
+ 409,
211
+ );
212
+ const [user] = await rows<{ email: string; token: string }>(
213
+ deps,
214
+ sql`select u.email,s.token from auth_users u join auth_sessions s on s.user_id=u.id where u.id=${actor.authUserId} and s.id=${actor.authSessionId}`,
215
+ );
216
+ if (!user) throw new HTTPException(401);
217
+ const request: Record<string, unknown> = {
218
+ kind,
219
+ operationId: body.operationId,
220
+ requestDigest: managedAuthSecretRequestDigest(deps.settings.betterAuthSecret!, {
221
+ kind,
222
+ ...body,
223
+ }),
224
+ expectedIdentityRevision: body.expectedIdentityRevision,
225
+ expectedIdentityId: body.expectedIdentityId,
226
+ usableProviders: (["credential", "google", "github"] as const).filter((p) =>
227
+ configured(deps, p),
228
+ ),
229
+ ...(actorFence ? { actorFence } : {}),
230
+ };
231
+ try {
232
+ const [prior] = await rows<{ result: unknown }>(
233
+ deps,
234
+ sql`select replay_managed_sign_in_method(${actor.authUserId},${actor.authSessionId},${JSON.stringify(request)}::jsonb) result`,
235
+ );
236
+ if (prior?.result)
237
+ return context.json(
238
+ kind === "connect"
239
+ ? {
240
+ url: new URL(
241
+ "/settings/security?signInMethod=connected",
242
+ deps.settings.publicBaseUrl!,
243
+ ).toString(),
244
+ }
245
+ : ManagedSignInMutationResponse.parse(prior.result),
246
+ );
247
+ } catch (error) {
248
+ return mutationError(context, error);
249
+ }
250
+ // Per-human, cross-replica admission before password hashing or creating
251
+ // OAuth state. Successful committed-result replay does not spend a slot.
252
+ const [limit] = await rows<{ count: number }>(
253
+ deps,
254
+ sql`
255
+ insert into auth_rate_limits(id,key,count,last_request)
256
+ values(${`sign-in-methods:${actor.authUserId}`},${`sign-in-methods:${actor.authUserId}`},1,(extract(epoch from clock_timestamp())*1000)::bigint)
257
+ on conflict(key) do update set
258
+ count=case when auth_rate_limits.last_request < (extract(epoch from clock_timestamp())*1000)::bigint-60000 then 1 else least(auth_rate_limits.count+1,11) end,
259
+ last_request=case when auth_rate_limits.last_request < (extract(epoch from clock_timestamp())*1000)::bigint-60000 then (extract(epoch from clock_timestamp())*1000)::bigint else auth_rate_limits.last_request end
260
+ returning count`,
261
+ );
262
+ if (!limit || limit.count > 10)
263
+ return context.json(
264
+ {
265
+ code: "SIGN_IN_METHOD_RATE_LIMITED",
266
+ message: "Too many sign-in method attempts; try again in one minute",
267
+ },
268
+ 429,
269
+ );
270
+ if ("provider" in body) {
271
+ request.provider = body.provider;
272
+ if (kind === "connect" && !configured(deps, body.provider))
273
+ throw new HTTPException(409, { message: "Sign-in provider is not configured" });
274
+ } else {
275
+ const [credential] = await rows<{ password: string | null }>(
276
+ deps,
277
+ sql`select password from auth_identities where user_id=${actor.authUserId} and provider_id='credential'`,
278
+ );
279
+ if (
280
+ credential?.password &&
281
+ (!body.currentPassword ||
282
+ !(await verifyManagedAuthPassword(body.currentPassword, credential.password)))
283
+ ) {
284
+ return context.json(
285
+ {
286
+ code: "SIGN_IN_METHOD_CURRENT_PASSWORD_REQUIRED",
287
+ message: "Enter your current password",
288
+ },
289
+ 403,
290
+ );
291
+ }
292
+ request.expectedPasswordHash = credential?.password ?? null;
293
+ request.passwordHash = await hashManagedAuthPassword(body.newPassword);
294
+ }
295
+ try {
296
+ await rows(
297
+ deps,
298
+ sql`select mutate_managed_sign_in_method(${actor.authUserId},${actor.authSessionId},${JSON.stringify(request)}::jsonb)`,
299
+ );
300
+ if (kind === "connect" && "provider" in body) {
301
+ const headers = await managedAuthSelectedProofHeaders(deps.managedAuth!, user.token);
302
+ headers.set("origin", new URL(deps.settings.publicBaseUrl!).origin);
303
+ const callbackURL = new URL(
304
+ "/settings/security?signInMethod=connected",
305
+ deps.settings.publicBaseUrl!,
306
+ ).toString();
307
+ const errorCallbackURL = new URL(
308
+ "/settings/security?signInMethod=error",
309
+ deps.settings.publicBaseUrl!,
310
+ ).toString();
311
+ const result = await deps.managedAuth!.api.linkSocialAccount({
312
+ headers,
313
+ returnHeaders: true,
314
+ body: {
315
+ provider: body.provider,
316
+ callbackURL,
317
+ errorCallbackURL,
318
+ disableRedirect: true,
319
+ additionalData: {
320
+ opengeniSignInMethod: { intentId: body.operationId, provider: body.provider },
321
+ },
322
+ },
323
+ });
324
+ for (const cookie of result.headers.getSetCookie())
325
+ context.header("set-cookie", cookie, { append: true });
326
+ return context.json({ url: result.response.url });
327
+ }
328
+ if (actorFence) markManagedAuthRequestActorTransitionApplied(context.req.raw);
329
+ return context.json({
330
+ reauthenticationRequired: true,
331
+ notification: await deliverManagedSignInNotification(
332
+ deps.db,
333
+ deps.managedEmailTransport,
334
+ body.operationId,
335
+ ),
336
+ });
337
+ } catch (error) {
338
+ return mutationError(context, error);
339
+ }
340
+ });
341
+ }
342
+ }
343
+
344
+ /** Intercept only database-backed, product-issued explicit connect states. */
345
+ export async function handleManagedSignInConnectCallback(
346
+ context: Context,
347
+ deps: ApiRouteDeps,
348
+ provider: "google" | "github",
349
+ ): Promise<Response | null> {
350
+ const state = context.req.query("state");
351
+ if (!state || !deps.managedAuth) return null;
352
+ const verification = await (
353
+ await deps.managedAuth.$context
354
+ ).internalAdapter.findVerificationValue(state);
355
+ if (!verification?.value) return null;
356
+ let rawState: unknown;
357
+ try {
358
+ rawState = JSON.parse(verification.value);
359
+ } catch {
360
+ return null;
361
+ }
362
+ if (!rawState || typeof rawState !== "object" || !("opengeniSignInMethod" in rawState))
363
+ return null;
364
+ const parsed = ConnectState.safeParse(rawState);
365
+ if (!parsed.success)
366
+ throw new HTTPException(403, { message: "Invalid sign-in method OAuth proof" });
367
+ const value = parsed.data,
368
+ proof = value.opengeniSignInMethod;
369
+ if (
370
+ proof.provider !== provider ||
371
+ value.callbackURL !==
372
+ new URL(
373
+ "/settings/security?signInMethod=connected",
374
+ deps.settings.publicBaseUrl!,
375
+ ).toString() ||
376
+ value.errorURL !==
377
+ new URL("/settings/security?signInMethod=error", deps.settings.publicBaseUrl!).toString()
378
+ )
379
+ throw new HTTPException(403);
380
+ const [intent] = await rows<{ value: string }>(
381
+ deps,
382
+ sql`select value from auth_verifications where identifier=${`managed-sign-in:${proof.intentId}`} and expires_at>clock_timestamp()`,
383
+ );
384
+ if (!intent) throw new HTTPException(403, { message: "Sign-in method connection expired" });
385
+ const request = ConnectIntent.parse(JSON.parse(intent.value));
386
+ const authority = getCookie(context, MANAGED_AUTH_SESSION_SET_COOKIE);
387
+ if (!request.actorFence) {
388
+ const ambient = await deps.managedAuthSessionAdapter?.resolveAmbientSession(
389
+ context.req.raw.headers,
390
+ );
391
+ if (
392
+ !ambient ||
393
+ ambient.session.id !== request.authSessionId ||
394
+ ambient.user.id !== request.authUserId
395
+ ) {
396
+ return context.redirect(
397
+ new URL(
398
+ "/settings/security?signInMethod=error&error=SIGN_IN_METHOD_IDENTITY_CHANGED",
399
+ deps.settings.publicBaseUrl!,
400
+ ).toString(),
401
+ );
402
+ }
403
+ }
404
+ if (
405
+ request.actorFence &&
406
+ (!authority || managedAuthSha256(authority) !== request.actorFence.authorityHash)
407
+ )
408
+ throw new HTTPException(403);
409
+ if (value.link?.userId !== request.authUserId || value.link?.email === undefined)
410
+ throw new HTTPException(403);
411
+ const isolated = await isolatedManagedAuthOAuthCallbackRequest(deps.managedAuth, context.req.raw);
412
+ const response = await runManagedSignInConnect(proof.intentId, () =>
413
+ deps.managedAuth!.handler(isolated.request),
414
+ );
415
+ const [linked] = await rows<{ email: string }>(
416
+ deps,
417
+ sql`select u.email from auth_identities a join auth_users u on u.id=a.user_id where a.managed_link_intent_id=${proof.intentId}`,
418
+ );
419
+ if (linked)
420
+ await deliverManagedSignInNotification(deps.db, deps.managedEmailTransport, proof.intentId);
421
+ if (response.status >= 400 || !linked) {
422
+ return context.redirect(
423
+ new URL(
424
+ "/settings/security?signInMethod=error&error=SIGN_IN_METHOD_CONNECT_FAILED",
425
+ deps.settings.publicBaseUrl!,
426
+ ).toString(),
427
+ );
428
+ }
429
+ return scrubManagedAuthProviderResponse(response, {
430
+ replacementCookies: [],
431
+ preserveCookieNames: [isolated.stateCookieName],
432
+ });
433
+ }
@@ -25,6 +25,7 @@ import {
25
25
  import type { Hono } from "hono";
26
26
  import { HTTPException } from "hono/http-exception";
27
27
  import { createOpenGeniSlackBotInteractionClient } from "../integrations/slack-bot";
28
+ import { parseRequestJson } from "../http/request-body";
28
29
 
29
30
  export function registerMemorySlackPublicationRoutes(app: Hono, deps: ApiRouteDeps): void {
30
31
  const base = "/v1/workspaces/:workspaceId/memory-slack-publications";
@@ -45,7 +46,7 @@ export function registerMemorySlackPublicationRoutes(app: Hono, deps: ApiRouteDe
45
46
  app.put(`${base}/configuration`, async (c) => {
46
47
  const workspaceId = c.req.param("workspaceId");
47
48
  const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
48
- const payload = UpdateMemorySlackPublicationConfigurationRequest.parse(await c.req.json());
49
+ const payload = await parseRequestJson(c, UpdateMemorySlackPublicationConfigurationRequest);
49
50
  let slackTeamId: string | null = null;
50
51
  let channelName = payload.slackChannelName;
51
52
  if (payload.connectionId || payload.slackChannelId) {
@@ -179,7 +180,7 @@ export function registerMemorySlackPublicationRoutes(app: Hono, deps: ApiRouteDe
179
180
  app.post(`${base}/:publicationId/action`, async (c) => {
180
181
  const workspaceId = c.req.param("workspaceId");
181
182
  const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
182
- const payload = MemorySlackPublicationActionRequest.parse(await c.req.json());
183
+ const payload = await parseRequestJson(c, MemorySlackPublicationActionRequest);
183
184
  const publication = await actOnMemorySlackPublication(deps.db, {
184
185
  workspaceId,
185
186
  publicationId: c.req.param("publicationId"),
@@ -0,0 +1,208 @@
1
+ import { claudeProviderId, withClaudeConnectionCatalog } from "@opengeni/config";
2
+ import {
3
+ configuredModels,
4
+ withCodexCatalogProvider,
5
+ withXaiSubscriptionCatalogProvider,
6
+ withOrganizationGatewayCatalogProvider,
7
+ withOrganizationOpenRouterCatalogProvider,
8
+ } from "@opengeni/config";
9
+ import { ModelConnectionAccessPolicy, ModelConnectionAccessResponse } from "@opengeni/contracts";
10
+ import {
11
+ requireAccessGrant,
12
+ resolveWorkspaceCatalogSettings,
13
+ type ApiRouteDeps,
14
+ } from "@opengeni/core";
15
+ import {
16
+ getModelConnectionAccess,
17
+ updateModelConnectionAccess,
18
+ getOrganizationAdministrationOverview,
19
+ getXaiSubscriptionAccountAuthoritySnapshot,
20
+ getClaudeSubscriptionAccountAuthoritySnapshot,
21
+ listOrganizationModelProviderCustomModels,
22
+ getWorkspaceProviderApiKeyConnectionMetadata,
23
+ type ModelConnectionTarget,
24
+ } from "@opengeni/db";
25
+ import type { Context, Hono } from "hono";
26
+ import { HTTPException } from "hono/http-exception";
27
+ import { z } from "zod";
28
+ import {
29
+ managedHumanOrAgent,
30
+ requireOrganizationCodexHuman,
31
+ requireSameOriginBrowserMutation,
32
+ } from "./codex";
33
+ import { requireScopeMutation } from "./supergrok";
34
+ import {
35
+ requirePrivateSubscriptionHuman,
36
+ requireSubscriptionScopeMutation,
37
+ } from "./subscription-pool-access";
38
+
39
+ const Kind = z.enum([
40
+ "codex",
41
+ "supergrok",
42
+ "vercel_gateway",
43
+ "openrouter",
44
+ "anthropic",
45
+ "claude_subscription",
46
+ ]);
47
+ function modelPrefix(target: ModelConnectionTarget) {
48
+ if (target.kind === "anthropic" || target.kind === "claude_subscription")
49
+ return (
50
+ claudeProviderId(target.kind, target.workspaceId === null ? "organization" : "workspace") +
51
+ "/"
52
+ );
53
+ if (target.kind === "codex" || target.kind === "supergrok") return `${target.kind}/`;
54
+ return `${target.workspaceId === null ? "organization" : "workspace"}-${target.kind === "vercel_gateway" ? "gateway" : "openrouter"}/`;
55
+ }
56
+
57
+ export function registerModelConnectionAccessRoutes(app: Hono, deps: ApiRouteDeps) {
58
+ for (const scope of ["organizations", "workspaces"] as const) {
59
+ const path = `/v1/${scope}/:scopeId/model-connections/:kind/:connectionId/access`;
60
+ async function target(c: Context, mutate: boolean): Promise<ModelConnectionTarget> {
61
+ const kind = Kind.parse(c.req.param("kind"));
62
+ if (kind === "claude_subscription" && !deps.settings.claudeSubscriptionEnabled)
63
+ throw new HTTPException(404, { message: "Claude subscriptions are not enabled" });
64
+ const scopeId = z.string().uuid().parse(c.req.param("scopeId"));
65
+ let connectionId = c.req.param("connectionId")!;
66
+ if (kind === "codex" || kind === "supergrok" || kind === "claude_subscription")
67
+ connectionId = z.string().uuid().parse(connectionId);
68
+ if (scope === "organizations") {
69
+ if (mutate) requireSameOriginBrowserMutation(c, deps);
70
+ const human = await requireOrganizationCodexHuman(c, deps, scopeId);
71
+ return {
72
+ kind,
73
+ connectionId,
74
+ accountId: scopeId,
75
+ workspaceId: null,
76
+ subjectId: human.subjectId,
77
+ };
78
+ }
79
+ const grant = await requireAccessGrant(c, deps, scopeId, "workspace:read");
80
+ if (kind === "supergrok") {
81
+ const snapshot = await getXaiSubscriptionAccountAuthoritySnapshot(deps.db, {
82
+ workspaceId: scopeId,
83
+ subjectId: grant.subjectId,
84
+ credentialId: connectionId,
85
+ });
86
+ if (!snapshot) throw new HTTPException(404, { message: "Subscription not found" });
87
+ if (snapshot.scope === "user") {
88
+ const human = await managedHumanOrAgent(c, deps);
89
+ if (!human || human.subjectId !== grant.subjectId)
90
+ throw new HTTPException(403, {
91
+ message: "Subscription owner browser session required",
92
+ });
93
+ }
94
+ if (mutate) await requireScopeMutation(c, deps, scopeId, snapshot.scope);
95
+ } else if (kind === "claude_subscription") {
96
+ const snapshot = await getClaudeSubscriptionAccountAuthoritySnapshot(deps.db, {
97
+ workspaceId: scopeId,
98
+ subjectId: grant.subjectId,
99
+ credentialId: connectionId,
100
+ });
101
+ if (!snapshot) throw new HTTPException(404, { message: "Subscription not found" });
102
+ if (snapshot.scope === "user") {
103
+ const human = await requirePrivateSubscriptionHuman(c, deps, scopeId, "Claude");
104
+ if (human.subjectId !== grant.subjectId)
105
+ throw new HTTPException(403, { message: "Subscription owner required" });
106
+ }
107
+ if (mutate) {
108
+ if (!c.req.header("authorization")) requireSameOriginBrowserMutation(c, deps);
109
+ await requireSubscriptionScopeMutation(c, deps, scopeId, snapshot.scope, "Claude");
110
+ }
111
+ } else if (mutate) await requireAccessGrant(c, deps, scopeId, "workspace:admin");
112
+ if (kind === "vercel_gateway" || kind === "openrouter" || kind === "anthropic") {
113
+ const metadata = await getWorkspaceProviderApiKeyConnectionMetadata(deps.db, scopeId, kind);
114
+ if (!metadata || (connectionId !== "current" && metadata.connectionId !== connectionId))
115
+ throw new HTTPException(404, { message: "Connection not found" });
116
+ connectionId = metadata.connectionId;
117
+ }
118
+ return {
119
+ kind,
120
+ connectionId,
121
+ accountId: grant.accountId,
122
+ workspaceId: scopeId,
123
+ subjectId: grant.subjectId,
124
+ };
125
+ }
126
+ app.get(path, async (c) => {
127
+ c.header("cache-control", "private, no-store");
128
+ const connection = await target(c, false);
129
+ const policy = await getModelConnectionAccess(deps.db, connection);
130
+ if (!policy) throw new HTTPException(404, { message: "Connection not found" });
131
+ let settings =
132
+ connection.workspaceId === null
133
+ ? (await deps.resolveCatalogSettings()).settings
134
+ : (
135
+ await resolveWorkspaceCatalogSettings(deps.db, deps.settings, {
136
+ accountId: connection.accountId,
137
+ workspaceId: connection.workspaceId,
138
+ })
139
+ ).settings;
140
+ settings = withCodexCatalogProvider(withXaiSubscriptionCatalogProvider(settings));
141
+ let workspaces: Array<{ id: string; name: string }> = [];
142
+ if (connection.workspaceId === null) {
143
+ const actor = {
144
+ organizationId: connection.accountId,
145
+ actorSubjectId: connection.subjectId,
146
+ };
147
+ workspaces = (await getOrganizationAdministrationOverview(deps.db, actor)).workspaces.map(
148
+ ({ id, name }) => ({ id, name }),
149
+ );
150
+ if (connection.kind === "anthropic" || connection.kind === "claude_subscription") {
151
+ const customModels = await listOrganizationModelProviderCustomModels(deps.db, {
152
+ organizationId: connection.accountId,
153
+ actorSubjectId: connection.subjectId,
154
+ providerKind: connection.kind,
155
+ });
156
+ settings = withClaudeConnectionCatalog(settings, {
157
+ [connection.kind]: { models: customModels },
158
+ });
159
+ }
160
+ if (connection.kind === "vercel_gateway" || connection.kind === "openrouter") {
161
+ const models = await listOrganizationModelProviderCustomModels(deps.db, {
162
+ ...actor,
163
+ providerKind: connection.kind,
164
+ });
165
+ settings =
166
+ connection.kind === "vercel_gateway"
167
+ ? withOrganizationGatewayCatalogProvider(settings, models)
168
+ : withOrganizationOpenRouterCatalogProvider(settings, models);
169
+ }
170
+ }
171
+ return c.json(
172
+ ModelConnectionAccessResponse.parse({
173
+ policy,
174
+ workspaces,
175
+ models: configuredModels(settings)
176
+ .filter((model) => model.id.startsWith(modelPrefix(connection)))
177
+ .map(({ id, label }) => ({ id, label })),
178
+ personalWorkspacesSupported:
179
+ connection.workspaceId === null &&
180
+ (connection.kind === "codex" ||
181
+ connection.kind === "supergrok" ||
182
+ connection.kind === "claude_subscription"),
183
+ }),
184
+ );
185
+ });
186
+ app.put(path, async (c) => {
187
+ const connection = await target(c, true);
188
+ const parsed = ModelConnectionAccessPolicy.safeParse(await c.req.json().catch(() => null));
189
+ if (!parsed.success)
190
+ throw new HTTPException(422, { message: "Invalid connection access policy" });
191
+ const policy = parsed.data;
192
+ if (policy.allowedModels?.some((id) => !id.startsWith(modelPrefix(connection))))
193
+ throw new HTTPException(422, {
194
+ message: "Model belongs to a different connection provider",
195
+ });
196
+ if (connection.workspaceId !== null && policy.allowedWorkspaces !== null)
197
+ throw new HTTPException(422, {
198
+ message: "Workspace connections cannot be assigned to other workspaces",
199
+ });
200
+ const updated = await updateModelConnectionAccess(deps.db, connection, policy);
201
+ if (!updated)
202
+ throw new HTTPException(409, {
203
+ message: "Connection access changed. Reload before saving.",
204
+ });
205
+ return c.json(updated);
206
+ });
207
+ }
208
+ }