@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,164 @@
1
+ import {
2
+ SIGNUP_ACQUISITION_SOURCES,
3
+ signupAcquisitionSource,
4
+ type SignupAcquisitionSource,
5
+ } from "@opengeni/contracts";
6
+ import type { Observability } from "@opengeni/observability";
7
+ import { getOAuthState } from "better-auth/api";
8
+
9
+ import {
10
+ currentManagedAuthProviderId,
11
+ shouldDiscardCurrentManagedAuthProviderSession,
12
+ } from "./managed-auth-attempt-context";
13
+
14
+ /**
15
+ * Content-free sign-up funnel counters. Every label is a closed set: no user,
16
+ * email, organization, workspace, or campaign value ever becomes a label.
17
+ */
18
+ export const AUTH_FUNNEL_EVENTS = ["sign_up", "email_verified", "sign_in"] as const;
19
+ export type AuthFunnelEvent = (typeof AUTH_FUNNEL_EVENTS)[number];
20
+ export const AUTH_FUNNEL_METHODS = ["email", "google", "github", "other"] as const;
21
+ export type AuthFunnelMethod = (typeof AUTH_FUNNEL_METHODS)[number];
22
+ export const ORGANIZATION_SETUP_OUTCOMES = ["created", "failed"] as const;
23
+ export type OrganizationSetupOutcome = (typeof ORGANIZATION_SETUP_OUTCOMES)[number];
24
+
25
+ const AUTH_EVENTS_METRIC = {
26
+ name: "opengeni_auth_events_total",
27
+ help: "Managed authentication funnel events (sign-up, email verification, sign-in) by closed method.",
28
+ } as const;
29
+ const ORGANIZATION_SETUP_METRIC = {
30
+ name: "opengeni_organization_setup_total",
31
+ help: "Self-service post-sign-in organization setup outcomes.",
32
+ } as const;
33
+ const SIGNUP_ACQUISITION_METRIC = {
34
+ name: "opengeni_signup_acquisition_total",
35
+ help: "New managed users by normalized first-touch acquisition source.",
36
+ } as const;
37
+
38
+ /** The only observability surface funnel telemetry uses. */
39
+ export type SignupFunnelObservability = Pick<Observability, "incrementCounter">;
40
+
41
+ /** Better Auth request-body / OAuth-state key that carries first-touch attribution. */
42
+ export const SIGNUP_ATTRIBUTION_AUTH_FIELD = "opengeniAttribution";
43
+
44
+ export type SignupFunnelMetrics = {
45
+ /** A managed auth user was created (Better Auth `user.create.after`). */
46
+ recordSignUp(authContext: unknown): Promise<void>;
47
+ /** A managed user verified their email address. */
48
+ recordEmailVerified(): void;
49
+ /**
50
+ * A provider session was created that is not an internally discarded one.
51
+ * In the legacy session-set mode this includes the session the first
52
+ * successful email-verification click creates: that is the new user's first
53
+ * sign-in, so it is counted rather than folded into `email_verified`.
54
+ */
55
+ recordSignIn(): void;
56
+ };
57
+
58
+ export function authFunnelMethod(providerId: string | null | undefined): AuthFunnelMethod {
59
+ if (providerId === "credential") return "email";
60
+ if (providerId === "google" || providerId === "github") return providerId;
61
+ return "other";
62
+ }
63
+
64
+ /**
65
+ * Publish every closed series at zero so dashboards and alerts can tell a quiet
66
+ * funnel from missing instrumentation. Never throws: a metric-registry failure
67
+ * must not stop managed auth (and with it API startup) from composing.
68
+ */
69
+ export function registerSignupFunnelMetricBaselines(
70
+ observability: SignupFunnelObservability,
71
+ ): void {
72
+ const baseline = (
73
+ metric: { name: string; help: string },
74
+ labels: Record<string, string>,
75
+ ): void => {
76
+ try {
77
+ observability.incrementCounter({ ...metric, labels, amount: 0 });
78
+ } catch {
79
+ // Telemetry only; the series appears on its first real increment.
80
+ }
81
+ };
82
+ for (const event of AUTH_FUNNEL_EVENTS) {
83
+ for (const method of AUTH_FUNNEL_METHODS) baseline(AUTH_EVENTS_METRIC, { event, method });
84
+ }
85
+ for (const outcome of ORGANIZATION_SETUP_OUTCOMES) {
86
+ baseline(ORGANIZATION_SETUP_METRIC, { outcome });
87
+ }
88
+ for (const source of SIGNUP_ACQUISITION_SOURCES) baseline(SIGNUP_ACQUISITION_METRIC, { source });
89
+ }
90
+
91
+ export function createSignupFunnelMetrics(
92
+ observability: SignupFunnelObservability,
93
+ ): SignupFunnelMetrics {
94
+ registerSignupFunnelMetricBaselines(observability);
95
+ const authEvent = (event: AuthFunnelEvent, method: AuthFunnelMethod) => {
96
+ observability.incrementCounter({ ...AUTH_EVENTS_METRIC, labels: { event, method } });
97
+ };
98
+ return {
99
+ recordSignUp: async (authContext) => {
100
+ try {
101
+ authEvent("sign_up", authFunnelMethod(currentManagedAuthProviderId()));
102
+ const source: SignupAcquisitionSource = signupAcquisitionSource(
103
+ await signupAttributionFromAuthContext(authContext),
104
+ );
105
+ observability.incrementCounter({ ...SIGNUP_ACQUISITION_METRIC, labels: { source } });
106
+ } catch {
107
+ // Funnel telemetry must never fail account creation.
108
+ }
109
+ },
110
+ recordEmailVerified: () => {
111
+ try {
112
+ authEvent("email_verified", "email");
113
+ } catch {
114
+ /* Telemetry only. */
115
+ }
116
+ },
117
+ recordSignIn: () => {
118
+ try {
119
+ // Session-set mode discards the provider session of a non-callback
120
+ // Better Auth call; the product transaction then creates the real one.
121
+ if (shouldDiscardCurrentManagedAuthProviderSession()) return;
122
+ authEvent("sign_in", authFunnelMethod(currentManagedAuthProviderId()));
123
+ } catch {
124
+ /* Telemetry only. */
125
+ }
126
+ },
127
+ };
128
+ }
129
+
130
+ /** Count one self-service organization setup request outcome. */
131
+ export function recordOrganizationSetupOutcome(
132
+ observability: SignupFunnelObservability | undefined,
133
+ outcome: OrganizationSetupOutcome,
134
+ ): void {
135
+ try {
136
+ observability?.incrementCounter({ ...ORGANIZATION_SETUP_METRIC, labels: { outcome } });
137
+ } catch {
138
+ // Telemetry must never change the setup response.
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Read untrusted first-touch attribution from the Better Auth endpoint that is
144
+ * creating the user: the email sign-up body, or the server-side OAuth state
145
+ * (`additionalData`) that the social start stored for its callback.
146
+ */
147
+ export async function signupAttributionFromAuthContext(authContext: unknown): Promise<unknown> {
148
+ const body =
149
+ authContext && typeof authContext === "object"
150
+ ? (authContext as { body?: unknown }).body
151
+ : undefined;
152
+ if (body && typeof body === "object" && SIGNUP_ATTRIBUTION_AUTH_FIELD in body) {
153
+ return (body as Record<string, unknown>)[SIGNUP_ATTRIBUTION_AUTH_FIELD];
154
+ }
155
+ try {
156
+ const state: unknown = await getOAuthState();
157
+ if (state && typeof state === "object" && SIGNUP_ATTRIBUTION_AUTH_FIELD in state) {
158
+ return (state as Record<string, unknown>)[SIGNUP_ATTRIBUTION_AUTH_FIELD];
159
+ }
160
+ } catch {
161
+ // Not inside a Better Auth OAuth callback.
162
+ }
163
+ return undefined;
164
+ }
@@ -1,186 +1 @@
1
- import { createHmac } from "node:crypto";
2
- import type {
3
- InteractionPlacement,
4
- NetworkRouteConfiguration,
5
- NetworkRouteConsistency,
6
- } from "@opengeni/contracts";
7
-
8
- type BrowserControllerAuthorityScope = {
9
- rootSecret: string;
10
- accountId: string;
11
- workspaceId: string;
12
- placement: InteractionPlacement;
13
- placementInstanceId: string;
14
- };
15
-
16
- type BrowserSessionAuthorityScope = BrowserControllerAuthorityScope & {
17
- browserSessionId: string;
18
- controllerGeneration: string;
19
- tokenGeneration: number;
20
- };
21
-
22
- type ComputerSessionAuthorityScope = BrowserControllerAuthorityScope & {
23
- computerSessionId: string;
24
- controllerGeneration: string;
25
- tokenGeneration: number;
26
- };
27
-
28
- /** Stable placement-admin authority. This token is installed owner-only inside
29
- * the exact placement and is never persisted or returned by the public API. */
30
- export function deriveBrowserControllerAdminToken(scope: BrowserControllerAuthorityScope): string {
31
- return derive(scope.rootSecret, "placement-admin.v1", [
32
- scope.accountId,
33
- scope.workspaceId,
34
- placementKey(scope.placement),
35
- scope.placementInstanceId,
36
- ]);
37
- }
38
-
39
- /** Deterministic controller credentials. The durable generations are the only
40
- * stored authority; plaintext tokens can be reconstructed only by API replicas
41
- * holding the deployment HMAC root. */
42
- export function deriveBrowserSessionControllerTokens(scope: BrowserSessionAuthorityScope): {
43
- controlToken: string;
44
- viewToken: string;
45
- } {
46
- const fields = [
47
- scope.accountId,
48
- scope.workspaceId,
49
- placementKey(scope.placement),
50
- scope.placementInstanceId,
51
- scope.browserSessionId,
52
- scope.controllerGeneration,
53
- scope.tokenGeneration,
54
- ] as const;
55
- return {
56
- controlToken: derive(scope.rootSecret, "session-control.v1", fields),
57
- viewToken: derive(scope.rootSecret, "session-view.v1", fields),
58
- };
59
- }
60
-
61
- /** Secret-safe durable identity for one exact route launch. The digest binds
62
- * the route snapshot and proxy credential without making a password-verifier
63
- * hash available to database readers. */
64
- export function deriveBrowserNetworkRouteAuthorityDigest(scope: {
65
- rootSecret: string;
66
- accountId: string;
67
- workspaceId: string;
68
- browserSessionId: string;
69
- routeId: string;
70
- routeVersion: number;
71
- credentialVersion: number | null;
72
- configuration: NetworkRouteConfiguration;
73
- consistency: NetworkRouteConsistency;
74
- proxyCredential: { username: string; password: string } | null;
75
- }): string {
76
- return derive(scope.rootSecret, "network-route-launch.v1", [
77
- scope.accountId,
78
- scope.workspaceId,
79
- scope.browserSessionId,
80
- scope.routeId,
81
- scope.routeVersion,
82
- scope.credentialVersion ?? "none",
83
- canonicalJson(scope.configuration),
84
- canonicalJson(scope.consistency),
85
- scope.proxyCredential?.username ?? "none",
86
- scope.proxyCredential?.password ?? "none",
87
- ]).replace(/^ogb\./u, "ogr.");
88
- }
89
-
90
- export function deriveBrowserViewGrantToken(
91
- scope: BrowserSessionAuthorityScope & { grantId: string; expiresAt: string },
92
- ): string {
93
- return derive(scope.rootSecret, "frame-view-grant.v1", [
94
- scope.accountId,
95
- scope.workspaceId,
96
- placementKey(scope.placement),
97
- scope.placementInstanceId,
98
- scope.browserSessionId,
99
- scope.controllerGeneration,
100
- scope.tokenGeneration,
101
- scope.grantId,
102
- scope.expiresAt,
103
- ]);
104
- }
105
-
106
- /** ComputerSession credentials share the placement controller root while using
107
- * resource-specific domains. Browser and computer authority cannot collide. */
108
- export function deriveComputerSessionControllerTokens(scope: ComputerSessionAuthorityScope): {
109
- controlToken: string;
110
- viewToken: string;
111
- } {
112
- const fields = [
113
- scope.accountId,
114
- scope.workspaceId,
115
- placementKey(scope.placement),
116
- scope.placementInstanceId,
117
- scope.computerSessionId,
118
- scope.controllerGeneration,
119
- scope.tokenGeneration,
120
- ] as const;
121
- return {
122
- controlToken: derive(scope.rootSecret, "computer-session-control.v1", fields),
123
- viewToken: derive(scope.rootSecret, "computer-session-view.v1", fields),
124
- };
125
- }
126
-
127
- export function deriveComputerViewGrantToken(
128
- scope: ComputerSessionAuthorityScope & { grantId: string; expiresAt: string },
129
- ): string {
130
- return derive(scope.rootSecret, "computer-frame-view-grant.v1", [
131
- scope.accountId,
132
- scope.workspaceId,
133
- placementKey(scope.placement),
134
- scope.placementInstanceId,
135
- scope.computerSessionId,
136
- scope.controllerGeneration,
137
- scope.tokenGeneration,
138
- scope.grantId,
139
- scope.expiresAt,
140
- ]);
141
- }
142
-
143
- function derive(rootSecret: string, domain: string, fields: readonly (string | number)[]): string {
144
- if (!rootSecret) throw new Error("browser controller authority root is unavailable");
145
- const hmac = createHmac("sha256", rootSecret);
146
- hmac.update("opengeni.browser-controller-authority\0", "utf8");
147
- writeField(hmac, domain);
148
- for (const field of fields) writeField(hmac, String(field));
149
- return `ogb.${hmac.digest("base64url")}`;
150
- }
151
-
152
- function writeField(hmac: ReturnType<typeof createHmac>, value: string): void {
153
- const bytes = Buffer.from(value, "utf8");
154
- hmac.update(String(bytes.byteLength), "utf8");
155
- hmac.update(":", "utf8");
156
- hmac.update(bytes);
157
- }
158
-
159
- function canonicalJson(value: unknown): string {
160
- return JSON.stringify(canonicalJsonValue(value));
161
- }
162
-
163
- function canonicalJsonValue(value: unknown): unknown {
164
- if (Array.isArray(value)) return value.map(canonicalJsonValue);
165
- if (value && typeof value === "object") {
166
- return Object.fromEntries(
167
- Object.entries(value as Record<string, unknown>)
168
- .sort(([left], [right]) => left.localeCompare(right))
169
- .map(([key, entry]) => [key, canonicalJsonValue(entry)]),
170
- );
171
- }
172
- return value;
173
- }
174
-
175
- function placementKey(placement: InteractionPlacement): string {
176
- switch (placement.kind) {
177
- case "sandbox_group":
178
- return `sandbox_group:${placement.sandboxGroupId}`;
179
- case "connected_machine":
180
- return `connected_machine:${placement.sandboxId}`;
181
- case "attached_device":
182
- return `attached_device:${placement.deviceId}`;
183
- case "external_provider":
184
- return `external_provider:${placement.providerId}:${placement.placementId}`;
185
- }
186
- }
1
+ export * from "@opengeni/interaction/browser-controller-authority";
@@ -0,0 +1,39 @@
1
+ import { createHmac } from "node:crypto";
2
+ import type { BrowserSession, CreateBrowserSessionRequest } from "@opengeni/contracts";
3
+ import { BrowserControlUnsupportedError } from "@opengeni/runtime/sandbox";
4
+
5
+ export function assertEphemeralBrowserCreateEnabled(
6
+ request: CreateBrowserSessionRequest,
7
+ enabled: boolean,
8
+ ): void {
9
+ if (request.storageMode === "ephemeral_context" && !enabled) {
10
+ throw new BrowserControlUnsupportedError(
11
+ "Ephemeral Chromium contexts are disabled by the operator",
12
+ );
13
+ }
14
+ }
15
+
16
+ /** Only persisted session identity and server-resolved physical placement enter
17
+ * this private controller partition. Public callers never supply a pool key. */
18
+ export function ephemeralBrowserPartition(
19
+ session: BrowserSession,
20
+ placementInstanceId: string,
21
+ rootSecret: string,
22
+ ): string {
23
+ if (session.placement.kind !== "sandbox_group")
24
+ throw new BrowserControlUnsupportedError(
25
+ "Ephemeral contexts require a managed sandbox placement",
26
+ );
27
+ return createHmac("sha256", rootSecret)
28
+ .update(
29
+ JSON.stringify({
30
+ version: "ephemeral-chromium-headless-default-egress-v1",
31
+ accountId: session.accountId,
32
+ workspaceId: session.workspaceId,
33
+ ownerSubjectId: session.createdBySubjectId,
34
+ sandboxGroupId: session.placement.sandboxGroupId,
35
+ placementInstanceId,
36
+ }),
37
+ )
38
+ .digest("hex");
39
+ }
@@ -1,236 +1 @@
1
- import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes } from "node:crypto";
2
- import { BROWSER_PROFILE_ARTIFACT_FORMAT } from "@opengeni/contracts";
3
-
4
- const ROOT_KEY_BYTES = 32;
5
- const DATA_KEY_BYTES = 32;
6
- const IV_BYTES = 12;
7
- const TAG_BYTES = 16;
8
- const WRAPPED_PREFIX = "ogbk1";
9
- const SHA256_PATTERN = /^[0-9a-f]{64}$/u;
10
- const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
11
-
12
- export type BrowserStateOperationScope = {
13
- accountId: string;
14
- workspaceId: string;
15
- browserSessionId: string;
16
- operationId: string;
17
- objectKey: string;
18
- };
19
-
20
- export type BrowserStateArtifactScope = {
21
- accountId: string;
22
- workspaceId: string;
23
- objectKey: string;
24
- artifactDigest: string;
25
- contentDigest: string;
26
- };
27
-
28
- /** Deterministic only within one idempotent publication operation. This lets a
29
- * control-plane retry present browserd with exactly the same secret authority
30
- * without storing a plaintext key or placing it in an operation row. */
31
- export function deriveBrowserStateDataKey(
32
- rootKey: Uint8Array,
33
- scopeInput: BrowserStateOperationScope,
34
- ): Buffer {
35
- const scope = operationScope(scopeInput);
36
- return createHmac("sha256", root(rootKey))
37
- .update("opengeni.browser-state.data-key.v1\0", "utf8")
38
- .update(canonicalJson(scope), "utf8")
39
- .digest();
40
- }
41
-
42
- /** Associated data for the encrypted profile object. It is reproducible from
43
- * durable non-secret artifact authority during restore. */
44
- export function browserStateArtifactAad(
45
- scopeInput: Pick<BrowserStateArtifactScope, "accountId" | "workspaceId" | "objectKey">,
46
- ): Buffer {
47
- const scope = baseArtifactScope(scopeInput);
48
- return Buffer.from(`opengeni.browser-state.artifact-aad.v1\0${canonicalJson(scope)}`, "utf8");
49
- }
50
-
51
- /** Wrap a 32-byte artifact data key under the operator-held root key. The
52
- * ciphertext is bound to workspace, object, and both integrity digests. */
53
- export function wrapBrowserStateDataKey(
54
- rootKey: Uint8Array,
55
- dataKeyInput: Uint8Array,
56
- scopeInput: BrowserStateArtifactScope,
57
- ): string {
58
- const dataKey = exactKey(dataKeyInput, "browser state data key");
59
- const scope = artifactScope(scopeInput);
60
- const iv = randomBytes(IV_BYTES);
61
- const wrappingKey = browserStateWrappingKey(rootKey, scope);
62
- try {
63
- const cipher = createCipheriv("aes-256-gcm", wrappingKey, iv);
64
- cipher.setAAD(wrapAad(scope));
65
- const ciphertext = Buffer.concat([cipher.update(dataKey), cipher.final()]);
66
- const payload = Buffer.concat([ciphertext, cipher.getAuthTag()]);
67
- return `${WRAPPED_PREFIX}:${iv.toString("base64")}:${payload.toString("base64")}`;
68
- } finally {
69
- wrappingKey.fill(0);
70
- }
71
- }
72
-
73
- export function unwrapBrowserStateDataKey(
74
- rootKey: Uint8Array,
75
- wrapped: string,
76
- scopeInput: BrowserStateArtifactScope,
77
- ): Buffer {
78
- const scope = artifactScope(scopeInput);
79
- const parts = wrapped.split(":");
80
- if (parts.length !== 3 || parts[0] !== WRAPPED_PREFIX) {
81
- throw new Error("browser state data-key envelope is unsupported");
82
- }
83
- const iv = canonicalBase64(parts[1]!, IV_BYTES, "browser state data-key envelope");
84
- const payload = canonicalBase64(
85
- parts[2]!,
86
- DATA_KEY_BYTES + TAG_BYTES,
87
- "browser state data-key envelope",
88
- );
89
- const ciphertext = payload.subarray(0, DATA_KEY_BYTES);
90
- const tag = payload.subarray(DATA_KEY_BYTES);
91
- const wrappingKey = browserStateWrappingKey(rootKey, scope);
92
- try {
93
- const decipher = createDecipheriv("aes-256-gcm", wrappingKey, iv);
94
- decipher.setAAD(wrapAad(scope));
95
- decipher.setAuthTag(tag);
96
- return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
97
- } catch {
98
- throw new Error("browser state data-key decryption failed");
99
- } finally {
100
- wrappingKey.fill(0);
101
- }
102
- }
103
-
104
- export function browserStateObjectKey(workspaceIdInput: string, operationIdInput: string): string {
105
- const workspaceId = uuid(workspaceIdInput, "workspace id");
106
- const operationId = uuid(operationIdInput, "browser state operation id");
107
- return `workspaces/${workspaceId}/browser-state/revisions/${operationId}/chromium-profile.ogbs`;
108
- }
109
-
110
- export function browserStateManifestDigest(manifest: unknown): string {
111
- return createHash("sha256").update(canonicalJson(manifest), "utf8").digest("hex");
112
- }
113
-
114
- function operationScope(input: BrowserStateOperationScope) {
115
- const base = baseArtifactScope(input);
116
- return {
117
- ...base,
118
- browserSessionId: uuid(input.browserSessionId, "browser session id"),
119
- operationId: uuid(input.operationId, "browser state operation id"),
120
- };
121
- }
122
-
123
- function artifactScope(input: BrowserStateArtifactScope) {
124
- return {
125
- ...baseArtifactScope(input),
126
- artifactDigest: sha256(input.artifactDigest, "browser state artifact digest"),
127
- contentDigest: sha256(input.contentDigest, "browser state content digest"),
128
- };
129
- }
130
-
131
- function baseArtifactScope(
132
- input: Pick<BrowserStateArtifactScope, "accountId" | "workspaceId" | "objectKey">,
133
- ) {
134
- const workspaceId = uuid(input.workspaceId, "workspace id");
135
- const objectKey = browserStateObjectKeyValue(input.objectKey, workspaceId);
136
- return {
137
- version: 1,
138
- accountId: uuid(input.accountId, "account id"),
139
- workspaceId,
140
- objectKey,
141
- format: BROWSER_PROFILE_ARTIFACT_FORMAT,
142
- };
143
- }
144
-
145
- function wrapAad(scope: ReturnType<typeof artifactScope>): Buffer {
146
- return Buffer.from(`opengeni.browser-state.data-key-wrap.v1\0${canonicalJson(scope)}`, "utf8");
147
- }
148
-
149
- function browserStateWrappingKey(
150
- rootKey: Uint8Array,
151
- scope: ReturnType<typeof artifactScope>,
152
- ): Buffer {
153
- return createHmac("sha256", root(rootKey))
154
- .update("opengeni.browser-state.wrapping-key.v1\0", "utf8")
155
- .update(canonicalJson(scope), "utf8")
156
- .digest();
157
- }
158
-
159
- function browserStateObjectKeyValue(value: string, workspaceId: string): string {
160
- if (
161
- typeof value !== "string" ||
162
- Buffer.byteLength(value) > 2_048 ||
163
- !new RegExp(
164
- `^workspaces/${workspaceId}/browser-state/[A-Za-z0-9._=-]+(?:/[A-Za-z0-9._=-]+)*$`,
165
- "u",
166
- ).test(value)
167
- ) {
168
- throw new Error("browser state object key is invalid");
169
- }
170
- return value;
171
- }
172
-
173
- function root(value: Uint8Array): Buffer {
174
- return exactKey(value, "browser state root key");
175
- }
176
-
177
- function exactKey(value: Uint8Array, label: string): Buffer {
178
- if (!(value instanceof Uint8Array) || value.byteLength !== ROOT_KEY_BYTES) {
179
- throw new Error(`${label} must be exactly ${ROOT_KEY_BYTES} bytes`);
180
- }
181
- return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
182
- }
183
-
184
- function uuid(value: string, label: string): string {
185
- if (typeof value !== "string" || !UUID_PATTERN.test(value)) {
186
- throw new Error(`${label} must be a UUID`);
187
- }
188
- return value.toLowerCase();
189
- }
190
-
191
- function sha256(value: string, label: string): string {
192
- if (typeof value !== "string" || !SHA256_PATTERN.test(value)) {
193
- throw new Error(`${label} is invalid`);
194
- }
195
- return value;
196
- }
197
-
198
- function canonicalBase64(value: string, length: number, label: string): Buffer {
199
- if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u.test(value)) {
200
- throw new Error(`${label} is unsupported`);
201
- }
202
- const decoded = Buffer.from(value, "base64");
203
- if (decoded.byteLength !== length || decoded.toString("base64") !== value) {
204
- decoded.fill(0);
205
- throw new Error(`${label} is unsupported`);
206
- }
207
- return decoded;
208
- }
209
-
210
- function canonicalJson(value: unknown): string {
211
- return JSON.stringify(canonicalValue(value));
212
- }
213
-
214
- function canonicalValue(value: unknown): unknown {
215
- if (
216
- value === null ||
217
- typeof value === "string" ||
218
- typeof value === "boolean" ||
219
- (typeof value === "number" && Number.isFinite(value))
220
- ) {
221
- return value;
222
- }
223
- if (Array.isArray(value)) return value.map(canonicalValue);
224
- if (typeof value === "object") {
225
- const input = value as Record<string, unknown>;
226
- const output: Record<string, unknown> = {};
227
- for (const key of Object.keys(input).sort()) {
228
- if (input[key] === undefined) {
229
- throw new Error("canonical JSON cannot contain undefined");
230
- }
231
- output[key] = canonicalValue(input[key]);
232
- }
233
- return output;
234
- }
235
- throw new Error("value cannot be represented as canonical JSON");
236
- }
1
+ export * from "@opengeni/interaction/browser-state-authority";
@@ -0,0 +1,12 @@
1
+ import { nestedPostgresSqlState, SubscriptionAccountChangedError } from "@opengeni/db";
2
+ import { HTTPException } from "hono/http-exception";
3
+
4
+ export function claudeAccountMutationFailure(error: unknown): never {
5
+ if (error instanceof SubscriptionAccountChangedError)
6
+ throw new HTTPException(409, { message: error.message });
7
+ if (nestedPostgresSqlState(error) === "23505")
8
+ throw new HTTPException(409, {
9
+ message: "This Claude subscription is already connected to this pool.",
10
+ });
11
+ throw error;
12
+ }
@@ -0,0 +1,48 @@
1
+ import { environmentsEncryptionKeyBytes, type Settings } from "@opengeni/config";
2
+ import {
3
+ resolveClaudeAccountCredential,
4
+ recordClaudeAccountUsage,
5
+ ClaudeSubscriptionConnectionChanged,
6
+ ClaudeSubscriptionRefreshUnavailable,
7
+ type ClaudeAccountUsageAuthority,
8
+ type Database,
9
+ } from "@opengeni/db";
10
+ import { HTTPException } from "hono/http-exception";
11
+ import { requestClaudeUsage } from "./claude-subscription-usage";
12
+
13
+ /** Profile quota requests never run inference and never select a different account. */
14
+ export async function refreshClaudeAccountUsage(
15
+ db: Database,
16
+ settings: Settings,
17
+ authority: ClaudeAccountUsageAuthority,
18
+ fetchImpl: typeof fetch = globalThis.fetch,
19
+ ) {
20
+ const credential = await resolveClaudeAccountCredential(db, settings, authority, {
21
+ fetchImpl,
22
+ }).catch((error) => {
23
+ if (error instanceof ClaudeSubscriptionRefreshUnavailable)
24
+ throw new HTTPException(503, { message: error.message, cause: error });
25
+ throw error;
26
+ });
27
+ if ("reconnectRequired" in credential) return credential.usage;
28
+ const current = credential.usage;
29
+ if (
30
+ current.refreshStatus === "scope_required" ||
31
+ (current.refreshCheckedAt && Date.now() - Date.parse(current.refreshCheckedAt) < 30_000)
32
+ )
33
+ return current;
34
+ const result = credential.secret.oauth?.scopes.includes("user:profile")
35
+ ? await requestClaudeUsage(credential.secret.token, fetchImpl)
36
+ : { status: "scope_required" as const, observation: null, checkedAt: new Date().toISOString() };
37
+ const encryptionKey = environmentsEncryptionKeyBytes(settings);
38
+ if (!encryptionKey) throw new Error("Claude credential encryption is unavailable");
39
+ const usage = await recordClaudeAccountUsage(db, authority, {
40
+ encryptionKey,
41
+ token: credential.secret.token,
42
+ expectedCredentialVersion: credential.version,
43
+ ...(result.observation ? { observation: result.observation } : {}),
44
+ refresh: { status: result.status, checkedAt: result.checkedAt },
45
+ });
46
+ if (!usage) throw new ClaudeSubscriptionConnectionChanged();
47
+ return usage;
48
+ }