@opengeni/api-router 3.0.1 → 3.1.2

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 (546) hide show
  1. package/dist/access-grant-rls.d.ts +8 -1
  2. package/dist/admission-trace.d.ts +8 -0
  3. package/dist/app.d.ts +50 -3
  4. package/dist/app.js +10 -1
  5. package/dist/artifact-catalog-cursor.d.ts +1 -0
  6. package/dist/attached-browser-viewer.d.ts +11 -0
  7. package/dist/auth/managed-auth-attempt-context.d.ts +2 -0
  8. package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
  9. package/dist/auth/managed-auth-session-adapter.d.ts +9 -1
  10. package/dist/auth/managed-auth.d.ts +72 -5
  11. package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
  12. package/dist/auth/new-signups-gate.d.ts +23 -0
  13. package/dist/auth/signup-funnel-metrics.d.ts +44 -0
  14. package/dist/azure-live.d.ts +28 -0
  15. package/dist/browser-action-fences.d.ts +13 -0
  16. package/dist/browser-controller-authority.d.ts +1 -61
  17. package/dist/browser-ephemeral.d.ts +5 -0
  18. package/dist/browser-lost-runtime-end.d.ts +24 -0
  19. package/dist/browser-state-authority.d.ts +1 -27
  20. package/dist/chunk-OGQDXVXY.js +18 -0
  21. package/dist/chunk-OGQDXVXY.js.map +1 -0
  22. package/dist/{chunk-AJ62T5QN.js → chunk-OT56OY4V.js} +80503 -39869
  23. package/dist/chunk-OT56OY4V.js.map +1 -0
  24. package/dist/claude-default-models.d.ts +19 -0
  25. package/dist/claude-subscription-core.d.ts +50 -0
  26. package/dist/claude-subscription-oauth.d.ts +36 -0
  27. package/dist/claude-subscription-profile.d.ts +9 -0
  28. package/dist/claude-subscription-usage.d.ts +6 -0
  29. package/dist/claude-workspace-connection.d.ts +15 -0
  30. package/dist/codemode.d.ts +40 -5
  31. package/dist/codex-realtime.d.ts +29 -3
  32. package/dist/codex-session-pointers.d.ts +19 -0
  33. package/dist/connection-ownership.d.ts +6 -3
  34. package/dist/controller-data-plane.d.ts +16 -0
  35. package/dist/credit-promotion-snapshot.d.ts +6 -0
  36. package/dist/editable-artifact-source-session.d.ts +3 -0
  37. package/dist/editable-artifact-websocket.d.ts +5 -3
  38. package/dist/fatal-process-boundary.d.ts +9 -1
  39. package/dist/github-access.d.ts +7 -1
  40. package/dist/github-browser-flow.d.ts +1 -1
  41. package/dist/http/acting-person.d.ts +36 -0
  42. package/dist/http/api-contract-compat.d.ts +19 -0
  43. package/dist/http/api-error.d.ts +50 -1
  44. package/dist/http/auth.d.ts +8 -1
  45. package/dist/http/cors.d.ts +12 -0
  46. package/dist/http/deprecation.d.ts +42 -0
  47. package/dist/http/keyed-admission.d.ts +12 -0
  48. package/dist/http/local-browser-boundary.d.ts +72 -0
  49. package/dist/http/metrics-listener.d.ts +22 -0
  50. package/dist/http/path-identifier.d.ts +17 -0
  51. package/dist/http/registered-route-label.d.ts +16 -0
  52. package/dist/http/rejection-telemetry.d.ts +34 -0
  53. package/dist/http/request-body.d.ts +27 -0
  54. package/dist/http/request-source.d.ts +41 -3
  55. package/dist/http/sse.d.ts +12 -1
  56. package/dist/http/unmatched-route.d.ts +18 -0
  57. package/dist/http/user-content.d.ts +36 -0
  58. package/dist/http/variable-sets-removed.d.ts +41 -0
  59. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  60. package/dist/index.js +1279 -108
  61. package/dist/index.js.map +1 -1
  62. package/dist/integration-connect-metrics.d.ts +35 -0
  63. package/dist/integration-endpoint-test.d.ts +20 -0
  64. package/dist/integrations/api-integrations.d.ts +2 -2
  65. package/dist/integrations/atlassian.d.ts +8 -3
  66. package/dist/integrations/fiken.d.ts +3 -1
  67. package/dist/integrations/github-lens-connect.d.ts +37 -66
  68. package/dist/integrations/google-drive.d.ts +2 -0
  69. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  70. package/dist/integrations/marketplace-plugin.d.ts +43 -43
  71. package/dist/integrations/oauth-client.d.ts +171 -12
  72. package/dist/integrations/oauth-profiles.d.ts +42 -13
  73. package/dist/integrations/onepassword-vault-provider.d.ts +9 -0
  74. package/dist/integrations/slack-bot.d.ts +285 -7
  75. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  76. package/dist/integrations/slack-interactions.d.ts +89 -10
  77. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  78. package/dist/integrations/slack-routing.d.ts +1 -1
  79. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  80. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  81. package/dist/integrations/slack-tool-review.d.ts +5 -0
  82. package/dist/interaction-agent-access.d.ts +13 -8
  83. package/dist/interaction-agent-version.d.ts +21 -0
  84. package/dist/interaction-holder-heartbeat.d.ts +5 -0
  85. package/dist/interaction-metrics.d.ts +27 -2
  86. package/dist/interaction-route-stages.d.ts +25 -0
  87. package/dist/interaction-secrets-vault.d.ts +20 -0
  88. package/dist/interaction-secrets.d.ts +103 -0
  89. package/dist/mcp/action-catalog-types.d.ts +14 -0
  90. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  91. package/dist/mcp/action-descriptions.d.ts +4 -0
  92. package/dist/mcp/action-schema-imports.gen.d.ts +1 -0
  93. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  94. package/dist/mcp/child-read-evidence.d.ts +9 -0
  95. package/dist/mcp/company-profile-agent-admin.d.ts +12 -0
  96. package/dist/mcp/contract-input.d.ts +13 -0
  97. package/dist/mcp/documents.d.ts +2 -0
  98. package/dist/mcp/first-party-tool-permissions.d.ts +3 -606
  99. package/dist/mcp/notification-tools.d.ts +26 -0
  100. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  101. package/dist/mcp/scheduled-task-input.d.ts +1309 -0
  102. package/dist/mcp/scheduled-task-view.d.ts +217 -3
  103. package/dist/mcp/secret-tools.d.ts +14 -0
  104. package/dist/mcp/server.d.ts +108 -5
  105. package/dist/mcp/session-admin-access-tools.d.ts +33 -0
  106. package/dist/mcp/session-event-errors.d.ts +28 -0
  107. package/dist/mcp/session-event-view.d.ts +62 -0
  108. package/dist/mcp/session-view.d.ts +15 -0
  109. package/dist/mcp/session-wait.d.ts +18 -0
  110. package/dist/mcp/site-agent-clamp-tools.d.ts +38 -0
  111. package/dist/mcp/site-data-tools.d.ts +22 -0
  112. package/dist/mcp/site-publication-tools.d.ts +19 -0
  113. package/dist/mcp/site-sql-tools.d.ts +27 -0
  114. package/dist/mcp-oauth.d.ts +37 -4
  115. package/dist/model-calls/chat-completions.d.ts +87 -0
  116. package/dist/model-calls/pending-usage-settlements.d.ts +57 -0
  117. package/dist/model-calls/service.d.ts +36 -0
  118. package/dist/model-catalog.d.ts +9 -3
  119. package/dist/native-push-dispatch.d.ts +69 -0
  120. package/dist/observability.d.ts +3 -1
  121. package/dist/organization-mcp.d.ts +82 -0
  122. package/dist/prepared-mcp-actor.d.ts +77 -0
  123. package/dist/prepared-mcp-permissions.d.ts +8 -0
  124. package/dist/routes/analytics-consent.d.ts +26 -0
  125. package/dist/routes/api-integrations.d.ts +11 -0
  126. package/dist/routes/api-keys.d.ts +7 -7
  127. package/dist/routes/automations.d.ts +2 -0
  128. package/dist/routes/billing.d.ts +59 -0
  129. package/dist/routes/browser-sessions.d.ts +65 -2
  130. package/dist/routes/chat-completions.d.ts +11 -0
  131. package/dist/routes/claude-core-usage.d.ts +20 -0
  132. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  133. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  134. package/dist/routes/client-errors.d.ts +182 -0
  135. package/dist/routes/codex-core.d.ts +401 -0
  136. package/dist/routes/codex.d.ts +64 -2
  137. package/dist/routes/computer-sessions.d.ts +6 -1
  138. package/dist/routes/desktop-distribution.d.ts +32 -0
  139. package/dist/routes/github-browser-fonts.gen.d.ts +2 -0
  140. package/dist/routes/github-browser-pages.d.ts +27 -0
  141. package/dist/routes/inbox.d.ts +13 -0
  142. package/dist/routes/insights-response-cache.d.ts +10 -0
  143. package/dist/routes/insights-usage.d.ts +12 -0
  144. package/dist/routes/insights.d.ts +28 -0
  145. package/dist/routes/interaction-placement-message.d.ts +7 -0
  146. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  147. package/dist/routes/model-account-choice.d.ts +13 -0
  148. package/dist/routes/model-account-settings.d.ts +19 -0
  149. package/dist/routes/native-app-auth.d.ts +12 -0
  150. package/dist/routes/organization-integration-policy.d.ts +8 -0
  151. package/dist/routes/organization-integrations.d.ts +6 -0
  152. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  153. package/dist/routes/organization-model-defaults.d.ts +9 -0
  154. package/dist/routes/organization-service-accounts.d.ts +3 -0
  155. package/dist/routes/personal-api-keys.d.ts +3 -0
  156. package/dist/routes/session-admin-access.d.ts +3 -0
  157. package/dist/routes/session-artifact-associations.d.ts +4 -0
  158. package/dist/routes/session-history-imports.d.ts +20 -0
  159. package/dist/routes/sessions.d.ts +38 -2
  160. package/dist/routes/site-data.d.ts +18 -0
  161. package/dist/routes/site-publishing.d.ts +5 -0
  162. package/dist/routes/site-runtime.d.ts +31 -0
  163. package/dist/routes/site-sql.d.ts +16 -0
  164. package/dist/routes/slack-bot-access.d.ts +3 -0
  165. package/dist/routes/subscription-account-pools.d.ts +21 -0
  166. package/dist/routes/subscription-core-http.d.ts +5 -0
  167. package/dist/routes/subscription-pool-access.d.ts +37 -0
  168. package/dist/routes/subscription-pool-core.d.ts +153 -0
  169. package/dist/routes/supergrok.d.ts +6 -6
  170. package/dist/routes/usage-allowances.d.ts +12 -0
  171. package/dist/routes/variable-sets-removed.d.ts +2 -0
  172. package/dist/routes/vault-providers.d.ts +34 -0
  173. package/dist/routes/vaults.d.ts +3 -0
  174. package/dist/routes/workspace-integrations.d.ts +35 -0
  175. package/dist/routes/workspace-model-providers.d.ts +4 -0
  176. package/dist/routes/workspaces.d.ts +11 -2
  177. package/dist/sandbox/agent-update.d.ts +64 -0
  178. package/dist/sandbox/auth-callout.d.ts +8 -0
  179. package/dist/sandbox/channel-a.d.ts +15 -1
  180. package/dist/sandbox/enrollment.d.ts +26 -4
  181. package/dist/sandbox/machine-audience.d.ts +29 -0
  182. package/dist/sandbox/machines.d.ts +15 -2
  183. package/dist/sandbox/metrics-ingestion.d.ts +6 -2
  184. package/dist/sandbox/screen-control.d.ts +85 -0
  185. package/dist/sandbox/viewer.d.ts +5 -1
  186. package/dist/sandbox-file-artifacts.d.ts +17 -1
  187. package/dist/scheduled-task-blockers.d.ts +39 -0
  188. package/dist/scheduled-task-deletion.d.ts +3 -4
  189. package/dist/scheduled-task-lifecycle.d.ts +14 -0
  190. package/dist/secret-answers.d.ts +40 -0
  191. package/dist/session-create-observability.d.ts +5 -0
  192. package/dist/session-event-view-36GO3IL7.js +528 -0
  193. package/dist/session-event-view-36GO3IL7.js.map +1 -0
  194. package/dist/signed-state-secret.d.ts +18 -0
  195. package/dist/site-agent-guard.d.ts +53 -0
  196. package/dist/site-data/operations.d.ts +103 -0
  197. package/dist/site-data/service.d.ts +203 -0
  198. package/dist/site-frame-guard.d.ts +32 -0
  199. package/dist/site-publishing/agent-data-tools.d.ts +84 -0
  200. package/dist/site-publishing/agent-model.d.ts +58 -0
  201. package/dist/site-publishing/agent-session.d.ts +16 -0
  202. package/dist/site-publishing/content-scanner.d.ts +31 -0
  203. package/dist/site-publishing/edge-sync.d.ts +48 -0
  204. package/dist/site-publishing/gateway-signature.d.ts +56 -0
  205. package/dist/site-publishing/limits.d.ts +63 -0
  206. package/dist/site-publishing/page-tool-authority.d.ts +30 -0
  207. package/dist/site-publishing/platform-usage.d.ts +113 -0
  208. package/dist/site-publishing/platform.d.ts +21 -0
  209. package/dist/site-publishing/readiness.d.ts +62 -0
  210. package/dist/site-publishing/runtime.d.ts +179 -0
  211. package/dist/site-publishing/service.d.ts +264 -0
  212. package/dist/site-publishing/session-events.d.ts +22 -0
  213. package/dist/site-publishing/session-views.d.ts +36 -0
  214. package/dist/site-publishing/viewer.d.ts +40 -0
  215. package/dist/site-session-origin.d.ts +31 -6
  216. package/dist/site-sql/format.d.ts +47 -0
  217. package/dist/site-sql/gateway.d.ts +50 -0
  218. package/dist/site-sql/service.d.ts +213 -0
  219. package/dist/temporal-schedule-sync.d.ts +26 -0
  220. package/dist/transcription/billing-refusal.d.ts +8 -0
  221. package/dist/transcription/normalize.d.ts +23 -0
  222. package/dist/transcription/providers/azure-mai.d.ts +12 -0
  223. package/dist/transcription/providers/azure-openai.d.ts +4 -0
  224. package/dist/transcription/providers/openai.d.ts +16 -0
  225. package/dist/transcription/providers/subscription-core.d.ts +39 -0
  226. package/dist/transcription/service.d.ts +10 -1
  227. package/dist/transcription/wav-duration.d.ts +8 -0
  228. package/dist/workspace-tool-gateway-attestations.d.ts +37 -0
  229. package/dist/workspace-tool-gateway-observability.d.ts +16 -0
  230. package/dist/workspace-tool-gateway-secrets.d.ts +27 -0
  231. package/dist/workspace-tool-gateway.d.ts +102 -6
  232. package/dist/workspace-tool-target-fence.d.ts +116 -0
  233. package/dist/workspace-tool-target.d.ts +225 -0
  234. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  235. package/dist/xai-subscription-core.d.ts +60 -0
  236. package/package.json +25 -20
  237. package/src/access-grant-rls.ts +64 -14
  238. package/src/admission-trace.ts +14 -0
  239. package/src/app.ts +1684 -252
  240. package/src/artifact-catalog-cursor.ts +1 -0
  241. package/src/attached-browser-viewer.ts +26 -0
  242. package/src/auth/managed-auth-attempt-context.ts +9 -0
  243. package/src/auth/managed-auth-rate-limits.ts +252 -0
  244. package/src/auth/managed-auth-session-adapter.ts +64 -29
  245. package/src/auth/managed-auth.ts +303 -35
  246. package/src/auth/managed-email.ts +18 -1
  247. package/src/auth/managed-sign-in-notifications.ts +81 -0
  248. package/src/auth/new-signups-gate.ts +49 -0
  249. package/src/auth/organization-user-setup.ts +3 -3
  250. package/src/auth/signup-funnel-metrics.ts +164 -0
  251. package/src/azure-live.ts +103 -0
  252. package/src/browser-action-fences.ts +45 -0
  253. package/src/browser-controller-authority.ts +1 -186
  254. package/src/browser-ephemeral.ts +39 -0
  255. package/src/browser-lost-runtime-end.ts +71 -0
  256. package/src/browser-state-authority.ts +1 -236
  257. package/src/claude-default-models.ts +37 -0
  258. package/src/claude-subscription-core.ts +154 -0
  259. package/src/claude-subscription-oauth.ts +352 -0
  260. package/src/claude-subscription-profile.ts +73 -0
  261. package/src/claude-subscription-usage.ts +51 -0
  262. package/src/claude-workspace-connection.ts +82 -0
  263. package/src/codemode.ts +236 -39
  264. package/src/codex-realtime.ts +181 -53
  265. package/src/codex-session-pointers.ts +80 -0
  266. package/src/company-brain-okf.ts +1 -1
  267. package/src/connected-machine-computer-access.ts +2 -1
  268. package/src/connection-ownership.ts +19 -13
  269. package/src/controller-data-plane.ts +34 -0
  270. package/src/credit-promotion-snapshot.ts +36 -0
  271. package/src/editable-artifact-production.ts +10 -0
  272. package/src/editable-artifact-source-session.ts +123 -0
  273. package/src/editable-artifact-websocket.ts +16 -3
  274. package/src/fatal-process-boundary.ts +67 -3
  275. package/src/gateway-realtime.ts +12 -8
  276. package/src/github-access.ts +31 -5
  277. package/src/github-browser-flow.ts +1 -1
  278. package/src/http/acting-person.ts +105 -0
  279. package/src/http/api-contract-compat.ts +49 -0
  280. package/src/http/api-error.ts +210 -2
  281. package/src/http/auth.ts +68 -4
  282. package/src/http/cors.ts +37 -5
  283. package/src/http/deprecation.ts +118 -0
  284. package/src/http/keyed-admission.ts +29 -0
  285. package/src/http/local-browser-boundary.ts +343 -0
  286. package/src/http/metrics-listener.ts +57 -0
  287. package/src/http/path-identifier.ts +54 -0
  288. package/src/http/registered-route-label.ts +34 -0
  289. package/src/http/rejection-telemetry.ts +120 -0
  290. package/src/http/request-body.ts +127 -0
  291. package/src/http/request-source.ts +154 -13
  292. package/src/http/sse.ts +88 -28
  293. package/src/http/unmatched-route.ts +60 -0
  294. package/src/http/user-content.ts +158 -0
  295. package/src/http/variable-sets-removed.ts +122 -0
  296. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  297. package/src/index.ts +107 -57
  298. package/src/integration-connect-metrics.ts +228 -0
  299. package/src/integration-endpoint-test.ts +291 -0
  300. package/src/integrations/api-integrations.ts +81 -7
  301. package/src/integrations/atlassian.ts +202 -83
  302. package/src/integrations/fiken.ts +66 -38
  303. package/src/integrations/github-app-connect.ts +64 -18
  304. package/src/integrations/github-lens-connect.ts +8 -29
  305. package/src/integrations/google-drive.ts +448 -152
  306. package/src/integrations/integration-commit-authority.ts +69 -0
  307. package/src/integrations/marketplace-plugin.ts +1 -1
  308. package/src/integrations/oauth-client.ts +733 -193
  309. package/src/integrations/oauth-profiles.ts +116 -45
  310. package/src/integrations/onepassword-vault-provider.ts +16 -0
  311. package/src/integrations/personal-github-repositories.ts +1 -1
  312. package/src/integrations/personal-github.ts +61 -35
  313. package/src/integrations/provider-oauth.ts +67 -85
  314. package/src/integrations/slack-app-home.ts +5 -5
  315. package/src/integrations/slack-bot.ts +893 -201
  316. package/src/integrations/slack-file-upload-flow.ts +147 -0
  317. package/src/integrations/slack-install.ts +7 -7
  318. package/src/integrations/slack-interactions.ts +1589 -299
  319. package/src/integrations/slack-mrkdwn.ts +193 -0
  320. package/src/integrations/slack-routing.ts +2 -2
  321. package/src/integrations/slack-session-defaults.ts +224 -0
  322. package/src/integrations/slack-task-file-upload.ts +323 -0
  323. package/src/integrations/slack-tool-review.ts +65 -0
  324. package/src/integrations/social-oauth.ts +90 -58
  325. package/src/interaction-agent-access.ts +40 -20
  326. package/src/interaction-agent-version.ts +85 -0
  327. package/src/interaction-holder-heartbeat.ts +24 -8
  328. package/src/interaction-metrics.ts +164 -2
  329. package/src/interaction-route-stages.ts +94 -0
  330. package/src/interaction-secrets-vault.ts +213 -0
  331. package/src/interaction-secrets.ts +426 -0
  332. package/src/mcp/action-catalog-types.ts +14 -0
  333. package/src/mcp/action-catalog.gen.ts +8014 -0
  334. package/src/mcp/action-descriptions.ts +299 -0
  335. package/src/mcp/action-schema-imports.gen.ts +304 -0
  336. package/src/mcp/capability-account-readiness.ts +17 -0
  337. package/src/mcp/child-read-evidence.ts +19 -0
  338. package/src/mcp/company-profile-agent-admin.ts +13 -0
  339. package/src/mcp/contract-input.ts +165 -0
  340. package/src/mcp/documents.ts +9 -2
  341. package/src/mcp/editable-artifacts.ts +29 -11
  342. package/src/mcp/files.ts +5 -1
  343. package/src/mcp/first-party-tool-permissions.ts +7 -285
  344. package/src/mcp/knowledge-entries.ts +108 -34
  345. package/src/mcp/notification-tools.ts +480 -0
  346. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  347. package/src/mcp/scheduled-task-input.ts +89 -0
  348. package/src/mcp/scheduled-task-view.ts +63 -3
  349. package/src/mcp/secret-tools.ts +185 -0
  350. package/src/mcp/server.ts +2213 -1116
  351. package/src/mcp/session-admin-access-tools.ts +163 -0
  352. package/src/mcp/session-event-errors.ts +123 -0
  353. package/src/mcp/session-event-view.ts +395 -13
  354. package/src/mcp/session-view.ts +3 -0
  355. package/src/mcp/session-wait.ts +67 -7
  356. package/src/mcp/site-agent-clamp-tools.ts +140 -0
  357. package/src/mcp/site-data-tools.ts +339 -0
  358. package/src/mcp/site-publication-tools.ts +201 -0
  359. package/src/mcp/site-sql-tools.ts +427 -0
  360. package/src/mcp-oauth.ts +635 -45
  361. package/src/model-calls/chat-completions.ts +352 -0
  362. package/src/model-calls/pending-usage-settlements.ts +125 -0
  363. package/src/model-calls/service.ts +694 -0
  364. package/src/model-catalog.ts +68 -17
  365. package/src/native-push-dispatch.ts +457 -0
  366. package/src/observability.ts +15 -1
  367. package/src/organization-mcp.ts +485 -0
  368. package/src/prepared-mcp-actor.ts +154 -0
  369. package/src/prepared-mcp-permissions.ts +38 -0
  370. package/src/routes/analytics-consent.ts +123 -0
  371. package/src/routes/api-integrations.ts +268 -9
  372. package/src/routes/api-keys.ts +164 -25
  373. package/src/routes/artifact-catalog.ts +111 -0
  374. package/src/routes/automations.ts +163 -90
  375. package/src/routes/billing.ts +535 -59
  376. package/src/routes/browser-sessions.ts +966 -342
  377. package/src/routes/canonical-human-identities.ts +61 -0
  378. package/src/routes/capabilities.ts +112 -5
  379. package/src/routes/channels.ts +4 -3
  380. package/src/routes/chat-completions.ts +235 -0
  381. package/src/routes/claude-core-usage.ts +147 -0
  382. package/src/routes/claude-subscription-accounts.ts +233 -0
  383. package/src/routes/claude-subscription-oauth.ts +175 -0
  384. package/src/routes/client-errors.ts +394 -0
  385. package/src/routes/codex-core.ts +687 -0
  386. package/src/routes/codex.ts +1277 -1119
  387. package/src/routes/company-brain.ts +4 -0
  388. package/src/routes/computer-sessions.ts +319 -85
  389. package/src/routes/connect.ts +277 -175
  390. package/src/routes/connections.ts +690 -363
  391. package/src/routes/desktop-distribution.ts +217 -0
  392. package/src/routes/documents.ts +13 -7
  393. package/src/routes/editable-artifacts.ts +74 -4
  394. package/src/routes/enrollments.ts +110 -16
  395. package/src/routes/external-identity-links.ts +13 -12
  396. package/src/routes/files.ts +41 -16
  397. package/src/routes/github-browser-fonts.gen.ts +12 -0
  398. package/src/routes/github-browser-pages.ts +258 -0
  399. package/src/routes/github.ts +200 -75
  400. package/src/routes/inbox.ts +353 -0
  401. package/src/routes/insights-response-cache.ts +83 -0
  402. package/src/routes/insights-usage.ts +345 -0
  403. package/src/routes/insights.ts +103 -8
  404. package/src/routes/install.ts +51 -10
  405. package/src/routes/integration-facets.ts +70 -28
  406. package/src/routes/interaction-placement-message.ts +12 -0
  407. package/src/routes/knowledge.ts +136 -27
  408. package/src/routes/machines.ts +189 -135
  409. package/src/routes/managed-auth-session-sets.ts +43 -10
  410. package/src/routes/managed-onboarding.ts +39 -19
  411. package/src/routes/managed-sign-in-methods.ts +433 -0
  412. package/src/routes/memory-slack-publications.ts +3 -2
  413. package/src/routes/model-account-choice.ts +194 -0
  414. package/src/routes/model-account-settings.ts +235 -0
  415. package/src/routes/model-connection-access.ts +210 -48
  416. package/src/routes/native-app-auth.ts +296 -0
  417. package/src/routes/organization-integration-policy.ts +116 -0
  418. package/src/routes/organization-integrations.ts +326 -0
  419. package/src/routes/organization-mcp-connections.ts +183 -0
  420. package/src/routes/organization-memberships.ts +205 -19
  421. package/src/routes/organization-model-defaults.ts +110 -0
  422. package/src/routes/organization-model-providers.ts +74 -3
  423. package/src/routes/organization-service-accounts.ts +128 -0
  424. package/src/routes/organization-sessions.ts +21 -5
  425. package/src/routes/personal-api-keys.ts +184 -0
  426. package/src/routes/personal-github-git-broker.ts +2 -2
  427. package/src/routes/personal-github.ts +9 -4
  428. package/src/routes/plugins.ts +46 -7
  429. package/src/routes/pr-review-github.ts +105 -118
  430. package/src/routes/pr-review.ts +88 -82
  431. package/src/routes/preference-registry.ts +18 -0
  432. package/src/routes/rigs.ts +48 -13
  433. package/src/routes/scheduled-tasks.ts +347 -27
  434. package/src/routes/session-admin-access.ts +271 -0
  435. package/src/routes/session-artifact-associations.ts +164 -0
  436. package/src/routes/session-history-imports.ts +305 -0
  437. package/src/routes/sessions.ts +1682 -363
  438. package/src/routes/site-data.ts +340 -0
  439. package/src/routes/site-publishing.ts +584 -0
  440. package/src/routes/site-runtime.ts +1944 -0
  441. package/src/routes/site-sql.ts +263 -0
  442. package/src/routes/skill-content.ts +72 -7
  443. package/src/routes/skills.ts +5 -4
  444. package/src/routes/slack-bot-access.ts +108 -0
  445. package/src/routes/social.ts +27 -15
  446. package/src/routes/subscription-account-pools.ts +209 -0
  447. package/src/routes/subscription-core-http.ts +18 -0
  448. package/src/routes/subscription-pool-access.ts +180 -0
  449. package/src/routes/subscription-pool-core.ts +552 -0
  450. package/src/routes/supergrok.ts +174 -655
  451. package/src/routes/transcription-recordings.ts +71 -4
  452. package/src/routes/transcriptions.ts +26 -2
  453. package/src/routes/usage-allowances.ts +381 -0
  454. package/src/routes/variable-sets-removed.ts +19 -0
  455. package/src/routes/vault-providers.ts +782 -0
  456. package/src/routes/vaults.ts +421 -0
  457. package/src/routes/video-generation.ts +30 -12
  458. package/src/routes/workspace-artifacts.ts +165 -53
  459. package/src/routes/workspace-integrations.ts +576 -0
  460. package/src/routes/workspace-model-providers.ts +148 -0
  461. package/src/routes/workspace-state.ts +4 -0
  462. package/src/routes/workspaces.ts +625 -117
  463. package/src/sandbox/agent-update.ts +315 -0
  464. package/src/sandbox/auth-callout.ts +104 -21
  465. package/src/sandbox/channel-a.ts +165 -55
  466. package/src/sandbox/enrollment.ts +131 -22
  467. package/src/sandbox/machine-audience.ts +192 -0
  468. package/src/sandbox/machines.ts +75 -31
  469. package/src/sandbox/metrics-ingestion.ts +133 -2
  470. package/src/sandbox/rematerialize.ts +51 -21
  471. package/src/sandbox/screen-control.ts +289 -0
  472. package/src/sandbox/viewer.ts +33 -58
  473. package/src/sandbox-file-artifacts.ts +53 -27
  474. package/src/scheduled-task-blockers.ts +293 -0
  475. package/src/scheduled-task-deletion.ts +13 -3
  476. package/src/scheduled-task-lifecycle.ts +84 -0
  477. package/src/secret-answers.ts +119 -0
  478. package/src/session-create-observability.ts +46 -0
  479. package/src/session-realtime-context.ts +26 -4
  480. package/src/signed-state-secret.ts +58 -0
  481. package/src/site-agent-guard.ts +261 -0
  482. package/src/site-data/operations.ts +777 -0
  483. package/src/site-data/service.ts +1043 -0
  484. package/src/site-frame-guard.ts +107 -0
  485. package/src/site-publishing/agent-data-tools.ts +250 -0
  486. package/src/site-publishing/agent-model.ts +127 -0
  487. package/src/site-publishing/agent-session.ts +148 -0
  488. package/src/site-publishing/content-scanner.ts +93 -0
  489. package/src/site-publishing/edge-sync.ts +148 -0
  490. package/src/site-publishing/gateway-signature.ts +198 -0
  491. package/src/site-publishing/limits.ts +315 -0
  492. package/src/site-publishing/page-tool-authority.ts +111 -0
  493. package/src/site-publishing/platform-usage.ts +479 -0
  494. package/src/site-publishing/platform.ts +98 -0
  495. package/src/site-publishing/readiness.ts +330 -0
  496. package/src/site-publishing/runtime.ts +831 -0
  497. package/src/site-publishing/service.ts +1282 -0
  498. package/src/site-publishing/session-events.ts +262 -0
  499. package/src/site-publishing/session-views.ts +262 -0
  500. package/src/site-publishing/viewer.ts +75 -0
  501. package/src/site-session-origin.ts +91 -6
  502. package/src/site-sql/format.ts +134 -0
  503. package/src/site-sql/gateway.ts +168 -0
  504. package/src/site-sql/service.ts +1636 -0
  505. package/src/site-uploads.ts +27 -5
  506. package/src/temporal-schedule-sync.ts +74 -0
  507. package/src/transcription/billing-refusal.ts +14 -0
  508. package/src/transcription/normalize.ts +77 -0
  509. package/src/transcription/providers/azure-mai.ts +98 -0
  510. package/src/transcription/providers/azure-openai.ts +16 -7
  511. package/src/transcription/providers/codex-subscription.ts +190 -67
  512. package/src/transcription/providers/openai.ts +79 -5
  513. package/src/transcription/providers/subscription-core.ts +125 -0
  514. package/src/transcription/providers/xai-subscription.ts +81 -83
  515. package/src/transcription/segmenter.ts +7 -1
  516. package/src/transcription/service.ts +239 -10
  517. package/src/transcription/wav-duration.ts +39 -0
  518. package/src/workspace-deletion.ts +25 -1
  519. package/src/workspace-tool-gateway-attestations.ts +133 -0
  520. package/src/workspace-tool-gateway-observability.ts +64 -0
  521. package/src/workspace-tool-gateway-secrets.ts +104 -0
  522. package/src/workspace-tool-gateway.ts +921 -103
  523. package/src/workspace-tool-target-fence.ts +380 -0
  524. package/src/workspace-tool-target.ts +554 -0
  525. package/src/workspace-webhook-dispatch.ts +225 -0
  526. package/src/xai-realtime.ts +85 -81
  527. package/src/xai-subscription-core.ts +172 -0
  528. package/dist/browser-auth-broker.d.ts +0 -20
  529. package/dist/chunk-AJ62T5QN.js.map +0 -1
  530. package/dist/connection-authority-owner.d.ts +0 -59
  531. package/dist/routes/connection-authorities.d.ts +0 -3
  532. package/dist/routes/environments.d.ts +0 -5
  533. package/dist/routes/host-mcp-bindings.d.ts +0 -5
  534. package/dist/routes/host-mcp-resolvers.d.ts +0 -3
  535. package/dist/routes/packs.d.ts +0 -3
  536. package/dist/session-event-view-MU3HMNV3.js +0 -264
  537. package/dist/session-event-view-MU3HMNV3.js.map +0 -1
  538. package/dist/xai-subscription-auth.d.ts +0 -23
  539. package/src/browser-auth-broker.ts +0 -155
  540. package/src/connection-authority-owner.ts +0 -61
  541. package/src/routes/connection-authorities.ts +0 -139
  542. package/src/routes/environments.ts +0 -388
  543. package/src/routes/host-mcp-bindings.ts +0 -122
  544. package/src/routes/host-mcp-resolvers.ts +0 -41
  545. package/src/routes/packs.ts +0 -784
  546. package/src/xai-subscription-auth.ts +0 -139
