@opengeni/api-router 0.30.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (436) hide show
  1. package/dist/access-grant-rls.d.ts +3 -0
  2. package/dist/admission-trace.d.ts +8 -0
  3. package/dist/api-websocket.d.ts +18 -0
  4. package/dist/app.d.ts +50 -2
  5. package/dist/app.js +12 -1
  6. package/dist/artifact-catalog-cursor.d.ts +27 -0
  7. package/dist/auth/managed-auth-attempt-context.d.ts +10 -0
  8. package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
  9. package/dist/auth/managed-auth-session-adapter.d.ts +6 -0
  10. package/dist/auth/managed-auth.d.ts +102 -3
  11. package/dist/auth/managed-email.d.ts +29 -0
  12. package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
  13. package/dist/auth/new-signups-gate.d.ts +23 -0
  14. package/dist/auth/organization-user-setup.d.ts +80 -0
  15. package/dist/auth/signup-funnel-metrics.d.ts +44 -0
  16. package/dist/browser-controller-authority.d.ts +1 -61
  17. package/dist/browser-ephemeral.d.ts +5 -0
  18. package/dist/browser-state-authority.d.ts +1 -27
  19. package/dist/chunk-6TZ5LG3O.js +123948 -0
  20. package/dist/chunk-6TZ5LG3O.js.map +1 -0
  21. package/dist/chunk-OGQDXVXY.js +18 -0
  22. package/dist/chunk-OGQDXVXY.js.map +1 -0
  23. package/dist/claude-subscription-account-conflicts.d.ts +1 -0
  24. package/dist/claude-subscription-account-usage.d.ts +39 -0
  25. package/dist/claude-subscription-oauth.d.ts +25 -0
  26. package/dist/claude-subscription-profile.d.ts +9 -0
  27. package/dist/claude-subscription-usage.d.ts +44 -0
  28. package/dist/claude-workspace-connection.d.ts +15 -0
  29. package/dist/codemode.d.ts +32 -1
  30. package/dist/company-brain-okf.d.ts +24 -0
  31. package/dist/connected-machine-computer-access.d.ts +11 -0
  32. package/dist/connection-ownership.d.ts +54 -0
  33. package/dist/controller-data-plane.d.ts +32 -0
  34. package/dist/editable-artifact-office-import.d.ts +7 -4
  35. package/dist/editable-artifact-source-session.d.ts +3 -0
  36. package/dist/editable-artifact-websocket.d.ts +10 -18
  37. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  38. package/dist/fatal-process-boundary.d.ts +25 -0
  39. package/dist/github-access.d.ts +31 -2
  40. package/dist/http/acting-person.d.ts +24 -0
  41. package/dist/http/api-contract-compat.d.ts +19 -0
  42. package/dist/http/api-error.d.ts +27 -1
  43. package/dist/http/cors.d.ts +17 -0
  44. package/dist/http/deprecation.d.ts +42 -0
  45. package/dist/http/interaction-control-error.d.ts +13 -0
  46. package/dist/http/keyed-admission.d.ts +12 -0
  47. package/dist/http/local-browser-boundary.d.ts +72 -0
  48. package/dist/http/metrics-listener.d.ts +22 -0
  49. package/dist/http/path-identifier.d.ts +17 -0
  50. package/dist/http/registered-route-label.d.ts +16 -0
  51. package/dist/http/request-body.d.ts +27 -0
  52. package/dist/http/request-source.d.ts +52 -0
  53. package/dist/http/sse.d.ts +17 -6
  54. package/dist/http/unmatched-route.d.ts +18 -0
  55. package/dist/http/user-content.d.ts +36 -0
  56. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  57. package/dist/index.d.ts +10 -3
  58. package/dist/index.js +1129 -166
  59. package/dist/index.js.map +1 -1
  60. package/dist/integration-endpoint-test.d.ts +20 -0
  61. package/dist/integrations/api-integrations.d.ts +2 -2
  62. package/dist/integrations/atlassian.d.ts +29 -3
  63. package/dist/integrations/connect-authority.d.ts +1 -0
  64. package/dist/integrations/connect-callback-return.d.ts +6 -0
  65. package/dist/integrations/fiken.d.ts +16 -2
  66. package/dist/integrations/github-app-connect.d.ts +47 -0
  67. package/dist/integrations/github-installation-proof.d.ts +3 -0
  68. package/dist/integrations/github-lens-connect.d.ts +116 -0
  69. package/dist/integrations/github-skill-source.d.ts +1 -5
  70. package/dist/integrations/google-drive.d.ts +25 -0
  71. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  72. package/dist/integrations/marketplace-plugin.d.ts +2691 -0
  73. package/dist/integrations/oauth-client.d.ts +178 -18
  74. package/dist/integrations/oauth-profiles.d.ts +222 -0
  75. package/dist/integrations/oauth-return-path.d.ts +1 -0
  76. package/dist/integrations/personal-github-repositories.d.ts +84 -0
  77. package/dist/integrations/personal-github.d.ts +42 -0
  78. package/dist/integrations/pr-review-provider.d.ts +22 -0
  79. package/dist/integrations/provider-oauth.d.ts +19 -1
  80. package/dist/integrations/slack-app-home.d.ts +24 -0
  81. package/dist/integrations/slack-bot.d.ts +367 -12
  82. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  83. package/dist/integrations/slack-install.d.ts +20 -0
  84. package/dist/integrations/slack-interactions.d.ts +113 -10
  85. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  86. package/dist/integrations/slack-routing.d.ts +120 -0
  87. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  88. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  89. package/dist/integrations/social-oauth.d.ts +7 -0
  90. package/dist/interaction-agent-access.d.ts +15 -0
  91. package/dist/interaction-frame-proxy.d.ts +68 -0
  92. package/dist/interaction-metrics.d.ts +2 -0
  93. package/dist/mcp/action-catalog-types.d.ts +9 -0
  94. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  95. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  96. package/dist/mcp/child-read-evidence.d.ts +9 -0
  97. package/dist/mcp/command-read.d.ts +24 -0
  98. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  99. package/dist/mcp/contract-input.d.ts +11 -0
  100. package/dist/mcp/documents.d.ts +7 -5
  101. package/dist/mcp/files.d.ts +2 -2
  102. package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
  103. package/dist/mcp/knowledge-entries.d.ts +5 -0
  104. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  105. package/dist/mcp/receipts.d.ts +9 -0
  106. package/dist/mcp/request-abort.d.ts +19 -0
  107. package/dist/mcp/scheduled-task-input.d.ts +1189 -0
  108. package/dist/mcp/scheduled-task-view.d.ts +22 -4
  109. package/dist/mcp/server.d.ts +255 -3
  110. package/dist/mcp/session-event-view.d.ts +94 -0
  111. package/dist/mcp/session-view.d.ts +66 -2
  112. package/dist/mcp/session-wait.d.ts +174 -0
  113. package/dist/mcp-oauth.d.ts +52 -0
  114. package/dist/model-catalog.d.ts +11 -31
  115. package/dist/observability.d.ts +3 -1
  116. package/dist/organization-mcp.d.ts +52 -0
  117. package/dist/organization-recovery-notifications.d.ts +41 -0
  118. package/dist/routes/analytics-consent.d.ts +26 -0
  119. package/dist/routes/api-integrations.d.ts +25 -0
  120. package/dist/routes/api-keys.d.ts +17 -0
  121. package/dist/routes/artifact-catalog.d.ts +6 -0
  122. package/dist/routes/automations.d.ts +19 -0
  123. package/dist/routes/billing.d.ts +49 -0
  124. package/dist/routes/browser-sessions.d.ts +71 -3
  125. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  126. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  127. package/dist/routes/client-errors.d.ts +146 -0
  128. package/dist/routes/codex.d.ts +76 -2
  129. package/dist/routes/company-brain.d.ts +3 -0
  130. package/dist/routes/company-profile.d.ts +2 -1
  131. package/dist/routes/computer-sessions.d.ts +14 -0
  132. package/dist/routes/connect.d.ts +5 -0
  133. package/dist/routes/editable-artifacts.d.ts +2 -0
  134. package/dist/routes/external-identity-links.d.ts +6 -0
  135. package/dist/routes/feedback.d.ts +3 -0
  136. package/dist/routes/files.d.ts +4 -0
  137. package/dist/routes/github-browser-pages.d.ts +12 -0
  138. package/dist/routes/github.d.ts +2 -0
  139. package/dist/routes/insights-response-cache.d.ts +10 -0
  140. package/dist/routes/insights-usage.d.ts +12 -0
  141. package/dist/routes/insights.d.ts +30 -1
  142. package/dist/routes/knowledge.d.ts +3 -0
  143. package/dist/routes/managed-auth-session-sets.d.ts +26 -0
  144. package/dist/routes/managed-onboarding.d.ts +29 -0
  145. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  146. package/dist/routes/model-connection-access.d.ts +3 -0
  147. package/dist/routes/organization-integration-policy.d.ts +3 -0
  148. package/dist/routes/organization-integrations.d.ts +6 -0
  149. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  150. package/dist/routes/organization-model-providers.d.ts +3 -0
  151. package/dist/routes/organization-recovery.d.ts +19 -0
  152. package/dist/routes/organization-service-accounts.d.ts +3 -0
  153. package/dist/routes/organization-sessions.d.ts +26 -0
  154. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  155. package/dist/routes/personal-github.d.ts +3 -0
  156. package/dist/routes/pr-review-github.d.ts +3 -0
  157. package/dist/routes/pr-review.d.ts +3 -0
  158. package/dist/routes/session-artifact-associations.d.ts +4 -0
  159. package/dist/routes/session-history-imports.d.ts +9 -0
  160. package/dist/routes/sessions.d.ts +44 -6
  161. package/dist/routes/skill-content.d.ts +4 -0
  162. package/dist/routes/skill-install-authority.d.ts +6 -0
  163. package/dist/routes/subscription-account-pools.d.ts +34 -0
  164. package/dist/routes/subscription-pool-access.d.ts +16 -0
  165. package/dist/routes/supergrok.d.ts +6 -1
  166. package/dist/routes/usage-allowances.d.ts +12 -0
  167. package/dist/routes/user-resource-authorities.d.ts +3 -0
  168. package/dist/routes/workspace-artifacts.d.ts +2 -1
  169. package/dist/routes/workspace-capture.d.ts +10 -2
  170. package/dist/routes/workspace-integrations.d.ts +35 -0
  171. package/dist/routes/workspace-learning.d.ts +3 -0
  172. package/dist/routes/workspace-model-providers.d.ts +4 -0
  173. package/dist/routes/workspaces.d.ts +29 -0
  174. package/dist/sandbox/auth-callout.d.ts +8 -0
  175. package/dist/sandbox/channel-a.d.ts +19 -1
  176. package/dist/sandbox/connection-authority.d.ts +3 -0
  177. package/dist/sandbox/enrollment.d.ts +9 -1
  178. package/dist/sandbox/machines.d.ts +5 -2
  179. package/dist/sandbox/metrics-ingestion.d.ts +28 -20
  180. package/dist/sandbox/rematerialize.d.ts +2 -0
  181. package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
  182. package/dist/sandbox/viewer.d.ts +26 -1
  183. package/dist/sandbox-file-artifacts.d.ts +50 -0
  184. package/dist/scheduled-task-deletion.d.ts +13 -0
  185. package/dist/session-create-observability.d.ts +5 -0
  186. package/dist/session-event-view-MPS2OZD3.js +292 -0
  187. package/dist/session-event-view-MPS2OZD3.js.map +1 -0
  188. package/dist/site-session-origin.d.ts +13 -0
  189. package/dist/site-uploads.d.ts +41 -0
  190. package/dist/slack-reaction-files.d.ts +1 -1
  191. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  192. package/dist/temporal-schedule-sync.d.ts +26 -0
  193. package/dist/transcription/providers/xai-subscription.d.ts +1 -0
  194. package/dist/transcription/service.d.ts +2 -1
  195. package/dist/work-discovery-observability.d.ts +33 -0
  196. package/dist/workspace-artifact-content.d.ts +28 -0
  197. package/dist/workspace-artifact-provenance.d.ts +7 -0
  198. package/dist/workspace-delete-observability.d.ts +10 -0
  199. package/dist/workspace-deletion.d.ts +6 -0
  200. package/dist/workspace-state-projection.d.ts +3 -5
  201. package/dist/workspace-tool-gateway-observability.d.ts +17 -0
  202. package/dist/workspace-tool-gateway.d.ts +123 -0
  203. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  204. package/package.json +23 -19
  205. package/src/access-grant-rls.ts +75 -0
  206. package/src/admission-trace.ts +14 -0
  207. package/src/api-websocket.ts +23 -0
  208. package/src/app.ts +1974 -256
  209. package/src/artifact-catalog-cursor.ts +60 -0
  210. package/src/auth/managed-auth-attempt-context.ts +70 -0
  211. package/src/auth/managed-auth-rate-limits.ts +252 -0
  212. package/src/auth/managed-auth-session-adapter.ts +222 -0
  213. package/src/auth/managed-auth.ts +536 -60
  214. package/src/auth/managed-email.ts +174 -0
  215. package/src/auth/managed-sign-in-notifications.ts +81 -0
  216. package/src/auth/new-signups-gate.ts +49 -0
  217. package/src/auth/organization-user-setup.ts +307 -0
  218. package/src/auth/signup-funnel-metrics.ts +164 -0
  219. package/src/browser-controller-authority.ts +1 -186
  220. package/src/browser-ephemeral.ts +39 -0
  221. package/src/browser-state-authority.ts +1 -236
  222. package/src/claude-subscription-account-conflicts.ts +12 -0
  223. package/src/claude-subscription-account-usage.ts +48 -0
  224. package/src/claude-subscription-oauth.ts +362 -0
  225. package/src/claude-subscription-profile.ts +73 -0
  226. package/src/claude-subscription-usage.ts +97 -0
  227. package/src/claude-workspace-connection.ts +82 -0
  228. package/src/codemode.ts +194 -30
  229. package/src/codex-realtime.ts +8 -2
  230. package/src/company-brain-okf.ts +340 -0
  231. package/src/connected-machine-computer-access.ts +33 -0
  232. package/src/connection-ownership.ts +199 -0
  233. package/src/controller-data-plane.ts +81 -0
  234. package/src/editable-artifact-native-kernel.ts +26 -15
  235. package/src/editable-artifact-office-import.ts +77 -9
  236. package/src/editable-artifact-production.ts +23 -7
  237. package/src/editable-artifact-source-session.ts +123 -0
  238. package/src/editable-artifact-websocket.ts +27 -21
  239. package/src/editable-artifact-workspace-files.ts +31 -6
  240. package/src/fatal-process-boundary.ts +246 -0
  241. package/src/gateway-realtime.ts +1 -1
  242. package/src/github-access.ts +147 -5
  243. package/src/http/acting-person.ts +71 -0
  244. package/src/http/api-contract-compat.ts +49 -0
  245. package/src/http/api-error.ts +115 -1
  246. package/src/http/auth.ts +48 -0
  247. package/src/http/cors.ts +67 -0
  248. package/src/http/deprecation.ts +118 -0
  249. package/src/http/interaction-control-error.ts +164 -0
  250. package/src/http/keyed-admission.ts +29 -0
  251. package/src/http/local-browser-boundary.ts +343 -0
  252. package/src/http/metrics-listener.ts +57 -0
  253. package/src/http/path-identifier.ts +54 -0
  254. package/src/http/registered-route-label.ts +34 -0
  255. package/src/http/request-body.ts +127 -0
  256. package/src/http/request-source.ts +178 -0
  257. package/src/http/sse.ts +486 -132
  258. package/src/http/unmatched-route.ts +60 -0
  259. package/src/http/user-content.ts +158 -0
  260. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  261. package/src/index.ts +157 -52
  262. package/src/integration-endpoint-test.ts +291 -0
  263. package/src/integrations/api-integrations.ts +98 -11
  264. package/src/integrations/atlassian.ts +474 -136
  265. package/src/integrations/connect-authority.ts +2 -0
  266. package/src/integrations/connect-callback-return.ts +86 -0
  267. package/src/integrations/fiken.ts +354 -64
  268. package/src/integrations/github-app-connect.ts +435 -0
  269. package/src/integrations/github-installation-proof.ts +60 -0
  270. package/src/integrations/github-lens-connect.ts +76 -0
  271. package/src/integrations/github-skill-source.ts +2 -142
  272. package/src/integrations/google-drive.ts +820 -222
  273. package/src/integrations/integration-commit-authority.ts +69 -0
  274. package/src/integrations/marketplace-plugin.ts +48 -0
  275. package/src/integrations/oauth-client.ts +1356 -459
  276. package/src/integrations/oauth-profiles.ts +537 -0
  277. package/src/integrations/oauth-return-path.ts +18 -0
  278. package/src/integrations/personal-github-repositories.ts +674 -0
  279. package/src/integrations/personal-github.ts +825 -0
  280. package/src/integrations/pr-review-provider.ts +246 -0
  281. package/src/integrations/provider-oauth.ts +250 -22
  282. package/src/integrations/slack-app-home.ts +300 -0
  283. package/src/integrations/slack-bot.ts +963 -239
  284. package/src/integrations/slack-file-upload-flow.ts +147 -0
  285. package/src/integrations/slack-install.ts +83 -0
  286. package/src/integrations/slack-interactions.ts +3170 -474
  287. package/src/integrations/slack-mrkdwn.ts +193 -0
  288. package/src/integrations/slack-routing.ts +337 -0
  289. package/src/integrations/slack-session-defaults.ts +224 -0
  290. package/src/integrations/slack-task-file-upload.ts +323 -0
  291. package/src/integrations/social-oauth.ts +213 -15
  292. package/src/interaction-agent-access.ts +48 -0
  293. package/src/interaction-frame-proxy.ts +409 -0
  294. package/src/interaction-metrics.ts +30 -0
  295. package/src/mcp/action-catalog-types.ts +9 -0
  296. package/src/mcp/action-catalog.gen.ts +6696 -0
  297. package/src/mcp/capability-account-readiness.ts +17 -0
  298. package/src/mcp/child-read-evidence.ts +19 -0
  299. package/src/mcp/command-read.ts +109 -0
  300. package/src/mcp/company-profile-agent-admin.ts +198 -0
  301. package/src/mcp/contract-input.ts +141 -0
  302. package/src/mcp/documents.ts +65 -377
  303. package/src/mcp/editable-artifacts.ts +12 -6
  304. package/src/mcp/files.ts +80 -38
  305. package/src/mcp/first-party-tool-permissions.ts +305 -0
  306. package/src/mcp/knowledge-entries.ts +322 -0
  307. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  308. package/src/mcp/receipts.ts +34 -0
  309. package/src/mcp/request-abort.ts +44 -0
  310. package/src/mcp/scheduled-task-input.ts +76 -0
  311. package/src/mcp/scheduled-task-view.ts +44 -3
  312. package/src/mcp/server.ts +3030 -1267
  313. package/src/mcp/session-event-view.ts +383 -0
  314. package/src/mcp/session-view.ts +84 -3
  315. package/src/mcp/session-wait.ts +665 -0
  316. package/src/mcp-oauth.ts +1123 -0
  317. package/src/model-catalog.ts +91 -333
  318. package/src/observability.ts +15 -1
  319. package/src/organization-mcp.ts +397 -0
  320. package/src/organization-recovery-notifications.ts +103 -0
  321. package/src/routes/analytics-consent.ts +123 -0
  322. package/src/routes/api-integrations.ts +364 -74
  323. package/src/routes/api-keys.ts +336 -10
  324. package/src/routes/artifact-catalog.ts +279 -0
  325. package/src/routes/automations.ts +768 -0
  326. package/src/routes/billing.ts +461 -46
  327. package/src/routes/browser-sessions.ts +839 -131
  328. package/src/routes/canonical-human-identities.ts +90 -14
  329. package/src/routes/capabilities.ts +107 -6
  330. package/src/routes/channels.ts +20 -3
  331. package/src/routes/claude-subscription-accounts.ts +334 -0
  332. package/src/routes/claude-subscription-oauth.ts +142 -0
  333. package/src/routes/client-errors.ts +362 -0
  334. package/src/routes/codex.ts +833 -116
  335. package/src/routes/company-brain.ts +322 -0
  336. package/src/routes/company-profile.ts +65 -1
  337. package/src/routes/computer-sessions.ts +557 -106
  338. package/src/routes/connect.ts +1938 -0
  339. package/src/routes/connections.ts +1040 -349
  340. package/src/routes/documents.ts +488 -287
  341. package/src/routes/editable-artifacts.ts +79 -9
  342. package/src/routes/enrollments.ts +135 -39
  343. package/src/routes/environments.ts +154 -58
  344. package/src/routes/external-identity-links.ts +201 -0
  345. package/src/routes/feedback.ts +113 -0
  346. package/src/routes/files.ts +337 -39
  347. package/src/routes/github-browser-pages.ts +162 -0
  348. package/src/routes/github.ts +446 -144
  349. package/src/routes/insights-response-cache.ts +83 -0
  350. package/src/routes/insights-usage.ts +345 -0
  351. package/src/routes/insights.ts +153 -19
  352. package/src/routes/install.ts +133 -38
  353. package/src/routes/integration-facets.ts +107 -33
  354. package/src/routes/interaction-resources.ts +30 -3
  355. package/src/routes/knowledge.ts +488 -0
  356. package/src/routes/machines.ts +313 -15
  357. package/src/routes/managed-auth-session-sets.ts +1218 -0
  358. package/src/routes/managed-onboarding.ts +337 -0
  359. package/src/routes/managed-sign-in-methods.ts +433 -0
  360. package/src/routes/memory-slack-publications.ts +3 -2
  361. package/src/routes/model-connection-access.ts +208 -0
  362. package/src/routes/organization-integration-policy.ts +116 -0
  363. package/src/routes/organization-integrations.ts +326 -0
  364. package/src/routes/organization-mcp-connections.ts +178 -0
  365. package/src/routes/organization-memberships.ts +1019 -27
  366. package/src/routes/organization-model-providers.ts +293 -0
  367. package/src/routes/organization-recovery.ts +325 -0
  368. package/src/routes/organization-service-accounts.ts +128 -0
  369. package/src/routes/organization-sessions.ts +350 -0
  370. package/src/routes/personal-github-git-broker.ts +785 -0
  371. package/src/routes/personal-github.ts +370 -0
  372. package/src/routes/plugins.ts +251 -22
  373. package/src/routes/pr-review-github.ts +881 -0
  374. package/src/routes/pr-review.ts +622 -0
  375. package/src/routes/preference-registry.ts +12 -93
  376. package/src/routes/rigs.ts +167 -50
  377. package/src/routes/scheduled-tasks.ts +346 -41
  378. package/src/routes/session-artifact-associations.ts +87 -0
  379. package/src/routes/session-history-imports.ts +280 -0
  380. package/src/routes/sessions.ts +2306 -264
  381. package/src/routes/skill-content.ts +297 -0
  382. package/src/routes/skill-install-authority.ts +64 -0
  383. package/src/routes/skills.ts +62 -9
  384. package/src/routes/social.ts +46 -18
  385. package/src/routes/subscription-account-pools.ts +436 -0
  386. package/src/routes/subscription-pool-access.ts +126 -0
  387. package/src/routes/supergrok.ts +219 -303
  388. package/src/routes/transcription-recordings.ts +38 -3
  389. package/src/routes/transcriptions.ts +4 -0
  390. package/src/routes/usage-allowances.ts +378 -0
  391. package/src/routes/user-resource-authorities.ts +138 -0
  392. package/src/routes/video-generation.ts +14 -10
  393. package/src/routes/workspace-artifacts.ts +275 -69
  394. package/src/routes/workspace-capture.ts +21 -0
  395. package/src/routes/workspace-integrations.ts +576 -0
  396. package/src/routes/workspace-learning.ts +159 -0
  397. package/src/routes/workspace-model-providers.ts +148 -0
  398. package/src/routes/workspace-state.ts +38 -25
  399. package/src/routes/workspaces.ts +1004 -127
  400. package/src/sandbox/auth-callout.ts +96 -19
  401. package/src/sandbox/channel-a.ts +323 -24
  402. package/src/sandbox/connection-authority.ts +3 -0
  403. package/src/sandbox/enrollment.ts +81 -6
  404. package/src/sandbox/machines.ts +218 -76
  405. package/src/sandbox/metrics-ingestion.ts +411 -62
  406. package/src/sandbox/rematerialize.ts +121 -19
  407. package/src/sandbox/session-attach-variable-sets.ts +131 -0
  408. package/src/sandbox/viewer.ts +280 -25
  409. package/src/sandbox-file-artifacts.ts +413 -0
  410. package/src/scheduled-task-deletion.ts +138 -0
  411. package/src/session-create-observability.ts +46 -0
  412. package/src/session-realtime-context.ts +6 -3
  413. package/src/site-session-origin.ts +48 -0
  414. package/src/site-uploads.ts +224 -0
  415. package/src/slack-reaction-files.ts +16 -5
  416. package/src/temporal-schedule-cleanup.ts +13 -0
  417. package/src/temporal-schedule-sync.ts +74 -0
  418. package/src/transcription/providers/codex-subscription.ts +2 -0
  419. package/src/transcription/providers/openai.ts +1 -0
  420. package/src/transcription/providers/xai-subscription.ts +49 -3
  421. package/src/transcription/segmenter.ts +8 -2
  422. package/src/transcription/service.ts +43 -6
  423. package/src/work-discovery-observability.ts +121 -0
  424. package/src/workspace-artifact-content.ts +144 -0
  425. package/src/workspace-artifact-provenance.ts +104 -0
  426. package/src/workspace-delete-observability.ts +75 -0
  427. package/src/workspace-deletion.ts +73 -0
  428. package/src/workspace-state-projection.ts +18 -148
  429. package/src/workspace-tool-gateway-observability.ts +100 -0
  430. package/src/workspace-tool-gateway.ts +870 -0
  431. package/src/workspace-webhook-dispatch.ts +190 -0
  432. package/src/xai-subscription-auth.ts +9 -2
  433. package/dist/chunk-2PQMSRCB.js +0 -49759
  434. package/dist/chunk-2PQMSRCB.js.map +0 -1
  435. package/dist/routes/packs.d.ts +0 -3
  436. package/src/routes/packs.ts +0 -729
