@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
@@ -0,0 +1,217 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import type { Hono } from "hono";
4
+ import { HTTPException } from "hono/http-exception";
5
+ import type { ApiRouteDeps } from "@opengeni/core";
6
+
7
+ // Public download routes for the desktop app. Like the agent install routes,
8
+ // they are unauthenticated so a person can install the app before signing in:
9
+ //
10
+ // GET /desktop/install.sh the macOS and Linux installer
11
+ // GET /desktop/latest 302 to the current release's page
12
+ // GET /desktop/latest/<asset> 302 to the current release's file
13
+ //
14
+ // <asset> is a version-less release file name such as Opengeni-mac.dmg. The
15
+ // route redirects to Opengeni-<version>-mac.dmg on the desktop-v<version>
16
+ // release. GitHub's repository-wide "latest release" can't be used: agent and
17
+ // package releases share the repository, so "latest" is rarely the desktop app.
18
+
19
+ const INSTALL_DIR =
20
+ [
21
+ new URL("./assets/desktop-install/", import.meta.url),
22
+ new URL("../../../desktop/install/", import.meta.url),
23
+ ].find((candidate) => existsSync(candidate)) ??
24
+ new URL("../../../desktop/install/", import.meta.url);
25
+
26
+ export const DESKTOP_INSTALLER_PATH = "/desktop/install.sh";
27
+ export const DESKTOP_RELEASE_PAGE_PATH = "/desktop/latest";
28
+ export const DESKTOP_DOWNLOAD_PREFIX = "/desktop/latest/";
29
+
30
+ // Every file a desktop release publishes for people to download, without its
31
+ // version. A strict list, so the redirect can't point anywhere else.
32
+ const RELEASE_FILE =
33
+ /^Opengeni-(mac\.dmg|mac\.zip|windows\.exe|windows-(?:x64|arm64)\.exe|linux-(?:x86_64|arm64)\.AppImage|linux-(?:amd64|arm64)\.deb|linux-(?:x86_64|aarch64)\.rpm)$/u;
34
+
35
+ const STABLE_VERSION = /^(\d+)\.(\d+)\.(\d+)$/u;
36
+ const TAG_PREFIX = "desktop-v";
37
+
38
+ /** The versioned release file for a version-less name, or null if it isn't one. */
39
+ export function desktopReleaseFile(asset: string, version: string): string | null {
40
+ if (asset === "SHA256SUMS") return asset;
41
+ const match = RELEASE_FILE.exec(asset);
42
+ return match ? `Opengeni-${version}-${match[1]}` : null;
43
+ }
44
+
45
+ /** The highest stable version among desktop-v<version> tags. */
46
+ export function newestDesktopVersion(tags: readonly string[]): string | null {
47
+ let best: number[] | null = null;
48
+ for (const tag of tags) {
49
+ if (!tag.startsWith(TAG_PREFIX)) continue;
50
+ const match = STABLE_VERSION.exec(tag.slice(TAG_PREFIX.length));
51
+ if (!match) continue;
52
+ const version = match.slice(1).map(Number);
53
+ if (!best || compareVersions(version, best) > 0) best = version;
54
+ }
55
+ return best ? best.join(".") : null;
56
+ }
57
+
58
+ function compareVersions(left: number[], right: number[]): number {
59
+ for (let index = 0; index < 3; index++) {
60
+ const difference = (left[index] ?? 0) - (right[index] ?? 0);
61
+ if (difference !== 0) return difference;
62
+ }
63
+ return 0;
64
+ }
65
+
66
+ /** owner/name for a https://github.com/<owner>/<name>/releases base, else null. */
67
+ export function githubRepositoryOf(releasesBase: string): string | null {
68
+ const match = /^https:\/\/github\.com\/([\w.-]+\/[\w.-]+)\/releases\/?$/u.exec(releasesBase);
69
+ return match?.[1] ?? null;
70
+ }
71
+
72
+ export interface DesktopVersionResolverOptions {
73
+ /** An operator pin. When set, it is the only version ever served. */
74
+ pinnedVersion?: string | undefined;
75
+ releasesBase: string;
76
+ fetchImpl?: typeof fetch;
77
+ now?: () => number;
78
+ /** How long a looked-up version is reused. */
79
+ freshForMs?: number;
80
+ /** How long to wait before looking again after a failed lookup. */
81
+ retryAfterMs?: number;
82
+ }
83
+
84
+ /**
85
+ * The version /desktop/latest serves: the pin, or the newest desktop-v tag on
86
+ * the release repository. A lookup is shared by concurrent requests and reused
87
+ * for ten minutes, well within GitHub's unauthenticated rate limit. When GitHub
88
+ * is unreachable the last known version keeps serving.
89
+ */
90
+ export function createDesktopVersionResolver(
91
+ options: DesktopVersionResolverOptions,
92
+ ): () => Promise<string> {
93
+ const { pinnedVersion } = options;
94
+ if (pinnedVersion) return async () => pinnedVersion;
95
+ const repository = githubRepositoryOf(options.releasesBase);
96
+ const fetchImpl = options.fetchImpl ?? fetch;
97
+ const now = options.now ?? Date.now;
98
+ const freshForMs = options.freshForMs ?? 10 * 60_000;
99
+ const retryAfterMs = options.retryAfterMs ?? 30_000;
100
+ let known: string | null = null;
101
+ let nextLookupAt = 0;
102
+ let inFlight: Promise<void> | null = null;
103
+
104
+ async function lookUp(): Promise<void> {
105
+ try {
106
+ const response = await fetchImpl(
107
+ `https://api.github.com/repos/${repository}/git/matching-refs/tags/${TAG_PREFIX}`,
108
+ {
109
+ headers: { accept: "application/vnd.github+json", "user-agent": "opengeni-api" },
110
+ signal: AbortSignal.timeout(5_000),
111
+ },
112
+ );
113
+ if (!response.ok) throw new Error(`GitHub answered ${response.status}`);
114
+ const refs = (await response.json()) as Array<{ ref?: unknown }>;
115
+ const version = newestDesktopVersion(
116
+ refs.flatMap((entry) =>
117
+ typeof entry.ref === "string" && entry.ref.startsWith("refs/tags/")
118
+ ? [entry.ref.slice("refs/tags/".length)]
119
+ : [],
120
+ ),
121
+ );
122
+ if (version) known = version;
123
+ nextLookupAt = now() + (version ? freshForMs : retryAfterMs);
124
+ } catch {
125
+ nextLookupAt = now() + retryAfterMs;
126
+ }
127
+ }
128
+
129
+ return async () => {
130
+ if (!repository) {
131
+ throw new HTTPException(503, {
132
+ message: "Desktop downloads need OPENGENI_DESKTOP_STABLE_VERSION for this release host.",
133
+ });
134
+ }
135
+ if (now() >= nextLookupAt) {
136
+ inFlight ??= lookUp().finally(() => {
137
+ inFlight = null;
138
+ });
139
+ // The first lookup has nothing to fall back to; later ones refresh in
140
+ // the background and keep serving the version already known.
141
+ if (!known) await inFlight;
142
+ }
143
+ if (!known) {
144
+ throw new HTTPException(503, { message: "No desktop release is available yet." });
145
+ }
146
+ return known;
147
+ };
148
+ }
149
+
150
+ let installerBody: string | undefined;
151
+
152
+ // The installer resolves releases through this server when it knows the
153
+ // server's address, so a deployment's version pin applies. A copy run from the
154
+ // repository looks the release up on GitHub itself.
155
+ const BASE_URL_MARKER = 'OPENGENI_DESKTOP_DEFAULT_BASE_URL=""';
156
+
157
+ export function desktopInstallerFor(body: string, publicBaseUrl: string | undefined): string {
158
+ if (!publicBaseUrl || !/^https?:\/\//u.test(publicBaseUrl)) return body;
159
+ const base = publicBaseUrl.replace(/\/+$/u, "");
160
+ return body.replace(BASE_URL_MARKER, `OPENGENI_DESKTOP_DEFAULT_BASE_URL="${base}"`);
161
+ }
162
+
163
+ export function registerDesktopDistributionRoutes(
164
+ app: Hono,
165
+ deps: ApiRouteDeps,
166
+ resolveVersion = createDesktopVersionResolver({
167
+ pinnedVersion: deps.settings.desktopStableVersion,
168
+ releasesBase: deps.settings.agentReleasesBaseUrl.replace(/\/+$/u, ""),
169
+ }),
170
+ ): void {
171
+ const releasesBase = deps.settings.agentReleasesBaseUrl.replace(/\/+$/u, "");
172
+
173
+ app.get(DESKTOP_INSTALLER_PATH, async (c) => {
174
+ installerBody ??= await readFile(new URL("install.sh", INSTALL_DIR), "utf8");
175
+ return c.text(desktopInstallerFor(installerBody, deps.settings.publicBaseUrl), 200, {
176
+ "content-type": "text/x-shellscript; charset=utf-8",
177
+ "cache-control": "public, max-age=300",
178
+ });
179
+ });
180
+
181
+ // The release page, listing every platform's download.
182
+ app.get(DESKTOP_RELEASE_PAGE_PATH, async () => {
183
+ const version = await resolveVersion();
184
+ return new Response(null, {
185
+ status: 302,
186
+ headers: {
187
+ location: `${releasesBase}/tag/${TAG_PREFIX}${version}`,
188
+ "cache-control": "public, max-age=300",
189
+ },
190
+ });
191
+ });
192
+
193
+ app.get(`${DESKTOP_DOWNLOAD_PREFIX}:asset`, async (c) => {
194
+ const asset = c.req.param("asset");
195
+ // Validate before resolving, so a bad name never costs a lookup.
196
+ if (!desktopReleaseFile(asset, "0.0.0")) {
197
+ throw new HTTPException(404, { message: "Unknown desktop download." });
198
+ }
199
+ const version = await resolveVersion();
200
+ const file = desktopReleaseFile(asset, version)!;
201
+ return new Response(null, {
202
+ status: 302,
203
+ headers: {
204
+ location: `${releasesBase}/download/${TAG_PREFIX}${version}/${file}`,
205
+ "cache-control": "public, max-age=300",
206
+ },
207
+ });
208
+ });
209
+ }
210
+
211
+ export function isDesktopDistributionPath(path: string): boolean {
212
+ return (
213
+ path === DESKTOP_INSTALLER_PATH ||
214
+ path === DESKTOP_RELEASE_PAGE_PATH ||
215
+ path.startsWith(DESKTOP_DOWNLOAD_PREFIX)
216
+ );
217
+ }
@@ -61,6 +61,8 @@ import {
61
61
  prepareMcpOAuthWorkspaceToolGateway,
62
62
  } from "../workspace-tool-gateway";
63
63
  import { sanitizeFilename } from "./files";
64
+ import { userContentSignedGetUrlOptions } from "../http/user-content";
65
+ import { parseRequestBody, parseRequestJson } from "../http/request-body";
64
66
 
65
67
  export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
66
68
  const { db, objectStorage, documentIndexer, getDocumentServices } = deps;
@@ -93,7 +95,7 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
93
95
  app.post("/v1/workspaces/:workspaceId/document-bases", async (c) => {
94
96
  const workspaceId = c.req.param("workspaceId");
95
97
  const grant = await requireAccessGrant(c, deps, workspaceId, "documents:manage");
96
- const payload = CreateDocumentBaseRequest.parse(await c.req.json());
98
+ const payload = await parseRequestJson(c, CreateDocumentBaseRequest);
97
99
  return c.json(
98
100
  DocumentBase.parse(
99
101
  await createDocumentBase(db, { ...payload, accountId: grant.accountId, workspaceId }),
@@ -137,7 +139,7 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
137
139
  throw new HTTPException(403, { message: "missing permission: account:admin" });
138
140
  }
139
141
  const accountAdminAuthorization = requireAccountAdminAuthorizationStamp(authorization);
140
- const payload = RunDocumentDefaultCollectionBackfillRequest.parse(await c.req.json());
142
+ const payload = await parseRequestJson(c, RunDocumentDefaultCollectionBackfillRequest);
141
143
  try {
142
144
  return c.json(
143
145
  DocumentDefaultCollectionBackfill.parse(
@@ -268,7 +270,7 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
268
270
  action: "document:index",
269
271
  quantity: 0,
270
272
  });
271
- const payload = AddDocumentRequest.parse(await c.req.json());
273
+ const payload = await parseRequestJson(c, AddDocumentRequest);
272
274
  const organizationAuthorityGranted =
273
275
  access.accountGrant?.permissions.includes("account:admin") === true;
274
276
  if (payload.authorityKind === "organization" && !organizationAuthorityGranted) {
@@ -338,7 +340,7 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
338
340
  workspaceId,
339
341
  "documents:manage",
340
342
  );
341
- const payload = ReclassifyDocumentAuthorityRequest.parse(await c.req.json());
343
+ const payload = await parseRequestJson(c, ReclassifyDocumentAuthorityRequest);
342
344
  const accountAdminAuthorized = hasAccountAdminAuthority(authorization);
343
345
  const accountAdminAuthorization = accountAdminAuthorized
344
346
  ? requireAccountAdminAuthorizationStamp(authorization)
@@ -435,7 +437,10 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
435
437
  if (file.status !== "ready") {
436
438
  throw new HTTPException(409, { message: `file is ${file.status}` });
437
439
  }
438
- const signed = await objectStorage.createGetUrl({ key: file.objectKey });
440
+ const signed = await objectStorage.createGetUrl({
441
+ key: file.objectKey,
442
+ ...userContentSignedGetUrlOptions(file.contentType, file.filename),
443
+ });
439
444
  await recordAuditEvent(db, {
440
445
  accountId: grant.accountId,
441
446
  workspaceId,
@@ -591,7 +596,7 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
591
596
  action: "document:index",
592
597
  quantity: 0,
593
598
  });
594
- const payload = CreateKnowledgeDropRequest.parse(await c.req.json());
599
+ const payload = await parseRequestJson(c, CreateKnowledgeDropRequest);
595
600
  const personalFileOwner =
596
601
  payload.authorityKind === "personal"
597
602
  ? (await fileOwnerContextForAccess(deps, access, "documents:manage"))
@@ -712,7 +717,7 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
712
717
  );
713
718
  const { grant } = authorization;
714
719
  const organizationAuthorityGranted = hasAccountAdminAuthority(authorization);
715
- const payload = MoveDocumentRequest.parse(await c.req.json().catch(() => ({})));
720
+ const payload = parseRequestBody(MoveDocumentRequest, await c.req.json().catch(() => ({})));
716
721
  try {
717
722
  const document = await getDocument(db, workspaceId, c.req.param("documentId"), {
718
723
  viewerSubjectId: grant.subjectId,
@@ -818,6 +823,7 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
818
823
  await requireAccessGrantAuthorization(c, deps, workspaceId, "documents:search"),
819
824
  "documents:search",
820
825
  ),
826
+ settings: deps.settings,
821
827
  },
822
828
  );
823
829
  await server.connect(transport);
@@ -11,6 +11,9 @@ import {
11
11
  editableArtifactScope,
12
12
  hasPermission,
13
13
  requireAccessGrant,
14
+ requireAccessGrantAuthorization,
15
+ externalActorContinuationForAuthorization,
16
+ requirePermission,
14
17
  requireSessionAuthorization,
15
18
  SessionAuthorizationDeniedError,
16
19
  SessionAuthorizationUnavailableError,
@@ -25,11 +28,13 @@ import {
25
28
  type EditableArtifactPinnedVersion,
26
29
  type EditableArtifactModality,
27
30
  } from "@opengeni/core";
28
- import { listEditableArtifactIdsForSession } from "@opengeni/db";
31
+ import { hasEditableArtifactSessionLink, listEditableArtifactIdsForSession } from "@opengeni/db";
29
32
  import type { Context, Hono } from "hono";
30
33
  import { z } from "zod";
31
34
 
32
35
  import { ApiHttpError } from "../http/api-error";
36
+ import { USER_CONTENT_SECURITY_HEADERS } from "../http/user-content";
37
+ import { withAccessGrantSessionRlsContext } from "../access-grant-rls";
33
38
 
34
39
  export const EDITABLE_ARTIFACT_HTTP_REQUEST_MAX_BYTES = 4 * 1024;
35
40
  export const EDITABLE_ARTIFACT_EXPORT_REQUEST_MAX_BYTES = 260 * 1024;
@@ -77,6 +82,7 @@ const ListEditableArtifactsQuery = z
77
82
 
78
83
  const MintEditableArtifactLiveTicketRequest = z
79
84
  .object({
85
+ sourceSessionId: SessionId.optional(),
80
86
  replicaId: ReplicaId,
81
87
  modality: z.enum(["document", "spreadsheet", "presentation"]),
82
88
  liveProtocolVersion: PositiveProtocolVersion,
@@ -471,7 +477,13 @@ export function registerEditableArtifactRoutes(
471
477
 
472
478
  // Workspace authentication precedes path/body parsing. Exact artifact
473
479
  // permission is intentionally enforced inside the injected application.
474
- const grant = await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
480
+ const authorization = await requireAccessGrantAuthorization(
481
+ context,
482
+ deps,
483
+ workspaceId,
484
+ "artifacts:read",
485
+ );
486
+ const grant = authorization.grant;
475
487
  const artifactId = editableArtifactId(parseArtifactId(context.req.param("artifactId")));
476
488
  const body = await parseBoundedTicketRequest(context);
477
489
  const actor = editableArtifactActorForGrant(grant, body.replicaId);
@@ -479,6 +491,18 @@ export function registerEditableArtifactRoutes(
479
491
  accountId: grant.accountId,
480
492
  workspaceId,
481
493
  });
494
+ if (body.sourceSessionId) {
495
+ requirePermission(grant, "sessions:read");
496
+ await withAccessGrantSessionRlsContext(deps, grant, async () => {
497
+ await authorizeSourceSession(deps, grant, body.sourceSessionId!);
498
+ if (
499
+ !(await hasEditableArtifactSessionLink(deps.db, scope, body.sourceSessionId!, artifactId))
500
+ ) {
501
+ throw applicationHttpError("not_found");
502
+ }
503
+ });
504
+ }
505
+ const externalContinuation = externalActorContinuationForAuthorization(authorization);
482
506
 
483
507
  let rawTicket: MintEditableArtifactLiveTicketOutput;
484
508
  try {
@@ -494,6 +518,44 @@ export function registerEditableArtifactRoutes(
494
518
  commandProtocolVersion: body.commandProtocolVersion,
495
519
  committedTransactionProtocolVersion: body.committedTransactionProtocolVersion,
496
520
  allowEdit: hasPermission(grant.permissions, "artifacts:publish"),
521
+ ...(body.sourceSessionId
522
+ ? {
523
+ sourceSessionAuthority: {
524
+ sessionId: body.sourceSessionId,
525
+ grant: {
526
+ accountId: grant.accountId,
527
+ workspaceId: grant.workspaceId,
528
+ subjectId: grant.subjectId,
529
+ ...(grant.principalKind ? { principalKind: grant.principalKind } : {}),
530
+ ...(grant.metadata
531
+ ? {
532
+ metadata: Object.fromEntries(
533
+ Object.entries(grant.metadata).filter(([key]) =>
534
+ [
535
+ "externalActor",
536
+ "delegated",
537
+ "sessionId",
538
+ "turnId",
539
+ "attemptId",
540
+ "executionGeneration",
541
+ ].includes(key),
542
+ ),
543
+ ),
544
+ }
545
+ : {}),
546
+ // Bind only editor capabilities, not a broad delegated wildcard.
547
+ permissions: [
548
+ "sessions:read",
549
+ "artifacts:read",
550
+ ...(hasPermission(grant.permissions, "artifacts:publish")
551
+ ? ["artifacts:publish" as const]
552
+ : []),
553
+ ],
554
+ },
555
+ ...(externalContinuation ? { externalContinuation } : {}),
556
+ },
557
+ }
558
+ : {}),
497
559
  });
498
560
  } catch (error) {
499
561
  throw editableArtifactHttpError(error);
@@ -547,6 +609,14 @@ export function registerEditableArtifactRoutes(
547
609
  const body = await parseBoundedMaterializationRequest(context);
548
610
  const scope = editableArtifactScope({ accountId: grant.accountId, workspaceId });
549
611
  const actor = editableArtifactActorForGrant(grant, body.replicaId);
612
+ // Without a materializer workload the job would stay queued forever.
613
+ if (!deps.settings.artifactMaterializerDeployed) {
614
+ throw new ApiHttpError(503, {
615
+ code: "upstream_unavailable",
616
+ message: "File export is not available on this deployment.",
617
+ retryable: false,
618
+ });
619
+ }
550
620
  try {
551
621
  const result = await requireEditableArtifactExports(deps).enqueueMaterialization({
552
622
  scope,
@@ -616,7 +686,7 @@ export function registerEditableArtifactRoutes(
616
686
  "content-length": String(download.byteSize),
617
687
  "content-type": download.mimeType,
618
688
  etag: `"${download.contentHash}"`,
619
- "x-content-type-options": "nosniff",
689
+ ...USER_CONTENT_SECURITY_HEADERS,
620
690
  },
621
691
  });
622
692
  });
@@ -1067,7 +1137,7 @@ export function editableArtifactHttpError(error: unknown): unknown {
1067
1137
  case "unsupported_format":
1068
1138
  return new ApiHttpError(422, {
1069
1139
  code: "validation_failed",
1070
- message: "Editable artifact format is not available for this artifact.",
1140
+ message: error.message,
1071
1141
  });
1072
1142
  case "not_ready":
1073
1143
  return new ApiHttpError(409, {
@@ -37,6 +37,7 @@ import {
37
37
  MintEnrollTokenRequest,
38
38
  MintEnrollTokenResponse,
39
39
  RemoveEnrollmentRequest,
40
+ RenewEnrollmentRequest,
40
41
  RevokeEnrollmentResponse,
41
42
  type EnrollmentArch,
42
43
  type EnrollmentOs,
@@ -46,10 +47,13 @@ import {
46
47
  listEnrollments,
47
48
  MachineRemovalIdempotencyError,
48
49
  MachineRemovalRevisionConflictError,
50
+ PersonalMachineConnectedElsewhereError,
49
51
  removeEnrollment,
50
52
  } from "@opengeni/db";
51
53
  import type { Context, Hono } from "hono";
52
54
  import { HTTPException } from "hono/http-exception";
55
+ import { trustedRequestSourceRateLimitKey } from "../http/request-source";
56
+ import { isPersonalConnectionOwnerPrincipal } from "../connection-ownership";
53
57
  import {
54
58
  requireAccessGrant,
55
59
  requireAccessGrantAuthorization,
@@ -64,9 +68,39 @@ import {
64
68
  mintEnrollToken,
65
69
  pollDeviceEnrollment,
66
70
  startDeviceEnrollment,
71
+ renewEnrollmentCredentials,
67
72
  toLookupResponse,
68
73
  } from "../sandbox/enrollment";
69
74
 
75
+ const ENROLLMENT_OUTCOMES = new Set([
76
+ "ok",
77
+ "authorized",
78
+ "expired",
79
+ "denied",
80
+ "disabled",
81
+ "invalid",
82
+ "used",
83
+ "unauthorized",
84
+ ]);
85
+
86
+ // A personal machine reconnects only from the workspace it was first connected
87
+ // from. The install script and the approval page show this message verbatim.
88
+ const PERSONAL_MACHINE_ELSEWHERE_MESSAGE =
89
+ "this machine was first connected as a personal machine from another workspace; connect it again from that workspace";
90
+
91
+ /** Machine enrollment decisions that never surface as an HTTP error status. */
92
+ function recordEnrollment(deps: ApiRouteDeps, flow: string, outcome: string): void {
93
+ try {
94
+ deps.observability?.incrementCounter({
95
+ name: "opengeni_machine_enrollment_total",
96
+ help: "Connected Machine enrollment decisions by flow (device_start, device_poll, token_exchange, renew) and closed outcome.",
97
+ labels: { flow, outcome: ENROLLMENT_OUTCOMES.has(outcome) ? outcome : "other" },
98
+ });
99
+ } catch {
100
+ // Telemetry never changes the enrollment decision.
101
+ }
102
+ }
103
+
70
104
  export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
71
105
  const { settings, db } = deps;
72
106
 
@@ -84,7 +118,8 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
84
118
  // poll). The relay tier owns the heavy stream rate-limiting; this
85
119
  // is the application-tier abuse cap on the device-flow endpoints. Per-IP buckets
86
120
  // are pruned lazily. Not a distributed limiter (one replica per bucket) — that is
87
- // acceptable for a bounded, access-key-gated, short-TTL flow.
121
+ // acceptable for a bounded, short-TTL flow. These routes are public even behind
122
+ // the deployment key, because a machine never holds that key.
88
123
  const startLimiter = new TokenBucket({ capacity: 10, refillPerSecond: 0.5 });
89
124
  const pollLimiter = new TokenBucket({ capacity: 60, refillPerSecond: 2 });
90
125
  // The click-Grant approve-page lookup (authenticated, but capped against a
@@ -98,12 +133,28 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
98
133
  });
99
134
 
100
135
  function rateLimit(c: Context, limiter: TokenBucket): void {
101
- const ip = clientIp(c);
136
+ const ip = trustedRequestSourceRateLimitKey(c, settings);
102
137
  if (!limiter.take(ip)) {
103
138
  throw new HTTPException(429, { message: "too many requests; slow down" });
104
139
  }
105
140
  }
106
141
 
142
+ // Machine authentication: signed install-key proof + current enrollment grant.
143
+ app.post("/v1/enrollments/renew", async (c) => {
144
+ assertSelfhostedEnabled();
145
+ rateLimit(c, exchangeLimiter);
146
+ const parsed = RenewEnrollmentRequest.safeParse(await c.req.json().catch(() => null));
147
+ if (!parsed.success) throw new HTTPException(400, { message: "invalid renewal request" });
148
+ const credentials = await renewEnrollmentCredentials({ db, settings }, parsed.data);
149
+ recordEnrollment(deps, "renew", credentials ? "ok" : "unauthorized");
150
+ if (!credentials)
151
+ throw new HTTPException(401, {
152
+ message: "machine renewal not authorized",
153
+ });
154
+ c.header("Cache-Control", "no-store");
155
+ return c.json(EnrollTokenExchangeResponse.parse({ credentials }), 200);
156
+ });
157
+
107
158
  // ── POST /enrollments/device/start (agent-side, user-unauthenticated) ───────
108
159
  app.post("/v1/enrollments/device/start", async (c) => {
109
160
  assertSelfhostedEnabled();
@@ -136,6 +187,7 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
136
187
  verificationOrigin: settings.publicBaseUrl ?? new URL(c.req.url).origin,
137
188
  },
138
189
  );
190
+ recordEnrollment(deps, "device_start", "ok");
139
191
  return c.json(result, 201);
140
192
  });
141
193
 
@@ -151,6 +203,8 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
151
203
  { db, settings },
152
204
  { deviceCode: parsed.data.deviceCode },
153
205
  );
206
+ // `pending` is the normal polling loop; count only decisions.
207
+ if (result.state !== "pending") recordEnrollment(deps, "device_poll", result.state);
154
208
  return c.json(result, 200);
155
209
  });
156
210
 
@@ -220,6 +274,7 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
220
274
  canOfferDisplay: body.canOfferDisplay,
221
275
  },
222
276
  );
277
+ recordEnrollment(deps, "token_exchange", result.ok ? "ok" : result.reason);
223
278
  if (!result.ok) {
224
279
  if (result.reason === "disabled") {
225
280
  // The credential plane is off for this deployment (no signing secret).
@@ -227,6 +282,30 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
227
282
  message: "enrollment credential plane is not configured",
228
283
  });
229
284
  }
285
+ if (result.reason === "used") {
286
+ // Single-use: another machine already redeemed this token. Same 401 as
287
+ // an invalid token, with a message the install script prints verbatim.
288
+ throw new HTTPException(401, {
289
+ message:
290
+ "this connect command was already used to connect another machine; create a new one for this machine",
291
+ });
292
+ }
293
+ if (result.reason === "owner_unavailable") {
294
+ // A personal command whose creator can no longer own a machine here.
295
+ throw new HTTPException(403, {
296
+ message:
297
+ "the person who created this connect command can no longer connect machines to this workspace; create a new command",
298
+ });
299
+ }
300
+ if (result.reason === "connected_elsewhere") {
301
+ // Nothing changed and the command was not used up.
302
+ throw new HTTPException(409, { message: PERSONAL_MACHINE_ELSEWHERE_MESSAGE });
303
+ }
304
+ if (result.reason === "busy") {
305
+ throw new HTTPException(503, {
306
+ message: "workspace membership is changing; run the connect command again",
307
+ });
308
+ }
230
309
  // An invalid / expired / wrong-typ token — the token is the auth, so 401.
231
310
  throw new HTTPException(401, {
232
311
  message: "invalid or expired enroll token",
@@ -287,7 +366,13 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
287
366
  approvedBySubjectId: grant.subjectId,
288
367
  approvedBySubjectLabel: grant.subjectLabel ?? null,
289
368
  },
290
- );
369
+ ).catch((error: unknown) => {
370
+ if (error instanceof PersonalMachineConnectedElsewhereError) {
371
+ // Nothing changed; the request stays pending.
372
+ throw new HTTPException(409, { message: PERSONAL_MACHINE_ELSEWHERE_MESSAGE });
373
+ }
374
+ throw error;
375
+ });
291
376
  if (!approved) {
292
377
  // An unknown / expired / already-terminal user_code in this workspace.
293
378
  throw new HTTPException(404, {
@@ -331,9 +416,22 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
331
416
  // Mint a short-TTL headless enroll token. Mirrors approve (enrollments:manage,
332
417
  // requireAccessGrant BEFORE the parse). The accountId comes from the grant. No
333
418
  // signing secret → 503/disabled (mirror poll). The token is SECRET — never logged.
419
+ // `scope: "user"` signs the authenticated person as the machine's owner. Only a
420
+ // verified person may ask for it: someone signed in, or a credential acting as
421
+ // them (a personal API key, or an organization key or organization MCP client
422
+ // acting as that person). A key, service or agent acting as itself gets 422.
423
+ // The owner is always the caller, never a request field.
334
424
  app.post("/v1/workspaces/:workspaceId/enrollments/token", async (c) => {
335
425
  const workspaceId = c.req.param("workspaceId");
336
- const grant = await requireAccessGrant(c, deps, workspaceId, "enrollments:manage");
426
+ // The permission is part of the authorization, so a request that lacks it
427
+ // is refused before any first-use workspace membership is provisioned.
428
+ const authorization = await requireAccessGrantAuthorization(
429
+ c,
430
+ deps,
431
+ workspaceId,
432
+ "enrollments:manage",
433
+ );
434
+ const grant = authorization.grant;
337
435
  assertSelfhostedEnabled();
338
436
  // All fields are optional/defaulted, so an empty POST body is valid (default
339
437
  // allowScreenControl=false). Coalesce a missing/empty body to {} before parse.
@@ -343,12 +441,20 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
343
441
  message: "invalid mint-enroll-token request",
344
442
  });
345
443
  }
444
+ const personal = parsed.data.scope === "user";
445
+ if (personal && !isPersonalConnectionOwnerPrincipal(authorization)) {
446
+ throw new HTTPException(422, {
447
+ message:
448
+ "only a person, or a credential acting as that person, can connect a machine for themselves; keys, services and agents acting as themselves can connect workspace machines",
449
+ });
450
+ }
346
451
  const minted = await mintEnrollToken(
347
452
  { db, settings },
348
453
  {
349
454
  accountId: grant.accountId,
350
455
  workspaceId,
351
456
  allowScreenControl: parsed.data.allowScreenControl,
457
+ ...(personal ? { ownerSubjectId: grant.subjectId } : {}),
352
458
  },
353
459
  );
354
460
  if (!minted) {
@@ -471,18 +577,6 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
471
577
  });
472
578
  }
473
579
 
474
- // The remote client IP for the per-IP rate-limit bucket. Honors the proxy's
475
- // X-Forwarded-For (the first hop) when present, falling back to a constant key when
476
- // neither is available (the bucket then caps the whole edge — still a useful cap).
477
- function clientIp(c: Context): string {
478
- const xff = c.req.header("x-forwarded-for");
479
- if (xff) {
480
- const first = xff.split(",")[0]?.trim();
481
- if (first) return first;
482
- }
483
- return c.req.header("x-real-ip")?.trim() || "unknown";
484
- }
485
-
486
580
  // A minimal per-key token bucket. capacity = burst; refillPerSecond = sustained
487
581
  // rate. Buckets are created lazily and reset their tokens by elapsed time on each
488
582
  // take, so an idle key fully refills without a background timer.