@@ -15,6 +15,7 @@ import {
15
15
  normalizeMimeType,
16
16
  requireAccessGrant,
17
17
  TRANSCRIPTION_PROVIDER_REQUEST_TIMEOUT_MILLISECONDS,
18
+ TranscriptionBillingRefusedError,
18
19
  TranscriptionServiceError,
19
20
  type ApiRouteDeps,
20
21
  } from "@opengeni/core";
@@ -45,10 +46,13 @@ import {
45
46
  TranscriptionRecordingStateError,
46
47
  isSessionEventPersistenceError,
47
48
  } from "@opengeni/db";
48
- import { getWorkspace } from "@opengeni/db";
49
+ import { getWorkspace, type CreditDebitAttribution } from "@opengeni/db";
49
50
  import type { Context, Hono } from "hono";
51
+ import { creditDebitAttributionForGrant } from "../access-grant-rls";
50
52
  import { ApiHttpError } from "../http/api-error";
53
+ import { wavDurationSeconds } from "../transcription/wav-duration";
51
54
  import { TranscriptionSegmenterError } from "../transcription/segmenter";
55
+ import { transcriptionBillingRefusal } from "../transcription/billing-refusal";
52
56
 
53
57
  const CHUNK_SHA256_HEADER = "x-opengeni-chunk-sha256";
