@opengeni/api-router 0.30.3 → 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 (434) 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-source-session.d.ts +3 -0
  35. package/dist/editable-artifact-websocket.d.ts +10 -18
  36. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  37. package/dist/fatal-process-boundary.d.ts +25 -0
  38. package/dist/github-access.d.ts +31 -2
  39. package/dist/http/acting-person.d.ts +24 -0
  40. package/dist/http/api-contract-compat.d.ts +19 -0
  41. package/dist/http/api-error.d.ts +27 -1
  42. package/dist/http/cors.d.ts +17 -0
  43. package/dist/http/deprecation.d.ts +42 -0
  44. package/dist/http/interaction-control-error.d.ts +13 -0
  45. package/dist/http/keyed-admission.d.ts +12 -0
  46. package/dist/http/local-browser-boundary.d.ts +72 -0
  47. package/dist/http/metrics-listener.d.ts +22 -0
  48. package/dist/http/path-identifier.d.ts +17 -0
  49. package/dist/http/registered-route-label.d.ts +16 -0
  50. package/dist/http/request-body.d.ts +27 -0
  51. package/dist/http/request-source.d.ts +52 -0
  52. package/dist/http/sse.d.ts +17 -6
  53. package/dist/http/unmatched-route.d.ts +18 -0
  54. package/dist/http/user-content.d.ts +36 -0
  55. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  56. package/dist/index.d.ts +10 -3
  57. package/dist/index.js +1091 -162
  58. package/dist/index.js.map +1 -1
  59. package/dist/integration-endpoint-test.d.ts +20 -0
  60. package/dist/integrations/api-integrations.d.ts +2 -2
  61. package/dist/integrations/atlassian.d.ts +29 -3
  62. package/dist/integrations/connect-authority.d.ts +1 -0
  63. package/dist/integrations/connect-callback-return.d.ts +6 -0
  64. package/dist/integrations/fiken.d.ts +16 -2
  65. package/dist/integrations/github-app-connect.d.ts +47 -0
  66. package/dist/integrations/github-installation-proof.d.ts +3 -0
  67. package/dist/integrations/github-lens-connect.d.ts +116 -0
  68. package/dist/integrations/github-skill-source.d.ts +1 -5
  69. package/dist/integrations/google-drive.d.ts +24 -0
  70. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  71. package/dist/integrations/marketplace-plugin.d.ts +2691 -0
  72. package/dist/integrations/oauth-client.d.ts +178 -18
  73. package/dist/integrations/oauth-profiles.d.ts +222 -0
  74. package/dist/integrations/oauth-return-path.d.ts +1 -0
  75. package/dist/integrations/personal-github-repositories.d.ts +84 -0
  76. package/dist/integrations/personal-github.d.ts +42 -0
  77. package/dist/integrations/pr-review-provider.d.ts +22 -0
  78. package/dist/integrations/provider-oauth.d.ts +19 -1
  79. package/dist/integrations/slack-app-home.d.ts +24 -0
  80. package/dist/integrations/slack-bot.d.ts +367 -12
  81. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  82. package/dist/integrations/slack-install.d.ts +20 -0
  83. package/dist/integrations/slack-interactions.d.ts +107 -9
  84. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  85. package/dist/integrations/slack-routing.d.ts +120 -0
  86. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  87. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  88. package/dist/integrations/social-oauth.d.ts +7 -0
  89. package/dist/interaction-agent-access.d.ts +15 -0
  90. package/dist/interaction-frame-proxy.d.ts +68 -0
  91. package/dist/interaction-metrics.d.ts +2 -0
  92. package/dist/mcp/action-catalog-types.d.ts +9 -0
  93. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  94. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  95. package/dist/mcp/child-read-evidence.d.ts +9 -0
  96. package/dist/mcp/command-read.d.ts +24 -0
  97. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  98. package/dist/mcp/contract-input.d.ts +11 -0
  99. package/dist/mcp/documents.d.ts +7 -5
  100. package/dist/mcp/files.d.ts +2 -2
  101. package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
  102. package/dist/mcp/knowledge-entries.d.ts +5 -0
  103. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  104. package/dist/mcp/receipts.d.ts +9 -0
  105. package/dist/mcp/request-abort.d.ts +19 -0
  106. package/dist/mcp/scheduled-task-input.d.ts +1189 -0
  107. package/dist/mcp/scheduled-task-view.d.ts +22 -4
  108. package/dist/mcp/server.d.ts +255 -3
  109. package/dist/mcp/session-event-view.d.ts +94 -0
  110. package/dist/mcp/session-view.d.ts +66 -2
  111. package/dist/mcp/session-wait.d.ts +174 -0
  112. package/dist/mcp-oauth.d.ts +52 -0
  113. package/dist/model-catalog.d.ts +11 -31
  114. package/dist/observability.d.ts +3 -1
  115. package/dist/organization-mcp.d.ts +52 -0
  116. package/dist/organization-recovery-notifications.d.ts +41 -0
  117. package/dist/routes/analytics-consent.d.ts +26 -0
  118. package/dist/routes/api-integrations.d.ts +25 -0
  119. package/dist/routes/api-keys.d.ts +17 -0
  120. package/dist/routes/artifact-catalog.d.ts +6 -0
  121. package/dist/routes/automations.d.ts +19 -0
  122. package/dist/routes/billing.d.ts +49 -0
  123. package/dist/routes/browser-sessions.d.ts +59 -2
  124. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  125. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  126. package/dist/routes/client-errors.d.ts +146 -0
  127. package/dist/routes/codex.d.ts +76 -2
  128. package/dist/routes/company-brain.d.ts +3 -0
  129. package/dist/routes/company-profile.d.ts +2 -1
  130. package/dist/routes/computer-sessions.d.ts +14 -0
  131. package/dist/routes/connect.d.ts +5 -0
  132. package/dist/routes/editable-artifacts.d.ts +2 -0
  133. package/dist/routes/external-identity-links.d.ts +6 -0
  134. package/dist/routes/feedback.d.ts +3 -0
  135. package/dist/routes/github-browser-pages.d.ts +12 -0
  136. package/dist/routes/github.d.ts +2 -0
  137. package/dist/routes/insights-response-cache.d.ts +10 -0
  138. package/dist/routes/insights-usage.d.ts +12 -0
  139. package/dist/routes/insights.d.ts +30 -1
  140. package/dist/routes/knowledge.d.ts +3 -0
  141. package/dist/routes/managed-auth-session-sets.d.ts +26 -0
  142. package/dist/routes/managed-onboarding.d.ts +29 -0
  143. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  144. package/dist/routes/model-connection-access.d.ts +3 -0
  145. package/dist/routes/organization-integration-policy.d.ts +3 -0
  146. package/dist/routes/organization-integrations.d.ts +6 -0
  147. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  148. package/dist/routes/organization-model-providers.d.ts +3 -0
  149. package/dist/routes/organization-recovery.d.ts +19 -0
  150. package/dist/routes/organization-service-accounts.d.ts +3 -0
  151. package/dist/routes/organization-sessions.d.ts +26 -0
  152. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  153. package/dist/routes/personal-github.d.ts +3 -0
  154. package/dist/routes/pr-review-github.d.ts +3 -0
  155. package/dist/routes/pr-review.d.ts +3 -0
  156. package/dist/routes/session-artifact-associations.d.ts +4 -0
  157. package/dist/routes/session-history-imports.d.ts +9 -0
  158. package/dist/routes/sessions.d.ts +44 -6
  159. package/dist/routes/skill-content.d.ts +4 -0
  160. package/dist/routes/skill-install-authority.d.ts +6 -0
  161. package/dist/routes/subscription-account-pools.d.ts +34 -0
  162. package/dist/routes/subscription-pool-access.d.ts +16 -0
  163. package/dist/routes/supergrok.d.ts +6 -1
  164. package/dist/routes/usage-allowances.d.ts +12 -0
  165. package/dist/routes/user-resource-authorities.d.ts +3 -0
  166. package/dist/routes/workspace-artifacts.d.ts +2 -1
  167. package/dist/routes/workspace-capture.d.ts +10 -2
  168. package/dist/routes/workspace-integrations.d.ts +35 -0
  169. package/dist/routes/workspace-learning.d.ts +3 -0
  170. package/dist/routes/workspace-model-providers.d.ts +4 -0
  171. package/dist/routes/workspaces.d.ts +29 -0
  172. package/dist/sandbox/auth-callout.d.ts +8 -0
  173. package/dist/sandbox/channel-a.d.ts +19 -1
  174. package/dist/sandbox/connection-authority.d.ts +3 -0
  175. package/dist/sandbox/enrollment.d.ts +9 -1
  176. package/dist/sandbox/machines.d.ts +5 -2
  177. package/dist/sandbox/metrics-ingestion.d.ts +28 -20
  178. package/dist/sandbox/rematerialize.d.ts +2 -0
  179. package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
  180. package/dist/sandbox/viewer.d.ts +26 -1
  181. package/dist/sandbox-file-artifacts.d.ts +50 -0
  182. package/dist/scheduled-task-deletion.d.ts +13 -0
  183. package/dist/session-create-observability.d.ts +5 -0
  184. package/dist/session-event-view-MPS2OZD3.js +292 -0
  185. package/dist/session-event-view-MPS2OZD3.js.map +1 -0
  186. package/dist/site-session-origin.d.ts +13 -0
  187. package/dist/site-uploads.d.ts +41 -0
  188. package/dist/slack-reaction-files.d.ts +1 -1
  189. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  190. package/dist/temporal-schedule-sync.d.ts +26 -0
  191. package/dist/transcription/providers/xai-subscription.d.ts +1 -0
  192. package/dist/transcription/service.d.ts +2 -1
  193. package/dist/work-discovery-observability.d.ts +33 -0
  194. package/dist/workspace-artifact-content.d.ts +28 -0
  195. package/dist/workspace-artifact-provenance.d.ts +7 -0
  196. package/dist/workspace-delete-observability.d.ts +10 -0
  197. package/dist/workspace-deletion.d.ts +6 -0
  198. package/dist/workspace-state-projection.d.ts +3 -5
  199. package/dist/workspace-tool-gateway-observability.d.ts +17 -0
  200. package/dist/workspace-tool-gateway.d.ts +123 -0
  201. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  202. package/package.json +23 -19
  203. package/src/access-grant-rls.ts +75 -0
  204. package/src/admission-trace.ts +14 -0
  205. package/src/api-websocket.ts +23 -0
  206. package/src/app.ts +1967 -252
  207. package/src/artifact-catalog-cursor.ts +60 -0
  208. package/src/auth/managed-auth-attempt-context.ts +70 -0
  209. package/src/auth/managed-auth-rate-limits.ts +252 -0
  210. package/src/auth/managed-auth-session-adapter.ts +222 -0
  211. package/src/auth/managed-auth.ts +536 -60
  212. package/src/auth/managed-email.ts +174 -0
  213. package/src/auth/managed-sign-in-notifications.ts +81 -0
  214. package/src/auth/new-signups-gate.ts +49 -0
  215. package/src/auth/organization-user-setup.ts +307 -0
  216. package/src/auth/signup-funnel-metrics.ts +164 -0
  217. package/src/browser-controller-authority.ts +1 -186
  218. package/src/browser-ephemeral.ts +39 -0
  219. package/src/browser-state-authority.ts +1 -236
  220. package/src/claude-subscription-account-conflicts.ts +12 -0
  221. package/src/claude-subscription-account-usage.ts +48 -0
  222. package/src/claude-subscription-oauth.ts +362 -0
  223. package/src/claude-subscription-profile.ts +73 -0
  224. package/src/claude-subscription-usage.ts +97 -0
  225. package/src/claude-workspace-connection.ts +82 -0
  226. package/src/codemode.ts +194 -30
  227. package/src/codex-realtime.ts +8 -2
  228. package/src/company-brain-okf.ts +340 -0
  229. package/src/connected-machine-computer-access.ts +33 -0
  230. package/src/connection-ownership.ts +199 -0
  231. package/src/controller-data-plane.ts +81 -0
  232. package/src/editable-artifact-native-kernel.ts +26 -15
  233. package/src/editable-artifact-office-import.ts +28 -3
  234. package/src/editable-artifact-production.ts +23 -7
  235. package/src/editable-artifact-source-session.ts +123 -0
  236. package/src/editable-artifact-websocket.ts +27 -21
  237. package/src/editable-artifact-workspace-files.ts +31 -6
  238. package/src/fatal-process-boundary.ts +246 -0
  239. package/src/gateway-realtime.ts +1 -1
  240. package/src/github-access.ts +147 -5
  241. package/src/http/acting-person.ts +71 -0
  242. package/src/http/api-contract-compat.ts +49 -0
  243. package/src/http/api-error.ts +115 -1
  244. package/src/http/auth.ts +48 -0
  245. package/src/http/cors.ts +67 -0
  246. package/src/http/deprecation.ts +118 -0
  247. package/src/http/interaction-control-error.ts +164 -0
  248. package/src/http/keyed-admission.ts +29 -0
  249. package/src/http/local-browser-boundary.ts +343 -0
  250. package/src/http/metrics-listener.ts +57 -0
  251. package/src/http/path-identifier.ts +54 -0
  252. package/src/http/registered-route-label.ts +34 -0
  253. package/src/http/request-body.ts +127 -0
  254. package/src/http/request-source.ts +178 -0
  255. package/src/http/sse.ts +486 -132
  256. package/src/http/unmatched-route.ts +60 -0
  257. package/src/http/user-content.ts +158 -0
  258. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  259. package/src/index.ts +157 -52
  260. package/src/integration-endpoint-test.ts +291 -0
  261. package/src/integrations/api-integrations.ts +98 -11
  262. package/src/integrations/atlassian.ts +474 -136
  263. package/src/integrations/connect-authority.ts +2 -0
  264. package/src/integrations/connect-callback-return.ts +86 -0
  265. package/src/integrations/fiken.ts +354 -64
  266. package/src/integrations/github-app-connect.ts +435 -0
  267. package/src/integrations/github-installation-proof.ts +60 -0
  268. package/src/integrations/github-lens-connect.ts +76 -0
  269. package/src/integrations/github-skill-source.ts +2 -142
  270. package/src/integrations/google-drive.ts +717 -225
  271. package/src/integrations/integration-commit-authority.ts +69 -0
  272. package/src/integrations/marketplace-plugin.ts +48 -0
  273. package/src/integrations/oauth-client.ts +1356 -459
  274. package/src/integrations/oauth-profiles.ts +537 -0
  275. package/src/integrations/oauth-return-path.ts +18 -0
  276. package/src/integrations/personal-github-repositories.ts +674 -0
  277. package/src/integrations/personal-github.ts +825 -0
  278. package/src/integrations/pr-review-provider.ts +246 -0
  279. package/src/integrations/provider-oauth.ts +250 -22
  280. package/src/integrations/slack-app-home.ts +300 -0
  281. package/src/integrations/slack-bot.ts +963 -239
  282. package/src/integrations/slack-file-upload-flow.ts +147 -0
  283. package/src/integrations/slack-install.ts +83 -0
  284. package/src/integrations/slack-interactions.ts +3167 -474
  285. package/src/integrations/slack-mrkdwn.ts +193 -0
  286. package/src/integrations/slack-routing.ts +337 -0
  287. package/src/integrations/slack-session-defaults.ts +224 -0
  288. package/src/integrations/slack-task-file-upload.ts +323 -0
  289. package/src/integrations/social-oauth.ts +213 -15
  290. package/src/interaction-agent-access.ts +48 -0
  291. package/src/interaction-frame-proxy.ts +409 -0
  292. package/src/interaction-metrics.ts +30 -0
  293. package/src/mcp/action-catalog-types.ts +9 -0
  294. package/src/mcp/action-catalog.gen.ts +6696 -0
  295. package/src/mcp/capability-account-readiness.ts +17 -0
  296. package/src/mcp/child-read-evidence.ts +19 -0
  297. package/src/mcp/command-read.ts +109 -0
  298. package/src/mcp/company-profile-agent-admin.ts +198 -0
  299. package/src/mcp/contract-input.ts +141 -0
  300. package/src/mcp/documents.ts +65 -377
  301. package/src/mcp/editable-artifacts.ts +12 -6
  302. package/src/mcp/files.ts +80 -43
  303. package/src/mcp/first-party-tool-permissions.ts +305 -0
  304. package/src/mcp/knowledge-entries.ts +322 -0
  305. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  306. package/src/mcp/receipts.ts +34 -0
  307. package/src/mcp/request-abort.ts +44 -0
  308. package/src/mcp/scheduled-task-input.ts +76 -0
  309. package/src/mcp/scheduled-task-view.ts +44 -3
  310. package/src/mcp/server.ts +3030 -1267
  311. package/src/mcp/session-event-view.ts +383 -0
  312. package/src/mcp/session-view.ts +84 -3
  313. package/src/mcp/session-wait.ts +665 -0
  314. package/src/mcp-oauth.ts +1123 -0
  315. package/src/model-catalog.ts +91 -333
  316. package/src/observability.ts +15 -1
  317. package/src/organization-mcp.ts +397 -0
  318. package/src/organization-recovery-notifications.ts +103 -0
  319. package/src/routes/analytics-consent.ts +123 -0
  320. package/src/routes/api-integrations.ts +364 -74
  321. package/src/routes/api-keys.ts +336 -10
  322. package/src/routes/artifact-catalog.ts +279 -0
  323. package/src/routes/automations.ts +768 -0
  324. package/src/routes/billing.ts +461 -46
  325. package/src/routes/browser-sessions.ts +780 -112
  326. package/src/routes/canonical-human-identities.ts +90 -14
  327. package/src/routes/capabilities.ts +107 -6
  328. package/src/routes/channels.ts +20 -3
  329. package/src/routes/claude-subscription-accounts.ts +334 -0
  330. package/src/routes/claude-subscription-oauth.ts +142 -0
  331. package/src/routes/client-errors.ts +362 -0
  332. package/src/routes/codex.ts +833 -116
  333. package/src/routes/company-brain.ts +322 -0
  334. package/src/routes/company-profile.ts +65 -1
  335. package/src/routes/computer-sessions.ts +557 -106
  336. package/src/routes/connect.ts +1938 -0
  337. package/src/routes/connections.ts +1039 -349
  338. package/src/routes/documents.ts +488 -287
  339. package/src/routes/editable-artifacts.ts +79 -9
  340. package/src/routes/enrollments.ts +135 -39
  341. package/src/routes/environments.ts +154 -58
  342. package/src/routes/external-identity-links.ts +201 -0
  343. package/src/routes/feedback.ts +113 -0
  344. package/src/routes/files.ts +267 -33
  345. package/src/routes/github-browser-pages.ts +162 -0
  346. package/src/routes/github.ts +446 -144
  347. package/src/routes/insights-response-cache.ts +83 -0
  348. package/src/routes/insights-usage.ts +345 -0
  349. package/src/routes/insights.ts +153 -19
  350. package/src/routes/install.ts +133 -38
  351. package/src/routes/integration-facets.ts +107 -33
  352. package/src/routes/interaction-resources.ts +30 -3
  353. package/src/routes/knowledge.ts +488 -0
  354. package/src/routes/machines.ts +313 -15
  355. package/src/routes/managed-auth-session-sets.ts +1218 -0
  356. package/src/routes/managed-onboarding.ts +337 -0
  357. package/src/routes/managed-sign-in-methods.ts +433 -0
  358. package/src/routes/memory-slack-publications.ts +3 -2
  359. package/src/routes/model-connection-access.ts +208 -0
  360. package/src/routes/organization-integration-policy.ts +116 -0
  361. package/src/routes/organization-integrations.ts +326 -0
  362. package/src/routes/organization-mcp-connections.ts +178 -0
  363. package/src/routes/organization-memberships.ts +1019 -27
  364. package/src/routes/organization-model-providers.ts +293 -0
  365. package/src/routes/organization-recovery.ts +325 -0
  366. package/src/routes/organization-service-accounts.ts +128 -0
  367. package/src/routes/organization-sessions.ts +350 -0
  368. package/src/routes/personal-github-git-broker.ts +785 -0
  369. package/src/routes/personal-github.ts +370 -0
  370. package/src/routes/plugins.ts +251 -22
  371. package/src/routes/pr-review-github.ts +881 -0
  372. package/src/routes/pr-review.ts +622 -0
  373. package/src/routes/preference-registry.ts +12 -93
  374. package/src/routes/rigs.ts +167 -50
  375. package/src/routes/scheduled-tasks.ts +346 -41
  376. package/src/routes/session-artifact-associations.ts +87 -0
  377. package/src/routes/session-history-imports.ts +280 -0
  378. package/src/routes/sessions.ts +2306 -264
  379. package/src/routes/skill-content.ts +297 -0
  380. package/src/routes/skill-install-authority.ts +64 -0
  381. package/src/routes/skills.ts +62 -9
  382. package/src/routes/social.ts +46 -18
  383. package/src/routes/subscription-account-pools.ts +436 -0
  384. package/src/routes/subscription-pool-access.ts +126 -0
  385. package/src/routes/supergrok.ts +219 -303
  386. package/src/routes/transcription-recordings.ts +38 -3
  387. package/src/routes/transcriptions.ts +4 -0
  388. package/src/routes/usage-allowances.ts +378 -0
  389. package/src/routes/user-resource-authorities.ts +138 -0
  390. package/src/routes/video-generation.ts +14 -10
  391. package/src/routes/workspace-artifacts.ts +275 -69
  392. package/src/routes/workspace-capture.ts +21 -0
  393. package/src/routes/workspace-integrations.ts +576 -0
  394. package/src/routes/workspace-learning.ts +159 -0
  395. package/src/routes/workspace-model-providers.ts +148 -0
  396. package/src/routes/workspace-state.ts +38 -25
  397. package/src/routes/workspaces.ts +1004 -127
  398. package/src/sandbox/auth-callout.ts +96 -19
  399. package/src/sandbox/channel-a.ts +323 -24
  400. package/src/sandbox/connection-authority.ts +3 -0
  401. package/src/sandbox/enrollment.ts +81 -6
  402. package/src/sandbox/machines.ts +218 -76
  403. package/src/sandbox/metrics-ingestion.ts +411 -62
  404. package/src/sandbox/rematerialize.ts +121 -19
  405. package/src/sandbox/session-attach-variable-sets.ts +131 -0
  406. package/src/sandbox/viewer.ts +280 -25
  407. package/src/sandbox-file-artifacts.ts +413 -0
  408. package/src/scheduled-task-deletion.ts +138 -0
  409. package/src/session-create-observability.ts +46 -0
  410. package/src/session-realtime-context.ts +6 -3
  411. package/src/site-session-origin.ts +48 -0
  412. package/src/site-uploads.ts +224 -0
  413. package/src/slack-reaction-files.ts +16 -5
  414. package/src/temporal-schedule-cleanup.ts +13 -0
  415. package/src/temporal-schedule-sync.ts +74 -0
  416. package/src/transcription/providers/codex-subscription.ts +2 -0
  417. package/src/transcription/providers/openai.ts +1 -0
  418. package/src/transcription/providers/xai-subscription.ts +49 -3
  419. package/src/transcription/segmenter.ts +8 -2
  420. package/src/transcription/service.ts +43 -6
  421. package/src/work-discovery-observability.ts +121 -0
  422. package/src/workspace-artifact-content.ts +144 -0
  423. package/src/workspace-artifact-provenance.ts +104 -0
  424. package/src/workspace-delete-observability.ts +75 -0
  425. package/src/workspace-deletion.ts +73 -0
  426. package/src/workspace-state-projection.ts +18 -148
  427. package/src/workspace-tool-gateway-observability.ts +100 -0
  428. package/src/workspace-tool-gateway.ts +870 -0
  429. package/src/workspace-webhook-dispatch.ts +190 -0
  430. package/src/xai-subscription-auth.ts +9 -2
  431. package/dist/chunk-WCXHI3FF.js +0 -49920
  432. package/dist/chunk-WCXHI3FF.js.map +0 -1
  433. package/dist/routes/packs.d.ts +0 -3
  434. package/src/routes/packs.ts +0 -729
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  CreateVariableSetRequest,
3
+ ResolveVariableSetAttachmentsRequest,
4
+ ResolveVariableSetAttachmentsResponse,
3
5
  SetVariableSetVariableRequest,
