@opengeni/api-router 0.30.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (436) hide show
  1. package/dist/access-grant-rls.d.ts +3 -0
  2. package/dist/admission-trace.d.ts +8 -0
  3. package/dist/api-websocket.d.ts +18 -0
  4. package/dist/app.d.ts +50 -2
  5. package/dist/app.js +12 -1
  6. package/dist/artifact-catalog-cursor.d.ts +27 -0
  7. package/dist/auth/managed-auth-attempt-context.d.ts +10 -0
  8. package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
  9. package/dist/auth/managed-auth-session-adapter.d.ts +6 -0
  10. package/dist/auth/managed-auth.d.ts +102 -3
  11. package/dist/auth/managed-email.d.ts +29 -0
  12. package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
  13. package/dist/auth/new-signups-gate.d.ts +23 -0
  14. package/dist/auth/organization-user-setup.d.ts +80 -0
  15. package/dist/auth/signup-funnel-metrics.d.ts +44 -0
  16. package/dist/browser-controller-authority.d.ts +1 -61
  17. package/dist/browser-ephemeral.d.ts +5 -0
  18. package/dist/browser-state-authority.d.ts +1 -27
  19. package/dist/chunk-6TZ5LG3O.js +123948 -0
  20. package/dist/chunk-6TZ5LG3O.js.map +1 -0
  21. package/dist/chunk-OGQDXVXY.js +18 -0
  22. package/dist/chunk-OGQDXVXY.js.map +1 -0
  23. package/dist/claude-subscription-account-conflicts.d.ts +1 -0
  24. package/dist/claude-subscription-account-usage.d.ts +39 -0
  25. package/dist/claude-subscription-oauth.d.ts +25 -0
  26. package/dist/claude-subscription-profile.d.ts +9 -0
  27. package/dist/claude-subscription-usage.d.ts +44 -0
  28. package/dist/claude-workspace-connection.d.ts +15 -0
  29. package/dist/codemode.d.ts +32 -1
  30. package/dist/company-brain-okf.d.ts +24 -0
  31. package/dist/connected-machine-computer-access.d.ts +11 -0
  32. package/dist/connection-ownership.d.ts +54 -0
  33. package/dist/controller-data-plane.d.ts +32 -0
  34. package/dist/editable-artifact-office-import.d.ts +7 -4
  35. package/dist/editable-artifact-source-session.d.ts +3 -0
  36. package/dist/editable-artifact-websocket.d.ts +10 -18
  37. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  38. package/dist/fatal-process-boundary.d.ts +25 -0
  39. package/dist/github-access.d.ts +31 -2
  40. package/dist/http/acting-person.d.ts +24 -0
  41. package/dist/http/api-contract-compat.d.ts +19 -0
  42. package/dist/http/api-error.d.ts +27 -1
  43. package/dist/http/cors.d.ts +17 -0
  44. package/dist/http/deprecation.d.ts +42 -0
  45. package/dist/http/interaction-control-error.d.ts +13 -0
  46. package/dist/http/keyed-admission.d.ts +12 -0
  47. package/dist/http/local-browser-boundary.d.ts +72 -0
  48. package/dist/http/metrics-listener.d.ts +22 -0
  49. package/dist/http/path-identifier.d.ts +17 -0
  50. package/dist/http/registered-route-label.d.ts +16 -0
  51. package/dist/http/request-body.d.ts +27 -0
  52. package/dist/http/request-source.d.ts +52 -0
  53. package/dist/http/sse.d.ts +17 -6
  54. package/dist/http/unmatched-route.d.ts +18 -0
  55. package/dist/http/user-content.d.ts +36 -0
  56. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  57. package/dist/index.d.ts +10 -3
  58. package/dist/index.js +1129 -166
  59. package/dist/index.js.map +1 -1
  60. package/dist/integration-endpoint-test.d.ts +20 -0
  61. package/dist/integrations/api-integrations.d.ts +2 -2
  62. package/dist/integrations/atlassian.d.ts +29 -3
  63. package/dist/integrations/connect-authority.d.ts +1 -0
  64. package/dist/integrations/connect-callback-return.d.ts +6 -0
  65. package/dist/integrations/fiken.d.ts +16 -2
  66. package/dist/integrations/github-app-connect.d.ts +47 -0
  67. package/dist/integrations/github-installation-proof.d.ts +3 -0
  68. package/dist/integrations/github-lens-connect.d.ts +116 -0
  69. package/dist/integrations/github-skill-source.d.ts +1 -5
  70. package/dist/integrations/google-drive.d.ts +25 -0
  71. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  72. package/dist/integrations/marketplace-plugin.d.ts +2691 -0
  73. package/dist/integrations/oauth-client.d.ts +178 -18
  74. package/dist/integrations/oauth-profiles.d.ts +222 -0
  75. package/dist/integrations/oauth-return-path.d.ts +1 -0
  76. package/dist/integrations/personal-github-repositories.d.ts +84 -0
  77. package/dist/integrations/personal-github.d.ts +42 -0
  78. package/dist/integrations/pr-review-provider.d.ts +22 -0
  79. package/dist/integrations/provider-oauth.d.ts +19 -1
  80. package/dist/integrations/slack-app-home.d.ts +24 -0
  81. package/dist/integrations/slack-bot.d.ts +367 -12
  82. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  83. package/dist/integrations/slack-install.d.ts +20 -0
  84. package/dist/integrations/slack-interactions.d.ts +113 -10
  85. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  86. package/dist/integrations/slack-routing.d.ts +120 -0
  87. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  88. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  89. package/dist/integrations/social-oauth.d.ts +7 -0
  90. package/dist/interaction-agent-access.d.ts +15 -0
  91. package/dist/interaction-frame-proxy.d.ts +68 -0
  92. package/dist/interaction-metrics.d.ts +2 -0
  93. package/dist/mcp/action-catalog-types.d.ts +9 -0
  94. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  95. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  96. package/dist/mcp/child-read-evidence.d.ts +9 -0
  97. package/dist/mcp/command-read.d.ts +24 -0
  98. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  99. package/dist/mcp/contract-input.d.ts +11 -0
  100. package/dist/mcp/documents.d.ts +7 -5
  101. package/dist/mcp/files.d.ts +2 -2
  102. package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
  103. package/dist/mcp/knowledge-entries.d.ts +5 -0
  104. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  105. package/dist/mcp/receipts.d.ts +9 -0
  106. package/dist/mcp/request-abort.d.ts +19 -0
  107. package/dist/mcp/scheduled-task-input.d.ts +1189 -0
  108. package/dist/mcp/scheduled-task-view.d.ts +22 -4
  109. package/dist/mcp/server.d.ts +255 -3
  110. package/dist/mcp/session-event-view.d.ts +94 -0
  111. package/dist/mcp/session-view.d.ts +66 -2
  112. package/dist/mcp/session-wait.d.ts +174 -0
  113. package/dist/mcp-oauth.d.ts +52 -0
  114. package/dist/model-catalog.d.ts +11 -31
  115. package/dist/observability.d.ts +3 -1
  116. package/dist/organization-mcp.d.ts +52 -0
  117. package/dist/organization-recovery-notifications.d.ts +41 -0
  118. package/dist/routes/analytics-consent.d.ts +26 -0
  119. package/dist/routes/api-integrations.d.ts +25 -0
  120. package/dist/routes/api-keys.d.ts +17 -0
  121. package/dist/routes/artifact-catalog.d.ts +6 -0
  122. package/dist/routes/automations.d.ts +19 -0
  123. package/dist/routes/billing.d.ts +49 -0
  124. package/dist/routes/browser-sessions.d.ts +71 -3
  125. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  126. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  127. package/dist/routes/client-errors.d.ts +146 -0
  128. package/dist/routes/codex.d.ts +76 -2
  129. package/dist/routes/company-brain.d.ts +3 -0
  130. package/dist/routes/company-profile.d.ts +2 -1
  131. package/dist/routes/computer-sessions.d.ts +14 -0
  132. package/dist/routes/connect.d.ts +5 -0
  133. package/dist/routes/editable-artifacts.d.ts +2 -0
  134. package/dist/routes/external-identity-links.d.ts +6 -0
  135. package/dist/routes/feedback.d.ts +3 -0
  136. package/dist/routes/files.d.ts +4 -0
  137. package/dist/routes/github-browser-pages.d.ts +12 -0
  138. package/dist/routes/github.d.ts +2 -0
  139. package/dist/routes/insights-response-cache.d.ts +10 -0
  140. package/dist/routes/insights-usage.d.ts +12 -0
  141. package/dist/routes/insights.d.ts +30 -1
  142. package/dist/routes/knowledge.d.ts +3 -0
  143. package/dist/routes/managed-auth-session-sets.d.ts +26 -0
  144. package/dist/routes/managed-onboarding.d.ts +29 -0
  145. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  146. package/dist/routes/model-connection-access.d.ts +3 -0
  147. package/dist/routes/organization-integration-policy.d.ts +3 -0
  148. package/dist/routes/organization-integrations.d.ts +6 -0
  149. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  150. package/dist/routes/organization-model-providers.d.ts +3 -0
  151. package/dist/routes/organization-recovery.d.ts +19 -0
  152. package/dist/routes/organization-service-accounts.d.ts +3 -0
  153. package/dist/routes/organization-sessions.d.ts +26 -0
  154. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  155. package/dist/routes/personal-github.d.ts +3 -0
  156. package/dist/routes/pr-review-github.d.ts +3 -0
  157. package/dist/routes/pr-review.d.ts +3 -0
  158. package/dist/routes/session-artifact-associations.d.ts +4 -0
  159. package/dist/routes/session-history-imports.d.ts +9 -0
  160. package/dist/routes/sessions.d.ts +44 -6
  161. package/dist/routes/skill-content.d.ts +4 -0
  162. package/dist/routes/skill-install-authority.d.ts +6 -0
  163. package/dist/routes/subscription-account-pools.d.ts +34 -0
  164. package/dist/routes/subscription-pool-access.d.ts +16 -0
  165. package/dist/routes/supergrok.d.ts +6 -1
  166. package/dist/routes/usage-allowances.d.ts +12 -0
  167. package/dist/routes/user-resource-authorities.d.ts +3 -0
  168. package/dist/routes/workspace-artifacts.d.ts +2 -1
  169. package/dist/routes/workspace-capture.d.ts +10 -2
  170. package/dist/routes/workspace-integrations.d.ts +35 -0
  171. package/dist/routes/workspace-learning.d.ts +3 -0
  172. package/dist/routes/workspace-model-providers.d.ts +4 -0
  173. package/dist/routes/workspaces.d.ts +29 -0
  174. package/dist/sandbox/auth-callout.d.ts +8 -0
  175. package/dist/sandbox/channel-a.d.ts +19 -1
  176. package/dist/sandbox/connection-authority.d.ts +3 -0
  177. package/dist/sandbox/enrollment.d.ts +9 -1
  178. package/dist/sandbox/machines.d.ts +5 -2
  179. package/dist/sandbox/metrics-ingestion.d.ts +28 -20
  180. package/dist/sandbox/rematerialize.d.ts +2 -0
  181. package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
  182. package/dist/sandbox/viewer.d.ts +26 -1
  183. package/dist/sandbox-file-artifacts.d.ts +50 -0
  184. package/dist/scheduled-task-deletion.d.ts +13 -0
  185. package/dist/session-create-observability.d.ts +5 -0
  186. package/dist/session-event-view-MPS2OZD3.js +292 -0
  187. package/dist/session-event-view-MPS2OZD3.js.map +1 -0
  188. package/dist/site-session-origin.d.ts +13 -0
  189. package/dist/site-uploads.d.ts +41 -0
  190. package/dist/slack-reaction-files.d.ts +1 -1
  191. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  192. package/dist/temporal-schedule-sync.d.ts +26 -0
  193. package/dist/transcription/providers/xai-subscription.d.ts +1 -0
  194. package/dist/transcription/service.d.ts +2 -1
  195. package/dist/work-discovery-observability.d.ts +33 -0
  196. package/dist/workspace-artifact-content.d.ts +28 -0
  197. package/dist/workspace-artifact-provenance.d.ts +7 -0
  198. package/dist/workspace-delete-observability.d.ts +10 -0
  199. package/dist/workspace-deletion.d.ts +6 -0
  200. package/dist/workspace-state-projection.d.ts +3 -5
  201. package/dist/workspace-tool-gateway-observability.d.ts +17 -0
  202. package/dist/workspace-tool-gateway.d.ts +123 -0
  203. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  204. package/package.json +23 -19
  205. package/src/access-grant-rls.ts +75 -0
  206. package/src/admission-trace.ts +14 -0
  207. package/src/api-websocket.ts +23 -0
  208. package/src/app.ts +1974 -256
  209. package/src/artifact-catalog-cursor.ts +60 -0
  210. package/src/auth/managed-auth-attempt-context.ts +70 -0
  211. package/src/auth/managed-auth-rate-limits.ts +252 -0
  212. package/src/auth/managed-auth-session-adapter.ts +222 -0
  213. package/src/auth/managed-auth.ts +536 -60
  214. package/src/auth/managed-email.ts +174 -0
  215. package/src/auth/managed-sign-in-notifications.ts +81 -0
  216. package/src/auth/new-signups-gate.ts +49 -0
  217. package/src/auth/organization-user-setup.ts +307 -0
  218. package/src/auth/signup-funnel-metrics.ts +164 -0
  219. package/src/browser-controller-authority.ts +1 -186
  220. package/src/browser-ephemeral.ts +39 -0
  221. package/src/browser-state-authority.ts +1 -236
  222. package/src/claude-subscription-account-conflicts.ts +12 -0
  223. package/src/claude-subscription-account-usage.ts +48 -0
  224. package/src/claude-subscription-oauth.ts +362 -0
  225. package/src/claude-subscription-profile.ts +73 -0
  226. package/src/claude-subscription-usage.ts +97 -0
  227. package/src/claude-workspace-connection.ts +82 -0
  228. package/src/codemode.ts +194 -30
  229. package/src/codex-realtime.ts +8 -2
  230. package/src/company-brain-okf.ts +340 -0
  231. package/src/connected-machine-computer-access.ts +33 -0
  232. package/src/connection-ownership.ts +199 -0
  233. package/src/controller-data-plane.ts +81 -0
  234. package/src/editable-artifact-native-kernel.ts +26 -15
  235. package/src/editable-artifact-office-import.ts +77 -9
  236. package/src/editable-artifact-production.ts +23 -7
  237. package/src/editable-artifact-source-session.ts +123 -0
  238. package/src/editable-artifact-websocket.ts +27 -21
  239. package/src/editable-artifact-workspace-files.ts +31 -6
  240. package/src/fatal-process-boundary.ts +246 -0
  241. package/src/gateway-realtime.ts +1 -1
  242. package/src/github-access.ts +147 -5
  243. package/src/http/acting-person.ts +71 -0
  244. package/src/http/api-contract-compat.ts +49 -0
  245. package/src/http/api-error.ts +115 -1
  246. package/src/http/auth.ts +48 -0
  247. package/src/http/cors.ts +67 -0
  248. package/src/http/deprecation.ts +118 -0
  249. package/src/http/interaction-control-error.ts +164 -0
  250. package/src/http/keyed-admission.ts +29 -0
  251. package/src/http/local-browser-boundary.ts +343 -0
  252. package/src/http/metrics-listener.ts +57 -0
  253. package/src/http/path-identifier.ts +54 -0
  254. package/src/http/registered-route-label.ts +34 -0
  255. package/src/http/request-body.ts +127 -0
  256. package/src/http/request-source.ts +178 -0
  257. package/src/http/sse.ts +486 -132
  258. package/src/http/unmatched-route.ts +60 -0
  259. package/src/http/user-content.ts +158 -0
  260. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  261. package/src/index.ts +157 -52
  262. package/src/integration-endpoint-test.ts +291 -0
  263. package/src/integrations/api-integrations.ts +98 -11
  264. package/src/integrations/atlassian.ts +474 -136
  265. package/src/integrations/connect-authority.ts +2 -0
  266. package/src/integrations/connect-callback-return.ts +86 -0
  267. package/src/integrations/fiken.ts +354 -64
  268. package/src/integrations/github-app-connect.ts +435 -0
  269. package/src/integrations/github-installation-proof.ts +60 -0
  270. package/src/integrations/github-lens-connect.ts +76 -0
  271. package/src/integrations/github-skill-source.ts +2 -142
  272. package/src/integrations/google-drive.ts +820 -222
  273. package/src/integrations/integration-commit-authority.ts +69 -0
  274. package/src/integrations/marketplace-plugin.ts +48 -0
  275. package/src/integrations/oauth-client.ts +1356 -459
  276. package/src/integrations/oauth-profiles.ts +537 -0
  277. package/src/integrations/oauth-return-path.ts +18 -0
  278. package/src/integrations/personal-github-repositories.ts +674 -0
  279. package/src/integrations/personal-github.ts +825 -0
  280. package/src/integrations/pr-review-provider.ts +246 -0
  281. package/src/integrations/provider-oauth.ts +250 -22
  282. package/src/integrations/slack-app-home.ts +300 -0
  283. package/src/integrations/slack-bot.ts +963 -239
  284. package/src/integrations/slack-file-upload-flow.ts +147 -0
  285. package/src/integrations/slack-install.ts +83 -0
  286. package/src/integrations/slack-interactions.ts +3170 -474
  287. package/src/integrations/slack-mrkdwn.ts +193 -0
  288. package/src/integrations/slack-routing.ts +337 -0
  289. package/src/integrations/slack-session-defaults.ts +224 -0
  290. package/src/integrations/slack-task-file-upload.ts +323 -0
  291. package/src/integrations/social-oauth.ts +213 -15
  292. package/src/interaction-agent-access.ts +48 -0
  293. package/src/interaction-frame-proxy.ts +409 -0
  294. package/src/interaction-metrics.ts +30 -0
  295. package/src/mcp/action-catalog-types.ts +9 -0
  296. package/src/mcp/action-catalog.gen.ts +6696 -0
  297. package/src/mcp/capability-account-readiness.ts +17 -0
  298. package/src/mcp/child-read-evidence.ts +19 -0
  299. package/src/mcp/command-read.ts +109 -0
  300. package/src/mcp/company-profile-agent-admin.ts +198 -0
  301. package/src/mcp/contract-input.ts +141 -0
  302. package/src/mcp/documents.ts +65 -377
  303. package/src/mcp/editable-artifacts.ts +12 -6
  304. package/src/mcp/files.ts +80 -38
  305. package/src/mcp/first-party-tool-permissions.ts +305 -0
  306. package/src/mcp/knowledge-entries.ts +322 -0
  307. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  308. package/src/mcp/receipts.ts +34 -0
  309. package/src/mcp/request-abort.ts +44 -0
  310. package/src/mcp/scheduled-task-input.ts +76 -0
  311. package/src/mcp/scheduled-task-view.ts +44 -3
  312. package/src/mcp/server.ts +3030 -1267
  313. package/src/mcp/session-event-view.ts +383 -0
  314. package/src/mcp/session-view.ts +84 -3
  315. package/src/mcp/session-wait.ts +665 -0
  316. package/src/mcp-oauth.ts +1123 -0
  317. package/src/model-catalog.ts +91 -333
  318. package/src/observability.ts +15 -1
  319. package/src/organization-mcp.ts +397 -0
  320. package/src/organization-recovery-notifications.ts +103 -0
  321. package/src/routes/analytics-consent.ts +123 -0
  322. package/src/routes/api-integrations.ts +364 -74
  323. package/src/routes/api-keys.ts +336 -10
  324. package/src/routes/artifact-catalog.ts +279 -0
  325. package/src/routes/automations.ts +768 -0
  326. package/src/routes/billing.ts +461 -46
  327. package/src/routes/browser-sessions.ts +839 -131
  328. package/src/routes/canonical-human-identities.ts +90 -14
  329. package/src/routes/capabilities.ts +107 -6
  330. package/src/routes/channels.ts +20 -3
  331. package/src/routes/claude-subscription-accounts.ts +334 -0
  332. package/src/routes/claude-subscription-oauth.ts +142 -0
  333. package/src/routes/client-errors.ts +362 -0
  334. package/src/routes/codex.ts +833 -116
  335. package/src/routes/company-brain.ts +322 -0
  336. package/src/routes/company-profile.ts +65 -1
  337. package/src/routes/computer-sessions.ts +557 -106
  338. package/src/routes/connect.ts +1938 -0
  339. package/src/routes/connections.ts +1040 -349
  340. package/src/routes/documents.ts +488 -287
  341. package/src/routes/editable-artifacts.ts +79 -9
  342. package/src/routes/enrollments.ts +135 -39
  343. package/src/routes/environments.ts +154 -58
  344. package/src/routes/external-identity-links.ts +201 -0
  345. package/src/routes/feedback.ts +113 -0
  346. package/src/routes/files.ts +337 -39
  347. package/src/routes/github-browser-pages.ts +162 -0
  348. package/src/routes/github.ts +446 -144
  349. package/src/routes/insights-response-cache.ts +83 -0
  350. package/src/routes/insights-usage.ts +345 -0
  351. package/src/routes/insights.ts +153 -19
  352. package/src/routes/install.ts +133 -38
  353. package/src/routes/integration-facets.ts +107 -33
  354. package/src/routes/interaction-resources.ts +30 -3
  355. package/src/routes/knowledge.ts +488 -0
  356. package/src/routes/machines.ts +313 -15
  357. package/src/routes/managed-auth-session-sets.ts +1218 -0
  358. package/src/routes/managed-onboarding.ts +337 -0
  359. package/src/routes/managed-sign-in-methods.ts +433 -0
  360. package/src/routes/memory-slack-publications.ts +3 -2
  361. package/src/routes/model-connection-access.ts +208 -0
  362. package/src/routes/organization-integration-policy.ts +116 -0
  363. package/src/routes/organization-integrations.ts +326 -0
  364. package/src/routes/organization-mcp-connections.ts +178 -0
  365. package/src/routes/organization-memberships.ts +1019 -27
  366. package/src/routes/organization-model-providers.ts +293 -0
  367. package/src/routes/organization-recovery.ts +325 -0
  368. package/src/routes/organization-service-accounts.ts +128 -0
  369. package/src/routes/organization-sessions.ts +350 -0
  370. package/src/routes/personal-github-git-broker.ts +785 -0
  371. package/src/routes/personal-github.ts +370 -0
  372. package/src/routes/plugins.ts +251 -22
  373. package/src/routes/pr-review-github.ts +881 -0
  374. package/src/routes/pr-review.ts +622 -0
  375. package/src/routes/preference-registry.ts +12 -93
  376. package/src/routes/rigs.ts +167 -50
  377. package/src/routes/scheduled-tasks.ts +346 -41
  378. package/src/routes/session-artifact-associations.ts +87 -0
  379. package/src/routes/session-history-imports.ts +280 -0
  380. package/src/routes/sessions.ts +2306 -264
  381. package/src/routes/skill-content.ts +297 -0
  382. package/src/routes/skill-install-authority.ts +64 -0
  383. package/src/routes/skills.ts +62 -9
  384. package/src/routes/social.ts +46 -18
  385. package/src/routes/subscription-account-pools.ts +436 -0
  386. package/src/routes/subscription-pool-access.ts +126 -0
  387. package/src/routes/supergrok.ts +219 -303
  388. package/src/routes/transcription-recordings.ts +38 -3
  389. package/src/routes/transcriptions.ts +4 -0
  390. package/src/routes/usage-allowances.ts +378 -0
  391. package/src/routes/user-resource-authorities.ts +138 -0
  392. package/src/routes/video-generation.ts +14 -10
  393. package/src/routes/workspace-artifacts.ts +275 -69
  394. package/src/routes/workspace-capture.ts +21 -0
  395. package/src/routes/workspace-integrations.ts +576 -0
  396. package/src/routes/workspace-learning.ts +159 -0
  397. package/src/routes/workspace-model-providers.ts +148 -0
  398. package/src/routes/workspace-state.ts +38 -25
  399. package/src/routes/workspaces.ts +1004 -127
  400. package/src/sandbox/auth-callout.ts +96 -19
  401. package/src/sandbox/channel-a.ts +323 -24
  402. package/src/sandbox/connection-authority.ts +3 -0
  403. package/src/sandbox/enrollment.ts +81 -6
  404. package/src/sandbox/machines.ts +218 -76
  405. package/src/sandbox/metrics-ingestion.ts +411 -62
  406. package/src/sandbox/rematerialize.ts +121 -19
  407. package/src/sandbox/session-attach-variable-sets.ts +131 -0
  408. package/src/sandbox/viewer.ts +280 -25
  409. package/src/sandbox-file-artifacts.ts +413 -0
  410. package/src/scheduled-task-deletion.ts +138 -0
  411. package/src/session-create-observability.ts +46 -0
  412. package/src/session-realtime-context.ts +6 -3
  413. package/src/site-session-origin.ts +48 -0
  414. package/src/site-uploads.ts +224 -0
  415. package/src/slack-reaction-files.ts +16 -5
  416. package/src/temporal-schedule-cleanup.ts +13 -0
  417. package/src/temporal-schedule-sync.ts +74 -0
  418. package/src/transcription/providers/codex-subscription.ts +2 -0
  419. package/src/transcription/providers/openai.ts +1 -0
  420. package/src/transcription/providers/xai-subscription.ts +49 -3
  421. package/src/transcription/segmenter.ts +8 -2
  422. package/src/transcription/service.ts +43 -6
  423. package/src/work-discovery-observability.ts +121 -0
  424. package/src/workspace-artifact-content.ts +144 -0
  425. package/src/workspace-artifact-provenance.ts +104 -0
  426. package/src/workspace-delete-observability.ts +75 -0
  427. package/src/workspace-deletion.ts +73 -0
  428. package/src/workspace-state-projection.ts +18 -148
  429. package/src/workspace-tool-gateway-observability.ts +100 -0
  430. package/src/workspace-tool-gateway.ts +870 -0
  431. package/src/workspace-webhook-dispatch.ts +190 -0
  432. package/src/xai-subscription-auth.ts +9 -2
  433. package/dist/chunk-2PQMSRCB.js +0 -49759
  434. package/dist/chunk-2PQMSRCB.js.map +0 -1
  435. package/dist/routes/packs.d.ts +0 -3
  436. package/src/routes/packs.ts +0 -729
