@opengeni/api-router 0.30.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (436) hide show
  1. package/dist/access-grant-rls.d.ts +3 -0
  2. package/dist/admission-trace.d.ts +8 -0
  3. package/dist/api-websocket.d.ts +18 -0
  4. package/dist/app.d.ts +50 -2
  5. package/dist/app.js +12 -1
  6. package/dist/artifact-catalog-cursor.d.ts +27 -0
  7. package/dist/auth/managed-auth-attempt-context.d.ts +10 -0
  8. package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
  9. package/dist/auth/managed-auth-session-adapter.d.ts +6 -0
  10. package/dist/auth/managed-auth.d.ts +102 -3
  11. package/dist/auth/managed-email.d.ts +29 -0
  12. package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
  13. package/dist/auth/new-signups-gate.d.ts +23 -0
  14. package/dist/auth/organization-user-setup.d.ts +80 -0
  15. package/dist/auth/signup-funnel-metrics.d.ts +44 -0
  16. package/dist/browser-controller-authority.d.ts +1 -61
  17. package/dist/browser-ephemeral.d.ts +5 -0
  18. package/dist/browser-state-authority.d.ts +1 -27
  19. package/dist/chunk-6TZ5LG3O.js +123948 -0
  20. package/dist/chunk-6TZ5LG3O.js.map +1 -0
  21. package/dist/chunk-OGQDXVXY.js +18 -0
  22. package/dist/chunk-OGQDXVXY.js.map +1 -0
  23. package/dist/claude-subscription-account-conflicts.d.ts +1 -0
  24. package/dist/claude-subscription-account-usage.d.ts +39 -0
  25. package/dist/claude-subscription-oauth.d.ts +25 -0
  26. package/dist/claude-subscription-profile.d.ts +9 -0
  27. package/dist/claude-subscription-usage.d.ts +44 -0
  28. package/dist/claude-workspace-connection.d.ts +15 -0
  29. package/dist/codemode.d.ts +32 -1
  30. package/dist/company-brain-okf.d.ts +24 -0
  31. package/dist/connected-machine-computer-access.d.ts +11 -0
  32. package/dist/connection-ownership.d.ts +54 -0
  33. package/dist/controller-data-plane.d.ts +32 -0
  34. package/dist/editable-artifact-office-import.d.ts +7 -4
  35. package/dist/editable-artifact-source-session.d.ts +3 -0
  36. package/dist/editable-artifact-websocket.d.ts +10 -18
  37. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  38. package/dist/fatal-process-boundary.d.ts +25 -0
  39. package/dist/github-access.d.ts +31 -2
  40. package/dist/http/acting-person.d.ts +24 -0
  41. package/dist/http/api-contract-compat.d.ts +19 -0
  42. package/dist/http/api-error.d.ts +27 -1
  43. package/dist/http/cors.d.ts +17 -0
  44. package/dist/http/deprecation.d.ts +42 -0
  45. package/dist/http/interaction-control-error.d.ts +13 -0
  46. package/dist/http/keyed-admission.d.ts +12 -0
  47. package/dist/http/local-browser-boundary.d.ts +72 -0
  48. package/dist/http/metrics-listener.d.ts +22 -0
  49. package/dist/http/path-identifier.d.ts +17 -0
  50. package/dist/http/registered-route-label.d.ts +16 -0
  51. package/dist/http/request-body.d.ts +27 -0
  52. package/dist/http/request-source.d.ts +52 -0
  53. package/dist/http/sse.d.ts +17 -6
  54. package/dist/http/unmatched-route.d.ts +18 -0
  55. package/dist/http/user-content.d.ts +36 -0
  56. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  57. package/dist/index.d.ts +10 -3
  58. package/dist/index.js +1129 -166
  59. package/dist/index.js.map +1 -1
  60. package/dist/integration-endpoint-test.d.ts +20 -0
  61. package/dist/integrations/api-integrations.d.ts +2 -2
  62. package/dist/integrations/atlassian.d.ts +29 -3
  63. package/dist/integrations/connect-authority.d.ts +1 -0
  64. package/dist/integrations/connect-callback-return.d.ts +6 -0
  65. package/dist/integrations/fiken.d.ts +16 -2
  66. package/dist/integrations/github-app-connect.d.ts +47 -0
  67. package/dist/integrations/github-installation-proof.d.ts +3 -0
  68. package/dist/integrations/github-lens-connect.d.ts +116 -0
  69. package/dist/integrations/github-skill-source.d.ts +1 -5
  70. package/dist/integrations/google-drive.d.ts +25 -0
  71. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  72. package/dist/integrations/marketplace-plugin.d.ts +2691 -0
  73. package/dist/integrations/oauth-client.d.ts +178 -18
  74. package/dist/integrations/oauth-profiles.d.ts +222 -0
  75. package/dist/integrations/oauth-return-path.d.ts +1 -0
  76. package/dist/integrations/personal-github-repositories.d.ts +84 -0
  77. package/dist/integrations/personal-github.d.ts +42 -0
  78. package/dist/integrations/pr-review-provider.d.ts +22 -0
  79. package/dist/integrations/provider-oauth.d.ts +19 -1
  80. package/dist/integrations/slack-app-home.d.ts +24 -0
  81. package/dist/integrations/slack-bot.d.ts +367 -12
  82. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  83. package/dist/integrations/slack-install.d.ts +20 -0
  84. package/dist/integrations/slack-interactions.d.ts +113 -10
  85. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  86. package/dist/integrations/slack-routing.d.ts +120 -0
  87. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  88. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  89. package/dist/integrations/social-oauth.d.ts +7 -0
  90. package/dist/interaction-agent-access.d.ts +15 -0
  91. package/dist/interaction-frame-proxy.d.ts +68 -0
  92. package/dist/interaction-metrics.d.ts +2 -0
  93. package/dist/mcp/action-catalog-types.d.ts +9 -0
  94. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  95. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  96. package/dist/mcp/child-read-evidence.d.ts +9 -0
  97. package/dist/mcp/command-read.d.ts +24 -0
  98. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  99. package/dist/mcp/contract-input.d.ts +11 -0
  100. package/dist/mcp/documents.d.ts +7 -5
  101. package/dist/mcp/files.d.ts +2 -2
  102. package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
  103. package/dist/mcp/knowledge-entries.d.ts +5 -0
  104. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  105. package/dist/mcp/receipts.d.ts +9 -0
  106. package/dist/mcp/request-abort.d.ts +19 -0
  107. package/dist/mcp/scheduled-task-input.d.ts +1189 -0
  108. package/dist/mcp/scheduled-task-view.d.ts +22 -4
  109. package/dist/mcp/server.d.ts +255 -3
  110. package/dist/mcp/session-event-view.d.ts +94 -0
  111. package/dist/mcp/session-view.d.ts +66 -2
  112. package/dist/mcp/session-wait.d.ts +174 -0
  113. package/dist/mcp-oauth.d.ts +52 -0
  114. package/dist/model-catalog.d.ts +11 -31
  115. package/dist/observability.d.ts +3 -1
  116. package/dist/organization-mcp.d.ts +52 -0
  117. package/dist/organization-recovery-notifications.d.ts +41 -0
  118. package/dist/routes/analytics-consent.d.ts +26 -0
  119. package/dist/routes/api-integrations.d.ts +25 -0
  120. package/dist/routes/api-keys.d.ts +17 -0
  121. package/dist/routes/artifact-catalog.d.ts +6 -0
  122. package/dist/routes/automations.d.ts +19 -0
  123. package/dist/routes/billing.d.ts +49 -0
  124. package/dist/routes/browser-sessions.d.ts +71 -3
  125. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  126. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  127. package/dist/routes/client-errors.d.ts +146 -0
  128. package/dist/routes/codex.d.ts +76 -2
  129. package/dist/routes/company-brain.d.ts +3 -0
  130. package/dist/routes/company-profile.d.ts +2 -1
  131. package/dist/routes/computer-sessions.d.ts +14 -0
  132. package/dist/routes/connect.d.ts +5 -0
  133. package/dist/routes/editable-artifacts.d.ts +2 -0
  134. package/dist/routes/external-identity-links.d.ts +6 -0
  135. package/dist/routes/feedback.d.ts +3 -0
  136. package/dist/routes/files.d.ts +4 -0
  137. package/dist/routes/github-browser-pages.d.ts +12 -0
  138. package/dist/routes/github.d.ts +2 -0
  139. package/dist/routes/insights-response-cache.d.ts +10 -0
  140. package/dist/routes/insights-usage.d.ts +12 -0
  141. package/dist/routes/insights.d.ts +30 -1
  142. package/dist/routes/knowledge.d.ts +3 -0
  143. package/dist/routes/managed-auth-session-sets.d.ts +26 -0
  144. package/dist/routes/managed-onboarding.d.ts +29 -0
  145. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  146. package/dist/routes/model-connection-access.d.ts +3 -0
  147. package/dist/routes/organization-integration-policy.d.ts +3 -0
  148. package/dist/routes/organization-integrations.d.ts +6 -0
  149. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  150. package/dist/routes/organization-model-providers.d.ts +3 -0
  151. package/dist/routes/organization-recovery.d.ts +19 -0
  152. package/dist/routes/organization-service-accounts.d.ts +3 -0
  153. package/dist/routes/organization-sessions.d.ts +26 -0
  154. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  155. package/dist/routes/personal-github.d.ts +3 -0
  156. package/dist/routes/pr-review-github.d.ts +3 -0
  157. package/dist/routes/pr-review.d.ts +3 -0
  158. package/dist/routes/session-artifact-associations.d.ts +4 -0
  159. package/dist/routes/session-history-imports.d.ts +9 -0
  160. package/dist/routes/sessions.d.ts +44 -6
  161. package/dist/routes/skill-content.d.ts +4 -0
  162. package/dist/routes/skill-install-authority.d.ts +6 -0
  163. package/dist/routes/subscription-account-pools.d.ts +34 -0
  164. package/dist/routes/subscription-pool-access.d.ts +16 -0
  165. package/dist/routes/supergrok.d.ts +6 -1
  166. package/dist/routes/usage-allowances.d.ts +12 -0
  167. package/dist/routes/user-resource-authorities.d.ts +3 -0
  168. package/dist/routes/workspace-artifacts.d.ts +2 -1
  169. package/dist/routes/workspace-capture.d.ts +10 -2
  170. package/dist/routes/workspace-integrations.d.ts +35 -0
  171. package/dist/routes/workspace-learning.d.ts +3 -0
  172. package/dist/routes/workspace-model-providers.d.ts +4 -0
  173. package/dist/routes/workspaces.d.ts +29 -0
  174. package/dist/sandbox/auth-callout.d.ts +8 -0
  175. package/dist/sandbox/channel-a.d.ts +19 -1
  176. package/dist/sandbox/connection-authority.d.ts +3 -0
  177. package/dist/sandbox/enrollment.d.ts +9 -1
  178. package/dist/sandbox/machines.d.ts +5 -2
  179. package/dist/sandbox/metrics-ingestion.d.ts +28 -20
  180. package/dist/sandbox/rematerialize.d.ts +2 -0
  181. package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
  182. package/dist/sandbox/viewer.d.ts +26 -1
  183. package/dist/sandbox-file-artifacts.d.ts +50 -0
  184. package/dist/scheduled-task-deletion.d.ts +13 -0
  185. package/dist/session-create-observability.d.ts +5 -0
  186. package/dist/session-event-view-MPS2OZD3.js +292 -0
  187. package/dist/session-event-view-MPS2OZD3.js.map +1 -0
  188. package/dist/site-session-origin.d.ts +13 -0
  189. package/dist/site-uploads.d.ts +41 -0
  190. package/dist/slack-reaction-files.d.ts +1 -1
  191. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  192. package/dist/temporal-schedule-sync.d.ts +26 -0
  193. package/dist/transcription/providers/xai-subscription.d.ts +1 -0
  194. package/dist/transcription/service.d.ts +2 -1
  195. package/dist/work-discovery-observability.d.ts +33 -0
  196. package/dist/workspace-artifact-content.d.ts +28 -0
  197. package/dist/workspace-artifact-provenance.d.ts +7 -0
  198. package/dist/workspace-delete-observability.d.ts +10 -0
  199. package/dist/workspace-deletion.d.ts +6 -0
  200. package/dist/workspace-state-projection.d.ts +3 -5
  201. package/dist/workspace-tool-gateway-observability.d.ts +17 -0
  202. package/dist/workspace-tool-gateway.d.ts +123 -0
  203. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  204. package/package.json +23 -19
  205. package/src/access-grant-rls.ts +75 -0
  206. package/src/admission-trace.ts +14 -0
  207. package/src/api-websocket.ts +23 -0
  208. package/src/app.ts +1974 -256
  209. package/src/artifact-catalog-cursor.ts +60 -0
  210. package/src/auth/managed-auth-attempt-context.ts +70 -0
  211. package/src/auth/managed-auth-rate-limits.ts +252 -0
  212. package/src/auth/managed-auth-session-adapter.ts +222 -0
  213. package/src/auth/managed-auth.ts +536 -60
  214. package/src/auth/managed-email.ts +174 -0
  215. package/src/auth/managed-sign-in-notifications.ts +81 -0
  216. package/src/auth/new-signups-gate.ts +49 -0
  217. package/src/auth/organization-user-setup.ts +307 -0
  218. package/src/auth/signup-funnel-metrics.ts +164 -0
  219. package/src/browser-controller-authority.ts +1 -186
  220. package/src/browser-ephemeral.ts +39 -0
  221. package/src/browser-state-authority.ts +1 -236
  222. package/src/claude-subscription-account-conflicts.ts +12 -0
  223. package/src/claude-subscription-account-usage.ts +48 -0
  224. package/src/claude-subscription-oauth.ts +362 -0
  225. package/src/claude-subscription-profile.ts +73 -0
  226. package/src/claude-subscription-usage.ts +97 -0
  227. package/src/claude-workspace-connection.ts +82 -0
  228. package/src/codemode.ts +194 -30
  229. package/src/codex-realtime.ts +8 -2
  230. package/src/company-brain-okf.ts +340 -0
  231. package/src/connected-machine-computer-access.ts +33 -0
  232. package/src/connection-ownership.ts +199 -0
  233. package/src/controller-data-plane.ts +81 -0
  234. package/src/editable-artifact-native-kernel.ts +26 -15
  235. package/src/editable-artifact-office-import.ts +77 -9
  236. package/src/editable-artifact-production.ts +23 -7
  237. package/src/editable-artifact-source-session.ts +123 -0
  238. package/src/editable-artifact-websocket.ts +27 -21
  239. package/src/editable-artifact-workspace-files.ts +31 -6
  240. package/src/fatal-process-boundary.ts +246 -0
  241. package/src/gateway-realtime.ts +1 -1
  242. package/src/github-access.ts +147 -5
  243. package/src/http/acting-person.ts +71 -0
  244. package/src/http/api-contract-compat.ts +49 -0
  245. package/src/http/api-error.ts +115 -1
  246. package/src/http/auth.ts +48 -0
  247. package/src/http/cors.ts +67 -0
  248. package/src/http/deprecation.ts +118 -0
  249. package/src/http/interaction-control-error.ts +164 -0
  250. package/src/http/keyed-admission.ts +29 -0
  251. package/src/http/local-browser-boundary.ts +343 -0
  252. package/src/http/metrics-listener.ts +57 -0
  253. package/src/http/path-identifier.ts +54 -0
  254. package/src/http/registered-route-label.ts +34 -0
  255. package/src/http/request-body.ts +127 -0
  256. package/src/http/request-source.ts +178 -0
  257. package/src/http/sse.ts +486 -132
  258. package/src/http/unmatched-route.ts +60 -0
  259. package/src/http/user-content.ts +158 -0
  260. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  261. package/src/index.ts +157 -52
  262. package/src/integration-endpoint-test.ts +291 -0
  263. package/src/integrations/api-integrations.ts +98 -11
  264. package/src/integrations/atlassian.ts +474 -136
  265. package/src/integrations/connect-authority.ts +2 -0
  266. package/src/integrations/connect-callback-return.ts +86 -0
  267. package/src/integrations/fiken.ts +354 -64
  268. package/src/integrations/github-app-connect.ts +435 -0
  269. package/src/integrations/github-installation-proof.ts +60 -0
  270. package/src/integrations/github-lens-connect.ts +76 -0
  271. package/src/integrations/github-skill-source.ts +2 -142
  272. package/src/integrations/google-drive.ts +820 -222
  273. package/src/integrations/integration-commit-authority.ts +69 -0
  274. package/src/integrations/marketplace-plugin.ts +48 -0
  275. package/src/integrations/oauth-client.ts +1356 -459
  276. package/src/integrations/oauth-profiles.ts +537 -0
  277. package/src/integrations/oauth-return-path.ts +18 -0
  278. package/src/integrations/personal-github-repositories.ts +674 -0
  279. package/src/integrations/personal-github.ts +825 -0
  280. package/src/integrations/pr-review-provider.ts +246 -0
  281. package/src/integrations/provider-oauth.ts +250 -22
  282. package/src/integrations/slack-app-home.ts +300 -0
  283. package/src/integrations/slack-bot.ts +963 -239
  284. package/src/integrations/slack-file-upload-flow.ts +147 -0
  285. package/src/integrations/slack-install.ts +83 -0
  286. package/src/integrations/slack-interactions.ts +3170 -474
  287. package/src/integrations/slack-mrkdwn.ts +193 -0
  288. package/src/integrations/slack-routing.ts +337 -0
  289. package/src/integrations/slack-session-defaults.ts +224 -0
  290. package/src/integrations/slack-task-file-upload.ts +323 -0
  291. package/src/integrations/social-oauth.ts +213 -15
  292. package/src/interaction-agent-access.ts +48 -0
  293. package/src/interaction-frame-proxy.ts +409 -0
  294. package/src/interaction-metrics.ts +30 -0
  295. package/src/mcp/action-catalog-types.ts +9 -0
  296. package/src/mcp/action-catalog.gen.ts +6696 -0
  297. package/src/mcp/capability-account-readiness.ts +17 -0
  298. package/src/mcp/child-read-evidence.ts +19 -0
  299. package/src/mcp/command-read.ts +109 -0
  300. package/src/mcp/company-profile-agent-admin.ts +198 -0
  301. package/src/mcp/contract-input.ts +141 -0
  302. package/src/mcp/documents.ts +65 -377
  303. package/src/mcp/editable-artifacts.ts +12 -6
  304. package/src/mcp/files.ts +80 -38
  305. package/src/mcp/first-party-tool-permissions.ts +305 -0
  306. package/src/mcp/knowledge-entries.ts +322 -0
  307. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  308. package/src/mcp/receipts.ts +34 -0
  309. package/src/mcp/request-abort.ts +44 -0
  310. package/src/mcp/scheduled-task-input.ts +76 -0
  311. package/src/mcp/scheduled-task-view.ts +44 -3
  312. package/src/mcp/server.ts +3030 -1267
  313. package/src/mcp/session-event-view.ts +383 -0
  314. package/src/mcp/session-view.ts +84 -3
  315. package/src/mcp/session-wait.ts +665 -0
  316. package/src/mcp-oauth.ts +1123 -0
  317. package/src/model-catalog.ts +91 -333
  318. package/src/observability.ts +15 -1
  319. package/src/organization-mcp.ts +397 -0
  320. package/src/organization-recovery-notifications.ts +103 -0
  321. package/src/routes/analytics-consent.ts +123 -0
  322. package/src/routes/api-integrations.ts +364 -74
  323. package/src/routes/api-keys.ts +336 -10
  324. package/src/routes/artifact-catalog.ts +279 -0
  325. package/src/routes/automations.ts +768 -0
  326. package/src/routes/billing.ts +461 -46
  327. package/src/routes/browser-sessions.ts +839 -131
  328. package/src/routes/canonical-human-identities.ts +90 -14
  329. package/src/routes/capabilities.ts +107 -6
  330. package/src/routes/channels.ts +20 -3
  331. package/src/routes/claude-subscription-accounts.ts +334 -0
  332. package/src/routes/claude-subscription-oauth.ts +142 -0
  333. package/src/routes/client-errors.ts +362 -0
  334. package/src/routes/codex.ts +833 -116
  335. package/src/routes/company-brain.ts +322 -0
  336. package/src/routes/company-profile.ts +65 -1
  337. package/src/routes/computer-sessions.ts +557 -106
  338. package/src/routes/connect.ts +1938 -0
  339. package/src/routes/connections.ts +1040 -349
  340. package/src/routes/documents.ts +488 -287
  341. package/src/routes/editable-artifacts.ts +79 -9
  342. package/src/routes/enrollments.ts +135 -39
  343. package/src/routes/environments.ts +154 -58
  344. package/src/routes/external-identity-links.ts +201 -0
  345. package/src/routes/feedback.ts +113 -0
  346. package/src/routes/files.ts +337 -39
  347. package/src/routes/github-browser-pages.ts +162 -0
  348. package/src/routes/github.ts +446 -144
  349. package/src/routes/insights-response-cache.ts +83 -0
  350. package/src/routes/insights-usage.ts +345 -0
  351. package/src/routes/insights.ts +153 -19
  352. package/src/routes/install.ts +133 -38
  353. package/src/routes/integration-facets.ts +107 -33
  354. package/src/routes/interaction-resources.ts +30 -3
  355. package/src/routes/knowledge.ts +488 -0
  356. package/src/routes/machines.ts +313 -15
  357. package/src/routes/managed-auth-session-sets.ts +1218 -0
  358. package/src/routes/managed-onboarding.ts +337 -0
  359. package/src/routes/managed-sign-in-methods.ts +433 -0
  360. package/src/routes/memory-slack-publications.ts +3 -2
  361. package/src/routes/model-connection-access.ts +208 -0
  362. package/src/routes/organization-integration-policy.ts +116 -0
  363. package/src/routes/organization-integrations.ts +326 -0
  364. package/src/routes/organization-mcp-connections.ts +178 -0
  365. package/src/routes/organization-memberships.ts +1019 -27
  366. package/src/routes/organization-model-providers.ts +293 -0
  367. package/src/routes/organization-recovery.ts +325 -0
  368. package/src/routes/organization-service-accounts.ts +128 -0
  369. package/src/routes/organization-sessions.ts +350 -0
  370. package/src/routes/personal-github-git-broker.ts +785 -0
  371. package/src/routes/personal-github.ts +370 -0
  372. package/src/routes/plugins.ts +251 -22
  373. package/src/routes/pr-review-github.ts +881 -0
  374. package/src/routes/pr-review.ts +622 -0
  375. package/src/routes/preference-registry.ts +12 -93
  376. package/src/routes/rigs.ts +167 -50
  377. package/src/routes/scheduled-tasks.ts +346 -41
  378. package/src/routes/session-artifact-associations.ts +87 -0
  379. package/src/routes/session-history-imports.ts +280 -0
  380. package/src/routes/sessions.ts +2306 -264
  381. package/src/routes/skill-content.ts +297 -0
  382. package/src/routes/skill-install-authority.ts +64 -0
  383. package/src/routes/skills.ts +62 -9
  384. package/src/routes/social.ts +46 -18
  385. package/src/routes/subscription-account-pools.ts +436 -0
  386. package/src/routes/subscription-pool-access.ts +126 -0
  387. package/src/routes/supergrok.ts +219 -303
  388. package/src/routes/transcription-recordings.ts +38 -3
  389. package/src/routes/transcriptions.ts +4 -0
  390. package/src/routes/usage-allowances.ts +378 -0
  391. package/src/routes/user-resource-authorities.ts +138 -0
  392. package/src/routes/video-generation.ts +14 -10
  393. package/src/routes/workspace-artifacts.ts +275 -69
  394. package/src/routes/workspace-capture.ts +21 -0
  395. package/src/routes/workspace-integrations.ts +576 -0
  396. package/src/routes/workspace-learning.ts +159 -0
  397. package/src/routes/workspace-model-providers.ts +148 -0
  398. package/src/routes/workspace-state.ts +38 -25
  399. package/src/routes/workspaces.ts +1004 -127
  400. package/src/sandbox/auth-callout.ts +96 -19
  401. package/src/sandbox/channel-a.ts +323 -24
  402. package/src/sandbox/connection-authority.ts +3 -0
  403. package/src/sandbox/enrollment.ts +81 -6
  404. package/src/sandbox/machines.ts +218 -76
  405. package/src/sandbox/metrics-ingestion.ts +411 -62
  406. package/src/sandbox/rematerialize.ts +121 -19
  407. package/src/sandbox/session-attach-variable-sets.ts +131 -0
  408. package/src/sandbox/viewer.ts +280 -25
  409. package/src/sandbox-file-artifacts.ts +413 -0
  410. package/src/scheduled-task-deletion.ts +138 -0
  411. package/src/session-create-observability.ts +46 -0
  412. package/src/session-realtime-context.ts +6 -3
  413. package/src/site-session-origin.ts +48 -0
  414. package/src/site-uploads.ts +224 -0
  415. package/src/slack-reaction-files.ts +16 -5
  416. package/src/temporal-schedule-cleanup.ts +13 -0
  417. package/src/temporal-schedule-sync.ts +74 -0
  418. package/src/transcription/providers/codex-subscription.ts +2 -0
  419. package/src/transcription/providers/openai.ts +1 -0
  420. package/src/transcription/providers/xai-subscription.ts +49 -3
  421. package/src/transcription/segmenter.ts +8 -2
  422. package/src/transcription/service.ts +43 -6
  423. package/src/work-discovery-observability.ts +121 -0
  424. package/src/workspace-artifact-content.ts +144 -0
  425. package/src/workspace-artifact-provenance.ts +104 -0
  426. package/src/workspace-delete-observability.ts +75 -0
  427. package/src/workspace-deletion.ts +73 -0
  428. package/src/workspace-state-projection.ts +18 -148
  429. package/src/workspace-tool-gateway-observability.ts +100 -0
  430. package/src/workspace-tool-gateway.ts +870 -0
  431. package/src/workspace-webhook-dispatch.ts +190 -0
  432. package/src/xai-subscription-auth.ts +9 -2
  433. package/dist/chunk-2PQMSRCB.js +0 -49759
  434. package/dist/chunk-2PQMSRCB.js.map +0 -1
  435. package/dist/routes/packs.d.ts +0 -3
  436. package/src/routes/packs.ts +0 -729
@@ -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
+ }