4
6
  UpdateVariableSetRequest,
5
7
  VariableSetVariableName,
6
8
  } from "@opengeni/contracts";
7
9
  import {
8
- countActiveSessionsUsingVariableSet,
9
- countScheduledTasksUsingVariableSet,
10
10
  countVariableSets,
11
11
  createVariableSet,
12
12
  decryptVariableSetValue,
@@ -16,12 +16,19 @@ import {
16
16
  getVariableSetByName,
17
17
  listVariableSets,
18
18
  readVariableSetSecretAtomically,
19
+ resolveVariableSetAttachments,
19
20
  setVariableSetVariable,
20
21
  updateVariableSet,
22
+ VariableSetAttachedError,
21
23
  } from "@opengeni/db";
22
24
  import type { Hono } from "hono";
23
25
  import { HTTPException } from "hono/http-exception";
24
- import { requireAccessGrant, requireLiteralPermission, requirePermission } from "@opengeni/core";
26
+ import {
27
+ requireAccessGrant,
28
+ requireAccessGrantAuthorization,
29
+ requireLiteralPermission,
30
+ requirePermission,
31
+ } from "@opengeni/core";
25
32
  import type { ApiRouteDeps } from "@opengeni/core";
26
33
  import {
27
34
  assertAllowedVariableSetVariableName,
@@ -31,6 +38,7 @@ import {
31
38
  requireVariableSetEncryption,
32
39
  requireVariableSetForApi,
33
40
  } from "@opengeni/core";
41
+ import { parseRequestJson } from "../http/request-body";
34
42
 
35
43
  export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
36
44
  const { settings, db } = deps;
@@ -45,15 +53,35 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
45
53
  const grant = await requireAccessGrant(c, deps, workspaceId);
46
54
  requirePermission(grant, "variable-sets:list");
47
55
  requirePermission(grant, "secrets:list");
48
- return c.json(await listVariableSets(db, workspaceId));
56
+ return c.json(
57
+ await listVariableSets(db, {
58
+ accountId: grant.accountId,
59
+ workspaceId,
60
+ subjectId: grant.subjectId,
61
+ }),
62
+ );
49
63
  });
