@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
@@ -1,16 +1,112 @@
1
- import { CreateApiKeyRequest, CreateApiKeyResponse, Permission } from "@opengeni/contracts";
2
- import { createApiKey, listApiKeys, revokeApiKey } from "@opengeni/db";
1
+ import {
2
+ CreateApiKeyRequest,
3
+ CreateApiKeyResponse,
4
+ CreateOrganizationApiKeyRequest,
5
+ UpdateOrganizationApiKeyRequest,
6
+ normalizeOrganizationAccessPolicy,
7
+ type OrganizationAccessPolicy,
8
+ DEVELOPER_SETUP_API_KEY_PRESET,
9
+ Permission,
10
+ type AccessContext,
11
+ type ApiKey,
12
+ type OrganizationApiKeyAccess,
13
+ } from "@opengeni/contracts";
14
+ import {
15
+ createApiKey,
16
+ createOrganizationApiKey as createOrganizationApiKeyRecord,
17
+ listApiKeys,
18
+ listOrganizationApiKeys,
19
+ getOrganizationApiKey,
20
+ updateOrganizationApiKey,
21
+ OrganizationApiKeyWorkspaceScopeError,
22
+ OrganizationApiKeyLimitExceededError,
23
+ OrganizationServiceAccountNotFoundError,
24
+ OrganizationServiceAccountRoleError,
25
+ revokeApiKey,
26
+ revokeOrganizationApiKey,
27
+ } from "@opengeni/db";
28
+ import { configuredStaticUsageLimits } from "@opengeni/config";
3
29
  import { zValidator } from "@hono/zod-validator";
4
30
  import type { Hono } from "hono";
5
31
  import { HTTPException } from "hono/http-exception";
6
32
  import type { ApiRouteDeps } from "@opengeni/core";
7
- import { requireAccessGrant } from "@opengeni/core";
33
+ import {
34
+ accountScopedApiKeyWorkspaceAuthority,
35
+ organizationApiKeyAccess,
36
+ hasPermission,
37
+ organizationWorkspaceInScope,
38
+ requireAccessContext,
39
+ requireAccessGrantAuthorization,
40
+ requireApiKeyManagementContext,
41
+ requireExplicitPermissionDelegation,
42
+ type AccessGrantAuthorization,
43
+ } from "@opengeni/core";
8
44
  import { requireLimit } from "@opengeni/core";
9
45
 
