@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
@@ -0,0 +1,362 @@
1
+ import { claudeAccountMutationFailure } from "./claude-subscription-account-conflicts";
2
+ import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
3
+ import {
4
+ CLAUDE_OAUTH_CLIENT_ID,
5
+ CLAUDE_OAUTH_REDIRECT_URL,
6
+ CLAUDE_OAUTH_TOKEN_URL,
7
+ CLAUDE_OAUTH_SCOPES,
8
+ ClaudeOAuthTokenResponse,
9
+ ClaudeSubscriptionCredential,
10
+ claudeAuthorizationUrl,
11
+ } from "@opengeni/config";
12
+ import {
13
+ ClaudeSubscriptionOAuthStartResponse,
14
+ ClaudeSubscriptionOAuthCompleteResponse,
15
+ ClaudeProviderAccountAuthoritySnapshotV1,
16
+ } from "@opengeni/contracts";
17
+ import { requireEnvironmentEncryption, type ApiRouteDeps } from "@opengeni/core";
18
+ import {
19
+ consumeIntegrationOAuthPendingState,
20
+ decryptEnvironmentValue,
21
+ encryptEnvironmentValue,
22
+ loadIntegrationOAuthPendingState,
23
+ storeIntegrationOAuthPendingState,
24
+ withRlsContext,
25
+ getClaudeSubscriptionAccountAuthoritySnapshot,
26
+ getClaudeSubscriptionAccountMetadata,
27
+ listOrganizationClaudeSubscriptions,
28
+ upsertOrganizationClaudeSubscription,
29
+ upsertClaudeSubscriptionAccount,
30
+ setInitialActiveClaudeCredential,
31
+ wakeClaudeCapacityWaiters,
32
+ } from "@opengeni/db";
33
+ import { readResponseJsonBounded } from "@opengeni/network";
34
+ import { HTTPException } from "hono/http-exception";
35
+ import { z } from "zod";
36
+ import { prepareClaudeSubscriptionCredential } from "./claude-workspace-connection";
37
+ import {
38
+ fetchClaudeSubscriptionProfile,
39
+ parseClaudeSubscriptionProfile,
40
+ } from "./claude-subscription-profile";
41
+
42
+ export type ClaudeOAuthScope = {
43
+ accountId: string;
44
+ workspaceId: string | null;
45
+ actorSubjectId: string;
46
+ browserSessionHash: string;
47
+ };
48
+ const AttemptScope = z
49
+ .object({
50
+ purpose: z.literal("claude-subscription-oauth"),
51
+ accountId: z.string().uuid(),
52
+ workspaceId: z.string().uuid().nullable(),
53
+ actorSubjectId: z.string().min(1),
54
+ browserSessionHash: z.string().min(1),
55
+ poolScope: z.enum(["organization", "workspace", "user"]),
56
+ credentialId: z.string().uuid().nullable(),
57
+ credentialVersion: z.number().int().nonnegative(),
58
+ authoritySnapshot: ClaudeProviderAccountAuthoritySnapshotV1.nullable(),
59
+ })
60
+ .strict();
61
+ const Attempt = z.discriminatedUnion("stage", [
62
+ AttemptScope.extend({
63
+ stage: z.literal("pending"),
64
+ state: z.string().min(32).max(128),
65
+ verifier: z.string().min(32).max(128),
66
+ }),
67
+ AttemptScope.extend({ stage: z.literal("complete") }),
68
+ ]);
69
+ const Tokens = ClaudeOAuthTokenResponse.extend({
70
+ refresh_token: z.string().min(1).max(16384),
71
+ account: z.object({ uuid: z.string().uuid() }).passthrough().optional(),
72
+ }).passthrough();
73
+ function same(left: string, right: string) {
74
+ const a = Buffer.from(left),
75
+ b = Buffer.from(right);
76
+ return a.length === b.length && timingSafeEqual(a, b);
77
+ }
78
+ const changed = () =>
79
+ new HTTPException(409, { message: "Claude account changed during sign-in. Start again." });
80
+ async function target(deps: ApiRouteDeps, scope: ClaudeOAuthScope, credentialId: string) {
81
+ if (!scope.workspaceId) {
82
+ const pool = await listOrganizationClaudeSubscriptions(deps.db, {
83
+ organizationId: scope.accountId,
84
+ actorSubjectId: scope.actorSubjectId,
85
+ });
86
+ const account = pool.accounts.find((candidate) => candidate.id === credentialId);
87
+ return account
88
+ ? { account, authoritySnapshot: { version: 1, scope: "organization" } as const }
89
+ : null;
90
+ }
91
+ const input = { workspaceId: scope.workspaceId, subjectId: scope.actorSubjectId, credentialId };
92
+ const authoritySnapshot = await getClaudeSubscriptionAccountAuthoritySnapshot(deps.db, input);
93
+ if (!authoritySnapshot) return null;
94
+ const account = await getClaudeSubscriptionAccountMetadata(deps.db, input);
95
+ return account ? { account, authoritySnapshot } : null;
96
+ }
97
+ export async function startClaudeSubscriptionOAuth(
98
+ deps: ApiRouteDeps,
99
+ scope: ClaudeOAuthScope,
100
+ input: { scope?: "workspace" | "user" | undefined; reconnectAccountId?: string | undefined } = {},
101
+ ) {
102
+ const key = requireEnvironmentEncryption(deps.settings);
103
+ const poolScope = scope.workspaceId ? (input.scope ?? "workspace") : "organization";
104
+ const current = input.reconnectAccountId
105
+ ? await target(deps, scope, input.reconnectAccountId)
106
+ : null;
107
+ if (input.reconnectAccountId && (!current || current.account.scope !== poolScope))
108
+ throw changed();
109
+ const verifier = randomBytes(32).toString("base64url"),
110
+ state = randomBytes(32).toString("base64url");
111
+ const id = randomUUID(),
112
+ expiresAt = new Date(Date.now() + 10 * 60_000);
113
+ const attempt = Attempt.parse({
114
+ stage: "pending",
115
+ purpose: "claude-subscription-oauth",
116
+ ...scope,
117
+ poolScope,
118
+ state,
119
+ verifier,
120
+ credentialId: current?.account.id ?? null,
121
+ credentialVersion: current?.account.version ?? 0,
122
+ authoritySnapshot: current?.authoritySnapshot ?? null,
123
+ });
124
+ await storeIntegrationOAuthPendingState(deps.db, {
125
+ ...scope,
126
+ id,
127
+ expiresAt,
128
+ stateEncrypted: encryptEnvironmentValue(key, JSON.stringify(attempt)),
129
+ });
130
+ return ClaudeSubscriptionOAuthStartResponse.parse({
131
+ attemptId: id,
132
+ expiresAt: expiresAt.toISOString(),
133
+ authorizationUrl: claudeAuthorizationUrl({
134
+ state,
135
+ challenge: createHash("sha256").update(verifier).digest("base64url"),
136
+ }),
137
+ });
138
+ }
139
+
140
+ /** Each attempt adds one account or reconnects one exact, generation-fenced target. */
141
+ export async function completeClaudeSubscriptionOAuth(
142
+ deps: ApiRouteDeps,
143
+ scope: ClaudeOAuthScope,
144
+ input: { attemptId: string; code: string },
145
+ reauthorize: (poolScope?: "workspace" | "user" | "organization") => Promise<void>,
146
+ fetchImpl: typeof fetch = globalThis.fetch,
147
+ ) {
148
+ const key = requireEnvironmentEncryption(deps.settings);
149
+ const encrypted = await loadIntegrationOAuthPendingState(deps.db, {
150
+ ...scope,
151
+ id: input.attemptId,
152
+ });
153
+ const parsed = (() => {
154
+ try {
155
+ return Attempt.safeParse(JSON.parse(decryptEnvironmentValue(key, encrypted!)));
156
+ } catch {
157
+ return { success: false as const };
158
+ }
159
+ })();
160
+ if (!parsed.success)
161
+ throw new HTTPException(410, {
162
+ message: "Claude sign-in expired or was already used. Start again.",
163
+ });
164
+ const attempt = parsed.data;
165
+ if (
166
+ attempt.accountId !== scope.accountId ||
167
+ attempt.workspaceId !== scope.workspaceId ||
168
+ attempt.actorSubjectId !== scope.actorSubjectId ||
169
+ !same(attempt.browserSessionHash, scope.browserSessionHash)
170
+ )
171
+ throw new HTTPException(403, {
172
+ message: "Complete Claude sign-in in the browser where you started it.",
173
+ });
174
+ await reauthorize(attempt.poolScope);
175
+ const current = attempt.credentialId ? await target(deps, scope, attempt.credentialId) : null;
176
+ if (
177
+ attempt.credentialId &&
178
+ (!current ||
179
+ current.account.version !== attempt.credentialVersion ||
180
+ current.account.scope !== attempt.poolScope ||
181
+ JSON.stringify(current.authoritySnapshot) !== JSON.stringify(attempt.authoritySnapshot))
182
+ )
183
+ throw changed();
184
+ if (attempt.stage === "complete")
185
+ return ClaudeSubscriptionOAuthCompleteResponse.parse({
186
+ connected: true,
187
+ accountId: attempt.credentialId,
188
+ scope: attempt.poolScope,
189
+ credentialVersion: attempt.credentialVersion,
190
+ });
191
+ const parts = input.code.trim().split("#");
192
+ if (parts.length !== 2 || !parts[0] || !same(parts[1]!, attempt.state))
193
+ throw new HTTPException(422, {
194
+ message: "Copy the full authorization code from the Claude page.",
195
+ });
196
+ if (
197
+ !(await consumeIntegrationOAuthPendingState(deps.db, {
198
+ ...scope,
199
+ id: input.attemptId,
200
+ stateEncrypted: encrypted!,
201
+ }))
202
+ )
203
+ throw new HTTPException(410, {
204
+ message: "Claude sign-in expired or was already used. Start again.",
205
+ });
206
+ let tokens: z.infer<typeof Tokens>;
207
+ try {
208
+ const signal = AbortSignal.timeout(30_000);
209
+ const response = await fetchImpl(CLAUDE_OAUTH_TOKEN_URL, {
210
+ method: "POST",
211
+ redirect: "error",
212
+ signal,
213
+ headers: { "content-type": "application/json" },
214
+ body: JSON.stringify({
215
+ grant_type: "authorization_code",
216
+ client_id: CLAUDE_OAUTH_CLIENT_ID,
217
+ redirect_uri: CLAUDE_OAUTH_REDIRECT_URL,
218
+ code: parts[0],
219
+ code_verifier: attempt.verifier,
220
+ state: attempt.state,
221
+ }),
222
+ });
223
+ if (!response.ok) {
224
+ await response.body?.cancel().catch(() => undefined);
225
+ throw new Error("Token exchange refused");
226
+ }
227
+ tokens = Tokens.parse(
228
+ await readResponseJsonBounded(response, 64 * 1024, "Claude sign-in", { signal }),
229
+ );
230
+ if (!CLAUDE_OAUTH_SCOPES.every((required) => tokens.scope.split(/\s+/).includes(required)))
231
+ throw new Error("Required scopes missing");
232
+ } catch {
233
+ throw new HTTPException(502, {
234
+ message: "Claude sign-in could not be completed. Start sign-in again.",
235
+ });
236
+ }
237
+ const scopes = tokens.scope.split(/\s+/).filter(Boolean);
238
+ const direct = parseClaudeSubscriptionProfile({
239
+ account: tokens.account,
240
+ organization: tokens.organization,
241
+ });
242
+ const profile = await fetchClaudeSubscriptionProfile(tokens.access_token, scopes, fetchImpl);
243
+ if (tokens.account && profile && tokens.account.uuid !== profile.accountUuid)
244
+ throw new HTTPException(502, {
245
+ message: "Claude returned inconsistent account details. Start sign-in again.",
246
+ });
247
+ const accountUuid = tokens.account?.uuid ?? profile?.accountUuid ?? "";
248
+ if (
249
+ current?.account.providerAccountId &&
250
+ !/^(setup|oauth):/.test(current.account.providerAccountId) &&
251
+ current.account.providerAccountId !== accountUuid
252
+ )
253
+ throw new HTTPException(409, {
254
+ message:
255
+ "Sign in to the same Claude account to reconnect. Use Add account for a different subscription.",
256
+ });
257
+ await reauthorize(attempt.poolScope);
258
+ const expiresAt = new Date(Date.now() + tokens.expires_in * 1000);
259
+ const bundle = ClaudeSubscriptionCredential.parse({
260
+ ...JSON.parse(
261
+ prepareClaudeSubscriptionCredential(
262
+ deps.settings,
263
+ scope.workspaceId ? "workspace:" + scope.workspaceId : "organization:" + scope.accountId,
264
+ tokens.access_token,
265
+ ),
266
+ ),
267
+ identity: {
268
+ accountUuid,
269
+ deviceId: createHmac("sha256", key)
270
+ .update("claude-device:" + (scope.workspaceId ?? scope.accountId))
271
+ .digest("hex"),
272
+ },
273
+ oauth: { refreshToken: tokens.refresh_token, expiresAt: expiresAt.toISOString(), scopes },
274
+ });
275
+ const providerAccountId =
276
+ accountUuid || "oauth:" + createHmac("sha256", key).update(tokens.access_token).digest("hex");
277
+ const details = {
278
+ encryptionKey: key,
279
+ secret: bundle,
280
+ providerAccountId,
281
+ accountEmail: profile?.email ?? direct?.email ?? null,
282
+ planType: profile?.plan ?? direct?.plan ?? null,
283
+ expiresAt,
284
+ label: current?.account.label ?? null,
285
+ };
286
+ const saved = await withRlsContext(deps.db, scope, async (tx) => {
287
+ const connected = scope.workspaceId
288
+ ? await upsertClaudeSubscriptionAccount(tx, {
289
+ ...details,
290
+ accountId: scope.accountId,
291
+ workspaceId: scope.workspaceId,
292
+ subjectId: scope.actorSubjectId,
293
+ scope: attempt.poolScope as "workspace" | "user",
294
+ ...(attempt.credentialId
295
+ ? {
296
+ credentialId: attempt.credentialId,
297
+ expectedCredentialVersion: attempt.credentialVersion,
298
+ expectedProviderAccountId: current!.account.providerAccountId,
299
+ authoritySnapshot: attempt.authoritySnapshot!,
300
+ }
301
+ : {}),
302
+ })
303
+ : await upsertOrganizationClaudeSubscription(tx, {
304
+ ...details,
305
+ organizationId: scope.accountId,
306
+ actorSubjectId: scope.actorSubjectId,
307
+ ...(attempt.credentialId
308
+ ? {
309
+ credentialId: attempt.credentialId,
310
+ expectedCredentialVersion: attempt.credentialVersion,
311
+ expectedProviderAccountId: current!.account.providerAccountId,
312
+ }
313
+ : {}),
314
+ });
315
+ const authoritySnapshot =
316
+ "authoritySnapshot" in connected
317
+ ? connected.authoritySnapshot
318
+ : ({ version: 1, scope: "organization" } as const);
319
+ if (scope.workspaceId)
320
+ await setInitialActiveClaudeCredential(tx, {
321
+ accountId: scope.accountId,
322
+ workspaceId: scope.workspaceId,
323
+ subjectId: scope.actorSubjectId,
324
+ credentialId: connected.account.id,
325
+ authoritySnapshot,
326
+ });
327
+ await storeIntegrationOAuthPendingState(tx, {
328
+ ...scope,
329
+ id: input.attemptId,
330
+ expiresAt: new Date(Date.now() + 10 * 60_000),
331
+ stateEncrypted: encryptEnvironmentValue(
332
+ key,
333
+ JSON.stringify({
334
+ purpose: "claude-subscription-oauth",
335
+ ...scope,
336
+ stage: "complete",
337
+ poolScope: attempt.poolScope,
338
+ credentialId: connected.account.id,
339
+ credentialVersion: connected.account.version,
340
+ authoritySnapshot,
341
+ }),
342
+ ),
343
+ });
344
+ return connected.account;
345
+ }).catch(claudeAccountMutationFailure);
346
+ if (scope.workspaceId)
347
+ await wakeClaudeCapacityWaiters(deps.db, {
348
+ workspaceId: scope.workspaceId,
349
+ subjectId: scope.actorSubjectId,
350
+ authoritySnapshot:
351
+ attempt.poolScope === "workspace"
352
+ ? { version: 1, scope: "workspace" }
353
+ : (await target(deps, scope, saved.id))!.authoritySnapshot,
354
+ reason: "claude_account_connected",
355
+ });
356
+ return ClaudeSubscriptionOAuthCompleteResponse.parse({
357
+ connected: true,
358
+ accountId: saved.id,
359
+ scope: attempt.poolScope,
360
+ credentialVersion: saved.version,
361
+ });
362
+ }
@@ -0,0 +1,73 @@
1
+ import { readResponseJsonBounded } from "@opengeni/network";
2
+ import { z } from "zod";
3
+
4
+ const Account = z
5
+ .object({
6
+ uuid: z.string().uuid(),
7
+ email: z.string().trim().email().max(320).optional(),
8
+ email_address: z.string().trim().email().max(320).optional(),
9
+ has_claude_max: z.boolean().optional(),
10
+ has_claude_pro: z.boolean().optional(),
11
+ })
12
+ .passthrough();
13
+ const Profile = z
14
+ .object({
15
+ account: Account,
16
+ organization: z
17
+ .object({
18
+ organization_type: z.string().trim().min(1).max(128).optional(),
19
+ })
20
+ .passthrough()
21
+ .optional(),
22
+ })
23
+ .passthrough();
24
+
25
+ export type ClaudeSubscriptionProfile = {
26
+ accountUuid: string;
27
+ email: string | null;
28
+ plan: string | null;
29
+ };
30
+
31
+ /** Only provider-reported identity; never derive email from a token or an organization name. */
32
+ export function parseClaudeSubscriptionProfile(value: unknown): ClaudeSubscriptionProfile | null {
33
+ const parsed = Profile.safeParse(value);
34
+ if (!parsed.success) return null;
35
+ const { account, organization } = parsed.data;
36
+ return {
37
+ accountUuid: account.uuid,
38
+ email: account.email ?? account.email_address ?? null,
39
+ plan:
40
+ organization?.organization_type ??
41
+ (account.has_claude_max === true
42
+ ? "claude_max"
43
+ : account.has_claude_pro === true
44
+ ? "claude_pro"
45
+ : null),
46
+ };
47
+ }
48
+
49
+ /** Optional profile read. A profile outage must not discard a valid sign-in. */
50
+ export async function fetchClaudeSubscriptionProfile(
51
+ token: string,
52
+ scopes: readonly string[],
53
+ fetchImpl: typeof fetch = globalThis.fetch,
54
+ ): Promise<ClaudeSubscriptionProfile | null> {
55
+ if (!scopes.includes("user:profile")) return null;
56
+ try {
57
+ const signal = AbortSignal.timeout(10_000);
58
+ const response = await fetchImpl("https://api.anthropic.com/api/oauth/profile", {
59
+ headers: { authorization: `Bearer ${token}`, accept: "application/json" },
60
+ redirect: "error",
61
+ signal,
62
+ });
63
+ if (!response.ok) {
64
+ await response.body?.cancel().catch(() => undefined);
65
+ return null;
66
+ }
67
+ return parseClaudeSubscriptionProfile(
68
+ await readResponseJsonBounded(response, 64 * 1024, "Claude profile", { signal }),
69
+ );
70
+ } catch {
71
+ return null;
72
+ }
73
+ }
@@ -0,0 +1,97 @@
1
+ import { parseClaudeUsageResponse, type Settings } from "@opengeni/config";
2
+ import { emptyClaudeUsage } from "@opengeni/config";
3
+ import type { ClaudeSubscriptionUsage } from "@opengeni/contracts";
4
+ import {
5
+ resolveClaudeSubscriptionCredential,
6
+ ClaudeSubscriptionConnectionChanged,
7
+ ClaudeSubscriptionRefreshUnavailable,
8
+ recordClaudeSubscriptionUsage,
9
+ type ClaudeUsageScope,
10
+ type Database,
11
+ } from "@opengeni/db";
12
+ import { readResponseJsonBounded } from "@opengeni/network";
13
+ import { HTTPException } from "hono/http-exception";
14
+
15
+ export async function requestClaudeUsage(
16
+ token: string,
17
+ fetchImpl: typeof fetch = globalThis.fetch,
18
+ ) {
19
+ const checkedAt = new Date().toISOString();
20
+ let status: ClaudeSubscriptionUsage["refreshStatus"] = "unavailable";
21
+ let observation: ReturnType<typeof parseClaudeUsageResponse> = null;
22
+ try {
23
+ const signal = AbortSignal.timeout(10_000);
24
+ const response = await fetchImpl("https://api.anthropic.com/api/oauth/usage", {
25
+ headers: {
26
+ authorization: `Bearer ${token}`,
27
+ "content-type": "application/json",
28
+ "cache-control": "no-cache",
29
+ },
30
+ redirect: "error",
31
+ signal,
32
+ });
33
+ if (response.ok || response.status === 403) {
34
+ const body = await readResponseJsonBounded<unknown>(response, 64 * 1024, "Claude usage", {
35
+ signal,
36
+ });
37
+ if (response.ok) {
38
+ observation = parseClaudeUsageResponse(body, new Date(checkedAt));
39
+ status = observation ? "available" : "unavailable";
40
+ } else {
41
+ const error = body && typeof body === "object" && "error" in body ? body.error : null;
42
+ const message =
43
+ error && typeof error === "object" && "message" in error ? error.message : null;
44
+ status =
45
+ typeof message === "string" &&
46
+ message.includes("scope requirement") &&
47
+ message.includes("user:profile")
48
+ ? "scope_required"
49
+ : "unavailable";
50
+ }
51
+ } else {
52
+ status = response.status === 401 ? "reconnect" : "unavailable";
53
+ await response.body?.cancel().catch(() => undefined);
54
+ }
55
+ } catch {
56
+ // Retain the last provider observation; never imply an unavailable quota is zero.
57
+ }
58
+
59
+ return { status, observation, checkedAt };
60
+ }
61
+
62
+ /** No inference calls. Inference-only setup tokens retain their response-header cache. */
63
+ export async function refreshClaudeSubscriptionUsage(
64
+ db: Database,
65
+ settings: Settings,
66
+ scope: ClaudeUsageScope,
67
+ fetchImpl: typeof fetch = globalThis.fetch,
68
+ ) {
69
+ const credential = await resolveClaudeSubscriptionCredential(db, settings, scope, {
70
+ fetchImpl,
71
+ }).catch((error) => {
72
+ if (error instanceof ClaudeSubscriptionConnectionChanged)
73
+ throw new HTTPException(409, { message: error.message });
74
+ if (error instanceof ClaudeSubscriptionRefreshUnavailable)
75
+ throw new HTTPException(503, { message: error.message });
76
+ throw error;
77
+ });
78
+ if (!credential) return emptyClaudeUsage(null);
79
+ if ("reconnectRequired" in credential) return credential.usage;
80
+ const current = credential.usage;
81
+ if (
82
+ current.refreshStatus === "scope_required" ||
83
+ (current.refreshCheckedAt && Date.now() - Date.parse(current.refreshCheckedAt) < 30_000)
84
+ )
85
+ return current;
86
+ const { status, observation, checkedAt } = await requestClaudeUsage(credential.token, fetchImpl);
87
+ const result = await recordClaudeSubscriptionUsage(db, settings, scope, {
88
+ token: credential.token,
89
+ expectedConnectionId: credential.connectionId,
90
+ expectedCredentialVersion: credential.credentialVersion,
91
+ ...(observation ? { observation } : {}),
92
+ refresh: { status, checkedAt },
93
+ });
94
+ if (!result)
95
+ throw new HTTPException(409, { message: "Claude connection changed; reload usage." });
96
+ return result;
97
+ }
@@ -0,0 +1,82 @@
1
+ import { createHmac } from "node:crypto";
2
+ import { requireEnvironmentEncryption } from "@opengeni/core";
3
+ import { ClaudeSubscriptionCredential, type Settings } from "@opengeni/config";
4
+ import { HTTPException } from "hono/http-exception";
5
+
6
+ /** Validate the canonical model lane before it bypasses integration acquisition. */
7
+ export function assertClaudeWorkspaceCredential(
8
+ settings: Pick<Settings, "claudeSubscriptionEnabled">,
9
+ input: {
10
+ subjectId: string | null;
11
+ providerDomain: string;
12
+ kind: string;
13
+ metadata?: Record<string, unknown>;
14
+ credential: unknown;
15
+ },
16
+ ): void {
17
+ const role = input.metadata?.credentialRole;
18
+ if (role !== "anthropic" && role !== "claude_subscription") return;
19
+ if (role === "claude_subscription" && !settings.claudeSubscriptionEnabled)
20
+ throw new HTTPException(404, { message: "Claude subscriptions are not enabled" });
21
+ if (role === "claude_subscription")
22
+ throw new HTTPException(410, { message: "Use individual Claude subscription accounts." });
23
+ if (
24
+ input.subjectId !== null ||
25
+ input.providerDomain !== "api.anthropic.com" ||
26
+ input.kind !== "api_key"
27
+ )
28
+ throw new HTTPException(422, {
29
+ message: "Claude model connections must belong to this workspace",
30
+ });
31
+ const credential = input.credential;
32
+ const key =
33
+ credential && typeof credential === "object" && "apiKey" in credential
34
+ ? credential.apiKey
35
+ : null;
36
+ if (typeof key !== "string")
37
+ throw new HTTPException(422, { message: "Claude connection credential is required" });
38
+ if (role === "anthropic") {
39
+ if (!/^sk-ant-api[0-9]+-\S+$/.test(key))
40
+ throw new HTTPException(422, {
41
+ message: "Enter an Anthropic API key. Use Claude subscription for setup tokens.",
42
+ });
43
+ return;
44
+ }
45
+ }
46
+
47
+ /** Stable installation identity; setup tokens do not grant profile access. */
48
+ export function prepareClaudeSubscriptionCredential(
49
+ settings: Settings,
50
+ scope: string,
51
+ token: string,
52
+ identity?: { accountUuid: string; deviceId: string },
53
+ ): string {
54
+ if (!settings.claudeSubscriptionEnabled)
55
+ throw new HTTPException(404, { message: "Claude subscriptions are not enabled" });
56
+ if (!/^sk-ant-oat[0-9]+-\S+$/.test(token))
57
+ throw new HTTPException(422, { message: "Enter the setup token from claude setup-token." });
58
+ return JSON.stringify(
59
+ ClaudeSubscriptionCredential.parse({
60
+ version: 1,
61
+ token,
62
+ identity: identity ?? {
63
+ accountUuid: "",
64
+ deviceId: createHmac("sha256", requireEnvironmentEncryption(settings))
65
+ .update("claude-device:" + scope)
66
+ .digest("hex"),
67
+ },
68
+ }),
69
+ );
70
+ }
71
+
72
+ export function prepareClaudeWorkspaceCredential(
73
+ settings: Settings,
74
+ workspaceId: string,
75
+ metadata: Record<string, unknown> | undefined,
76
+ credential: Record<string, unknown>,
77
+ ): Record<string, unknown> {
78
+ if (metadata?.credentialRole !== "claude_subscription") return credential;
79
+ if (!settings.claudeSubscriptionEnabled)
80
+ throw new HTTPException(404, { message: "Claude subscriptions are not enabled" });
81
+ throw new HTTPException(410, { message: "Use individual Claude subscription accounts." });
82
+ }