50
64
 
51
65
  app.post(`${prefix}`, async (c) => {
52
66
  const workspaceId = c.req.param("workspaceId")!;
53
- const grant = await requireAccessGrant(c, deps, workspaceId);
67
+ const authorization = await requireAccessGrantAuthorization(c, deps, workspaceId);
68
+ const grant = authorization.grant;
54
69
  requirePermission(grant, "variable-sets:write");
55
70
  const key = requireVariableSetEncryption(settings);
56
- const payload = CreateVariableSetRequest.parse(await c.req.json());
71
+ const payload = await parseRequestJson(c, CreateVariableSetRequest);
72
+ if (prefix.endsWith("/environments") && payload.scope !== "workspace") {
73
+ throw new HTTPException(422, {
74
+ message: "the legacy environments route only creates workspace-scoped variable sets",
75
+ });
76
+ }
77
+ if (
78
+ payload.scope === "organization" &&
79
+ authorization.accountGrant?.permissions.includes("account:admin") !== true
80
+ ) {
81
+ throw new HTTPException(403, {
82
+ message: "missing permission: account:admin",
83
+ });
84
+ }
57
85
  if (payload.variables.length > 0) {
58
86
  requirePermission(grant, "secrets:write");
59
87
  }
@@ -73,12 +101,17 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
73
101
  }
74
102
  variableNames.add(variable.name);
75
103
  }