46
+ export { organizationApiKeyAccess } from "@opengeni/core";
47
+
48
+ /** Permissions minted onto a `full` organization API key. */
49
+ export const organizationApiKeyPermissions: Permission[] = [
50
+ "account:read",
51
+ "workspace:create",
52
+ "workspace:read",
53
+ "workspace:admin",
54
+ "api_keys:manage",
55
+ ];
56
+
57
+ /**
58
+ * Permissions minted onto a `read` organization API key. The key inventories
59
+ * shared workspaces and reads their sessions, events, and files; it holds no
60
+ * `workspace:admin` wildcard, so every control, create, and key-management
61
+ * route denies it, and no `api_keys:manage`, so it cannot mint keys.
62
+ */
63
+ export const organizationReadApiKeyPermissions: Permission[] = [
64
+ "account:read",
65
+ "workspace:read",
66
+ "sessions:read",
67
+ "files:read",
68
+ ];
69
+
70
+ export function organizationApiKeyPermissionsForAccess(
71
+ access: OrganizationApiKeyAccess,
72
+ ): Permission[] {
73
+ return access === "developer_setup"
74
+ ? [...DEVELOPER_SETUP_API_KEY_PRESET.permissions]
75
+ : access === "read"
76
+ ? [...organizationReadApiKeyPermissions]
77
+ : [...organizationApiKeyPermissions];
78
+ }
79
+
80
+ /** Existing callers retain their expiry; setup keys default to one day. */
81
+ export function organizationApiKeyExpiryDate(
82
+ request: Pick<CreateOrganizationApiKeyRequest, "preset" | "expiresAt"> &
83
+ Partial<Pick<CreateOrganizationApiKeyRequest, "access">>,
84
+ now: Date = new Date(),
85
+ ): Date | null {
86
+ if (request.expiresAt !== undefined) return new Date(request.expiresAt);
87
+ return request.preset === "developer_setup" || request.access === "developer_setup"
88
+ ? new Date(now.getTime() + DEVELOPER_SETUP_API_KEY_PRESET.defaultExpiryHours * 60 * 60 * 1000)
89
+ : null;
90
+ }
91
+
92
+ function withOrganizationApiKeyAccess(apiKey: ApiKey): ApiKey {
93
+ const workspaceScope = apiKey.workspaceScope ?? { kind: "all" as const };
94
+ return {
95
+ ...apiKey,
96
+ access: organizationApiKeyAccess(apiKey.permissions),
97
+ workspaceScope,
98
+ policy: normalizeOrganizationAccessPolicy({
99
+ preset: "custom",
100
+ permissions: apiKey.permissions,
101
+ workspaceScope,
102
+ }),
103
+ };
104
+ }
105
+
10
106
  export function registerApiKeyRoutes(app: Hono, deps: ApiRouteDeps): void {
11
107
  app.get("/v1/workspaces/:workspaceId/api-keys", async (c) => {
12
108
  const workspaceId = c.req.param("workspaceId");
13
- await requireAccessGrant(c, deps, workspaceId, "api_keys:manage");
109
+ await requireWorkspaceApiKeyControl(c, deps, workspaceId);
14
110
  return c.json({ apiKeys: await listApiKeys(deps.db, workspaceId) });
15
111
  });
16
112
 
@@ -19,11 +115,12 @@ export function registerApiKeyRoutes(app: Hono, deps: ApiRouteDeps): void {
19
115
  zValidator("json", CreateApiKeyRequest.omit({ workspaceId: true })),
20
116
  async (c) => {
21
117
  const workspaceId = c.req.param("workspaceId");
22
- const grant = await requireAccessGrant(c, deps, workspaceId, "api_keys:manage");
118
+ const authorization = await requireWorkspaceApiKeyControl(c, deps, workspaceId);
119
+ const grant = authorization.grant;
23
120
  const body = c.req.valid("json");
24
121
  const permissions: Permission[] =
25
122
  body.permissions.length > 0 ? (body.permissions as Permission[]) : ["workspace:read"];
26
- ensureDelegablePermissions(grant.permissions, permissions);
123
+ ensureDelegablePermissions(authorization, permissions);
27
124
  await requireLimit(deps, {
28
125
  accountId: grant.accountId,
29
126
  workspaceId,
@@ -36,6 +133,7 @@ export function registerApiKeyRoutes(app: Hono, deps: ApiRouteDeps): void {
36
133
  accountId: grant.accountId,
37
134
  workspaceId: grant.workspaceId,
38
135
  name: body.name,
136
+ description: body.description ?? null,
39
137
  prefix,
40
138
  keyHash: await sha256Hex(token),
41
139
  permissions,
@@ -47,15 +145,172 @@ export function registerApiKeyRoutes(app: Hono, deps: ApiRouteDeps): void {
47
145
 
48
146
  app.delete("/v1/workspaces/:workspaceId/api-keys/:apiKeyId", async (c) => {
49
147
  const workspaceId = c.req.param("workspaceId");
50
- await requireAccessGrant(c, deps, workspaceId, "api_keys:manage");
148
+ await requireWorkspaceApiKeyControl(c, deps, workspaceId);
51
149
  return c.json(await revokeApiKey(deps.db, workspaceId, c.req.param("apiKeyId")));
52
150
  });
151
+
152
+ app.get("/v1/organizations/:organizationId/api-keys", async (c) => {
153
+ const organizationId = c.req.param("organizationId");
154
+ const context = await requireAccessContext(c, deps);
155
+ requireOrganizationApiKeyControlPermission(context, organizationId);
156
+ return c.json({
157
+ apiKeys: (await listOrganizationApiKeys(deps.db, organizationId)).map(
158
+ withOrganizationApiKeyAccess,
159
+ ),
160
+ });
161
+ });
162
+
163
+ app.post(
164
+ "/v1/organizations/:organizationId/api-keys",
165
+ zValidator("json", CreateOrganizationApiKeyRequest),
166
+ async (c) => {
167
+ const organizationId = c.req.param("organizationId");
168
+ const context = await requireAccessContext(c, deps);
169
+ requireOrganizationApiKeyControlPermission(context, organizationId);
170
+ const body = c.req.valid("json");
171
+ const rawBody: Record<string, unknown> = await c.req.json();
172
+ if (body.policy && (rawBody.access !== undefined || rawBody.preset !== undefined))
173
+ throw new HTTPException(400, {
174
+ message: "Choose either a policy or a legacy access tier/preset",
175
+ });
176
+ const token = generateApiKeyToken();
177
+ const permissions =
178
+ body.policy?.permissions ??
179
+ (body.preset === "developer_setup"
180
+ ? [...DEVELOPER_SETUP_API_KEY_PRESET.permissions]
181
+ : organizationApiKeyPermissionsForAccess(body.access));
182
+ ensureOrganizationPolicyDelegable(
183
+ context,
184
+ body.policy ?? {
185
+ preset: "custom",
186
+ permissions,
187
+ workspaceScope: { kind: "all" },
188
+ },
189
+ !body.policy,
190
+ );
191
+ try {
192
+ const apiKey = await createOrganizationApiKeyRecord(deps.db, {
193
+ accountId: organizationId,
194
+ name: body.name,
195
+ description: body.description ?? null,
196
+ prefix: token.slice(0, 14),
197
+ keyHash: await sha256Hex(token),
198
+ permissions,
199
+ ...(body.policy ? { policy: body.policy } : {}),
200
+ expiresAt: organizationApiKeyExpiryDate(body),
201
+ maxActiveKeys: organizationApiKeyLimit(deps),
202
+ rotationSourceApiKeyId: authenticatedApiKeyId(context),
203
+ serviceAccountId: body.serviceAccountId ?? null,
204
+ createdBySubjectId: context.subjectId,
205
+ });
206
+ return c.json(
207
+ CreateApiKeyResponse.parse({ apiKey: withOrganizationApiKeyAccess(apiKey), token }),
208
+ 201,
209
+ );
210
+ } catch (error) {
211
+ if (error instanceof OrganizationApiKeyLimitExceededError) {
212
+ throw new HTTPException(429, { message: error.message });
213
+ }
214
+ if (error instanceof OrganizationApiKeyWorkspaceScopeError)
215
+ throw new HTTPException(400, { message: error.message });
216
+ throwServiceAccountError(error);
217
+ throw error;
218
+ }
219
+ },
220
+ );
221
+
222
+ app.get("/v1/organizations/:organizationId/api-keys/:apiKeyId", async (c) => {
223
+ const organizationId = c.req.param("organizationId");
224
+ requireOrganizationApiKeyControlPermission(await requireAccessContext(c, deps), organizationId);
225
+ const apiKey = await getOrganizationApiKey(deps.db, organizationId, c.req.param("apiKeyId"));
226
+ if (!apiKey) throw new HTTPException(404, { message: "API key not found" });
227
+ return c.json(withOrganizationApiKeyAccess(apiKey));
228
+ });
229
+
230
+ app.patch(
231
+ "/v1/organizations/:organizationId/api-keys/:apiKeyId",
232
+ zValidator("json", UpdateOrganizationApiKeyRequest),
233
+ async (c) => {
234
+ const organizationId = c.req.param("organizationId");
235
+ const context = await requireAccessContext(c, deps);
236
+ requireOrganizationApiKeyControlPermission(context, organizationId);
237
+ const body = c.req.valid("json");
238
+ if (body.policy) ensureOrganizationPolicyDelegable(context, body.policy);
239
+ try {
240
+ const apiKey = await updateOrganizationApiKey(
241
+ deps.db,
242
+ organizationId,
243
+ c.req.param("apiKeyId"),
244
+ body,
245
+ );
246
+ if (!apiKey) throw new HTTPException(404, { message: "API key not found" });
247
+ return c.json(withOrganizationApiKeyAccess(apiKey));
248
+ } catch (error) {
249
+ if (error instanceof OrganizationApiKeyWorkspaceScopeError)
250
+ throw new HTTPException(400, { message: error.message });
251
+ throwServiceAccountError(error);
252
+ throw error;
253
+ }
254
+ },
255
+ );
256
+
257
+ app.delete("/v1/organizations/:organizationId/api-keys/:apiKeyId", async (c) => {
258
+ const organizationId = c.req.param("organizationId");
259
+ const context = await requireAccessContext(c, deps);
260
+ requireOrganizationApiKeyControlPermission(context, organizationId);
261
+ const apiKey = await revokeOrganizationApiKey(deps.db, organizationId, c.req.param("apiKeyId"));
262
+ if (!apiKey) {
263
+ throw new HTTPException(404, { message: "API key not found" });
264
+ }
265
+ return c.json(withOrganizationApiKeyAccess(apiKey));
266
+ });
267
+ }
268
+
269
+ /** Service account problems read as the person would expect. */
270
+ export function throwServiceAccountError(error: unknown): void {
271
+ if (error instanceof OrganizationServiceAccountNotFoundError)
272
+ throw new HTTPException(404, { message: error.message });
273
+ if (error instanceof OrganizationServiceAccountRoleError)
274
+ throw new HTTPException(400, { message: error.message });
275
+ }
276
+
277
+ function requireAccountPermission(
278
+ context: AccessContext,
279
+ accountId: string,
280
+ permission: Permission,
281
+ ): void {
282
+ const grant = context.accountGrants.find((candidate) => candidate.accountId === accountId);
283
+ if (
284
+ !grant ||
285
+ (!grant.permissions.includes(permission) && !grant.permissions.includes("account:admin"))
286
+ ) {
287
+ throw new HTTPException(403, { message: `missing permission: ${permission}` });
288
+ }
53
289
  }
54
290
 
55
- function ensureDelegablePermissions(grantPermissions: Permission[], requested: Permission[]): void {
56
- if (grantPermissions.includes("workspace:admin")) {
291
+ function ensureDelegablePermissions(
292
+ authorization: AccessGrantAuthorization,
293
+ requested: Permission[],
294
+ ): void {
295
+ requireExplicitPermissionDelegation(authorization.grant, requested);
296
+ const grantPermissions = authorization.grant.permissions;
297
+ if (
298
+ grantPermissions.includes("workspace:admin") &&
299
+ authorization.grant.permissionMode !== "explicit"
300
+ ) {
301
+ const accountLiteralPermissions = new Set<Permission>([
302
+ "account:read",
303
+ "account:admin",
304
+ "workspace:create",
305
+ "billing:read",
306
+ "billing:manage",
307
+ ]);
308
+ const workspaceLiteralPermissions = new Set<Permission>(["members:manage", "secrets:read"]);
57
309
  const highTrustMissing = requested.filter(
58
- (permission) => permission === "secrets:read" && !grantPermissions.includes("secrets:read"),
310
+ (permission) =>
311
+ (accountLiteralPermissions.has(permission) &&
312
+ !authorization.accountGrant?.permissions.includes(permission)) ||
313
+ (workspaceLiteralPermissions.has(permission) && !grantPermissions.includes(permission)),
59
314
  );
60
315
  if (highTrustMissing.length === 0) return;
61
316
  throw new HTTPException(403, {
@@ -70,6 +325,77 @@ function ensureDelegablePermissions(grantPermissions: Permission[], requested: P
70
325
  }
71
326
  }
72
327
 
328
+ /** Key management is not a way for a policy credential to amplify itself. */
329
+ function ensureOrganizationPolicyDelegable(
330
+ context: AccessContext,
331
+ policy: OrganizationAccessPolicy,
332
+ legacy = false,
333
+ ): void {
334
+ const authority = accountScopedApiKeyWorkspaceAuthority(context);
335
+ const source = context.credential?.policy;
336
+ if (!authority || authority.permissionMode !== "explicit" || !source) return;
337
+ const requested = legacy
338
+ ? Permission.options.filter((permission) => hasPermission(policy.permissions, permission))
339
+ : policy.permissions;
340
+ if (requested.some((permission) => !source.permissions.includes(permission)))
341
+ throw new HTTPException(403, {
342
+ message: "cannot delegate permissions beyond organization key policy",
343
+ });
344
+ if (
345
+ source.workspaceScope.kind === "selected" &&
346
+ (policy.workspaceScope.kind === "all" ||
347
+ policy.workspaceScope.workspaceIds.some(
348
+ (id) => !organizationWorkspaceInScope(source.workspaceScope, id),
349
+ ))
350
+ )
351
+ throw new HTTPException(403, {
352
+ message: "cannot delegate workspaces beyond organization key scope",
353
+ });
354
+ }
355
+
356
+ export function requireOrganizationApiKeyControlPermission(
357
+ context: AccessContext,
358
+ organizationId: string,
359
+ ): void {
360
+ requireApiKeyManagementContext(context);
361
+ requireAccountPermission(context, organizationId, "api_keys:manage");
362
+ if (!context.subjectId.startsWith("api_key:")) return;
363
+ const authority = accountScopedApiKeyWorkspaceAuthority(context);
364
+ if (
365
+ !authority ||
366
+ authority.accountId !== organizationId ||
367
+ (!authority.permissions.includes("api_keys:manage") &&
368
+ !context.accountGrants.some(
369
+ (grant) =>
370
+ grant.accountId === organizationId && grant.permissions.includes("account:admin"),
371
+ ))
372
+ ) {
373
+ throw new HTTPException(403, { message: "organization API key authority required" });
374
+ }
375
+ }
376
+
377
+ async function requireWorkspaceApiKeyControl(
378
+ c: Parameters<typeof requireAccessContext>[0],
379
+ deps: ApiRouteDeps,
380
+ workspaceId: string,
381
+ ): Promise<AccessGrantAuthorization> {
382
+ requireApiKeyManagementContext(await requireAccessContext(c, deps));
383
+ return await requireAccessGrantAuthorization(c, deps, workspaceId, "api_keys:manage");
384
+ }
385
+
386
+ function authenticatedApiKeyId(context: AccessContext): string | null {
387
+ return context.subjectId.startsWith("api_key:")
388
+ ? context.subjectId.slice("api_key:".length)
389
+ : null;
390
+ }
391
+
392
+ function organizationApiKeyLimit(deps: ApiRouteDeps): number | null {
393
+ if (deps.settings.usageLimitsMode !== "static" && deps.settings.usageLimitsMode !== "managed") {
394
+ return null;
395
+ }
396
+ return configuredStaticUsageLimits(deps.settings).maxApiKeysPerWorkspace ?? null;
397
+ }
398
+
73
399
  function generateApiKeyToken(): string {
74
400
  const bytes = new Uint8Array(32);
75
401
  crypto.getRandomValues(bytes);
@@ -0,0 +1,279 @@
1
+ import { resolveFirstPartyDelegationSecret } from "@opengeni/config";
2
+ import {
3
+ ArtifactCatalogItem,
4
+ ArtifactCatalogKind,
5
+ ArtifactCatalogListQuery,
6
+ ArtifactCatalogListResponse,
7
+ retainedArtifactReferenceFromFile,
8
+ retainedGeneratedImageReferenceFromFile,
9
+ type AccessGrant,
10
+ } from "@opengeni/contracts";
11
+ import {
12
+ editableArtifactId,
13
+ editableArtifactScope,
14
+ fileOwnerContextForAccess,
15
+ grantHasAgentAttemptAuthority,
16
+ hasPermission,
17
+ requireAccessGrantAuthorization,
18
+ requireLiveAgentAttemptAuthorization,
19
+ requireSessionAuthorization,
20
+ SessionAuthorizationDeniedError,
21
+ SessionAuthorizationUnavailableError,
22
+ type ApiRouteDeps,
23
+ } from "@opengeni/core";
24
+ import {
25
+ getFilesForSubject,
26
+ getGeneratedImageArtifact,
27
+ getSessionAuthorityProjection,
28
+ listArtifactCatalogCandidates,
29
+ withSessionRlsActorContext,
30
+ type ArtifactCatalogCandidate,
31
+ type ArtifactCatalogPosition,
32
+ type SessionRlsActorContext,
33
+ } from "@opengeni/db";
34
+ import type { Hono } from "hono";
35
+ import { HTTPException } from "hono/http-exception";
36
+ import { artifactCatalogCursorCodec } from "../artifact-catalog-cursor";
37
+ import {
38
+ editableArtifactActorForGrant,
39
+ editableArtifactHttpError,
40
+ isInvisibleListCandidate,
41
+ type EditableArtifactRouteDependencies,
42
+ } from "./editable-artifacts";
43
+ import { fileAuthoritySubjectIdForGrant } from "./files";
44
+
45
+ type Dependencies = ApiRouteDeps & EditableArtifactRouteDependencies;
46
+ const editableKinds = new Set(["document", "spreadsheet", "presentation"]);
47
+ const CANDIDATE_BATCH = 200;
48
+ const MAX_BATCHES = 10;
49
+ const iso = (value: Date | string) => new Date(value).toISOString();
50
+ const position = (row: ArtifactCatalogCandidate): ArtifactCatalogPosition => ({
51
+ key: row.sort_key,
52
+ kind: row.kind,
53
+ id: row.id,
54
+ });
55
+
56
+ export function registerArtifactCatalogRoutes(app: Hono, deps: Dependencies): void {
57
+ app.get("/v1/workspaces/:workspaceId/artifact-catalog", async (context) => {
58
+ const workspaceId = context.req.param("workspaceId");
59
+ const authorization = await requireAccessGrantAuthorization(context, deps, workspaceId);
60
+ const grant = authorization.grant;
61
+ const parsed = ArtifactCatalogListQuery.safeParse(context.req.query());
62
+ if (!parsed.success)
63
+ throw new HTTPException(422, { message: "Invalid artifact catalog query" });
64
+ const query = parsed.data;
65
+ const artifactsAllowed = hasPermission(grant.permissions, "artifacts:read");
66
+ const filesAllowed = hasPermission(grant.permissions, "files:read");
67
+ if (!artifactsAllowed && !filesAllowed)
68
+ throw new HTTPException(403, { message: "Artifact catalog read access required" });
69
+ let kinds = ArtifactCatalogKind.options.filter(
70
+ (kind) =>
71
+ (kind === "image" || kind === "file" ? filesAllowed : artifactsAllowed) &&
72
+ (!query.kind || kind === query.kind),
73
+ );
74
+ if (!deps.editableArtifacts) {
75
+ if (query.kind && editableKinds.has(query.kind) && artifactsAllowed)
76
+ throw new HTTPException(503, { message: "Editable artifacts are unavailable" });
77
+ kinds = kinds.filter((kind) => !editableKinds.has(kind));
78
+ }
79
+ const includesFiles = kinds.includes("file") || kinds.includes("image");
80
+ const actor: SessionRlsActorContext = includesFiles
81
+ ? await fileOwnerContextForAccess(deps, authorization, "files:read")
82
+ : { subjectId: grant.subjectId, privateFileOwnerSubjectId: null };
83
+ // Session visibility follows the frozen live initiator independently of
84
+ // which artifact domains were selected. Never infer it from token labels
85
+ // or require file ownership merely to discover Sites/editable artifacts.
86
+ if (grantHasAgentAttemptAuthority(grant) && actor.initiatingHumanSubjectId === undefined) {
87
+ const callerSessionId = grant.metadata?.["sessionId"];
88
+ try {
89
+ if (typeof callerSessionId !== "string")
90
+ throw new SessionAuthorizationDeniedError("caller_stale");
91
+ const attempt = await requireLiveAgentAttemptAuthorization(deps.db, grant, callerSessionId);
92
+ actor.initiatingHumanSubjectId = attempt.initiatingHumanSubjectId;
93
+ } catch (error) {
94
+ if (error instanceof SessionAuthorizationDeniedError)
95
+ throw new HTTPException(404, { message: "Session not found", cause: error });
96
+ throw error;
97
+ }
98
+ }
99
+ const sourceDecisions = new Map<string, boolean>();
100
+ const canReadSession = async (sessionId: string): Promise<boolean> => {
101
+ if (!hasPermission(grant.permissions, "sessions:read")) return false;
102
+ if (sourceDecisions.has(sessionId)) return sourceDecisions.get(sessionId)!;
103
+ try {
104
+ await requireSessionAuthorization(deps, grant, {
105
+ sessionId,
106
+ operation: "session.read",
107
+ surface: "http",
108
+ });
109
+ // The optional-host seam can return null for both a shared standalone
110
+ // session and an RLS-hidden/missing row. Prove visibility independently
111
+ // AFTER it, so a permissive null is never itself provenance authority.
112
+ if (!(await getSessionAuthorityProjection(deps.db, workspaceId, sessionId))) {
113
+ sourceDecisions.set(sessionId, false);
114
+ return false;
115
+ }
116
+ sourceDecisions.set(sessionId, true);
117
+ return true;
118
+ } catch (error) {
119
+ if (error instanceof SessionAuthorizationDeniedError) {
120
+ sourceDecisions.set(sessionId, false);
121
+ return false;
122
+ }
123
+ if (error instanceof SessionAuthorizationUnavailableError)
124
+ throw new HTTPException(503, { message: "Session authorization is unavailable" });
125
+ throw error;
126
+ }
127
+ };
128
+ context.header("cache-control", "private, no-store");
129
+ return withSessionRlsActorContext(actor, async () => {
130
+ if (query.sourceSessionId && !(await canReadSession(query.sourceSessionId)))
131
+ throw new HTTPException(404, { message: "Session not found" });
132
+ const secret = resolveFirstPartyDelegationSecret(deps.settings);
133
+ if (!secret)
134
+ throw new HTTPException(503, { message: "Artifact catalog cursor signing is unavailable" });
135
+ const filters = { ...query, cursor: undefined };
136
+ const codec = artifactCatalogCursorCodec(
137
+ secret,
138
+ JSON.stringify({
139
+ accountId: grant.accountId,
140
+ workspaceId,
141
+ subjectId: grant.subjectId,
142
+ principalKind: grant.principalKind,
143
+ metadata: grant.metadata,
144
+ permissions: [...grant.permissions].sort(),
145
+ initiatingHumanSubjectId: actor.initiatingHumanSubjectId ?? null,
146
+ owner: actor.privateFileOwnerSubjectId ?? null,
147
+ kinds,
148
+ filters,
149
+ }),
150
+ );
151
+ const prior = query.cursor ? codec.decode(query.cursor) : undefined;
152
+ const snapshotAt = prior?.snapshotAt ?? new Date().toISOString();
153
+ const expiresAt = prior?.expiresAt ?? Date.now() + 60 * 60_000;
154
+ let after = prior?.after;
155
+ const items: ArtifactCatalogItem[] = [];
156
+ let lastReturned: ArtifactCatalogPosition | undefined;
157
+ let nextCursor: string | null = null;
158
+ const fileSubject = includesFiles ? await fileAuthoritySubjectIdForGrant(deps, grant) : null;
159
+ for (let batch = 0; batch < MAX_BATCHES; batch++) {
160
+ const candidates = await listArtifactCatalogCandidates(
161
+ deps.db,
162
+ { accountId: grant.accountId, workspaceId },
163
+ {
164
+ query,
165
+ kinds,
166
+ snapshotAt,
167
+ ...(after ? { after } : {}),
168
+ limit: CANDIDATE_BATCH,
169
+ },
170
+ );
171
+ for (const candidate of candidates) {
172
+ after = position(candidate);
173
+ const item = await projectCandidate(deps, grant, candidate, fileSubject);
174
+ if (
175
+ !item ||
176
+ item.status !== query.status ||
177
+ (query.q && !item.title.toLowerCase().includes(query.q.toLowerCase()))
178
+ )
179
+ continue;
180
+ if (items.length === query.limit) {
181
+ nextCursor = codec.encode({ version: 1, snapshotAt, expiresAt, after: lastReturned! });
182
+ return context.json(ArtifactCatalogListResponse.parse({ items, nextCursor }));
183
+ }
184
+ if (candidate.source_session_id && (await canReadSession(candidate.source_session_id)))
185
+ item.sourceSessionId = candidate.source_session_id;
186
+ items.push(ArtifactCatalogItem.parse(item));
187
+ lastReturned = after;
188
+ }
189
+ if (candidates.length < CANDIDATE_BATCH) break;
190
+ // Bounded scanning may produce an empty page; the encrypted frontier
191
+ // reveals neither denied identity nor provenance and can be continued.
192
+ if (batch === MAX_BATCHES - 1 && after)
193
+ nextCursor = codec.encode({ version: 1, snapshotAt, expiresAt, after });
194
+ }
195
+ return context.json(ArtifactCatalogListResponse.parse({ items, nextCursor }));
196
+ });
197
+ });
198
+ }
199
+
200
+ async function projectCandidate(
201
+ deps: Dependencies,
202
+ grant: AccessGrant,
203
+ row: ArtifactCatalogCandidate,
204
+ fileSubject: string | null,
205
+ ): Promise<ArtifactCatalogItem | null> {
206
+ const item: ArtifactCatalogItem = {
207
+ id: row.id,
208
+ kind: row.kind,
209
+ title: row.title,
210
+ status: row.status,
211
+ createdAt: iso(row.created_at),
212
+ updatedAt: iso(row.updated_at),
213
+ };
214
+ if (row.version_id) item.versionId = row.version_id;
215
+ if (editableKinds.has(row.kind)) {
216
+ const scope = editableArtifactScope({
217
+ accountId: grant.accountId,
218
+ workspaceId: grant.workspaceId,
219
+ });
220
+ try {
221
+ // This is the HTTP application's read-only domain.getArtifact seam, NOT
222
+ // EditableArtifactAgentApplication.read (which touches session links).
223
+ const artifact = await deps.editableArtifacts!.readArtifact({
224
+ scope,
225
+ actor: editableArtifactActorForGrant(grant, "0000000000000001"),
226
+ artifactId: editableArtifactId(row.id),
227
+ });
228
+ if (
229
+ artifact.scope.accountId !== scope.accountId ||
230
+ artifact.scope.workspaceId !== scope.workspaceId ||
231
+ artifact.id !== row.id ||
232
+ artifact.modality !== row.kind
233
+ )
234
+ throw new Error("Artifact application returned mismatched catalog metadata");
235
+ return {
236
+ ...item,
237
+ title: artifact.title,
238
+ status: artifact.lifecycle,
239
+ createdAt: artifact.createdAt,
240
+ updatedAt: artifact.updatedAt,
241
+ };
242
+ } catch (error) {
243
+ if (isInvisibleListCandidate(error)) return null;
244
+ throw editableArtifactHttpError(error);
245
+ }
246
+ }
247
+ if (row.kind === "file" || row.kind === "image") {
248
+ const [file] = await getFilesForSubject(deps.db, {
249
+ accountId: grant.accountId,
250
+ workspaceId: grant.workspaceId,
251
+ subjectId: fileSubject,
252
+ fileIds: [row.id],
253
+ });
254
+ if (!file || file.status !== "ready") return null;
255
+ const generated =
256
+ row.origin === "generated_image"
257
+ ? await getGeneratedImageArtifact(deps.db, grant.workspaceId, row.id)
258
+ : null;
259
+ const reference =
260
+ row.origin === "generated_image"
261
+ ? generated?.status === "ready"
262
+ ? retainedGeneratedImageReferenceFromFile({
263
+ ...file,
264
+ width: generated.width,
265
+ height: generated.height,
266
+ })
267
+ : null
268
+ : retainedArtifactReferenceFromFile(file, "file");
269
+ if (!reference) return null;
270
+ return {
271
+ ...item,
272
+ file: reference,
273
+ filename: file.filename,
274
+ contentType: reference.contentType,
275
+ sizeBytes: file.sizeBytes,
276
+ };
277
+ }
278
+ return item;
279
+ }