54
58
  const CHUNK_START_HEADER = "x-opengeni-chunk-start-milliseconds";
@@ -60,6 +64,8 @@ type RecordingAuthority = {
60
64
  workspaceId: string;
61
65
  subjectId: string;
62
66
  voiceInput?: WorkspaceVoiceInputSettings | undefined;
67
+ /** Trusted payer for deployment-funded segments. */
68
+ attribution: CreditDebitAttribution;
63
69
  };
64
70
 
65
71
  class RecordingProcessingError extends Error {
@@ -370,6 +376,8 @@ export function registerResumableTranscriptionRoutes(app: Hono, deps: ApiRouteDe
370
376
  !(await service.available({
371
377
  workspaceId: authority.workspaceId,
372
378
  subjectId: authority.subjectId,
379
+ preferredProvider: authority.voiceInput?.preferredProvider,
380
+ fallbackEnabled: authority.voiceInput?.fallbackEnabled,
373
381
  }))
374
382
  ) {
375
383
  return c.json({ code: "unavailable" }, 503);
@@ -420,6 +428,37 @@ export function registerResumableTranscriptionRoutes(app: Hono, deps: ApiRouteDe
420
428
  false,
421
429
  );
422
430
  }
431
+ const segmentProviderId =
432
+ claim.segment.providerId && claim.segment.providerId !== "host"
433
+ ? claim.segment.providerId
434
+ : null;
435
+ // Credit admission for the exact pinned provider, before the durable
436
+ // provider-start fence. A refusal releases the claim untouched (no
437
+ // audio sent) and surfaces 402 so the client stops retrying.
438
+ if (segmentProviderId && service.admit) {
439
+ try {
440
+ await service.admit({
441
+ providerId: segmentProviderId,
442
+ accountId: authority.accountId,
443
+ workspaceId: authority.workspaceId,
444
+ attribution: authority.attribution,
445
+ });
446
+ } catch (error) {
447
+ if (!(error instanceof TranscriptionBillingRefusedError)) throw error;
448
+ await failTranscriptionRecordingSegment(deps.db, {
449
+ workspaceId: authority.workspaceId,
450
+ subjectId: authority.subjectId,
451
+ recordingId: uuidParam(c, "recordingId"),
452
+ segmentNumber,
453
+ attemptId,
454
+ fallbackProviderId: null,
455
+ // The real refusal, so a reloaded recording still explains it.
456
+ errorCode: error.code,
457
+ retryable: true,
458
+ }).catch(() => null);
459
+ return transcriptionBillingRefusal(c, error);
460
+ }
461
+ }
423
462
  const providerStartedAt = new Date();
424
463
  const providerDeadlineAt = new Date(
425
464
  providerStartedAt.getTime() + TRANSCRIPTION_PROVIDER_REQUEST_TIMEOUT_MILLISECONDS,
@@ -442,10 +481,22 @@ export function registerResumableTranscriptionRoutes(app: Hono, deps: ApiRouteDe
442
481
  durationSeconds: claim.segment.durationMilliseconds / 1_000,
443
482
  requestId: attemptId,
444
483
  providerDeadlineAt,
445
- ...(claim.segment.providerId && claim.segment.providerId !== "host"
446
- ? { providerId: claim.segment.providerId }
447
- : {}),
484
+ deferBillingSettlement: true,
485
+ ...(segmentProviderId ? { providerId: segmentProviderId } : {}),
486
+ billing: {
487
+ // One settlement per prepared segment of this exact recording,
488
+ // however many provider attempts it takes. The recording id is
489
+ // client-chosen, so the unit id also binds its server creation
490
+ // time and the server-produced segment bytes.
491
+ sourceId: `${claim.recording.recording.id}:${Date.parse(claim.recording.recording.createdAt)}:${segmentNumber}:${claim.segment.sha256}`,
492
+ attribution: authority.attribution,
493
+ trustedDurationSeconds: wavDurationSeconds(stored.bytes) ?? undefined,
494
+ },
448
495
  });
496
+ // The transcript commits first and on its own: a billing failure can
497
+ // never roll back text the user already waited for. Only the attempt
498
+ // that durably completed the segment settles it (a stale attempt is
499
+ // refused here and never charges); settlement itself never throws.
449
500
  const completed = await completeTranscriptionRecordingSegment(deps.db, {
450
501
  workspaceId: authority.workspaceId,
451
502
  subjectId: authority.subjectId,
@@ -456,6 +507,9 @@ export function registerResumableTranscriptionRoutes(app: Hono, deps: ApiRouteDe
456
507
  languages: result.languages,
457
508
  providerId: claim.segment.providerId ?? result.providerId,
458
509
  });
510
+ // Never rejects for the built-in service (it logs and retries); a
511
+ // custom service's failure must not turn a durable transcript into an error.
512
+ await result.settleBilling?.().catch(() => undefined);
459
513
  return c.json(await cleanupTerminalObjects(deps, authority, completed));
460
514
  } catch (error) {
461
515
  if (authority && attemptId && segmentNumber !== null) {
@@ -489,6 +543,11 @@ export function registerResumableTranscriptionRoutes(app: Hono, deps: ApiRouteDe
489
543
  errorCode: failure.code,
490
544
  retryable: failure.retryable,
491
545
  }).catch(() => null);
546
+ // A credit refusal sent no audio; the released segment stays
547
+ // retryable, but the client must see the definitive refusal.
548
+ if (error instanceof TranscriptionBillingRefusedError) {
549
+ return transcriptionBillingRefusal(c, error);
550
+ }
492
551
  if (persisted) return c.json(persisted);
493
552
  }
494
553
  return routeError(c, error);
@@ -545,6 +604,7 @@ async function requireRecordingAuthority(
545
604
  accountId: grant.accountId,
546
605
  workspaceId,
547
606
  subjectId: grant.subjectId,
607
+ attribution: creditDebitAttributionForGrant(grant),
548
608
  };
549
609
  }