76
- if ((await countVariableSets(db, workspaceId)) >= MAX_ENVIRONMENTS_PER_WORKSPACE) {
104
+ const access = {
105
+ accountId: grant.accountId,
106
+ workspaceId,
107
+ subjectId: grant.subjectId,
108
+ };
109
+ if ((await countVariableSets(db, access, payload.scope)) >= MAX_ENVIRONMENTS_PER_WORKSPACE) {
77
110
  throw new HTTPException(422, {
78
111
  message: `a workspace supports at most ${MAX_ENVIRONMENTS_PER_WORKSPACE} variable sets`,
79
112
  });
80
113
  }
81
- if (await getVariableSetByName(db, workspaceId, name)) {
114
+ if (await getVariableSetByName(db, access, name, payload.scope)) {
82
115
  throw new HTTPException(409, {
83
116
  message: `variable set name is already in use: ${name}`,
84
117
  });
@@ -88,6 +121,9 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
88
121
  const created = await createVariableSet(db, {
89
122
  accountId: grant.accountId,
90
123
  workspaceId,
124
+ scope: payload.scope,
125
+ subjectId: grant.subjectId,
126
+ allowOrganization: payload.scope === "organization",
91
127
  name,
92
128
  description: payload.description ?? null,
93
129
  variables: payload.variables.map((variable) => ({
@@ -103,12 +139,32 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
103
139
  return c.json(created, 201);
104
140
  });
105
141
 
142
+ if (prefix.endsWith("/variable-sets")) {
143
+ app.post(`${prefix}/resolve-attachments`, async (c) => {
144
+ const workspaceId = c.req.param("workspaceId")!;
145
+ const grant = await requireAccessGrant(c, deps, workspaceId);
146
+ requirePermission(grant, "variable-sets:attach");
147
+ requirePermission(grant, "variable-sets:use");
148
+ const payload = await parseRequestJson(c, ResolveVariableSetAttachmentsRequest);
149
+ const variableSets = await resolveVariableSetAttachments(
150
+ db,
151
+ {
152
+ accountId: grant.accountId,
153
+ workspaceId,
154
+ subjectId: grant.subjectId,
155
+ },
156
+ payload.variableSetIds,
157
+ );
158
+ return c.json(ResolveVariableSetAttachmentsResponse.parse({ variableSets }));
159
+ });
160
+ }
161
+
106
162
  app.get(`${prefix}/:variableSetId`, async (c) => {
107
163
  const workspaceId = c.req.param("workspaceId")!;
108
164
  const grant = await requireAccessGrant(c, deps, workspaceId);
109
165
  requirePermission(grant, "variable-sets:read");
110
166
  requirePermission(grant, "secrets:list");
111
- return c.json(await requireVariableSetForApi(db, workspaceId, c.req.param("variableSetId")!));
167
+ return c.json(await requireVariableSetForApi(db, grant, c.req.param("variableSetId")!));
112
168
  });
113
169
 
114
170
  if (prefix.endsWith("/variable-sets")) {
@@ -139,27 +195,47 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
139
195
 
140
196
  app.patch(`${prefix}/:variableSetId`, async (c) => {
141
197
  const workspaceId = c.req.param("workspaceId")!;
142
- const grant = await requireAccessGrant(c, deps, workspaceId);
198
+ const authorization = await requireAccessGrantAuthorization(c, deps, workspaceId);
199
+ const grant = authorization.grant;
143
200
  requirePermission(grant, "variable-sets:write");
144
- const variableSet = await requireVariableSetForApi(
145
- db,
146
- workspaceId,
147
- c.req.param("variableSetId")!,
148
- );
149
- const payload = UpdateVariableSetRequest.parse(await c.req.json());
201
+ const variableSet = await requireVariableSetForApi(db, grant, c.req.param("variableSetId")!);
202
+ const allowOrganization =
203
+ variableSet.scope === "organization" &&
204
+ authorization.accountGrant?.permissions.includes("account:admin") === true;
205
+ if (variableSet.scope === "organization" && !allowOrganization) {
206
+ throw new HTTPException(403, {
207
+ message: "missing permission: account:admin",
208
+ });
209
+ }
210
+ const payload = await parseRequestJson(c, UpdateVariableSetRequest);
150
211
  const name = payload.name !== undefined ? trimmedVariableSetName(payload.name) : undefined;
151
212
  if (name !== undefined && name !== variableSet.name) {
152
- const existing = await getVariableSetByName(db, workspaceId, name);
213
+ const existing = await getVariableSetByName(
214
+ db,
215
+ {
216
+ accountId: grant.accountId,
217
+ workspaceId,
218
+ subjectId: grant.subjectId,
219
+ },
220
+ name,
221
+ variableSet.scope,
222
+ );
153
223
  if (existing && existing.id !== variableSet.id) {
154
224
  throw new HTTPException(409, {
155
225
  message: `variable set name is already in use: ${name}`,
156
226
  });
157
227
  }
158
228
  }
159
- const updated = await updateVariableSet(db, workspaceId, variableSet.id, {
160
- ...(name !== undefined ? { name } : {}),
161
- ...(payload.description !== undefined ? { description: payload.description } : {}),
162
- });
229
+ const updated = await updateVariableSet(
230
+ db,
231
+ { accountId: grant.accountId, workspaceId, subjectId: grant.subjectId },
232
+ variableSet.id,
233
+ {
234
+ ...(name !== undefined ? { name } : {}),
235
+ ...(payload.description !== undefined ? { description: payload.description } : {}),
236
+ allowOrganization,
237
+ },
238
+ );
163
239
  await recordVariableSetAuditEvent(db, {
164
240
  grant,
165
241
  action: "variable_set.updated",
@@ -170,35 +246,36 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
170
246
 
171
247
  app.delete(`${prefix}/:variableSetId`, async (c) => {
172
248
  const workspaceId = c.req.param("workspaceId")!;
173
- const grant = await requireAccessGrant(c, deps, workspaceId);
249
+ const authorization = await requireAccessGrantAuthorization(c, deps, workspaceId);
250
+ const grant = authorization.grant;
174
251
  requirePermission(grant, "variable-sets:write");
175
252
  requirePermission(grant, "secrets:write");
176
- const variableSet = await requireVariableSetForApi(
177
- db,
178
- workspaceId,
179
- c.req.param("variableSetId")!,
180
- );
181
- const attachedTasks = await countScheduledTasksUsingVariableSet(
182
- db,
183
- workspaceId,
184
- variableSet.id,
185
- );
186
- if (attachedTasks > 0) {
187
- throw new HTTPException(409, {
188
- message: `variable set is attached to ${attachedTasks} scheduled task(s); detach first`,
253
+ const variableSet = await requireVariableSetForApi(db, grant, c.req.param("variableSetId")!);
254
+ const allowOrganization =
255
+ variableSet.scope === "organization" &&
256
+ authorization.accountGrant?.permissions.includes("account:admin") === true;
257
+ if (variableSet.scope === "organization" && !allowOrganization) {
258
+ throw new HTTPException(403, {
259
+ message: "missing permission: account:admin",
189
260
  });
190
261
  }
191
- const activeSessions = await countActiveSessionsUsingVariableSet(
192
- db,
193
- workspaceId,
194
- variableSet.id,
195
- );
196
- if (activeSessions > 0) {
197
- throw new HTTPException(409, {
198
- message: `variable set is attached to ${activeSessions} active session(s); wait for them to finish or cancel them first`,
199
- });
262
+ try {
263
+ await deleteVariableSet(
264
+ db,
265
+ {
266
+ accountId: grant.accountId,
267
+ workspaceId,
268
+ subjectId: grant.subjectId,
269
+ },
270
+ variableSet.id,
271
+ { allowOrganization },
272
+ );
273
+ } catch (error) {
274
+ if (error instanceof VariableSetAttachedError) {
275
+ throw new HTTPException(409, { message: error.message });
276
+ }
277
+ throw error;
200
278
  }
201
- await deleteVariableSet(db, workspaceId, variableSet.id);
202
279
  await recordVariableSetAuditEvent(db, {
203
280
  grant,
204
281
  action: "variable_set.deleted",
@@ -209,17 +286,22 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
209
286
 
210
287
  app.put(`${prefix}/:variableSetId/variables/:name`, async (c) => {
211
288
  const workspaceId = c.req.param("workspaceId")!;
212
- const grant = await requireAccessGrant(c, deps, workspaceId);
289
+ const authorization = await requireAccessGrantAuthorization(c, deps, workspaceId);
290
+ const grant = authorization.grant;
213
291
  requirePermission(grant, "variable-sets:write");
214
292
  requirePermission(grant, "secrets:write");
215
293
  const key = requireVariableSetEncryption(settings);
216
294
  const name = parseVariableName(c.req.param("name")!);
217
- const variableSet = await requireVariableSetForApi(
218
- db,
219
- workspaceId,
220
- c.req.param("variableSetId")!,
221
- );
222
- const payload = SetVariableSetVariableRequest.parse(await c.req.json());
295
+ const variableSet = await requireVariableSetForApi(db, grant, c.req.param("variableSetId")!);
296
+ const allowOrganization =
297
+ variableSet.scope === "organization" &&
298
+ authorization.accountGrant?.permissions.includes("account:admin") === true;
299
+ if (variableSet.scope === "organization" && !allowOrganization) {
300
+ throw new HTTPException(403, {
301
+ message: "missing permission: account:admin",
302
+ });
303
+ }
304
+ const payload = await parseRequestJson(c, SetVariableSetVariableRequest);
223
305
  const exists = variableSet.variables.some((variable) => variable.name === name);
224
306
  if (!exists && variableSet.variables.length >= MAX_VARIABLES_PER_ENVIRONMENT) {
225
307
  throw new HTTPException(422, {
@@ -229,9 +311,11 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
229
311
  const metadata = await setVariableSetVariable(db, {
230
312
  accountId: grant.accountId,
231
313
  workspaceId,
314
+ subjectId: grant.subjectId,
232
315
  variableSetId: variableSet.id,
233
316
  name,
234
317
  valueEncrypted: encryptVariableSetValue(key, payload.value),
318
+ allowOrganization,
235
319
  });
236
320
  await recordVariableSetAuditEvent(db, {
237
321
  grant,
@@ -244,16 +328,28 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
244
328
 
245
329
  app.delete(`${prefix}/:variableSetId/variables/:name`, async (c) => {
246
330
  const workspaceId = c.req.param("workspaceId")!;
247
- const grant = await requireAccessGrant(c, deps, workspaceId);
331
+ const authorization = await requireAccessGrantAuthorization(c, deps, workspaceId);
332
+ const grant = authorization.grant;
248
333
  requirePermission(grant, "variable-sets:write");
249
334
  requirePermission(grant, "secrets:write");
250
335
  const name = parseVariableName(c.req.param("name")!);
251
- const variableSet = await requireVariableSetForApi(
252
- db,
336
+ const variableSet = await requireVariableSetForApi(db, grant, c.req.param("variableSetId")!);
337
+ const allowOrganization =
338
+ variableSet.scope === "organization" &&
339
+ authorization.accountGrant?.permissions.includes("account:admin") === true;
340
+ if (variableSet.scope === "organization" && !allowOrganization) {
341
+ throw new HTTPException(403, {
342
+ message: "missing permission: account:admin",
343
+ });
344
+ }
345
+ const deleted = await deleteVariableSetVariable(db, {
346
+ accountId: grant.accountId,
253
347
  workspaceId,
254
- c.req.param("variableSetId")!,
255
- );
256
- const deleted = await deleteVariableSetVariable(db, workspaceId, variableSet.id, name);
348
+ subjectId: grant.subjectId,
349
+ variableSetId: variableSet.id,
350
+ name,
351
+ allowOrganization,
352
+ });
257
353
  if (!deleted) {
258
354
  throw new HTTPException(404, {
259
355
  message: "variable set variable not found",
@@ -0,0 +1,201 @@
1
+ import type { Hono } from "hono";
2
+ import { HTTPException } from "hono/http-exception";
3
+ import { z } from "zod";
4
+ import {
5
+ BeginExternalIdentityLinkRequest,
6
+ ConfirmExternalIdentityLinkRequest,
7
+ } from "@opengeni/contracts/external-identities";
8
+ import {
9
+ beginExternalIdentityLink,
10
+ confirmExternalIdentityLink,
11
+ getExternalIdentityLink,
12
+ listExternalIdentityLinks,
13
+ previewExternalIdentityLink,
14
+ revokeExternalIdentityLink,
15
+ ensureExternalIdentity,
16
+ ExternalIdentityLinkConflictError,
17
+ withWorkspaceSubjectRls,
18
+ lockExternalWorkspaceMembershipLifecycle,
19
+ getWorkspaceGrant,
20
+ namedSubjectPersonalWorkspaceId,
21
+ managedPersonalWorkspacePermissions,
22
+ } from "@opengeni/db";
23
+ import {
24
+ requireAccessGrantAuthorization,
25
+ externalActorContinuationForAuthorization,
26
+ externalContinuationCommitAuthorizer,
27
+ hasPermission,
28
+ type AccessGrantAuthorization,
29
+ type ApiRouteDeps,
30
+ } from "@opengeni/core";
31
+ import { parseRequestBody, parseRequestJson, readRequestJson } from "../http/request-body";
32
+
33
+ function nativeConfirmation(authorization: AccessGrantAuthorization) {
34
+ if (
35
+ !authorization.contextIntegrity ||
36
+ !authorization.canonicalManagedHumanSession ||
37
+ authorization.authenticatedSubjectId !== authorization.grant.subjectId ||
38
+ !authorization.grant.subjectId.startsWith("user:")
39
+ )
40
+ throw new HTTPException(403, { message: "Confirm using your authenticated Opengeni account" });
41
+ }
42
+
43
+ /** Both products address the link through a workspace they already own. The
44
+ * link itself is organization-local; the host's Personal workspace need not be
45
+ * exposed to the native human, and neither side names the other's subject. */
46
+ export function registerExternalIdentityLinkRoutes(app: Hono, deps: ApiRouteDeps) {
47
+ const base = "/v1/workspaces/:workspaceId/identity-links";
48
+ app.get(base, async (c) => {
49
+ const authorization = await requireAccessGrantAuthorization(
50
+ c,
51
+ deps,
52
+ c.req.param("workspaceId"),
53
+ "workspace:read",
54
+ );
55
+ if (!externalActorContinuationForAuthorization(authorization))
56
+ nativeConfirmation(authorization);
57
+ const parsedCursor = z.string().uuid().optional().safeParse(c.req.query("cursor"));
58
+ if (!parsedCursor.success) throw new HTTPException(400, { message: "Invalid link cursor" });
59
+ const cursor = parsedCursor.data;
60
+ const grant = authorization.grant;
61
+ return c.json(
62
+ await withWorkspaceSubjectRls(deps.db, grant.workspaceId, grant.subjectId, async (tx) => {
63
+ await externalContinuationCommitAuthorizer(authorization)?.(tx);
64
+ return listExternalIdentityLinks(tx, {
65
+ accountId: grant.accountId,
66
+ subjectId: grant.subjectId,
67
+ ...(cursor ? { cursor } : {}),
68
+ });
69
+ }),
70
+ );
71
+ });
72
+ app.post(base, async (c) => {
73
+ const authorization = await requireAccessGrantAuthorization(
74
+ c,
75
+ deps,
76
+ c.req.param("workspaceId"),
77
+ "workspace:read",
78
+ );
79
+ const continuation = externalActorContinuationForAuthorization(authorization);
80
+ if (!continuation || continuation.actor.actingMode !== "external")
81
+ throw new HTTPException(403, { message: "Start linking as the external product user" });
82
+ const input = await parseRequestJson(c, BeginExternalIdentityLinkRequest);
83
+ if (input.expiresAt !== null && Date.parse(input.expiresAt) <= Date.now())
84
+ throw new HTTPException(422, { message: "Link expiry must be in the future" });
85
+ const commit = externalContinuationCommitAuthorizer(authorization)!;
86
+ try {
87
+ const result = await withWorkspaceSubjectRls(
88
+ deps.db,
89
+ authorization.grant.workspaceId,
90
+ authorization.grant.subjectId,
91
+ async (tx) => {
92
+ await commit(tx);
93
+ const identity = await ensureExternalIdentity(tx, {
94
+ accountId: authorization.grant.accountId,
95
+ ...continuation.identity,
96
+ });
97
+ return beginExternalIdentityLink(tx, identity, input);
98
+ },
99
+ );
100
+ return c.json(result, 201);
101
+ } catch (error) {
102
+ if (error instanceof ExternalIdentityLinkConflictError)
103
+ throw new HTTPException(409, { message: error.message });
104
+ throw error;
105
+ }
106
+ });
107
+ app.on(["GET", "POST"], [base + "/:linkId", base + "/:linkId/:operation"], async (c) => {
108
+ const workspaceId = c.req.param("workspaceId")!;
109
+ const linkId = z.string().uuid().parse(c.req.param("linkId"));
110
+ const operation = c.req.param("operation");
111
+ if (
112
+ !(
113
+ (c.req.method === "GET" && !operation) ||
114
+ (c.req.method === "POST" && ["preview", "confirm", "revoke"].includes(operation ?? ""))
115
+ )
116
+ )
117
+ throw new HTTPException(404, { message: "Not found" });
118
+ const authorization = await requireAccessGrantAuthorization(
119
+ c,
120
+ deps,
121
+ workspaceId,
122
+ "workspace:read",
123
+ );
124
+ const external = externalActorContinuationForAuthorization(authorization);
125
+ if (operation === "preview" || operation === "confirm" || !external)
126
+ nativeConfirmation(authorization);
127
+ const grant = authorization.grant;
128
+ const input = c.req.method === "POST" ? await readRequestJson(c) : null;
129
+ try {
130
+ const result = await withWorkspaceSubjectRls(
131
+ deps.db,
132
+ workspaceId,
133
+ grant.subjectId,
134
+ async (tx) => {
135
+ await externalContinuationCommitAuthorizer(authorization)?.(tx);
136
+ if (operation === "preview") {
137
+ const request = parseRequestBody(
138
+ z.object({ challenge: ConfirmExternalIdentityLinkRequest.shape.challenge }).strict(),
139
+ input,
140
+ );
141
+ const preview = await previewExternalIdentityLink(tx, {
142
+ accountId: grant.accountId,
143
+ linkId,
144
+ ...request,
145
+ });
146
+ return preview
147
+ ? { ...preview, nativeSubjectId: grant.subjectId, organizationId: grant.accountId }
148
+ : null;
149
+ }
150
+ if (operation === "confirm") {
151
+ const request = parseRequestBody(ConfirmExternalIdentityLinkRequest, input);
152
+ await lockExternalWorkspaceMembershipLifecycle(tx, grant.accountId);
153
+ const personalWorkspaceId = await namedSubjectPersonalWorkspaceId(tx, {
154
+ accountId: grant.accountId,
155
+ subjectId: grant.subjectId,
156
+ });
157
+ const current =
158
+ personalWorkspaceId === workspaceId
159
+ ? { accountId: grant.accountId, permissions: managedPersonalWorkspacePermissions }
160
+ : await getWorkspaceGrant(tx, grant.subjectId, workspaceId, {
161
+ principalKind: "human_session",
162
+ });
163
+ if (
164
+ !current ||
165
+ current.accountId !== grant.accountId ||
166
+ request.permissions.some(
167
+ (permission) =>
168
+ !hasPermission(grant.permissions, permission) ||
169
+ !hasPermission(current.permissions, permission),
170
+ )
171
+ )
172
+ throw new HTTPException(403, {
173
+ message: "Link permissions exceed your authority in this workspace",
174
+ });
175
+ return confirmExternalIdentityLink(tx, {
176
+ accountId: grant.accountId,
177
+ linkId,
178
+ nativeSubjectId: grant.subjectId,
179
+ request,
180
+ });
181
+ }
182
+ const scope = { accountId: grant.accountId, linkId, subjectId: grant.subjectId };
183
+ if (operation === "revoke") {
184
+ const request = parseRequestBody(
185
+ z.object({ expectedRevision: z.number().int().positive().safe() }).strict(),
186
+ input,
187
+ );
188
+ return revokeExternalIdentityLink(tx, { ...scope, ...request });
189
+ }
190
+ return getExternalIdentityLink(tx, scope);
191
+ },
192
+ );
193
+ if (!result) throw new HTTPException(404, { message: "Identity link not found or expired" });
194
+ return c.json(result);
195
+ } catch (error) {
196
+ if (error instanceof ExternalIdentityLinkConflictError)
197
+ throw new HTTPException(409, { message: error.message });
198
+ throw error;
199
+ }
200
+ });
201
+ }
@@ -0,0 +1,113 @@
1
+ import { CreateFeedbackRequest } from "@opengeni/contracts";
2
+ import {
3
+ requireAccessGrant,
4
+ requireSessionAuthorization,
5
+ withResolvedSessionAuthorization,
6
+ SessionAuthorizationDeniedError,
7
+ SessionAuthorizationUnavailableError,
8
+ type ApiRouteDeps,
9
+ } from "@opengeni/core";
10
+ import {
11
+ createFeedback,
12
+ listOwnFeedback,
13
+ FeedbackConflictError,
14
+ FeedbackTargetNotFoundError,
15
+ } from "@opengeni/db";
16
+ import type { Hono } from "hono";
17
+ import { HTTPException } from "hono/http-exception";
18
+ import { z } from "zod";
19
+
20
+ export function registerFeedbackRoutes(app: Hono, deps: ApiRouteDeps): void {
21
+ app.post("/v1/workspaces/:workspaceId/feedback", async (c) => {
22
+ const workspaceId = c.req.param("workspaceId");
23
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:read");
24
+ await requireAccessGrant(c, deps, workspaceId, "sessions:create");
25
+ const parsed = CreateFeedbackRequest.safeParse(await c.req.json().catch(() => null));
26
+ if (!parsed.success)
27
+ throw new HTTPException(400, {
28
+ message: parsed.error.issues[0]?.message ?? "Invalid feedback",
29
+ });
30
+ // Agent turns must not manufacture user satisfaction evidence. Product SDK
31
+ // credentials are allowed but retain their own authenticated author/kind.
32
+ if (
33
+ grant.principalKind === "agent_attempt" ||
34
+ grant.metadata?.["turnId"] !== undefined ||
35
+ grant.metadata?.["attemptId"] !== undefined
36
+ )
37
+ throw new HTTPException(403, { message: "Agent attempts cannot submit feedback" });
38
+ try {
39
+ const save = () =>
40
+ createFeedback(deps.db, {
41
+ accountId: grant.accountId,
42
+ workspaceId,
43
+ subjectId: grant.subjectId,
44
+ principalKind: grant.principalKind ?? null,
45
+ request: parsed.data,
46
+ });
47
+ let result;
48
+ if (parsed.data.sessionId) {
49
+ await requireAccessGrant(c, deps, workspaceId, "sessions:read");
50
+ const authorization = await requireSessionAuthorization(deps, grant, {
51
+ sessionId: parsed.data.sessionId,
52
+ operation: "session.feedback.write",
53
+ surface: "http",
54
+ });
55
+ result = authorization
56
+ ? await withResolvedSessionAuthorization(authorization, save)
57
+ : await save();
58
+ } else result = await save();
59
+ c.header("cache-control", "private, no-store");
60
+ return c.json(result, result.replayed ? 200 : 201);
61
+ } catch (error) {
62
+ throw feedbackHttpError(error);
63
+ }
64
+ });
65
+ app.get("/v1/workspaces/:workspaceId/feedback", async (c) => {
66
+ const workspaceId = c.req.param("workspaceId");
67
+ const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:read");
68
+ const query = z
69
+ .object({
70
+ sessionId: z.string().uuid().optional(),
71
+ includeTurns: z
72
+ .enum(["true", "false"])
73
+ .default("true")
74
+ .transform((value) => value === "true"),
75
+ limit: z.coerce.number().int().min(1).max(100).default(50),
76
+ })
77
+ .safeParse(c.req.query());
78
+ if (!query.success) throw new HTTPException(400, { message: "Invalid feedback query" });
79
+ try {
80
+ const read = () =>
81
+ listOwnFeedback(deps.db, { workspaceId, subjectId: grant.subjectId, ...query.data });
82
+ let feedback;
83
+ if (query.data.sessionId) {
84
+ await requireAccessGrant(c, deps, workspaceId, "sessions:read");
85
+ const authorization = await requireSessionAuthorization(deps, grant, {
86
+ sessionId: query.data.sessionId,
87
+ operation: "session.read",
88
+ surface: "http",
89
+ });
90
+ feedback = authorization
91
+ ? await withResolvedSessionAuthorization(authorization, read)
92
+ : await read();
93
+ } else feedback = await read();
94
+ c.header("cache-control", "private, no-store");
95
+ return c.json({ feedback });
96
+ } catch (error) {
97
+ throw feedbackHttpError(error);
98
+ }
99
+ });
100
+ }
101
+ function feedbackHttpError(error: unknown): Error {
102
+ if (error instanceof FeedbackConflictError)
103
+ return new HTTPException(409, { message: error.message });
104
+ if (
105
+ error instanceof FeedbackTargetNotFoundError ||
106
+ error instanceof SessionAuthorizationDeniedError
107
+ )
108
+ return new HTTPException(404, { message: "Feedback target not found" });
109
+ if (error instanceof SessionAuthorizationUnavailableError)
110
+ return new HTTPException(503, { message: "Session authorization unavailable" });
111
+ if (error instanceof Error) return error;
112
+ return new Error("Feedback request failed");
113
+ }