@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,622 @@
1
+ import { environmentsEncryptionKeyBytes } from "@opengeni/config";
2
+ import { withOrganizationIntegrationAcquisition } from "@opengeni/db/organization-integration-policy";
3
+ import {
4
+ CreatePrReviewAppRegistrationRequest,
5
+ CreatePrReviewRepositoryBindingRequest,
6
+ PrReviewAppRegistration,
7
+ PrReviewRepositoryBinding,
8
+ UpdatePrReviewAppRegistrationRequest,
9
+ UpdatePrReviewRepositoryBindingRequest,
10
+ } from "@opengeni/contracts";
11
+ import {
12
+ assertWorkspaceModelPolicyAllows,
13
+ canonicalConfiguredModel,
14
+ defaultPrReviewProviderBaseUrl,
15
+ workspaceCustomModelReference,
16
+ lockActiveCustomModelForAdmission,
17
+ modelUnavailableHttpException,
18
+ prReviewWebhookAuthKind,
19
+ normalizePrReviewProviderBaseUrl,
20
+ requireAccessGrant,
21
+ requireAccessGrantAuthorization,
22
+ requirePermission,
23
+ resolveWorkspaceCatalogSettings,
24
+ type ApiRouteDeps,
25
+ PR_REVIEW_AUTOMATION_SETUP,
26
+ } from "@opengeni/core";
27
+ import {
28
+ createPrReviewAppRegistration,
29
+ createPrReviewRepositoryBinding,
30
+ deletePrReviewAppRegistration,
31
+ deletePrReviewRepositoryBinding,
32
+ decryptVariableSetValue,
33
+ encryptVariableSetValue,
34
+ getPrReviewAppRegistrationSecret,
35
+ listPrReviewAppRegistrations,
36
+ listPrReviewRepositoryBindings,
37
+ nestedPostgresSqlState,
38
+ recordAuditEvent,
39
+ updatePrReviewAppRegistration,
40
+ updatePrReviewRepositoryBinding,
41
+ } from "@opengeni/db";
42
+ import { listGitHubAppRepositoriesWithSigningSettings } from "@opengeni/github";
43
+ import type { Hono } from "hono";
44
+ import { HTTPException } from "hono/http-exception";
45
+ import {
46
+ PrReviewProviderRepositoryError,
47
+ verifyPrReviewProviderRepository,
48
+ } from "../integrations/pr-review-provider";
49
+ import { registerPrReviewGitHubRoutes } from "./pr-review-github";
50
+ import { integrationCommitGrant } from "../integrations/integration-commit-authority";
51
+ import { parseRequestJson } from "../http/request-body";
52
+
53
+ export function registerPrReviewRoutes(app: Hono, deps: ApiRouteDeps): void {
54
+ const { db, settings } = deps;
55
+ registerPrReviewGitHubRoutes(app, deps);
56
+
57
+ app.get("/v1/workspaces/:workspaceId/pr-review/registrations", async (c) => {
58
+ const workspaceId = c.req.param("workspaceId");
59
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:read");
60
+
61
+ return c.json({
62
+ registrations: await listPrReviewAppRegistrations(db, grant.accountId, workspaceId),
63
+ repositories: await listPrReviewRepositoryBindings(db, grant.accountId, workspaceId),
64
+ });
65
+ });
66
+
67
+ app.post("/v1/workspaces/:workspaceId/pr-review/registrations", async (c) => {
68
+ const workspaceId = c.req.param("workspaceId");
69
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
70
+ requirePermission(grant, "secrets:write");
71
+
72
+ assertPrReviewSandboxBackend(deps);
73
+ const payload = await parseRequestJson(c, CreatePrReviewAppRegistrationRequest);
74
+ const encryptionKey = requirePrReviewEncryptionKey(deps);
75
+ let providerBaseUrl: string;
76
+ try {
77
+ providerBaseUrl = normalizePrReviewProviderBaseUrl(
78
+ payload.provider,
79
+ payload.providerBaseUrl ?? defaultPrReviewProviderBaseUrl(payload.provider),
80
+ );
81
+ } catch (error) {
82
+ throw new HTTPException(422, {
83
+ message:
84
+ error instanceof Error
85
+ ? error.message
86
+ : "PR Review providerBaseUrl must be a credential-free HTTPS origin or path",
87
+ });
88
+ }
89
+ if (
90
+ payload.provider === "azure_devops" &&
91
+ new URL(providerBaseUrl).pathname.split("/").filter(Boolean).length === 0
92
+ ) {
93
+ throw new HTTPException(422, {
94
+ message: "Azure DevOps PR Review providerBaseUrl must include the organization path",
95
+ });
96
+ }
97
+ const registration = await mapPrReviewUniqueConflict(
98
+ withOrganizationIntegrationAcquisition(
99
+ db,
100
+ grant,
101
+ [prReviewIntegrationKey(payload.provider)],
102
+ (tx) =>
103
+ createPrReviewAppRegistration(tx, {
104
+ accountId: grant.accountId,
105
+ workspaceId,
106
+ name: payload.name,
107
+ provider: payload.provider,
108
+ providerBaseUrl,
109
+ appId: payload.appId ?? null,
110
+ credentialKind: payload.credentialKind,
111
+ credentialEncrypted: encryptVariableSetValue(
112
+ encryptionKey,
113
+ payload.privateKey ?? payload.accessToken!,
114
+ ),
115
+ accessTokenExpiresAt: payload.accessTokenExpiresAt
116
+ ? new Date(payload.accessTokenExpiresAt)
117
+ : null,
118
+ webhookAuthKind: prReviewWebhookAuthKind(payload.provider),
119
+ webhookSecretEncrypted: encryptVariableSetValue(encryptionKey, payload.webhookSecret),
120
+ webhookUsername: payload.webhookUsername ?? null,
121
+ createdBySubjectId: grant.subjectId,
122
+ }),
123
+ ),
124
+ "A PR Review registration with this provider and name already exists",
125
+ );
126
+ await recordAuditEvent(db, {
127
+ accountId: grant.accountId,
128
+ workspaceId,
129
+ subjectId: grant.subjectId,
130
+ action: "prReview.app_registration.created",
131
+ targetType: "pr_review_app_registration",
132
+ targetId: registration.id,
133
+ metadata: {
134
+ provider: registration.provider,
135
+ credentialKind: registration.credentialKind,
136
+ webhookAuthKind: registration.webhookAuthKind,
137
+ },
138
+ });
139
+ return c.json(PrReviewAppRegistration.parse(registration), 201);
140
+ });
141
+
142
+ app.patch("/v1/workspaces/:workspaceId/pr-review/registrations/:registrationId", async (c) => {
143
+ const workspaceId = c.req.param("workspaceId");
144
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
145
+ requirePermission(grant, "secrets:write");
146
+
147
+ const payload = await parseRequestJson(c, UpdatePrReviewAppRegistrationRequest);
148
+ const existing = await getPrReviewAppRegistrationSecret(db, {
149
+ accountId: grant.accountId,
150
+ workspaceId,
151
+ registrationId: c.req.param("registrationId"),
152
+ });
153
+ if (!existing)
154
+ throw new HTTPException(404, {
155
+ message: "PR Review app registration not found",
156
+ });
157
+ if (existing.credentialKind === "managed_github_app") {
158
+ if (
159
+ payload.accessToken !== undefined ||
160
+ payload.privateKey !== undefined ||
161
+ payload.webhookSecret !== undefined ||
162
+ payload.webhookUsername !== undefined ||
163
+ payload.accessTokenExpiresAt !== undefined
164
+ ) {
165
+ throw new HTTPException(422, {
166
+ message: "Opengeni Lens credentials are managed by the deployment",
167
+ });
168
+ }
169
+ if (payload.status === "active") {
170
+ throw new HTTPException(409, {
171
+ message: "Reconnect Opengeni Lens to reactivate and resync its repositories",
172
+ });
173
+ }
174
+ }
175
+ if (payload.accessToken && existing.credentialKind !== "provider_token") {
176
+ throw new HTTPException(422, {
177
+ message: "GitHub App registrations accept private keys, not access tokens",
178
+ });
179
+ }
180
+ if (payload.privateKey && existing.credentialKind !== "github_app") {
181
+ throw new HTTPException(422, {
182
+ message: "Provider-token registrations do not accept GitHub private keys",
183
+ });
184
+ }
185
+ if (
186
+ payload.accessTokenExpiresAt !== undefined &&
187
+ existing.credentialKind !== "provider_token"
188
+ ) {
189
+ throw new HTTPException(422, {
190
+ message: "GitHub App registrations do not accept access-token expiry",
191
+ });
192
+ }
193
+ const encryptionKey =
194
+ payload.privateKey || payload.accessToken || payload.webhookSecret
195
+ ? requirePrReviewEncryptionKey(deps)
196
+ : null;
197
+ const updated = await mapPrReviewUniqueConflict(
198
+ updatePrReviewAppRegistration(db, {
199
+ accountId: grant.accountId,
200
+ workspaceId,
201
+ registrationId: existing.id,
202
+ ...(payload.name !== undefined ? { name: payload.name } : {}),
203
+ ...(payload.accessToken !== undefined
204
+ ? {
205
+ credentialEncrypted: encryptVariableSetValue(encryptionKey!, payload.accessToken),
206
+ }
207
+ : {}),
208
+ ...(payload.privateKey !== undefined
209
+ ? {
210
+ credentialEncrypted: encryptVariableSetValue(encryptionKey!, payload.privateKey),
211
+ }
212
+ : {}),
213
+ ...(payload.accessTokenExpiresAt !== undefined
214
+ ? {
215
+ accessTokenExpiresAt: payload.accessTokenExpiresAt
216
+ ? new Date(payload.accessTokenExpiresAt)
217
+ : null,
218
+ }
219
+ : {}),
220
+ ...(payload.webhookSecret !== undefined
221
+ ? {
222
+ webhookSecretEncrypted: encryptVariableSetValue(
223
+ encryptionKey!,
224
+ payload.webhookSecret,
225
+ ),
226
+ }
227
+ : {}),
228
+ ...(payload.webhookUsername !== undefined
229
+ ? { webhookUsername: payload.webhookUsername }
230
+ : {}),
231
+ ...(payload.status !== undefined ? { status: payload.status } : {}),
232
+ }),
233
+ "A PR Review registration with this provider and name already exists",
234
+ );
235
+ await recordAuditEvent(db, {
236
+ accountId: grant.accountId,
237
+ workspaceId,
238
+ subjectId: grant.subjectId,
239
+ action: "prReview.app_registration.updated",
240
+ targetType: "pr_review_app_registration",
241
+ targetId: existing.id,
242
+ metadata: {
243
+ fields: Object.keys(payload).filter(
244
+ (field) => field !== "accessToken" && field !== "privateKey" && field !== "webhookSecret",
245
+ ),
246
+ credentialRotated: payload.accessToken !== undefined || payload.privateKey !== undefined,
247
+ webhookSecretRotated: payload.webhookSecret !== undefined,
248
+ },
249
+ });
250
+ return c.json(PrReviewAppRegistration.parse(updated));
251
+ });
252
+
253
+ app.delete("/v1/workspaces/:workspaceId/pr-review/registrations/:registrationId", async (c) => {
254
+ const workspaceId = c.req.param("workspaceId");
255
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
256
+ requirePermission(grant, "secrets:write");
257
+ const deleted = await deletePrReviewAppRegistration(db, {
258
+ accountId: grant.accountId,
259
+ workspaceId,
260
+ registrationId: c.req.param("registrationId"),
261
+ });
262
+ if (!deleted)
263
+ throw new HTTPException(404, {
264
+ message: "PR Review app registration not found",
265
+ });
266
+ await recordAuditEvent(db, {
267
+ accountId: grant.accountId,
268
+ workspaceId,
269
+ subjectId: grant.subjectId,
270
+ action: "prReview.app_registration.disabled",
271
+ targetType: "pr_review_app_registration",
272
+ targetId: c.req.param("registrationId"),
273
+ metadata: {},
274
+ });
275
+ return c.body(null, 204);
276
+ });
277
+
278
+ app.post("/v1/workspaces/:workspaceId/pr-review/repositories", async (c) => {
279
+ const workspaceId = c.req.param("workspaceId");
280
+ const grant = await integrationCommitGrant(
281
+ await requireAccessGrantAuthorization(c, deps, workspaceId, "workspace:admin"),
282
+ ["workspace:admin"],
283
+ { settings: deps.settings, authorizationHeader: c.req.header("authorization") },
284
+ );
285
+
286
+ const payload = await parseRequestJson(c, CreatePrReviewRepositoryBindingRequest);
287
+ const registration = await getPrReviewAppRegistrationSecret(db, {
288
+ accountId: grant.accountId,
289
+ workspaceId,
290
+ registrationId: payload.registrationId,
291
+ });
292
+ if (!registration)
293
+ throw new HTTPException(404, {
294
+ message: "PR Review app registration not found",
295
+ });
296
+ const integrationKey = prReviewIntegrationKey(registration.provider);
297
+ await withOrganizationIntegrationAcquisition(db, grant, [integrationKey], async () => {});
298
+ const repositoryUrl = new URL(payload.repositoryUri);
299
+ let canonicalRepositoryUri = repositoryUrl.href;
300
+ let canonicalRepositoryFullName = payload.repositoryFullName;
301
+ let canonicalProviderRepositoryId = String(payload.providerRepositoryId);
302
+ let canonicalProjectId = payload.projectId === undefined ? null : String(payload.projectId);
303
+ const providerUrl = new URL(registration.providerBaseUrl);
304
+ const providerPath = providerUrl.pathname.replace(/\/$/, "");
305
+ if (
306
+ repositoryUrl.protocol !== "https:" ||
307
+ repositoryUrl.username ||
308
+ repositoryUrl.password ||
309
+ repositoryUrl.host.toLowerCase() !== providerUrl.host.toLowerCase() ||
310
+ (providerPath !== "" &&
311
+ providerPath !== "/" &&
312
+ !repositoryUrl.pathname.startsWith(`${providerPath}/`))
313
+ ) {
314
+ throw new HTTPException(422, {
315
+ message:
316
+ "repositoryUri must be a credential-free HTTPS URL on the registered provider host",
317
+ });
318
+ }
319
+ if (registration.provider === "github") {
320
+ const installationId = positiveInteger(payload.installationId);
321
+ const repositoryId = positiveInteger(payload.providerRepositoryId);
322
+ if (!installationId || !repositoryId || !registration.appId) {
323
+ throw new HTTPException(422, {
324
+ message: "GitHub repository bindings require App, installation, and repository IDs",
325
+ });
326
+ }
327
+ const encryptionKey = requirePrReviewEncryptionKey(deps);
328
+ if (!registration.credentialEncrypted) {
329
+ throw new HTTPException(409, {
330
+ message: "PR Review GitHub App credential is unavailable",
331
+ });
332
+ }
333
+ let allowedRepositories;
334
+ try {
335
+ allowedRepositories = await listGitHubAppRepositoriesWithSigningSettings(
336
+ {
337
+ githubAppId: registration.appId,
338
+ githubAppPrivateKey: decryptVariableSetValue(
339
+ encryptionKey,
340
+ registration.credentialEncrypted,
341
+ ),
342
+ },
343
+ { installationIds: [installationId] },
344
+ );
345
+ } catch {
346
+ throw new HTTPException(502, {
347
+ message: "Could not verify the repository against the registered GitHub App",
348
+ });
349
+ }
350
+ const allowedRepository = allowedRepositories.find(
351
+ (candidate) =>
352
+ candidate.id === repositoryId &&
353
+ candidate.fullName.toLowerCase() === payload.repositoryFullName.toLowerCase(),
354
+ );
355
+ if (!allowedRepository) {
356
+ throw new HTTPException(403, {
357
+ message: "GitHub repository is not installed for this PR Review App",
358
+ });
359
+ }
360
+ canonicalRepositoryUri = allowedRepository.cloneUrl;
361
+ canonicalRepositoryFullName = allowedRepository.fullName;
362
+ canonicalProviderRepositoryId = String(allowedRepository.id);
363
+ }
364
+ if (registration.provider !== "github") {
365
+ if (
366
+ registration.accessTokenExpiresAt &&
367
+ Date.parse(registration.accessTokenExpiresAt) <= Date.now()
368
+ ) {
369
+ throw new HTTPException(409, {
370
+ message: "PR Review provider credential has expired",
371
+ });
372
+ }
373
+ const encryptionKey = requirePrReviewEncryptionKey(deps);
374
+ if (!registration.credentialEncrypted) {
375
+ throw new HTTPException(409, {
376
+ message: "PR Review provider credential is unavailable",
377
+ });
378
+ }
379
+ try {
380
+ const verified = await verifyPrReviewProviderRepository({
381
+ provider: registration.provider,
382
+ providerBaseUrl: registration.providerBaseUrl,
383
+ providerRepositoryId: String(payload.providerRepositoryId),
384
+ ...(payload.projectId !== undefined ? { projectId: String(payload.projectId) } : {}),
385
+ token: decryptVariableSetValue(encryptionKey, registration.credentialEncrypted),
386
+ username: registration.webhookUsername,
387
+ settings,
388
+ });
389
+ canonicalRepositoryUri = verified.repositoryUri;
390
+ canonicalRepositoryFullName = verified.repositoryFullName;
391
+ canonicalProviderRepositoryId = verified.providerRepositoryId;
392
+ canonicalProjectId = verified.projectId;
393
+ } catch (error) {
394
+ if (error instanceof PrReviewProviderRepositoryError) {
395
+ const status =
396
+ error.reason === "denied" ? 403 : error.reason === "identity_mismatch" ? 422 : 502;
397
+ throw new HTTPException(status, { message: error.message });
398
+ }
399
+ throw error;
400
+ }
401
+ }
402
+ const catalogSettings = (
403
+ await resolveWorkspaceCatalogSettings(db, deps.settings, {
404
+ accountId: grant.accountId,
405
+ workspaceId,
406
+ })
407
+ ).settings;
408
+ const model = payload.model
409
+ ? (canonicalConfiguredModel(catalogSettings, payload.model) ?? null)
410
+ : null;
411
+ if (model) await assertWorkspaceModelPolicyAllows(db, catalogSettings, workspaceId, model);
412
+ const beforeCreateCommit = model
413
+ ? prReviewCustomModelCommitGuard({
414
+ settings: catalogSettings,
415
+ accountId: grant.accountId,
416
+ workspaceId,
417
+ modelId: model,
418
+ })
419
+ : undefined;
420
+ const template = PR_REVIEW_AUTOMATION_SETUP;
421
+
422
+ const binding = await mapPrReviewUniqueConflict(
423
+ withOrganizationIntegrationAcquisition(db, grant, [integrationKey], async (tx) => {
424
+ await grant.authorizeCommit(tx);
425
+ return createPrReviewRepositoryBinding(tx, {
426
+ accountId: grant.accountId,
427
+ workspaceId,
428
+ registrationId: registration.id,
429
+ provider: registration.provider,
430
+ repositoryUri: canonicalRepositoryUri,
431
+ repositoryFullName: canonicalRepositoryFullName,
432
+ providerRepositoryId: canonicalProviderRepositoryId,
433
+ installationId:
434
+ payload.installationId === undefined ? null : String(payload.installationId),
435
+ projectId: canonicalProjectId,
436
+ model,
437
+ additionalInstructions: payload.additionalInstructions ?? null,
438
+ status: payload.status,
439
+ createdBySubjectId: grant.subjectId,
440
+
441
+ adapterId: template.adapterId,
442
+ eventTypes: template.eventTypes,
443
+ configuration: template.configuration,
444
+ sessionTemplate: template.sessionTemplate,
445
+ ...(beforeCreateCommit ? { beforeCreateCommit } : {}),
446
+ });
447
+ }),
448
+ "This repository is already bound to the selected PR Review registration",
449
+ );
450
+ await recordAuditEvent(db, {
451
+ accountId: grant.accountId,
452
+ workspaceId,
453
+ subjectId: grant.subjectId,
454
+ action: "prReview.repository_binding.created",
455
+ targetType: "pr_review_repository_binding",
456
+ targetId: binding.id,
457
+ metadata: {
458
+ provider: binding.provider,
459
+ registrationId: binding.registrationId,
460
+ providerRepositoryId: binding.providerRepositoryId,
461
+ },
462
+ });
463
+ return c.json(PrReviewRepositoryBinding.parse(binding), 201);
464
+ });
465
+
466
+ app.patch("/v1/workspaces/:workspaceId/pr-review/repositories/:bindingId", async (c) => {
467
+ const workspaceId = c.req.param("workspaceId");
468
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
469
+
470
+ const payload = await parseRequestJson(c, UpdatePrReviewRepositoryBindingRequest);
471
+ const catalogSettings = (
472
+ await resolveWorkspaceCatalogSettings(db, deps.settings, {
473
+ accountId: grant.accountId,
474
+ workspaceId,
475
+ })
476
+ ).settings;
477
+ const model =
478
+ payload.model === undefined
479
+ ? undefined
480
+ : payload.model === null
481
+ ? null
482
+ : (canonicalConfiguredModel(catalogSettings, payload.model) ?? null);
483
+ if (model) await assertWorkspaceModelPolicyAllows(db, catalogSettings, workspaceId, model);
484
+ const beforeUpdateCommit = async (
485
+ tx: ApiRouteDeps["db"],
486
+ context: {
487
+ currentModel: string | null;
488
+ currentStatus: "active" | "disabled";
489
+ nextModel: string | null;
490
+ nextStatus: "active" | "disabled";
491
+ },
492
+ ): Promise<void> => {
493
+ const materialExecutionChange =
494
+ payload.model !== undefined ||
495
+ payload.additionalInstructions !== undefined ||
496
+ (context.currentStatus === "disabled" && context.nextStatus === "active");
497
+ if (!materialExecutionChange || !context.nextModel) return;
498
+ await prReviewCustomModelCommitGuard({
499
+ settings: catalogSettings,
500
+ accountId: grant.accountId,
501
+ workspaceId,
502
+ modelId: context.nextModel,
503
+ })?.(tx);
504
+ };
505
+ const binding = await updatePrReviewRepositoryBinding(db, {
506
+ accountId: grant.accountId,
507
+ workspaceId,
508
+ bindingId: c.req.param("bindingId"),
509
+ subjectId: grant.subjectId,
510
+ ...(model !== undefined ? { model } : {}),
511
+ ...(payload.additionalInstructions !== undefined
512
+ ? { additionalInstructions: payload.additionalInstructions }
513
+ : {}),
514
+ ...(payload.status !== undefined ? { status: payload.status } : {}),
515
+ beforeUpdateCommit,
516
+ });
517
+ if (!binding)
518
+ throw new HTTPException(404, {
519
+ message: "PR Review repository binding not found",
520
+ });
521
+ await recordAuditEvent(db, {
522
+ accountId: grant.accountId,
523
+ workspaceId,
524
+ subjectId: grant.subjectId,
525
+ action: "prReview.repository_binding.updated",
526
+ targetType: "pr_review_repository_binding",
527
+ targetId: binding.id,
528
+ metadata: { fields: Object.keys(payload) },
529
+ });
530
+ return c.json(PrReviewRepositoryBinding.parse(binding));
531
+ });
532
+
533
+ app.delete("/v1/workspaces/:workspaceId/pr-review/repositories/:bindingId", async (c) => {
534
+ const workspaceId = c.req.param("workspaceId");
535
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
536
+ const deleted = await deletePrReviewRepositoryBinding(db, {
537
+ accountId: grant.accountId,
538
+ workspaceId,
539
+ bindingId: c.req.param("bindingId"),
540
+ subjectId: grant.subjectId,
541
+ });
542
+ if (!deleted)
543
+ throw new HTTPException(404, {
544
+ message: "PR Review repository binding not found",
545
+ });
546
+ await recordAuditEvent(db, {
547
+ accountId: grant.accountId,
548
+ workspaceId,
549
+ subjectId: grant.subjectId,
550
+ action: "prReview.repository_binding.disabled",
551
+ targetType: "pr_review_repository_binding",
552
+ targetId: c.req.param("bindingId"),
553
+ metadata: {},
554
+ });
555
+ return c.body(null, 204);
556
+ });
557
+ }
558
+
559
+ /** PR Review's server-owned provider, not a repository URL or user label,
560
+ * establishes Lens identity. Other providers have no curated acquisition key. */
561
+ function prReviewIntegrationKey(provider: string): "github-lens" | null {
562
+ return provider === "github" ? "github-lens" : null;
563
+ }
564
+
565
+ function prReviewCustomModelCommitGuard(input: {
566
+ settings: ApiRouteDeps["settings"];
567
+ accountId: string;
568
+ workspaceId: string;
569
+ modelId: string;
570
+ }): ((tx: ApiRouteDeps["db"]) => Promise<void>) | undefined {
571
+ const reference = workspaceCustomModelReference(input.settings, input.modelId);
572
+ if (!reference) return undefined;
573
+ return async (tx): Promise<void> => {
574
+ const active = await lockActiveCustomModelForAdmission(tx, {
575
+ accountId: input.accountId,
576
+ workspaceId: input.workspaceId,
577
+ reference,
578
+ });
579
+ if (!active) {
580
+ throw modelUnavailableHttpException(input.modelId);
581
+ }
582
+ };
583
+ }
584
+
585
+ function assertPrReviewSandboxBackend(deps: ApiRouteDeps): void {
586
+ if (deps.settings.sandboxBackend === "selfhosted") {
587
+ throw new HTTPException(409, {
588
+ message:
589
+ "Opengeni Review Bot requires managed compute so it can materialize and verify the exact pull-request head",
590
+ });
591
+ }
592
+ }
593
+
594
+ function requirePrReviewEncryptionKey(deps: ApiRouteDeps): Uint8Array {
595
+ const key = environmentsEncryptionKeyBytes(deps.settings);
596
+ if (!key) {
597
+ throw new HTTPException(503, {
598
+ message: "Opengeni Review Bot requires configured secret encryption",
599
+ });
600
+ }
601
+ return key;
602
+ }
603
+
604
+ async function mapPrReviewUniqueConflict<T>(operation: Promise<T>, message: string): Promise<T> {
605
+ try {
606
+ return await operation;
607
+ } catch (error) {
608
+ if (nestedPostgresSqlState(error) === "23505") {
609
+ throw new HTTPException(409, { message });
610
+ }
611
+ throw error;
612
+ }
613
+ }
614
+
615
+ function positiveInteger(value: unknown): number | null {
616
+ if (typeof value === "number" && Number.isSafeInteger(value) && value > 0) return value;
617
+ if (typeof value === "string" && /^\d+$/.test(value)) {
618
+ const parsed = Number(value);
619
+ return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;
620
+ }
621
+ return null;
622
+ }