550
610
 
@@ -641,6 +701,10 @@ function processingFailure(error: unknown): {
641
701
  if (error instanceof TranscriptionSegmenterError) {
642
702
  return { code: error.code, retryable: error.retryable };
643
703
  }
704
+ if (error instanceof TranscriptionBillingRefusedError) {
705
+ // Refused before any audio was sent; retryable once the payer is funded.
706
+ return { code: error.code, retryable: true };
707
+ }
644
708
  if (error instanceof TranscriptionServiceError) {
645
709
  return {
646
710
  code: error.code,
@@ -663,6 +727,9 @@ function routeError(c: Context, error: unknown): Response | Promise<Response> {
663
727
  if (error instanceof TranscriptionRecordingNotFoundError) {
664
728
  return c.json({ code: "not_found" }, 404);
665
729
  }
730
+ if (error instanceof TranscriptionBillingRefusedError) {
731
+ return transcriptionBillingRefusal(c, error);
732
+ }
666
733
  if (error instanceof TranscriptionRecordingConflictError) {
667
734
  return c.json({ code: "conflict" }, 409);
668
735
  }
@@ -3,9 +3,16 @@ import {
3
3
  WorkspaceVoiceInputSettings,
4
4
  type TranscribeAudioResponse,
5
5
  } from "@opengeni/contracts";
6
- import { type ApiRouteDeps, requireAccessGrant, TranscriptionServiceError } from "@opengeni/core";
6
+ import {
7
+ type ApiRouteDeps,
8
+ requireAccessGrant,
9
+ TranscriptionBillingRefusedError,
10
+ TranscriptionServiceError,
11
+ } from "@opengeni/core";
7
12
  import { getWorkspace } from "@opengeni/db";
8
13
  import type { Hono } from "hono";
14
+ import { creditDebitAttributionForGrant } from "../access-grant-rls";
15
+ import { transcriptionBillingRefusal } from "../transcription/billing-refusal";
9
16
  import { registerResumableTranscriptionRoutes } from "./transcription-recordings";
10
17
 
11
18
  export function registerTranscriptionRoutes(app: Hono, deps: ApiRouteDeps): void {
@@ -20,12 +27,26 @@ export function registerTranscriptionRoutes(app: Hono, deps: ApiRouteDeps): void
20
27
  }
21
28
  const preferences = WorkspaceVoiceInputSettings.safeParse(workspace.settings.voiceInput).data;
22
29
  const service = deps.transcription;
23
- if (!service || !(await service.available({ workspaceId, subjectId: grant.subjectId }))) {
30
+ if (
31
+ !service ||
32
+ !(await service.available({
33
+ workspaceId,
34
+ subjectId: grant.subjectId,
35
+ preferredProvider: preferences?.preferredProvider,
36
+ fallbackEnabled: preferences?.fallbackEnabled,
37
+ }))
38
+ ) {
24
39
  return c.json({ code: "unavailable" }, 503);
25
40
  }
26
41
  try {
27
42
  const body = await audioRequest(c.req.raw, service.limits().maxSizeBytes);
43
+ // Server-generated: the correlation id is client-chosen and a reused
44
+ // settlement key would make every later call with it free.
28
45
  const result = await service.transcribe({
46
+ billing: {
47
+ sourceId: crypto.randomUUID(),
48
+ attribution: creditDebitAttributionForGrant(grant),
49
+ },
29
50
  preferredProvider: preferences?.preferredProvider,
30
51
  fallbackEnabled: preferences?.fallbackEnabled,
31
52
  workspaceId,
@@ -46,6 +67,9 @@ export function registerTranscriptionRoutes(app: Hono, deps: ApiRouteDeps): void
46
67
  if (error instanceof TranscriptionServiceError) {
47
68
  return c.json({ code: error.code }, error.status as never);
48
69
  }
70
+ if (error instanceof TranscriptionBillingRefusedError) {
71
+ return transcriptionBillingRefusal(c, error);
72
+ }
49
73
  if (isAbort(error)) return c.json({ code: "cancelled" }, 499 as never);
50
74
  return c.json({ code: "unknown" }, 500);
51
75
  }
@@ -0,0 +1,381 @@
1
+ import type { Context, Hono } from "hono";
2
+ import { HTTPException } from "hono/http-exception";
3
+ import {
4
+ ClearWorkspaceAllowanceRequest,
5
+ GetMyUsageRequest,
6
+ GetUsageRequest,
7
+ GrantWorkspaceCreditsRequest,
8
+ SetMemberAllowanceRequest,
9
+ SetWorkspaceAllowanceRequest,
10
+ WorkspaceAllowance,
11
+ WorkspaceAllowanceState,
12
+ WorkspaceCreditGrant,
13
+ WorkspaceUsageResponse,
14
+ MemberAllowance,
15
+ ClearWorkspaceAllowanceResponse,
16
+ type AccessContext,
17
+ } from "@opengeni/contracts";
18
+ import { ExternalIdentityReference } from "@opengeni/contracts/external-identities";
19
+ import {
20
+ accountScopedApiKeyWorkspaceAuthority,
21
+ accessGrantAuthorizationFromContext,
22
+ requireAccountAdminAuthorizationStamp,
23
+ requireAccessContext,
24
+ requireAccessGrantAuthorization,
25
+ requireResolvedAccessGrantAuthorization,
26
+ type AccessGrantAuthorization,
27
+ type ApiRouteDeps,
28
+ } from "@opengeni/core";
29
+ import {
30
+ clearWorkspaceAllowance,
31
+ findWorkspaceByExternalIdentity,
32
+ getWorkspaceAllowance,
33
+ getWorkspaceAllowanceState,
34
+ getWorkspace,
35
+ getWorkspaceUsage,
36
+ grantWorkspaceCredits,
37
+ nestedPostgresSqlState,
38
+ setMemberAllowance,
39
+ setWorkspaceAllowance,
40
+ withAccountRls,
41
+ UsageAllowanceVersionConflictError,
42
+ } from "@opengeni/db";
43
+ import { parseRequestBody, parseRequestJson } from "../http/request-body";
44
+
45
+ type Authority = { authorization: AccessGrantAuthorization; context: AccessContext };
46
+ type Operation = "read" | "budget-read" | "workspace-write" | "member-write" | "own";
47
+
48
+ /** No workspace wildcard, service initiator, or actor label can confer budget authority. */
49
+ export function requireAllowanceAuthority(
50
+ { authorization, context }: Authority,
51
+ operation: Operation,
52
+ ): void {
53
+ const grant = requireResolvedAccessGrantAuthorization(
54
+ authorization,
55
+ authorization.grant.workspaceId,
56
+ );
57
+ if (grant.principalKind === "agent_attempt" || grant.metadata?.sessionId !== undefined) {
58
+ throw new HTTPException(403, { message: "Agents cannot access usage allowances" });
59
+ }
60
+ const organizationKey = accountScopedApiKeyWorkspaceAuthority(context);
61
+ const sameOrganizationKey =
62
+ organizationKey?.accountId === grant.accountId ? organizationKey : null;
63
+ const accountAdmin =
64
+ authorization.accountGrant?.permissions.includes("account:admin") === true &&
65
+ requireAccountAdminAuthorizationStamp(authorization).accountId === grant.accountId;
66
+ const workspaceAdmin = grant.permissions.includes("workspace:admin");
67
+ if (
68
+ sameOrganizationKey?.permissionMode === "explicit" &&
69
+ (operation === "workspace-write" || operation === "member-write")
70
+ ) {
71
+ if (authorization.accountGrant?.permissions.includes("usage_allowances:manage")) return;
72
+ throw new HTTPException(403, { message: "missing permission: usage_allowances:manage" });
73
+ }
74
+ if (operation === "own") {
75
+ if (grant.principalKind !== "human_session" || grant.serviceInitiator) {
76
+ throw new HTTPException(403, { message: "Own usage requires an authenticated member" });
77
+ }
78
+ return;
79
+ }
80
+ if (operation === "read" || operation === "budget-read") {
81
+ if (
82
+ workspaceAdmin ||
83
+ accountAdmin ||
84
+ sameOrganizationKey?.permissions.includes("workspace:read")
85
+ )
86
+ return;
87
+ } else if (operation === "workspace-write") {
88
+ // Existing full keys retain key-control budget authority. Setup keys use
89
+ // literal account allowance authority plus the canonical organization-key
90
+ // workspace stamp; asUser carries neither account scope nor key stamp.
91
+ if (sameOrganizationKey) {
92
+ if (
93
+ sameOrganizationKey.permissions.includes("workspace:admin") &&
94
+ (sameOrganizationKey.permissions.includes("api_keys:manage") ||
95
+ authorization.accountGrant?.permissions.includes("usage_allowances:manage"))
96
+ )
97
+ return;
98
+ } else if (
99
+ accountAdmin &&
100
+ grant.principalKind === "human_session" &&
101
+ !grant.serviceInitiator &&
102
+ !context.subjectId.startsWith("api_key:")
103
+ )
104
+ return;
105
+ } else if (operation === "member-write") {
106
+ if (
107
+ sameOrganizationKey?.permissions.includes("workspace:admin") ||
108
+ (workspaceAdmin &&
109
+ grant.principalKind === "human_session" &&
110
+ !grant.serviceInitiator &&
111
+ !context.subjectId.startsWith("api_key:"))
112
+ )
113
+ return;
114
+ }
115
+ throw new HTTPException(403, { message: `Missing usage allowance authority: ${operation}` });
116
+ }
117
+
118
+ async function resolveWorkspace(c: Context, deps: ApiRouteDeps): Promise<string> {
119
+ const workspaceId = c.req.param("workspaceId");
120
+ if (workspaceId) return workspaceId;
121
+ const context = await requireAccessContext(c, deps);
122
+ const organizationKey = accountScopedApiKeyWorkspaceAuthority(context);
123
+ // External tenant paths are host-service lookups, never caller-selected
124
+ // default-account guesses or provisioning.
125
+ const externalAccountId =
126
+ c.req.header("x-opengeni-external-actor") !== undefined ? context.defaultAccountId : null;
127
+ const accountId = organizationKey?.accountId ?? externalAccountId;
128
+ if (!accountId)
129
+ throw new HTTPException(403, { message: "Organization API key or external user required" });
130
+ const reference = parseRequestBody(ExternalIdentityReference, {
131
+ source: c.req.param("workspaceSource"),
132
+ externalId: c.req.param("workspaceExternalId"),
133
+ });
134
+ const workspace = await withAccountRls(deps.db, accountId, (tx) =>
135
+ findWorkspaceByExternalIdentity(tx, {
136
+ accountId,
137
+ externalSource: reference.source,
138
+ externalId: reference.externalId,
139
+ }),
140
+ );
141
+ if (!workspace) throw new HTTPException(404, { message: "Workspace not found" });
142
+ return workspace.id;
143
+ }
144
+
145
+ async function authorize(c: Context, deps: ApiRouteDeps, operation: Operation) {
146
+ const workspaceId = await resolveWorkspace(c, deps);
147
+ const context = await requireAccessContext(c, deps);
148
+ if (
149
+ (operation === "workspace-write" || operation === "budget-read") &&
150
+ !c.req.header("x-opengeni-external-actor") &&
151
+ !context.subjectId.startsWith("api_key:")
152
+ ) {
153
+ // Organization budget management does not require membership in the
154
+ // target shared workspace. Validate the existing authenticated account
155
+ // authority on its own anchor, never manufacture a target workspace grant.
156
+ for (const account of context.accountGrants) {
157
+ if (account.subjectId !== context.subjectId || !account.permissions.includes("account:admin"))
158
+ continue;
159
+ const anchor = context.workspaceGrants.find(
160
+ (grant) =>
161
+ grant.accountId === account.accountId &&
162
+ grant.subjectId === context.subjectId &&
163
+ grant.principalKind === "human_session" &&
164
+ !grant.serviceInitiator &&
165
+ grant.metadata?.sessionId === undefined,
166
+ );
167
+ if (!anchor) continue;
168
+ const stamp = requireAccountAdminAuthorizationStamp(
169
+ accessGrantAuthorizationFromContext(context, anchor),
170
+ );
171
+ const target = await withAccountRls(deps.db, stamp.accountId, (tx) =>
172
+ getWorkspace(tx, workspaceId),
173
+ );
174
+ if (!target || target.accountId !== stamp.accountId) continue;
175
+ if (target.kind !== "shared") {
176
+ throw new HTTPException(403, {
177
+ message: "Organization budgets require a shared workspace",
178
+ });
179
+ }
180
+ return {
181
+ accountId: stamp.accountId,
182
+ workspaceId,
183
+ actorSubjectId: stamp.actorSubjectId,
184
+ actorType: "human_session" as const,
185
+ };
186
+ }
187
+ // An administrator of another organization may still hold an ordinary
188
+ // target grant. A budget lookup miss grants nothing and must not mask it.
189
+ }
190
+ const authorization = await requireAccessGrantAuthorization(c, deps, workspaceId);
191
+ requireAllowanceAuthority({ authorization, context }, operation);
192
+ return {
193
+ accountId: authorization.grant.accountId,
194
+ workspaceId,
195
+ actorSubjectId: authorization.grant.subjectId,
196
+ actorType: authorization.grant.principalKind ?? "subject",
197
+ };
198
+ }
199
+
200
+ function usageQuery(c: Context, own: boolean) {
201
+ const input = c.req.query();
202
+ const parsed = parseRequestBody(own ? GetMyUsageRequest : GetUsageRequest, {
203
+ ...input,
204
+ ...(input.limit !== undefined ? { limit: Number(input.limit) } : {}),
205
+ });
206
+ return {
207
+ ...(parsed.period === undefined ? {} : { period: parsed.period }),
208
+ ...("limit" in parsed && parsed.limit !== undefined ? { limit: parsed.limit as number } : {}),
209
+ ...("cursor" in parsed && parsed.cursor !== undefined
210
+ ? { cursor: parsed.cursor as string }
211
+ : {}),
212
+ };
213
+ }
214
+
215
+ function requireAllowanceProducersEnabled(deps: ApiRouteDeps): void {
216
+ if (!deps.settings.usageAllowancesEnabled) {
217
+ throw new HTTPException(409, {
218
+ message:
219
+ "Usage allowance changes are not enabled. Upgrade every API and worker before enabling usage allowances.",
220
+ });
221
+ }
222
+ }
223
+
224
+ /** Map lifecycle refusals without treating a failed CAS as an applied mutation. */
225
+ async function lifecycle<T>(operation: () => Promise<T>): Promise<T> {
226
+ try {
227
+ return await operation();
228
+ } catch (error) {
229
+ if (error instanceof UsageAllowanceVersionConflictError)
230
+ throw new HTTPException(409, { message: error.message });
231
+ const state = nestedPostgresSqlState(error);
232
+ if (state === "40001" || state === "23505")
233
+ throw new HTTPException(409, { message: "Allowance version or operation conflicts" });
234
+ if (state === "42501")
235
+ throw new HTTPException(403, { message: "Allowance operation is not authorized" });
236
+ if (state === "P0002" || state === "23503")
237
+ throw new HTTPException(404, { message: "Allowance or member not found" });
238
+ if (state === "22023" || state === "23514")
239
+ throw new HTTPException(400, { message: "Invalid allowance request" });
240
+ throw error;
241
+ }
242
+ }
243
+
244
+ export function registerUsageAllowanceRoutes(app: Hono, deps: ApiRouteDeps): void {
245
+ const bases = [
246
+ "/v1/workspaces/:workspaceId",
247
+ "/v1/workspaces/external/:workspaceSource/:workspaceExternalId",
248
+ ];
249
+ for (const base of bases) {
250
+ app.get(`${base}/allowance`, async (c) => {
251
+ const scope = await authorize(c, deps, "budget-read");
252
+ const result = await getWorkspaceAllowance(deps.db, scope);
253
+ return c.json(result === null ? null : WorkspaceAllowance.parse(result));
254
+ });
255
+ app.get(`${base}/allowance/state`, async (c) => {
256
+ const scope = await authorize(c, deps, "budget-read");
257
+ return c.json(
258
+ WorkspaceAllowanceState.parse(await getWorkspaceAllowanceState(deps.db, scope)),
259
+ );
260
+ });
261
+ app.put(`${base}/allowance`, async (c) => {
262
+ const scope = await authorize(c, deps, "workspace-write");
263
+ const request = await parseRequestJson(c, SetWorkspaceAllowanceRequest);
264
+ requireAllowanceProducersEnabled(deps);
265
+ return c.json(
266
+ WorkspaceAllowance.parse(
267
+ await lifecycle(() =>
268
+ setWorkspaceAllowance(deps.db, {
269
+ ...scope,
270
+ expectedVersion: request.expectedVersion,
271
+ includedCredits: request.includedCredits,
272
+ period: request.period,
273
+ ...(request.anchorDay === undefined ? {} : { anchorDay: request.anchorDay }),
274
+ ...(request.memberDefault === undefined
275
+ ? {}
276
+ : { memberDefault: request.memberDefault }),
277
+ ...(request.thresholds === undefined
278
+ ? {}
279
+ : {
280
+ thresholds: {
281
+ ...(request.thresholds.workspace === undefined
282
+ ? {}
283
+ : { workspace: request.thresholds.workspace }),
284
+ ...(request.thresholds.member === undefined
285
+ ? {}
286
+ : { member: request.thresholds.member }),
287
+ },
288
+ }),
289
+ ...(request.unbilledUsage === undefined
290
+ ? {}
291
+ : { unbilledUsage: request.unbilledUsage }),
292
+ }),
293
+ ),
294
+ ),
295
+ );
296
+ });
297
+ app.delete(`${base}/allowance`, async (c) => {
298
+ const scope = await authorize(c, deps, "workspace-write");
299
+ const request = await parseRequestJson(c, ClearWorkspaceAllowanceRequest);
300
+ return c.json(
301
+ ClearWorkspaceAllowanceResponse.parse(
302
+ await lifecycle(() =>
303
+ clearWorkspaceAllowance(deps.db, {
304
+ ...scope,
305
+ expectedVersion: request.expectedVersion,
306
+ ...(request.operationId === undefined ? {} : { operationId: request.operationId }),
307
+ }),
308
+ ),
309
+ ),
310
+ );
311
+ });
312
+ app.post(`${base}/allowance/grants`, async (c) => {
313
+ const scope = await authorize(c, deps, "workspace-write");
314
+ const request = await parseRequestJson(c, GrantWorkspaceCreditsRequest);
315
+ requireAllowanceProducersEnabled(deps);
316
+ return c.json(
317
+ WorkspaceCreditGrant.parse(
318
+ await lifecycle(() =>
319
+ grantWorkspaceCredits(deps.db, {
320
+ ...scope,
321
+ operationId: request.operationId,
322
+ credits: request.credits,
323
+ ...(request.expiresAt === undefined ? {} : { expiresAt: request.expiresAt }),
324
+ }),
325
+ ),
326
+ ),
327
+ );
328
+ });
329
+ for (const memberPath of [
330
+ "members/:subjectId",
331
+ "members/external/:memberSource/:memberExternalId",
332
+ ]) {
333
+ app.put(`${base}/${memberPath}/allowance`, async (c) => {
334
+ const scope = await authorize(c, deps, "member-write");
335
+ const request = await parseRequestJson(c, SetMemberAllowanceRequest);
336
+ if (request.rule !== null) requireAllowanceProducersEnabled(deps);
337
+ const subjectId = c.req.param("subjectId");
338
+ const target = subjectId
339
+ ? { subjectId }
340
+ : {
341
+ externalIdentity: parseRequestBody(ExternalIdentityReference, {
342
+ source: c.req.param("memberSource"),
343
+ externalId: c.req.param("memberExternalId"),
344
+ }),
345
+ };
346
+ // Resolve the exact external identity and live member inside the same
347
+ // protected mutation; never enumerate a roster or provision an identity.
348
+ return c.json(
349
+ MemberAllowance.parse(
350
+ await lifecycle(() => setMemberAllowance(deps.db, { ...scope, ...target, ...request })),
351
+ ),
352
+ );
353
+ });
354
+ }
355
+ app.get(`${base}/usage`, async (c) => {
356
+ const scope = await authorize(c, deps, "read");
357
+ return c.json(
358
+ WorkspaceUsageResponse.parse(
359
+ await getWorkspaceUsage(deps.db, { ...scope, ...usageQuery(c, false) }),
360
+ ),
361
+ );
362
+ });
363
+ app.get(`${base}/usage/me`, async (c) => {
364
+ const scope = await authorize(c, deps, "own");
365
+ const result = WorkspaceUsageResponse.parse(
366
+ await getWorkspaceUsage(deps.db, {
367
+ ...scope,
368
+ ...usageQuery(c, true),
369
+ subjectId: scope.actorSubjectId,
370
+ }),
371
+ );
372
+ // Defense in depth: the own endpoint never serializes another member or a
373
+ // roster cursor even if the storage adapter returns an overbroad page.
374
+ return c.json({
375
+ ...result,
376
+ members: result.members.filter((member) => member.subjectId === scope.actorSubjectId),
377
+ nextCursor: null,
378
+ });
379
+ });
380
+ }
381
+ }
@@ -0,0 +1,19 @@
1
+ import type { Hono } from "hono";
2
+ import { variableSetsRemovedResponse } from "../http/variable-sets-removed";
3
+
4
+ /**
5
+ * Variable Sets were replaced by vaults (RM-1). Every legacy route, including
6
+ * the deprecated `/environments` alias, answers 410 `variable_sets_removed`
7
+ * with a pointer to `/vaults`. No grant is checked: the answer reveals nothing.
8
+ */
9
+ const LEGACY_PREFIXES = [
10
+ "/v1/workspaces/:workspaceId/variable-sets",
11
+ "/v1/workspaces/:workspaceId/environments",
12
+ ] as const;
13
+
14
+ export function registerVariableSetsRemovedRoutes(app: Hono): void {
15
+ for (const prefix of LEGACY_PREFIXES) {
16
+ app.all(prefix, (c) => variableSetsRemovedResponse(c, 410));
17
+ app.all(`${prefix}/*`, (c) => variableSetsRemovedResponse(c, 410));
18
+ }
19
+ }