@@ -6,6 +6,7 @@ import {
6
6
  } from "@opengeni/contracts";
7
7
  import {
8
8
  getVideoGenerationOperationSummary,
9
+ withSessionRlsActorContext,
9
10
  getWorkspaceVercelAiGatewayConnectionMetadata,
10
11
  getWorkspaceVideoGenerationPolicy,
11
12
  updateWorkspaceVideoGenerationPolicy,
@@ -14,6 +15,9 @@ import {
14
15
  } from "@opengeni/db";
15
16
  import {
16
17
  requireAccessGrant,
18
+ requireAccessGrantAuthorization,
19
+ fileOwnerContextForAccess,
20
+ requireWorkspaceSettingsGrant,
17
21
  VIDEO_GENERATION_MODEL_CATALOG,
18
22
  videoGenerationModelSupportsFundingSource,
19
23
  videoGenerationCapabilitiesForPolicy,
@@ -21,6 +25,7 @@ import {
21
25
  } from "@opengeni/core";
22
26
  import type { Hono } from "hono";
23
27
  import { HTTPException } from "hono/http-exception";
28
+ import { parseRequestJson } from "../http/request-body";
24
29
 
25
30
  export function registerVideoGenerationRoutes(app: Hono, deps: ApiRouteDeps): void {
26
31
  app.get("/v1/workspaces/:workspaceId/video-generation", async (c) => {
@@ -58,8 +63,8 @@ export function registerVideoGenerationRoutes(app: Hono, deps: ApiRouteDeps): vo
58
63
 
59
64
  app.put("/v1/workspaces/:workspaceId/video-generation/policy", async (c) => {
60
65
  const workspaceId = c.req.param("workspaceId");
61
- const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
62
- const payload = UpdateVideoGenerationPolicyRequest.parse(await c.req.json());
66
+ const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
67
+ const payload = await parseRequestJson(c, UpdateVideoGenerationPolicyRequest);
63
68
  const [connection, supergrokConfigured] = await Promise.all([
64
69
  getWorkspaceVercelAiGatewayConnectionMetadata(deps.db, workspaceId),
65
70
  workspaceXaiSubscriptionActive(deps.db, deps.settings, workspaceId, grant.subjectId),
@@ -107,11 +112,10 @@ export function registerVideoGenerationRoutes(app: Hono, deps: ApiRouteDeps): vo
107
112
 
108
113
  app.get("/v1/workspaces/:workspaceId/video-generation/operations/:operationId", async (c) => {
109
114
  const workspaceId = c.req.param("workspaceId");
110
- await requireAccessGrant(c, deps, workspaceId, "workspace:read");
111
- const summary = await getVideoGenerationOperationSummary(
112
- deps.db,
113
- workspaceId,
114
- c.req.param("operationId"),
115
+ const access = await requireAccessGrantAuthorization(c, deps, workspaceId, "workspace:read");
116
+ const actor = await fileOwnerContextForAccess(deps, access, "workspace:read");
117
+ const summary = await withSessionRlsActorContext(actor, () =>
118
+ getVideoGenerationOperationSummary(deps.db, workspaceId, c.req.param("operationId")),
115
119
  );
116
120
  if (!summary)
117
121
  throw new HTTPException(404, {
@@ -133,12 +137,12 @@ function videoGenerationFundingOptions(input: {
133
137
  return [
134
138
  {
135
139
  source: "opengeni_credits" as const,
136
- label: "OpenGeni",
137
- description: "Uses OpenGeni credits through the managed Gateway route.",
140
+ label: "Opengeni",
141
+ description: "Uses Opengeni credits through the managed Gateway route.",
138
142
  available: input.managedConfigured,
139
143
  unavailableReason: input.managedConfigured
140
144
  ? null
141
- : "OpenGeni-managed video generation is not configured.",
145
+ : "Opengeni-managed video generation is not configured.",
142
146
  },
143
147
  {
144
148
  source: "supergrok_subscription" as const,
@@ -3,21 +3,32 @@ import {
3
3
  CreateWorkspaceArtifactRequest,
4
4
  PublishWorkspaceArtifactVersionRequest,
5
5
  RollbackWorkspaceArtifactRequest,
6
+ SetWorkspaceArtifactStatusRequest,
6
7
  WorkspaceArtifactContentResponse,
7
8
  WorkspaceArtifactDetailResponse,
8
9
  WorkspaceArtifactListQuery,
9
10
  WorkspaceArtifactListResponse,
10
11
  WorkspaceArtifactMutationResponse,
11
12
  normalizeWorkspaceArtifactSlug,
13
+ type AccessGrant,
12
14
  } from "@opengeni/contracts";
13
- import { requireAccessGrant, type ApiRouteDeps } from "@opengeni/core";
15
+ import {
16
+ requireAccessGrant,
17
+ requireAccessGrantAuthorization,
18
+ requireSessionAuthorization,
19
+ SessionAuthorizationDeniedError,
20
+ SessionAuthorizationUnavailableError,
21
+ type ApiRouteDeps,
22
+ } from "@opengeni/core";
14
23
  import {
15
24
  createWorkspaceArtifact,
16
25
  getWorkspaceArtifact,
17
26
  getWorkspaceArtifactContentRef,
18
27
  listWorkspaceArtifacts,
28
+ nestedPostgresSqlState,
19
29
  publishWorkspaceArtifactVersion,
20
30
  rollbackWorkspaceArtifact,
31
+ setWorkspaceArtifactStatus,
21
32
  WorkspaceArtifactConflictError,
22
33
  WorkspaceArtifactNotFoundError,
23
34
  WorkspaceArtifactOperationError,
@@ -25,10 +36,22 @@ import {
25
36
  import type { Context, Hono } from "hono";
26
37
  import { HTTPException } from "hono/http-exception";
27
38
  import { z } from "zod";
39
+ import { readWorkspaceArtifactContent } from "../workspace-artifact-content";
40
+ import { userContentDispositionHeaders } from "../http/user-content";
41
+ import {
42
+ projectWorkspaceArtifactDetailProvenance,
43
+ projectWorkspaceArtifactMutationProvenance,
44
+ redactWorkspaceArtifactListProvenance,
45
+ } from "../workspace-artifact-provenance";
46
+
47
+ import {
48
+ prepareWorkspaceArtifactPublication,
49
+ prepareWorkspaceArtifactUpload,
50
+ workspaceArtifactDownloads,
51
+ readArtifactObject,
52
+ } from "../site-uploads";
28
53
 
29
54
  const ArtifactId = z.string().uuid();
30
- const encoder = new TextEncoder();
31
- const decoder = new TextDecoder("utf-8", { fatal: true });
32
55
 
33
56
  async function body<S extends z.ZodType>(context: Context, schema: S): Promise<z.infer<S>> {
34
57
  const parsed = schema.safeParse(await context.req.json().catch(() => null));
@@ -36,13 +59,20 @@ async function body<S extends z.ZodType>(context: Context, schema: S): Promise<z
36
59
  return parsed.data;
37
60
  }
38
61
 
62
+ function parseVersionId(value: string | undefined): string | undefined {
63
+ if (value !== undefined && !ArtifactId.safeParse(value).success) {
64
+ throw new HTTPException(422, { message: "Invalid artifact version id" });
65
+ }
66
+ return value;
67
+ }
68
+
39
69
  function artifactId(context: Context): string {
40
70
  const parsed = ArtifactId.safeParse(context.req.param("artifactId"));
41
71
  if (!parsed.success) throw new HTTPException(422, { message: "Invalid artifact id" });
42
72
  return parsed.data;
43
73
  }
44
74
 
45
- function errorResponse(context: Context, error: unknown): Response {
75
+ export function workspaceArtifactErrorResponse(context: Context, error: unknown): Response {
46
76
  if (error instanceof WorkspaceArtifactNotFoundError) {
47
77
  return context.json({ code: "WORKSPACE_ARTIFACT_NOT_FOUND", message: error.message }, 404);
48
78
  }
@@ -62,41 +92,28 @@ function errorResponse(context: Context, error: unknown): Response {
62
92
  422,
63
93
  );
64
94
  }
65
- if (typeof error === "object" && error !== null && "code" in error && error.code === "23505") {
95
+ if (nestedPostgresSqlState(error) === "23505") {
66
96
  return context.json(
67
- { code: "WORKSPACE_ARTIFACT_CONFLICT", message: "Artifact slug or operation already exists" },
97
+ {
98
+ code: "WORKSPACE_ARTIFACT_CONFLICT",
99
+ message: "Artifact slug or operation already exists",
100
+ },
68
101
  409,
69
102
  );
70
103
  }
71
104
  throw error;
72
105
  }
73
106
 
74
- function contentMetadata(workspaceId: string, html: string) {
75
- const bytes = encoder.encode(html);
76
- const sha256 = createHash("sha256").update(bytes).digest("hex");
77
- return {
78
- bytes,
79
- contentSha256: sha256,
80
- sizeBytes: bytes.byteLength,
81
- contentKey: `workspaces/${workspaceId}/workspace-artifacts/blobs/${sha256}.html`,
82
- };
83
- }
84
-
85
- function prepareHtml(deps: ApiRouteDeps, workspaceId: string, html: string) {
107
+ function prepareContent(
108
+ deps: ApiRouteDeps,
109
+ grant: AccessGrant,
110
+ input: Parameters<typeof prepareWorkspaceArtifactPublication>[2],
111
+ ) {
86
112
  if (!deps.objectStorage)
87
- throw new HTTPException(503, { message: "Object storage is not configured" });
88
- const content = contentMetadata(workspaceId, html);
89
- return {
90
- ...content,
91
- persistContent: async () => {
92
- await deps.objectStorage!.putObject({
93
- key: content.contentKey,
94
- contentType: "text/html; charset=utf-8",
95
- body: content.bytes,
96
- sha256: content.contentSha256,
97
- });
98
- },
99
- };
113
+ throw new HTTPException(503, {
114
+ message: "Object storage is not configured",
115
+ });
116
+ return prepareWorkspaceArtifactPublication(deps, grant, input);
100
117
  }
101
118
 
102
119
  function provenance(subjectId: string, idempotencyKey: string) {
@@ -111,49 +128,138 @@ function provenance(subjectId: string, idempotencyKey: string) {
111
128
  };
112
129
  }
113
130
 
131
+ async function canReadProvenanceSession(
132
+ deps: ApiRouteDeps,
133
+ grant: AccessGrant,
134
+ sessionId: string,
135
+ ): Promise<boolean> {
136
+ try {
137
+ await requireSessionAuthorization(deps, grant, {
138
+ sessionId,
139
+ operation: "session.read",
140
+ surface: "http",
141
+ });
142
+ return true;
143
+ } catch (error) {
144
+ if (error instanceof SessionAuthorizationDeniedError) return false;
145
+ if (error instanceof SessionAuthorizationUnavailableError) {
146
+ throw new HTTPException(503, {
147
+ message: "Session authorization is unavailable",
148
+ });
149
+ }
150
+ throw error;
151
+ }
152
+ }
153
+
154
+ async function mutationResponse(
155
+ deps: ApiRouteDeps,
156
+ grant: AccessGrant,
157
+ response: WorkspaceArtifactMutationResponse,
158
+ ): Promise<WorkspaceArtifactMutationResponse> {
159
+ return WorkspaceArtifactMutationResponse.parse(
160
+ await projectWorkspaceArtifactMutationProvenance(response, (sessionId) =>
161
+ canReadProvenanceSession(deps, grant, sessionId),
162
+ ),
163
+ );
164
+ }
165
+
114
166
  export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps): void {
115
167
  // `published-artifacts` deliberately avoids the existing `/artifacts/:id`
116
168
  // retained-output API. The product route remains simply `/artifacts`.
117
169
  const base = "/v1/workspaces/:workspaceId/published-artifacts";
118
170
 
119
- app.get(base, async (context) => {
171
+ app.post(`${base}/uploads`, async (context) => {
172
+ const grant = await requireAccessGrant(
173
+ context,
174
+ deps,
175
+ context.req.param("workspaceId"),
176
+ "artifacts:publish",
177
+ );
178
+ return context.json(await prepareWorkspaceArtifactUpload(deps, grant));
179
+ });
180
+
181
+ app.get(`${base}/:artifactId/downloads`, async (context) => {
120
182
  const workspaceId = context.req.param("workspaceId");
121
183
  await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
184
+ if (!deps.objectStorage)
185
+ throw new HTTPException(503, {
186
+ message: "Object storage is not configured",
187
+ });
188
+ const ref = await getWorkspaceArtifactContentRef(
189
+ deps.db,
190
+ workspaceId,
191
+ artifactId(context),
192
+ parseVersionId(context.req.query("versionId")),
193
+ );
194
+ return context.json(await workspaceArtifactDownloads(deps.objectStorage, ref, "public"));
195
+ });
196
+
197
+ app.get(base, async (context) => {
198
+ const workspaceId = context.req.param("workspaceId");
199
+ const grant = await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
122
200
  const query = WorkspaceArtifactListQuery.safeParse({
123
201
  limit: context.req.query("limit"),
124
202
  cursor: context.req.query("cursor"),
203
+ status: context.req.query("status"),
204
+ sourceSessionId: context.req.query("sourceSessionId"),
125
205
  });
126
206
  if (!query.success) throw new HTTPException(422, { message: "Invalid artifact list query" });
207
+ if (
208
+ query.data.sourceSessionId &&
209
+ !(await canReadProvenanceSession(deps, grant, query.data.sourceSessionId))
210
+ ) {
211
+ throw new HTTPException(404, { message: "Session not found" });
212
+ }
127
213
  try {
128
214
  return context.json(
129
215
  WorkspaceArtifactListResponse.parse(
130
- await listWorkspaceArtifacts(deps.db, workspaceId, {
131
- limit: query.data.limit,
132
- ...(query.data.cursor ? { cursor: query.data.cursor } : {}),
133
- }),
216
+ redactWorkspaceArtifactListProvenance(
217
+ await listWorkspaceArtifacts(deps.db, workspaceId, {
218
+ limit: query.data.limit,
219
+ ...(query.data.cursor ? { cursor: query.data.cursor } : {}),
220
+ ...(query.data.status ? { status: query.data.status } : {}),
221
+ ...(query.data.sourceSessionId
222
+ ? { sourceSessionId: query.data.sourceSessionId }
223
+ : {}),
224
+ }),
225
+ ),
134
226
  ),
135
227
  );
136
228
  } catch (error) {
137
- return errorResponse(context, error);
229
+ return workspaceArtifactErrorResponse(context, error);
138
230
  }
139
231
  });
140
232
 
141
233
  app.post(base, async (context) => {
142
234
  const workspaceId = context.req.param("workspaceId");
143
- const grant = await requireAccessGrant(context, deps, workspaceId, "artifacts:publish");
235
+ const authorization = await requireAccessGrantAuthorization(
236
+ context,
237
+ deps,
238
+ workspaceId,
239
+ "artifacts:publish",
240
+ );
241
+ const grant = authorization.grant;
144
242
  const request = await body(context, CreateWorkspaceArtifactRequest);
145
243
  const id = crypto.randomUUID();
146
244
  const slugBase = request.slug ?? (normalizeWorkspaceArtifactSlug(request.title) || "artifact");
147
245
  const slug = request.slug ?? `${slugBase.slice(0, 87)}-${id.slice(0, 8)}`;
148
- const content = prepareHtml(deps, workspaceId, request.html);
149
246
  try {
247
+ const content = await prepareContent(deps, grant, {
248
+ ...(request.html !== undefined ? { html: request.html } : {}),
249
+ ...(request.uploadId ? { uploadId: request.uploadId } : {}),
250
+ ...(request.source ? { source: request.source } : {}),
251
+ ...(request.requestedTools ? { requestedTools: request.requestedTools } : {}),
252
+ });
150
253
  return context.json(
151
- WorkspaceArtifactMutationResponse.parse(
254
+ await mutationResponse(
255
+ deps,
256
+ grant,
152
257
  await createWorkspaceArtifact(deps.db, {
153
258
  accountId: grant.accountId,
154
259
  workspaceId,
155
260
  artifactId: id,
156
261
  slug,
262
+ requestedSlug: request.slug ?? null,
157
263
  title: request.title,
158
264
  description: request.description ?? null,
159
265
  ...content,
@@ -163,33 +269,82 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
163
269
  201,
164
270
  );
165
271
  } catch (error) {
166
- return errorResponse(context, error);
272
+ return workspaceArtifactErrorResponse(context, error);
167
273
  }
168
274
  });
169
275
 
170
276
  app.get(`${base}/:artifactId`, async (context) => {
171
277
  const workspaceId = context.req.param("workspaceId");
172
- await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
278
+ const grant = await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
173
279
  try {
280
+ const detail = await getWorkspaceArtifact(deps.db, workspaceId, artifactId(context));
174
281
  return context.json(
175
282
  WorkspaceArtifactDetailResponse.parse(
176
- await getWorkspaceArtifact(deps.db, workspaceId, artifactId(context)),
283
+ await projectWorkspaceArtifactDetailProvenance(detail, (sessionId) =>
284
+ canReadProvenanceSession(deps, grant, sessionId),
285
+ ),
177
286
  ),
178
287
  );
179
288
  } catch (error) {
180
- return errorResponse(context, error);
289
+ return workspaceArtifactErrorResponse(context, error);
181
290
  }
182
291
  });
183
292
 
293
+ app.get(`${base}/:artifactId/html`, async (context) => {
294
+ const workspaceId = context.req.param("workspaceId");
295
+ await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
296
+ if (!deps.objectStorage)
297
+ throw new HTTPException(503, {
298
+ message: "Object storage is not configured",
299
+ });
300
+ const ref = await getWorkspaceArtifactContentRef(
301
+ deps.db,
302
+ workspaceId,
303
+ artifactId(context),
304
+ parseVersionId(context.req.query("versionId")),
305
+ );
306
+ const iterator = readArtifactObject(deps.objectStorage, ref.contentKey);
307
+ return new Response(
308
+ new ReadableStream({
309
+ async pull(controller) {
310
+ try {
311
+ const item = await iterator.next();
312
+ if (item.done) controller.close();
313
+ else controller.enqueue(item.value);
314
+ } catch (error) {
315
+ controller.error(error);
316
+ }
317
+ },
318
+ async cancel() {
319
+ await iterator.return();
320
+ },
321
+ }),
322
+ {
323
+ headers: {
324
+ "Content-Type": "text/html; charset=utf-8",
325
+ "Cache-Control": "private, no-store",
326
+ // A Site runs its own scripts, but only inside an opaque origin: no
327
+ // same-origin access to the console, and no cross-site embedding.
328
+ "Content-Security-Policy": "sandbox allow-scripts",
329
+ "Cross-Origin-Resource-Policy": "same-origin",
330
+ "X-Content-Type-Options": "nosniff",
331
+ // Clients read this HTML with fetch and render it in their own frame
332
+ // (the console uses srcdoc). Opening the raw URL downloads it rather
333
+ // than running a publisher-authored page at an app-origin URL.
334
+ ...userContentDispositionHeaders("text/html", "site.html"),
335
+ },
336
+ },
337
+ );
338
+ });
339
+
184
340
  app.get(`${base}/:artifactId/content`, async (context) => {
185
341
  const workspaceId = context.req.param("workspaceId");
186
342
  await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
187
343
  if (!deps.objectStorage)
188
- throw new HTTPException(503, { message: "Object storage is not configured" });
189
- const parsedVersion = context.req.query("versionId");
190
- if (parsedVersion && !ArtifactId.safeParse(parsedVersion).success) {
191
- throw new HTTPException(422, { message: "Invalid artifact version id" });
192
- }
344
+ throw new HTTPException(503, {
345
+ message: "Object storage is not configured",
346
+ });
347
+ const parsedVersion = parseVersionId(context.req.query("versionId"));
193
348
  try {
194
349
  const ref = await getWorkspaceArtifactContentRef(
195
350
  deps.db,
@@ -197,17 +352,14 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
197
352
  artifactId(context),
198
353
  parsedVersion,
199
354
  );
200
- const object = await deps.objectStorage.getObjectBytes(ref.contentKey);
201
- if (!object) throw new HTTPException(503, { message: "Artifact content is unavailable" });
202
- const actualHash = createHash("sha256").update(object.bytes).digest("hex");
203
- if (actualHash !== ref.version.contentSha256) {
204
- throw new HTTPException(503, { message: "Artifact content failed integrity verification" });
205
- }
206
- let html: string;
355
+ let content: Awaited<ReturnType<typeof readWorkspaceArtifactContent>>;
207
356
  try {
208
- html = decoder.decode(object.bytes);
209
- } catch {
210
- throw new HTTPException(503, { message: "Artifact content is not valid UTF-8" });
357
+ content = await readWorkspaceArtifactContent(deps.objectStorage, ref);
358
+ } catch (error) {
359
+ throw new HTTPException(503, {
360
+ message: error instanceof Error ? error.message : "Artifact content is unavailable",
361
+ cause: error,
362
+ });
211
363
  }
212
364
  return context.json(
213
365
  WorkspaceArtifactContentResponse.parse({
@@ -215,23 +367,36 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
215
367
  versionId: ref.version.id,
216
368
  contentType: "text/html",
217
369
  contentSha256: ref.version.contentSha256,
218
- html,
370
+ ...content,
219
371
  }),
220
372
  );
221
373
  } catch (error) {
222
- return errorResponse(context, error);
374
+ return workspaceArtifactErrorResponse(context, error);
223
375
  }
224
376
  });
225
377
 
226
378
  app.post(`${base}/:artifactId/versions`, async (context) => {
227
379
  const workspaceId = context.req.param("workspaceId");
228
- const grant = await requireAccessGrant(context, deps, workspaceId, "artifacts:publish");
380
+ const authorization = await requireAccessGrantAuthorization(
381
+ context,
382
+ deps,
383
+ workspaceId,
384
+ "artifacts:publish",
385
+ );
386
+ const grant = authorization.grant;
229
387
  const request = await body(context, PublishWorkspaceArtifactVersionRequest);
230
388
  const id = artifactId(context);
231
- const content = prepareHtml(deps, workspaceId, request.html);
232
389
  try {
390
+ const content = await prepareContent(deps, grant, {
391
+ ...(request.html !== undefined ? { html: request.html } : {}),
392
+ ...(request.uploadId ? { uploadId: request.uploadId } : {}),
393
+ ...(request.source ? { source: request.source } : {}),
394
+ ...(request.requestedTools ? { requestedTools: request.requestedTools } : {}),
395
+ });
233
396
  return context.json(
234
- WorkspaceArtifactMutationResponse.parse(
397
+ await mutationResponse(
398
+ deps,
399
+ grant,
235
400
  await publishWorkspaceArtifactVersion(deps.db, {
236
401
  accountId: grant.accountId,
237
402
  workspaceId,
@@ -245,21 +410,30 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
245
410
  ),
246
411
  );
247
412
  } catch (error) {
248
- return errorResponse(context, error);
413
+ return workspaceArtifactErrorResponse(context, error);
249
414
  }
250
415
  });
251
416
 
252
417
  app.post(`${base}/:artifactId/rollback`, async (context) => {
253
418
  const workspaceId = context.req.param("workspaceId");
254
- const grant = await requireAccessGrant(context, deps, workspaceId, "artifacts:publish");
419
+ const authorization = await requireAccessGrantAuthorization(
420
+ context,
421
+ deps,
422
+ workspaceId,
423
+ "artifacts:publish",
424
+ );
425
+ const grant = authorization.grant;
255
426
  const request = await body(context, RollbackWorkspaceArtifactRequest);
427
+ const id = artifactId(context);
256
428
  try {
257
429
  return context.json(
258
- WorkspaceArtifactMutationResponse.parse(
430
+ await mutationResponse(
431
+ deps,
432
+ grant,
259
433
  await rollbackWorkspaceArtifact(deps.db, {
260
434
  accountId: grant.accountId,
261
435
  workspaceId,
262
- artifactId: artifactId(context),
436
+ artifactId: id,
263
437
  versionId: request.versionId,
264
438
  expectedCurrentVersionId: request.expectedCurrentVersionId,
265
439
  reason: request.reason,
@@ -268,7 +442,39 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
268
442
  ),
269
443
  );
270
444
  } catch (error) {
271
- return errorResponse(context, error);
445
+ return workspaceArtifactErrorResponse(context, error);
446
+ }
447
+ });
448
+
449
+ app.patch(`${base}/:artifactId/status`, async (context) => {
450
+ const workspaceId = context.req.param("workspaceId");
451
+ const authorization = await requireAccessGrantAuthorization(
452
+ context,
453
+ deps,
454
+ workspaceId,
455
+ "artifacts:publish",
456
+ );
457
+ const grant = authorization.grant;
458
+ const request = await body(context, SetWorkspaceArtifactStatusRequest);
459
+ const id = artifactId(context);
460
+ try {
461
+ return context.json(
462
+ await mutationResponse(
463
+ deps,
464
+ grant,
465
+ await setWorkspaceArtifactStatus(deps.db, {
466
+ accountId: grant.accountId,
467
+ workspaceId,
468
+ artifactId: id,
469
+ status: request.status,
470
+ expectedCurrentVersionId: request.expectedCurrentVersionId,
471
+ reason: request.reason,
472
+ ...provenance(grant.subjectId, request.idempotencyKey),
473
+ }),
474
+ ),
475
+ );
476
+ } catch (error) {
477
+ return workspaceArtifactErrorResponse(context, error);
272
478
  }
273
479
  });
274
480
  }
@@ -215,10 +215,20 @@ async function loadManifest(
215
215
  * manifest blob has been GC'd (all graceful cold-fallback states — never errors).
216
216
  * Inline manifest for ≤2MB, signed URL above.
217
217
  */
218
+ /** Awaited before a signed capture URL is returned to the caller: the route
219
+ * records the metadata-only issuance audit fact. A throwing recorder fails
220
+ * the serve closed - no recorded fact, no bearer capability. */
221
+ export type CaptureSignedUrlIssuanceRecorder = (fact: {
222
+ kind: "capture_manifest" | "capture_file";
223
+ revision: number;
224
+ expiresAt: string;
225
+ }) => Promise<void>;
226
+
218
227
  export async function serveWorkspaceCapture(
219
228
  row: WorkspaceCaptureRow | null,
220
229
  storage: CaptureStoragePort,
221
230
  cache?: WorkspaceCaptureManifestCache,
231
+ onSignedUrlIssued?: CaptureSignedUrlIssuanceRecorder,
222
232
  ): Promise<GetWorkspaceCaptureResponse> {
223
233
  if (!row) {
224
234
  return { available: false };
@@ -274,6 +284,11 @@ export async function serveWorkspaceCapture(
274
284
  key: row.manifestKey,
275
285
  expiresInSeconds: CAPTURE_SIGNED_URL_TTL_SECONDS,
276
286
  });
287
+ await onSignedUrlIssued?.({
288
+ kind: "capture_manifest",
289
+ revision: row.revision,
290
+ expiresAt: signed.expiresAt.toISOString(),
291
+ });
277
292
  return GetWorkspaceCaptureResponse.parse({
278
293
  ...meta,
279
294
  manifest: null,
@@ -293,6 +308,7 @@ export async function serveWorkspaceCaptureFile(
293
308
  row: WorkspaceCaptureRow | null,
294
309
  path: string,
295
310
  storage: CaptureStoragePort,
311
+ onSignedUrlIssued?: CaptureSignedUrlIssuanceRecorder,
296
312
  ): Promise<GetWorkspaceCaptureFileResponse> {
297
313
  const loaded = row ? await loadManifest(row, storage) : null;
298
314
  if (!loaded) {
@@ -347,6 +363,11 @@ export async function serveWorkspaceCaptureFile(
347
363
  key: file.contentRef,
348
364
  expiresInSeconds: CAPTURE_SIGNED_URL_TTL_SECONDS,
349
365
  });
366
+ await onSignedUrlIssued?.({
367
+ kind: "capture_file",
368
+ revision: row!.revision,
369
+ expiresAt: signed.expiresAt.toISOString(),
370
+ });
350
371
  return GetWorkspaceCaptureFileResponse.parse({
351
372
  ...base,
352
373
  encoding: null,