@@ -0,0 +1,768 @@
1
+ import { environmentsEncryptionKeyBytes } from "@opengeni/config";
2
+ import { modelUnavailableHttpException } from "@opengeni/core";
3
+ import {
4
+ AUTOMATION_WEBHOOK_MAX_BYTES,
5
+ AUTOMATION_MAX_MATCHED_TRIGGERS,
6
+ AutomationNormalizedEvent,
7
+ AutomationWebhookResult,
8
+ CreateAutomationSourceRequest,
9
+ CreateAutomationTriggerRequest,
10
+ TriggerAutomationManuallyRequest,
11
+ UpdateAutomationSourceRequest,
12
+ UpdateAutomationTriggerRequest,
13
+ stableJson,
14
+ resolveBundledSkillSelection,
15
+ type AccessGrant,
16
+ type BundledSkillId,
17
+ } from "@opengeni/contracts";
18
+ import {
19
+ AutomationCredentialRestrictionConflictError,
20
+ AutomationDeliveryConflictError,
21
+ AutomationRevisionConflictError,
22
+ createAutomationRun,
23
+ createAutomationSource,
24
+ createAutomationTrigger,
25
+ decryptVariableSetValue,
26
+ encryptVariableSetValue,
27
+ getAutomationSourceSecret,
28
+ getAutomationTriggerRevisions,
29
+ getSession,
30
+ listActiveAutomationTriggersForSource,
31
+ listAutomationRuns,
32
+ listAutomationSources,
33
+ listAutomationTriggers,
34
+ recordAutomationEvent,
35
+ resolveAutomationWebhookEndpoint,
36
+ updateAutomationSource,
37
+ updateAutomationTrigger,
38
+ withWorkspaceGatewayCustomModelReadLock,
39
+ withWorkspaceOpenRouterCustomModelReadLock,
40
+ type AutomationSourceSecret,
41
+ } from "@opengeni/db";
42
+ import {
43
+ automationRequestDigest,
44
+ automationCredentialRestrictionForGrant,
45
+ assertWorkspaceModelPolicyAllows,
46
+ buildAutomationAcceptedExecution,
47
+ canonicalConfiguredModel,
48
+ creationInitiatorForGrant,
49
+ workspaceCustomModelReference,
50
+ lockActiveCustomModelForAdmission,
51
+ requireAccessGrant,
52
+ requireAutomationAdapter,
53
+ requirePermission,
54
+ requireAutomationCredentialRestrictionPermissions,
55
+ resolveWorkspaceCatalogSettings,
56
+ type ApiRouteDeps,
57
+ } from "@opengeni/core";
58
+ import type { Hono } from "hono";
59
+ import { HTTPException } from "hono/http-exception";
60
+ import { parseRequestJson } from "../http/request-body";
61
+
62
+ async function callerBundleSelection(
63
+ deps: ApiRouteDeps,
64
+ grant: AccessGrant,
65
+ requested: BundledSkillId[] | undefined,
66
+ ) {
67
+ const actor = creationInitiatorForGrant(grant).actor;
68
+ const parent = actor ? await getSession(deps.db, grant.workspaceId, actor.sessionId) : null;
69
+ if (actor && (!parent || parent.accountId !== grant.accountId))
70
+ throw new HTTPException(403, {
71
+ message: "Automation Skill selection requires the creating agent's session",
72
+ });
73
+ try {
74
+ return resolveBundledSkillSelection(requested, parent?.bundledSkillIds);
75
+ } catch (error) {
76
+ throw new HTTPException(422, {
77
+ message: error instanceof Error ? error.message : "Invalid bundled Skill selection",
78
+ });
79
+ }
80
+ }
81
+
82
+ export function registerAutomationRoutes(app: Hono, deps: ApiRouteDeps): void {
83
+ app.get("/v1/workspaces/:workspaceId/automations/sources", async (c) => {
84
+ const workspaceId = c.req.param("workspaceId");
85
+ await requireAccessGrant(c, deps, workspaceId, "workspace:read");
86
+ return c.json({
87
+ sources: await listAutomationSources(deps.db, workspaceId),
88
+ });
89
+ });
90
+
91
+ app.post("/v1/workspaces/:workspaceId/automations/sources", async (c) => {
92
+ const workspaceId = c.req.param("workspaceId");
93
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
94
+ requirePermission(grant, "secrets:write");
95
+ const request = await parseRequestJson(c, CreateAutomationSourceRequest);
96
+ assertGenericTriggerMutable(request);
97
+ requireAutomationAdapter(request.adapterId).validateSourceConfiguration(request.configuration);
98
+ const key = requireEncryptionKey(deps);
99
+ const source = await createAutomationSource(deps.db, {
100
+ accountId: grant.accountId,
101
+ workspaceId,
102
+ createdBySubjectId: grant.subjectId,
103
+ request,
104
+ webhookSecretEncrypted: encryptVariableSetValue(key, request.webhookSecret),
105
+ });
106
+ return c.json(source, 201);
107
+ });
108
+
109
+ app.patch("/v1/workspaces/:workspaceId/automations/sources/:sourceId", async (c) => {
110
+ const workspaceId = c.req.param("workspaceId");
111
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
112
+ const request = await parseRequestJson(c, UpdateAutomationSourceRequest);
113
+ const current = await requireSource(
114
+ deps,
115
+ grant.accountId,
116
+ workspaceId,
117
+ c.req.param("sourceId"),
118
+ );
119
+ assertGenericSourceMutable(current);
120
+ if (request.configuration) {
121
+ requireAutomationAdapter(current.adapterId).validateSourceConfiguration(
122
+ request.configuration,
123
+ );
124
+ }
125
+ let webhookSecretEncrypted: string | undefined;
126
+ if (request.webhookSecret !== undefined) {
127
+ requirePermission(grant, "secrets:write");
128
+ webhookSecretEncrypted = encryptVariableSetValue(
129
+ requireEncryptionKey(deps),
130
+ request.webhookSecret,
131
+ );
132
+ }
133
+ const source = await updateAutomationSource(deps.db, {
134
+ workspaceId,
135
+ sourceId: current.id,
136
+ request,
137
+ ...(webhookSecretEncrypted ? { webhookSecretEncrypted } : {}),
138
+ });
139
+ if (!source)
140
+ throw new HTTPException(404, {
141
+ message: "automation source not found",
142
+ });
143
+ return c.json(source);
144
+ });
145
+
146
+ app.delete("/v1/workspaces/:workspaceId/automations/sources/:sourceId", async (c) => {
147
+ const workspaceId = c.req.param("workspaceId");
148
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
149
+ const current = await requireSource(
150
+ deps,
151
+ grant.accountId,
152
+ workspaceId,
153
+ c.req.param("sourceId"),
154
+ );
155
+ assertGenericSourceMutable(current);
156
+ const source = await updateAutomationSource(deps.db, {
157
+ workspaceId,
158
+ sourceId: c.req.param("sourceId"),
159
+ request: { status: "disabled" },
160
+ });
161
+ if (!source)
162
+ throw new HTTPException(404, {
163
+ message: "automation source not found",
164
+ });
165
+ return c.body(null, 204);
166
+ });
167
+
168
+ app.get("/v1/workspaces/:workspaceId/automations/triggers", async (c) => {
169
+ const workspaceId = c.req.param("workspaceId");
170
+ await requireAccessGrant(c, deps, workspaceId, "workspace:read");
171
+ return c.json({
172
+ triggers: await listAutomationTriggers(deps.db, workspaceId),
173
+ });
174
+ });
175
+
176
+ app.post("/v1/workspaces/:workspaceId/automations/triggers", async (c) => {
177
+ const workspaceId = c.req.param("workspaceId");
178
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
179
+ const request = await parseRequestJson(c, CreateAutomationTriggerRequest);
180
+ const credentialRestriction = await automationCredentialRestrictionForGrant(deps.db, grant);
181
+ requireAutomationCredentialRestrictionPermissions(
182
+ credentialRestriction,
183
+ request.sessionTemplate.firstPartyMcpPermissions,
184
+ );
185
+ request.sessionTemplate.bundledSkillIds = await callerBundleSelection(
186
+ deps,
187
+ grant,
188
+ request.sessionTemplate.bundledSkillIds,
189
+ );
190
+ const source = await requireSource(deps, grant.accountId, workspaceId, request.sourceId);
191
+ assertGenericSourceMutable(source);
192
+ if (source.status !== "active") {
193
+ throw new HTTPException(409, {
194
+ message: "automation source is disabled",
195
+ });
196
+ }
197
+ const adapter = requireAutomationAdapter(source.adapterId);
198
+ adapter.validateTriggerConfiguration(request.configuration);
199
+ adapter.validateTriggerParameters(request.parameters);
200
+ for (const permission of request.sessionTemplate.firstPartyMcpPermissions) {
201
+ requirePermission(grant, permission);
202
+ }
203
+ const catalogSettings = (
204
+ await resolveWorkspaceCatalogSettings(deps.db, deps.settings, {
205
+ accountId: grant.accountId,
206
+ workspaceId,
207
+ })
208
+ ).settings;
209
+ const model = canonicalConfiguredModel(catalogSettings, request.sessionTemplate.model) ?? null;
210
+ if (model) {
211
+ await assertWorkspaceModelPolicyAllows(deps.db, catalogSettings, workspaceId, model);
212
+ }
213
+ const normalizedRequest = {
214
+ ...request,
215
+ sessionTemplate: { ...request.sessionTemplate, model },
216
+ };
217
+ const beforeCreateCommit = model
218
+ ? workspaceCustomModelCommitGuard({
219
+ settings: catalogSettings,
220
+ accountId: grant.accountId,
221
+ workspaceId,
222
+ modelId: model,
223
+ })
224
+ : undefined;
225
+ return c.json(
226
+ await createAutomationTrigger(deps.db, {
227
+ accountId: grant.accountId,
228
+ workspaceId,
229
+ createdBySubjectId: grant.subjectId,
230
+ request: normalizedRequest,
231
+ adapterId: adapter.id,
232
+ ...(credentialRestriction ? { credentialRestriction } : {}),
233
+ ...(beforeCreateCommit ? { beforeCreateCommit } : {}),
234
+ }),
235
+ 201,
236
+ );
237
+ });
238
+
239
+ app.patch("/v1/workspaces/:workspaceId/automations/triggers/:triggerId", async (c) => {
240
+ const workspaceId = c.req.param("workspaceId");
241
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
242
+ const request = await parseRequestJson(c, UpdateAutomationTriggerRequest);
243
+ const existing = (await listAutomationTriggers(deps.db, workspaceId)).find(
244
+ (trigger) => trigger.id === c.req.param("triggerId"),
245
+ );
246
+ if (!existing)
247
+ throw new HTTPException(404, {
248
+ message: "automation trigger not found",
249
+ });
250
+ assertGenericTriggerMutable(existing);
251
+ const credentialRestriction =
252
+ existing.sessionTemplate.credentialRestriction ??
253
+ (await automationCredentialRestrictionForGrant(deps.db, grant));
254
+ requireAutomationCredentialRestrictionPermissions(
255
+ credentialRestriction,
256
+ (request.sessionTemplate ?? existing.sessionTemplate).firstPartyMcpPermissions,
257
+ );
258
+ if (request.configuration) {
259
+ requireAutomationAdapter(existing.adapterId).validateTriggerConfiguration(
260
+ request.configuration,
261
+ );
262
+ }
263
+ if (request.parameters) {
264
+ requireAutomationAdapter(existing.adapterId).validateTriggerParameters(request.parameters);
265
+ }
266
+ if (request.sessionTemplate) {
267
+ request.sessionTemplate.bundledSkillIds = await callerBundleSelection(
268
+ deps,
269
+ grant,
270
+ request.sessionTemplate.bundledSkillIds,
271
+ );
272
+ for (const permission of request.sessionTemplate.firstPartyMcpPermissions) {
273
+ requirePermission(grant, permission);
274
+ }
275
+ }
276
+ const catalogSettings = (
277
+ await resolveWorkspaceCatalogSettings(deps.db, deps.settings, {
278
+ accountId: grant.accountId,
279
+ workspaceId,
280
+ })
281
+ ).settings;
282
+ const normalizedRequest = request.sessionTemplate
283
+ ? {
284
+ ...request,
285
+ sessionTemplate: {
286
+ ...request.sessionTemplate,
287
+ model: canonicalConfiguredModel(catalogSettings, request.sessionTemplate.model) ?? null,
288
+ },
289
+ }
290
+ : request;
291
+ if (normalizedRequest.sessionTemplate?.model) {
292
+ await assertWorkspaceModelPolicyAllows(
293
+ deps.db,
294
+ catalogSettings,
295
+ workspaceId,
296
+ normalizedRequest.sessionTemplate.model,
297
+ );
298
+ }
299
+ const effectiveModel = normalizedRequest.sessionTemplate
300
+ ? normalizedRequest.sessionTemplate.model
301
+ : existing.sessionTemplate.model;
302
+ const materialExecutionChange =
303
+ request.eventTypes !== undefined ||
304
+ request.configuration !== undefined ||
305
+ request.parameters !== undefined ||
306
+ request.sessionTemplate !== undefined ||
307
+ (request.status === "active" && existing.status !== "active");
308
+ const beforeUpdateCommit =
309
+ materialExecutionChange && effectiveModel
310
+ ? workspaceCustomModelCommitGuard({
311
+ settings: catalogSettings,
312
+ accountId: grant.accountId,
313
+ workspaceId,
314
+ modelId: effectiveModel,
315
+ })
316
+ : undefined;
317
+ try {
318
+ const trigger = await updateAutomationTrigger(deps.db, {
319
+ workspaceId,
320
+ triggerId: c.req.param("triggerId"),
321
+ subjectId: grant.subjectId,
322
+ request: normalizedRequest,
323
+ ...(credentialRestriction ? { credentialRestriction } : {}),
324
+ ...(beforeUpdateCommit ? { beforeUpdateCommit } : {}),
325
+ });
326
+ if (!trigger)
327
+ throw new HTTPException(404, {
328
+ message: "automation trigger not found",
329
+ });
330
+ return c.json(trigger);
331
+ } catch (error) {
332
+ if (error instanceof AutomationRevisionConflictError) {
333
+ throw new HTTPException(409, { message: error.message });
334
+ }
335
+ throw error;
336
+ }
337
+ });
338
+
339
+ app.delete("/v1/workspaces/:workspaceId/automations/triggers/:triggerId", async (c) => {
340
+ const workspaceId = c.req.param("workspaceId");
341
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
342
+ const expectedRevision = Number(c.req.query("expectedRevision"));
343
+ if (!Number.isSafeInteger(expectedRevision) || expectedRevision < 1) {
344
+ throw new HTTPException(400, {
345
+ message: "expectedRevision must be a positive integer",
346
+ });
347
+ }
348
+ const existing = (await listAutomationTriggers(deps.db, workspaceId)).find(
349
+ (trigger) => trigger.id === c.req.param("triggerId"),
350
+ );
351
+ if (!existing)
352
+ throw new HTTPException(404, {
353
+ message: "automation trigger not found",
354
+ });
355
+ assertGenericTriggerMutable(existing);
356
+ try {
357
+ const trigger = await updateAutomationTrigger(deps.db, {
358
+ workspaceId,
359
+ triggerId: c.req.param("triggerId"),
360
+ subjectId: grant.subjectId,
361
+ request: { expectedRevision, status: "disabled" },
362
+ });
363
+ if (!trigger)
364
+ throw new HTTPException(404, {
365
+ message: "automation trigger not found",
366
+ });
367
+ return c.body(null, 204);
368
+ } catch (error) {
369
+ if (error instanceof AutomationRevisionConflictError) {
370
+ throw new HTTPException(409, { message: error.message });
371
+ }
372
+ throw error;
373
+ }
374
+ });
375
+
376
+ app.get("/v1/workspaces/:workspaceId/automations/runs", async (c) => {
377
+ const workspaceId = c.req.param("workspaceId");
378
+ await requireAccessGrant(c, deps, workspaceId, "workspace:read");
379
+ return c.json({ runs: await listAutomationRuns(deps.db, workspaceId) });
380
+ });
381
+
382
+ app.post("/v1/workspaces/:workspaceId/automations/sources/:sourceId/events", async (c) => {
383
+ const workspaceId = c.req.param("workspaceId");
384
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
385
+ const request = await parseRequestJson(c, TriggerAutomationManuallyRequest);
386
+ const credentialRestriction = await automationCredentialRestrictionForGrant(deps.db, grant);
387
+ const source = await requireSource(deps, grant.accountId, workspaceId, c.req.param("sourceId"));
388
+ if (source.status !== "active") {
389
+ throw new HTTPException(409, {
390
+ message: "automation source is disabled",
391
+ });
392
+ }
393
+ const normalizedEvent = AutomationNormalizedEvent.parse({
394
+ adapterId: source.adapterId,
395
+ eventType: request.eventType,
396
+ occurrenceKey: request.occurrenceKey,
397
+ occurredAt: request.occurredAt,
398
+ subject: request.subject,
399
+ resource: request.resource,
400
+ payload: request.payload,
401
+ });
402
+ const bytes = new TextEncoder().encode(stableJson(request));
403
+ try {
404
+ return c.json(
405
+ await acceptAutomationEvent(deps, source, {
406
+ deliveryKey:
407
+ request.deliveryId ?? `manual:${automationRequestDigest(source.adapterId, bytes)}`,
408
+ requestDigest: automationRequestDigest(source.adapterId, bytes),
409
+ normalizedEvent,
410
+ ...(credentialRestriction ? { credentialRestriction } : {}),
411
+ }),
412
+ 202,
413
+ );
414
+ } catch (error) {
415
+ if (
416
+ error instanceof AutomationDeliveryConflictError ||
417
+ error instanceof AutomationCredentialRestrictionConflictError
418
+ ) {
419
+ throw new HTTPException(409, { message: error.message });
420
+ }
421
+ throw error;
422
+ }
423
+ });
424
+
425
+ app.post("/v1/webhooks/automations/:endpointId", async (c) => {
426
+ const endpointId = c.req.param("endpointId");
427
+ if (
428
+ !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
429
+ endpointId,
430
+ )
431
+ ) {
432
+ throw new HTTPException(404, {
433
+ message: "automation endpoint not found",
434
+ });
435
+ }
436
+ const endpoint = await resolveAutomationWebhookEndpoint(deps.db, endpointId);
437
+ if (!endpoint)
438
+ throw new HTTPException(404, {
439
+ message: "automation endpoint not found",
440
+ });
441
+ const source = await requireSource(
442
+ deps,
443
+ endpoint.accountId,
444
+ endpoint.workspaceId,
445
+ endpoint.sourceId,
446
+ );
447
+ if (source.status !== "active") {
448
+ throw new HTTPException(410, {
449
+ message: "automation source is disabled",
450
+ });
451
+ }
452
+ const rawBody = await readAutomationWebhookBody(c.req.raw, AUTOMATION_WEBHOOK_MAX_BYTES);
453
+ const adapter = requireAutomationAdapter(source.adapterId);
454
+ const secret = decryptVariableSetValue(
455
+ requireEncryptionKey(deps),
456
+ source.webhookSecretEncrypted,
457
+ );
458
+ if (
459
+ !adapter.verify({
460
+ rawBody,
461
+ headers: c.req.raw.headers,
462
+ secret,
463
+ sourceConfiguration: source.configuration,
464
+ })
465
+ ) {
466
+ throw new HTTPException(401, {
467
+ message: "automation signature is invalid",
468
+ });
469
+ }
470
+ const requestDigest = automationRequestDigest(source.adapterId, rawBody);
471
+ try {
472
+ const result = await acceptAutomationEvent(deps, source, {
473
+ deliveryKey: adapter.deliveryKey({
474
+ headers: c.req.raw.headers,
475
+ requestDigest,
476
+ }),
477
+ requestDigest,
478
+ normalizedEvent: adapter.normalize({
479
+ rawBody,
480
+ headers: c.req.raw.headers,
481
+ sourceConfiguration: source.configuration,
482
+ }),
483
+ });
484
+ return c.json(result, 202);
485
+ } catch (error) {
486
+ if (
487
+ error instanceof AutomationDeliveryConflictError ||
488
+ error instanceof AutomationCredentialRestrictionConflictError
489
+ ) {
490
+ throw new HTTPException(409, { message: error.message });
491
+ }
492
+ throw error;
493
+ }
494
+ });
495
+ }
496
+
497
+ export async function acceptAutomationEvent(
498
+ deps: ApiRouteDeps,
499
+ source: AutomationSourceSecret,
500
+ input: {
501
+ deliveryKey: string;
502
+ requestDigest: string;
503
+ normalizedEvent: AutomationNormalizedEvent;
504
+ /** Canonical manual caller restriction, not normalized event metadata. */
505
+ credentialRestriction?: "developer_setup";
506
+ },
507
+ ) {
508
+ const { credentialRestriction: _untrustedRestriction, ...eventData } = input.normalizedEvent;
509
+ const normalizedEvent = AutomationNormalizedEvent.parse(eventData);
510
+ if (normalizedEvent.adapterId !== source.adapterId) {
511
+ throw new HTTPException(422, {
512
+ message: "automation event adapter does not match source",
513
+ });
514
+ }
515
+ const adapter = requireAutomationAdapter(source.adapterId);
516
+ const triggers = await listActiveAutomationTriggersForSource(deps.db, {
517
+ accountId: source.accountId,
518
+ workspaceId: source.workspaceId,
519
+ sourceId: source.id,
520
+ });
521
+ const matchingByEvent = triggers.filter((trigger) =>
522
+ adapter.matches({ event: normalizedEvent, trigger }),
523
+ );
524
+ if (matchingByEvent.length > AUTOMATION_MAX_MATCHED_TRIGGERS) {
525
+ throw new HTTPException(422, {
526
+ message: `automation event matches more than ${AUTOMATION_MAX_MATCHED_TRIGGERS} triggers`,
527
+ });
528
+ }
529
+ const stored =
530
+ matchingByEvent.length === 0
531
+ ? await recordAutomationEvent(deps.db, {
532
+ accountId: source.accountId,
533
+ workspaceId: source.workspaceId,
534
+ sourceId: source.id,
535
+ sourceVersion: source.version,
536
+ sourceConfiguration: source.configuration,
537
+ matchedTriggerRevisions: [],
538
+ deliveryKey: input.deliveryKey,
539
+ requestDigest: input.requestDigest,
540
+ normalizedEvent,
541
+ ...(input.credentialRestriction
542
+ ? { credentialRestriction: input.credentialRestriction }
543
+ : {}),
544
+ ignoredReason: "no_matching_triggers",
545
+ })
546
+ : await withWorkspaceGatewayCustomModelReadLock(
547
+ deps.db,
548
+ { accountId: source.accountId, workspaceId: source.workspaceId },
549
+ async (gatewayLockedDb) =>
550
+ await withWorkspaceOpenRouterCustomModelReadLock(
551
+ gatewayLockedDb,
552
+ { accountId: source.accountId, workspaceId: source.workspaceId },
553
+ async (lockedDb) => {
554
+ const catalogSourceSettings = deps.catalogSourceSettings ?? deps.settings;
555
+ const catalogSettings = (
556
+ await resolveWorkspaceCatalogSettings(lockedDb, catalogSourceSettings, {
557
+ accountId: source.accountId,
558
+ workspaceId: source.workspaceId,
559
+ })
560
+ ).settings;
561
+ const matchingAtAcceptance = [];
562
+ for (const trigger of matchingByEvent) {
563
+ try {
564
+ const render = adapter.render({
565
+ event: normalizedEvent,
566
+ trigger,
567
+ source,
568
+ });
569
+ requireAutomationCredentialRestrictionPermissions(
570
+ trigger.sessionTemplate.credentialRestriction ?? input.credentialRestriction,
571
+ render.sessionTemplate.firstPartyMcpPermissions,
572
+ );
573
+ const requestedModel =
574
+ render.sessionTemplate.model ?? catalogSettings.openaiModel;
575
+ const model = canonicalConfiguredModel(catalogSettings, requestedModel);
576
+ if (!model) continue;
577
+ await assertWorkspaceModelPolicyAllows(
578
+ lockedDb,
579
+ catalogSettings,
580
+ source.workspaceId,
581
+ model,
582
+ );
583
+ matchingAtAcceptance.push(trigger);
584
+ } catch (error) {
585
+ if (isUnprocessableEntity(error)) continue;
586
+ throw error;
587
+ }
588
+ }
589
+ return await recordAutomationEvent(lockedDb, {
590
+ accountId: source.accountId,
591
+ workspaceId: source.workspaceId,
592
+ sourceId: source.id,
593
+ sourceVersion: source.version,
594
+ sourceConfiguration: source.configuration,
595
+ matchedTriggerRevisions: matchingAtAcceptance.map((trigger) => ({
596
+ triggerId: trigger.id,
597
+ revision: trigger.revision,
598
+ })),
599
+ deliveryKey: input.deliveryKey,
600
+ requestDigest: input.requestDigest,
601
+ normalizedEvent,
602
+ ...(input.credentialRestriction
603
+ ? { credentialRestriction: input.credentialRestriction }
604
+ : {}),
605
+ ignoredReason:
606
+ matchingAtAcceptance.length === 0 ? "no_executable_triggers" : null,
607
+ });
608
+ },
609
+ ),
610
+ );
611
+ const matching = await getAutomationTriggerRevisions(deps.db, {
612
+ workspaceId: source.workspaceId,
613
+ refs: stored.event.matchedTriggerRevisions,
614
+ });
615
+ const acceptedSource = {
616
+ ...source,
617
+ version: stored.event.sourceVersion,
618
+ configuration: stored.event.sourceConfiguration,
619
+ };
620
+ const { credentialRestriction, ...acceptedEvent } = stored.event.normalizedEvent;
621
+ const runIds: string[] = [];
622
+ const triggerAutomationRun = deps.workflowClient.triggerAutomationRun;
623
+ if (matching.length > 0 && !triggerAutomationRun) {
624
+ throw new HTTPException(503, {
625
+ message: "automation dispatcher is unavailable",
626
+ });
627
+ }
628
+ for (const trigger of matching) {
629
+ const render = adapter.render({
630
+ event: acceptedEvent,
631
+ trigger,
632
+ source: acceptedSource,
633
+ });
634
+ const acceptedExecution = buildAutomationAcceptedExecution({
635
+ accountId: source.accountId,
636
+ workspaceId: source.workspaceId,
637
+ source: acceptedSource,
638
+ trigger,
639
+ eventId: stored.event.id,
640
+ event: acceptedEvent,
641
+ render,
642
+ ...(credentialRestriction ? { credentialRestriction } : {}),
643
+ });
644
+ const { run } = await createAutomationRun(deps.db, {
645
+ accountId: source.accountId,
646
+ workspaceId: source.workspaceId,
647
+ sourceId: source.id,
648
+ triggerId: trigger.id,
649
+ triggerRevision: trigger.revision,
650
+ eventId: stored.event.id,
651
+ occurrenceKey: stored.event.normalizedEvent.occurrenceKey,
652
+ acceptedExecution,
653
+ });
654
+ runIds.push(run.id);
655
+ await triggerAutomationRun!({
656
+ accountId: source.accountId,
657
+ workspaceId: source.workspaceId,
658
+ runId: run.id,
659
+ });
660
+ }
661
+ return AutomationWebhookResult.parse({
662
+ accepted: true,
663
+ duplicate: stored.duplicate,
664
+ ignoredReason: stored.event.ignoredReason,
665
+ eventId: stored.event.id,
666
+ runIds,
667
+ });
668
+ }
669
+
670
+ function isUnprocessableEntity(error: unknown): boolean {
671
+ return (
672
+ error instanceof Error &&
673
+ "status" in error &&
674
+ (error as Error & { status?: unknown }).status === 422
675
+ );
676
+ }
677
+
678
+ function workspaceCustomModelCommitGuard(input: {
679
+ settings: ApiRouteDeps["settings"];
680
+ accountId: string;
681
+ workspaceId: string;
682
+ modelId: string;
683
+ }): ((tx: ApiRouteDeps["db"]) => Promise<void>) | undefined {
684
+ const reference = workspaceCustomModelReference(input.settings, input.modelId);
685
+ if (!reference) return undefined;
686
+ return async (tx): Promise<void> => {
687
+ const active = await lockActiveCustomModelForAdmission(tx, {
688
+ accountId: input.accountId,
689
+ workspaceId: input.workspaceId,
690
+ reference,
691
+ });
692
+ if (!active) {
693
+ throw modelUnavailableHttpException(input.modelId);
694
+ }
695
+ };
696
+ }
697
+
698
+ async function requireSource(
699
+ deps: ApiRouteDeps,
700
+ accountId: string,
701
+ workspaceId: string,
702
+ sourceId: string,
703
+ ): Promise<AutomationSourceSecret> {
704
+ const source = await getAutomationSourceSecret(deps.db, {
705
+ accountId,
706
+ workspaceId,
707
+ sourceId,
708
+ });
709
+ if (!source) throw new HTTPException(404, { message: "automation source not found" });
710
+ return source;
711
+ }
712
+
713
+ function assertGenericSourceMutable(source: AutomationSourceSecret): void {
714
+ assertGenericTriggerMutable(source);
715
+ }
716
+
717
+ function assertGenericTriggerMutable(trigger: { adapterId: string }): void {
718
+ if (trigger.adapterId === "source-control.pull-request.v1") {
719
+ throw new HTTPException(409, {
720
+ message: "PR Review automations must be managed through the PR Review setup API",
721
+ });
722
+ }
723
+ }
724
+
725
+ function requireEncryptionKey(deps: ApiRouteDeps): Uint8Array {
726
+ const key = environmentsEncryptionKeyBytes(deps.settings);
727
+ if (!key) {
728
+ throw new HTTPException(503, {
729
+ message: "OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is required for automations",
730
+ });
731
+ }
732
+ return key;
733
+ }
734
+
735
+ export async function readAutomationWebhookBody(
736
+ request: Request,
737
+ maxBytes: number,
738
+ ): Promise<Uint8Array> {
739
+ const declared = Number(request.headers.get("content-length"));
740
+ if (Number.isFinite(declared) && declared > maxBytes) {
741
+ throw new HTTPException(413, {
742
+ message: "automation webhook payload is too large",
743
+ });
744
+ }
745
+ if (!request.body) return new Uint8Array();
746
+ const reader = request.body.getReader();
747
+ const chunks: Uint8Array[] = [];
748
+ let length = 0;
749
+ while (true) {
750
+ const { value, done } = await reader.read();
751
+ if (done) break;
752
+ length += value.byteLength;
753
+ if (length > maxBytes) {
754
+ await reader.cancel();
755
+ throw new HTTPException(413, {
756
+ message: "automation webhook payload is too large",
757
+ });
758
+ }
759
+ chunks.push(value);
760
+ }
761
+ const result = new Uint8Array(length);
762
+ let offset = 0;
763
+ for (const chunk of chunks) {
764
+ result.set(chunk, offset);
765
+ offset += chunk.byteLength;
766
+ }
767
+ return result;
768
+ }