@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
@@ -22,6 +22,7 @@ import {
22
22
  hasGitCredentialRepositorySelection,
23
23
  hasGitHubRepositorySelection,
24
24
  sandboxLifecycleTransitionWaitMs,
25
+ sandboxWarmRateMicrosPerSecond,
25
26
  stableSandboxEnvironmentForRun,
26
27
  type Settings,
27
28
  } from "@opengeni/config";
@@ -30,25 +31,33 @@ import type { Session } from "@opengeni/contracts";
30
31
  import {
31
32
  acquireLease,
32
33
  getSandboxSessionEnvelope,
33
- getEnrollment,
34
+ getLiveEnrollmentConnection,
34
35
  getSandbox,
35
- loadWorkspaceEnvironmentForRun,
36
+ touchLeaseHolder,
36
37
  markWarmLeaseInstanceLost,
37
38
  readActiveSandbox,
38
39
  readLease,
39
40
  releaseLeaseHolder,
41
+ SandboxImageConflictError,
40
42
  SandboxProviderReadLockUnavailableError,
43
+ SandboxRigConflictError,
44
+ SandboxPaidComputeAdmissionError,
41
45
  withSandboxProviderReadLock,
42
46
  type Database,
43
47
  type LeaseSnapshot,
44
48
  } from "@opengeni/db";
45
49
  import { appendAndPublishEvents, type EventBus } from "@opengeni/events";
46
50
  import {
51
+ recordTenancyCompatibilityLaneUse,
47
52
  sandboxLeaseTelemetryKey,
48
53
  sandboxOperationMetricObserver,
54
+ sandboxCaptureWaitMetricObserver,
49
55
  type Observability,
50
56
  } from "@opengeni/observability";
51
57
  import { HTTPException } from "hono/http-exception";
58
+ import { ApiHttpError } from "../http/api-error";
59
+ import { loadSessionAttachVariableSetValues } from "./session-attach-variable-sets";
60
+ import type { ObjectStorage } from "@opengeni/storage";
52
61
 
53
62
  import {
54
63
  buildSelfhostedBackendSession,
@@ -59,27 +68,43 @@ import {
59
68
  NatsOpStreamTransport,
60
69
  SandboxResumeIdentityMismatchError,
61
70
  SandboxResumeIdentityUnavailableError,
71
+ RoutingActiveRouteChangedError,
72
+ RoutingWorkspaceRootChangedError,
73
+ SelfhostedWorkspaceRootChangedError,
62
74
  ChannelAConflictError,
75
+ ChannelAFileSystemRouteChangedError,
63
76
  ChannelANotFoundError,
64
77
  ChannelAUnsupportedError,
65
78
  ChannelAUnavailableError,
66
79
  ChannelAValidationError,
67
80
  BrowserControlRequestError,
68
81
  BrowserControlTransportError,
82
+ SelfhostedControlError,
83
+ agentErrorToControlError,
69
84
  codemodeTokenFileFromEnvironment,
85
+ offlineAgentError,
86
+ resolveConnectedMachineWorkspaceRoot,
70
87
  withCodemodeTokenSession,
71
88
  withRunCredentialsSession,
72
89
  type ChannelASession,
73
90
  type EstablishedSandboxSession,
74
91
  type RoutingSandboxSession,
75
92
  } from "@opengeni/runtime/sandbox";
76
- import { relayConfigFromSettings, wrapChannelABoxWithRouting } from "@opengeni/core";
93
+ import {
94
+ managedSessionGroupBackend,
95
+ managedSessionGroupOs,
96
+ providerSettingsForSessionSandboxRuntime,
97
+ relayConfigFromSettings,
98
+ resolveSessionSandboxRuntime,
99
+ wrapChannelABoxWithRouting,
100
+ } from "@opengeni/core";
77
101
  import { establishApiSandboxSpawner } from "./rematerialize";
78
102
 
79
103
  export type ChannelAServices = {
80
104
  db: Database;
81
105
  settings: Settings;
82
106
  bus: EventBus;
107
+ objectStorage?: ObjectStorage | null;
83
108
  observability?: Observability | undefined;
84
109
  };
85
110
 
@@ -87,6 +112,7 @@ export type ChannelAOperation =
87
112
  | "fs.list"
88
113
  | "fs.list-batch"
89
114
  | "fs.read"
115
+ | "artifact.publish"
90
116
  | "fs.write"
91
117
  | "fs.delete"
92
118
  | "fs.move"
@@ -132,6 +158,10 @@ export type ChannelAContext = {
132
158
  * provider handle and replay the request. Tab/lifecycle mutations that lack
133
159
  * a controller operation id must never opt into this recovery. */
134
160
  retryControllerTransport?: boolean | undefined;
161
+ /** Ephemeral browser callbacks must never replay after an ambiguous result. */
162
+ allowOperationReplay?: boolean | undefined;
163
+ /** Exact existing interaction provider; may not spawn/rotate on image drift. */
164
+ retainedInstanceId?: string | undefined;
135
165
  };
136
166
 
137
167
  export type ChannelAOperationFailureReason =
@@ -379,6 +409,8 @@ type ChannelAReadRecoveryOptions = {
379
409
  /** Modal may expose one more stale command-router route after the first
380
410
  * successful handle rebuild. Keep this closed and statically bounded. */
381
411
  maxFreshHandleRetries?: 1 | 2;
412
+ /** Explicit opt-out overrides every transport/provider retry classification. */
413
+ allowOperationReplay?: boolean | undefined;
382
414
  /** Never start another provider attempt after the originating request ends. */
383
415
  waitSignal?: AbortSignal | undefined;
384
416
  /** Additional callback-specific failure that is safe to replay. */
@@ -405,7 +437,11 @@ export async function runChannelAReadWithFreshHandleRetry<T>(
405
437
  } catch (error) {
406
438
  const retryable =
407
439
  error instanceof ChannelAUnavailableError || options.retryableError?.(error) === true;
408
- if (!retryable || retries >= maxFreshHandleRetries) {
440
+ if (
441
+ options.allowOperationReplay === false ||
442
+ !retryable ||
443
+ retries >= maxFreshHandleRetries
444
+ ) {
409
445
  throw error;
410
446
  }
411
447
  options.waitSignal?.throwIfAborted();
@@ -507,6 +543,9 @@ async function withChannelAOperation<T>(
507
543
  const onSandboxOperation = services.observability
508
544
  ? sandboxOperationMetricObserver(services.observability)
509
545
  : undefined;
546
+ const onSandboxCaptureWait = services.observability
547
+ ? sandboxCaptureWaitMetricObserver(services.observability)
548
+ : undefined;
510
549
  const { accountId, workspaceId, session } = ctx;
511
550
 
512
551
  if (session.sandboxBackend === "none") {
@@ -522,19 +561,19 @@ async function withChannelAOperation<T>(
522
561
 
523
562
  // The STABLE run-environment used by both a cloud home and a machine home.
524
563
  // It also carries the per-session Codemode pointer selected below.
525
- const workspaceEnvironment = await loadWorkspaceEnvironmentForRun(
526
- db,
527
- settings,
564
+ const workspaceEnvironmentValues = await loadSessionAttachVariableSetValues(db, settings, {
565
+ accountId,
528
566
  workspaceId,
529
- session.environmentId,
530
- );
567
+ session,
568
+ subjectId: ctx.subjectId,
569
+ });
531
570
  const settingsForSession =
532
571
  session.sandboxBackend !== settings.sandboxBackend
533
572
  ? { ...settings, sandboxBackend: session.sandboxBackend }
534
573
  : settings;
535
574
  const environment = stableSandboxEnvironmentForRun(
536
575
  settingsForSession,
537
- workspaceEnvironment?.values ?? {},
576
+ workspaceEnvironmentValues,
538
577
  { workspaceId },
539
578
  );
540
579
  if (hasGitCredentialRepositorySelection(session.resources)) {
@@ -566,12 +605,27 @@ async function withChannelAOperation<T>(
566
605
  codemodeTokenFileFromEnvironment(environment, session.id),
567
606
  )
568
607
  : credentialSession;
608
+ const fileSystemAuthority = await routingSession.fileSystemAuthority();
609
+ const fileSystemEpoch =
610
+ fileSystemAuthority.backendKind === "selfhosted"
611
+ ? fileSystemAuthority.activeEpoch
612
+ : (lease?.leaseEpoch ?? fileSystemAuthority.activeEpoch);
569
613
  const service = new SandboxChannelAService({
570
614
  session: scopedSession as ChannelASession,
571
- leaseEpoch: lease?.leaseEpoch ?? session.activeEpoch,
615
+ workspaceRoot: fileSystemAuthority.root,
616
+ leaseEpoch: fileSystemEpoch,
617
+ ...(fileSystemAuthority.backendKind === "selfhosted"
618
+ ? { providerPathMode: "workspace-relative" as const, fileReadScope: "machine" as const }
619
+ : {}),
572
620
  emit,
573
621
  });
574
- const result = await fn({ service, lease, homeSession, routingSession, requestId });
622
+ const result = await fn({
623
+ service,
624
+ lease,
625
+ homeSession,
626
+ routingSession,
627
+ requestId,
628
+ });
575
629
  // The direct request has accepted the result in memory. Finalize every
576
630
  // Connected Machine backend the routing proxy reached so a mid-request
577
631
  // route transition cannot leave completed output retained until TTL.
@@ -588,27 +642,81 @@ async function withChannelAOperation<T>(
588
642
  ctx.waitSignal?.throwIfAborted();
589
643
  const pointer = await readActiveSandbox(db, workspaceId, session.id);
590
644
  if (!pointer?.activeSandboxId) {
645
+ // A machine-home session with no selected machine uses the deployment's
646
+ // managed group box, exactly like the worker turn path. Keep the durable
647
+ // home label honest; only this request's effective backend changes.
648
+ const groupBackend = managedSessionGroupBackend(
649
+ settings.sandboxBackend,
650
+ session.sandboxBackend,
651
+ );
652
+ if (groupBackend) {
653
+ return await withChannelAOperation(
654
+ services,
655
+ {
656
+ ...ctx,
657
+ session: {
658
+ ...session,
659
+ sandboxBackend: groupBackend,
660
+ sandboxOs: managedSessionGroupOs(session.sandboxBackend, session.sandboxOs),
661
+ },
662
+ },
663
+ readOnly,
664
+ fn,
665
+ );
666
+ }
591
667
  throw new HTTPException(409, {
592
- message: "machine-home session has no active Connected Machine",
668
+ message: "machine-home session has no active Connected Machine or managed sandbox",
593
669
  });
594
670
  }
595
- const sandbox = await getSandbox(db, workspaceId, pointer.activeSandboxId);
671
+ const sandbox = await getSandbox(
672
+ db,
673
+ { accountId: ctx.accountId, workspaceId, subjectId: ctx.subjectId },
674
+ pointer.activeSandboxId,
675
+ );
596
676
  if (sandbox?.kind !== "selfhosted" || !sandbox.enrollmentId) {
597
677
  throw new HTTPException(409, {
598
678
  message: "machine-home session points to an unavailable Connected Machine",
599
679
  });
600
680
  }
601
- const enrollment = await getEnrollment(db, workspaceId, sandbox.enrollmentId);
681
+ const originWorkspaceId = sandbox.workspaceId;
682
+ const enrollment = await getLiveEnrollmentConnection(
683
+ db,
684
+ { accountId, workspaceId, subjectId: ctx.subjectId },
685
+ sandbox.enrollmentId,
686
+ );
687
+ if (!enrollment?.connectionInstanceId) {
688
+ // Preserve causal machine liveness through Channel-A. Generic callers
689
+ // retain the established 409 mapping below; Browser/Computer callers can
690
+ // project the same bounded `agent_offline` contract as control RPC.
691
+ throw agentErrorToControlError(
692
+ offlineAgentError("Connected Machine has no live runner connection", true),
693
+ );
694
+ }
695
+ if (!enrollment.workspaceRoot) {
696
+ throw new HTTPException(409, {
697
+ message:
698
+ "Connected Machine has not reported an absolute workspace root; reconnect it with a current agent",
699
+ });
700
+ }
602
701
  const built = await buildSelfhostedBackendSession({
603
- workspaceId,
702
+ workspaceId: originWorkspaceId,
604
703
  agentId: sandbox.enrollmentId,
704
+ connectionInstanceId: enrollment.connectionInstanceId,
705
+ workspaceRoot: resolveConnectedMachineWorkspaceRoot(
706
+ enrollment.workspaceRoot,
707
+ pointer.workingDir,
708
+ ),
605
709
  relay: relayConfigFromSettings(settings),
606
710
  controlRpcFactory: () => new NatsControlRpc(async () => bus.getRequestConnection()),
607
711
  epoch: pointer.activeEpoch,
608
712
  environment,
609
- workingDir: pointer.workingDir,
610
713
  timeoutMs: settings.sandboxSelfhostedControlTimeoutMs,
611
714
  execTimeoutMs: settings.sandboxSelfhostedExecTimeoutMs,
715
+ operationResourcePolicy: enrollment.operationPolicy,
716
+ operationResourcePolicySupported:
717
+ enrollment.agentCapabilities.operationResourcePolicy === true,
718
+ operationCpuQuotaSupported: enrollment.agentCapabilities.operationCpuQuota === true,
719
+ transactionalFsWriteSupported: enrollment.agentCapabilities.transactionalFsWrite === true,
612
720
  ...(settings.agentOpStreamEnabled === true &&
613
721
  enrollment?.opStream === true &&
614
722
  bus.getOpStreamConnection
@@ -634,12 +742,14 @@ async function withChannelAOperation<T>(
634
742
  settings,
635
743
  bus,
636
744
  ...(onSandboxOperation ? { onSandboxOperation } : {}),
745
+ ...(onSandboxCaptureWait ? { onSandboxCaptureWait } : {}),
637
746
  ...(ctx.waitSignal ? { waitSignal: ctx.waitSignal } : {}),
638
747
  },
639
748
  {
640
749
  accountId,
641
750
  workspaceId,
642
751
  sessionId: session.id,
752
+ resourceSubjectId: ctx.subjectId,
643
753
  pinnedSelfhosted: {
644
754
  sandboxId: sandbox.id,
645
755
  epoch: pointer.activeEpoch,
@@ -665,6 +775,12 @@ async function withChannelAOperation<T>(
665
775
  }
666
776
  }
667
777
 
778
+ // One session has one logical runtime across turns and every API-direct
779
+ // surface. Without this, Terminal/Files/Browser/Computer/viewers could rearm
780
+
781
+ // deployment image for the same durable sandbox group.
782
+ const sandboxRuntime = await resolveSessionSandboxRuntime(db, settings, session);
783
+
668
784
  const release = async (): Promise<void> => {
669
785
  await releaseLeaseHolder(db, {
670
786
  accountId,
@@ -692,7 +808,15 @@ async function withChannelAOperation<T>(
692
808
  holderId,
693
809
  subjectId: session.id,
694
810
  backend: session.sandboxBackend,
811
+ warmBilling: {
812
+ mode: settings.sandboxWarmBillingMode,
813
+ rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond(settings, session.sandboxBackend),
814
+ },
695
815
  os: session.sandboxOs,
816
+ image: sandboxRuntime.image,
817
+ imagePolicy: "new_creates_only",
818
+ ...(ctx.retainedInstanceId ? { retainedInstanceId: ctx.retainedInstanceId } : {}),
819
+ rigVersionId: session.rigVersionId,
696
820
  leaseTtlMs,
697
821
  warmingLeaseTtlMs: settings.sandboxWarmingTimeoutMs,
698
822
  captureWaitMs: sandboxLifecycleTransitionWaitMs(settings),
@@ -716,6 +840,56 @@ async function withChannelAOperation<T>(
716
840
  });
717
841
  }
718
842
  } catch (error) {
843
+ let mappedError: unknown = error;
844
+ if (error instanceof SandboxImageConflictError) {
845
+ // A durable Browser/Computer holder can outlive its provider container.
846
+ // Runtime drift is checked before a new direct holder is admitted, so a
847
+ // dead old container would otherwise strand the lease behind a permanent
848
+ // conflict. Probe the exact old identity without replacement; only an
849
+ // authoritative provider-missing result may retire it and unblock the
850
+ // next request's cold successor election.
851
+ const live = await readLease(db, workspaceId, sandboxGroupId).catch(() => null);
852
+ if (live?.liveness === "warm" && live.instanceId !== null && live.resumeState !== null) {
853
+ let probe: EstablishedSandboxSession | undefined;
854
+ try {
855
+ probe = await establishSandboxSessionFromEnvelope(
856
+ sandboxRuntime.settings,
857
+ live.resumeState,
858
+ {
859
+ sessionId: session.id,
860
+ recovery: "resume-only",
861
+ backendOverride: session.sandboxBackend,
862
+ environment,
863
+ },
864
+ );
865
+ } catch (probeError) {
866
+ if (isProviderSandboxNotFoundError(session.sandboxBackend, probeError)) {
867
+ const marked = await markWarmLeaseInstanceLost(db, {
868
+ accountId,
869
+ workspaceId,
870
+ sandboxGroupId,
871
+ expectedEpoch: live.leaseEpoch,
872
+ expectedInstanceId: live.instanceId,
873
+ }).catch(() => null);
874
+ if (marked?.status === "marked") {
875
+ await appendAndPublishEvents(db, bus, workspaceId, session.id, [
876
+ {
877
+ type: "sandbox.box.lost",
878
+ payload: { sandboxId: live.instanceId },
879
+ },
880
+ ]).catch(() => undefined);
881
+ mappedError = new ApiHttpError(409, {
882
+ code: "conflict",
883
+ message: "sandbox instance was lost; retry to restore it",
884
+ retryable: true,
885
+ });
886
+ }
887
+ }
888
+ } finally {
889
+ await dropEstablishedHandle(probe);
890
+ }
891
+ }
892
+ }
719
893
  // Release is idempotent. If acquisition committed before the request was
720
894
  // cancelled, this removes that exact direct holder; a transient DB failure
721
895
  // must not overwrite the original structural error (holder TTL is the final
@@ -727,12 +901,28 @@ async function withChannelAOperation<T>(
727
901
  backend: session.sandboxBackend,
728
902
  operation,
729
903
  durationMs: performance.now() - operationStartedAt,
730
- error,
904
+ error: mappedError,
731
905
  waitSignal: ctx.waitSignal,
732
906
  });
733
- throw mapChannelAError(error, ctx.waitSignal);
907
+ throw mapChannelAError(mappedError, ctx.waitSignal);
734
908
  }
735
909
 
910
+ // Keep the exact direct-request owner visible for the full operation. A
911
+ // yielded command is also tracked by a non-TTL process holder, but the
912
+ // retained-process reconciler must not poll that provider session while this
913
+ // request is still its active owner. Stale direct holders remain crash-
914
+ // recoverable through the ordinary holder TTL reaper.
915
+ const directHolderHeartbeat = setInterval(() => {
916
+ void touchLeaseHolder(db, {
917
+ accountId,
918
+ workspaceId,
919
+ sandboxGroupId,
920
+ kind: "direct",
921
+ holderId,
922
+ }).catch(() => undefined);
923
+ }, 10_000);
924
+ directHolderHeartbeat.unref?.();
925
+
736
926
  let established: EstablishedSandboxSession | undefined;
737
927
  let leaseSnapshot: LeaseSnapshot = acquired.lease;
738
928
  let establishedCacheKey: string | null = null;
@@ -747,7 +937,7 @@ async function withChannelAOperation<T>(
747
937
  ): Promise<{ established: EstablishedSandboxSession; cacheKey: string }> => {
748
938
  const cacheKey = establishedHandleCacheKey(workspaceId, session.id, live);
749
939
  const establish = () =>
750
- establishSandboxSessionFromEnvelope(settings, live.resumeState, {
940
+ establishSandboxSessionFromEnvelope(sandboxRuntime.settings, live.resumeState, {
751
941
  sessionId: session.id,
752
942
  recovery: "resume-only",
753
943
  backendOverride: session.sandboxBackend,
@@ -781,8 +971,10 @@ async function withChannelAOperation<T>(
781
971
  },
782
972
  ]);
783
973
  }
784
- throw new HTTPException(409, {
974
+ throw new ApiHttpError(409, {
975
+ code: "conflict",
785
976
  message: `sandbox instance was lost; retry to restore it`,
977
+ retryable: true,
786
978
  });
787
979
  }
788
980
  };
@@ -802,9 +994,13 @@ async function withChannelAOperation<T>(
802
994
  // resume_state is the lease's authoritative box descriptor; the session
803
995
  // `_sandbox` envelope is only the per-session fallback.
804
996
  try {
997
+ const providerSettings = await providerSettingsForSessionSandboxRuntime(
998
+ sandboxRuntime,
999
+ session.sandboxBackend,
1000
+ );
805
1001
  const result = await establishApiSandboxSpawner({
806
1002
  db,
807
- settings,
1003
+ settings: providerSettings,
808
1004
  accountId,
809
1005
  workspaceId,
810
1006
  sandboxGroupId,
@@ -815,6 +1011,9 @@ async function withChannelAOperation<T>(
815
1011
  acquiredLease: acquired.lease,
816
1012
  fallbackEnvelope: envelope,
817
1013
  dataPlaneUrl: acquired.lease.dataPlaneUrl,
1014
+ ...(services.objectStorage !== undefined
1015
+ ? { objectStorage: services.objectStorage }
1016
+ : {}),
818
1017
  });
819
1018
  established = result.established;
820
1019
  leaseSnapshot = result.lease;
@@ -857,12 +1056,14 @@ async function withChannelAOperation<T>(
857
1056
  settings,
858
1057
  bus,
859
1058
  ...(onSandboxOperation ? { onSandboxOperation } : {}),
1059
+ ...(onSandboxCaptureWait ? { onSandboxCaptureWait } : {}),
860
1060
  ...(ctx.waitSignal ? { waitSignal: ctx.waitSignal } : {}),
861
1061
  },
862
1062
  {
863
1063
  accountId,
864
1064
  workspaceId,
865
1065
  sessionId: session.id,
1066
+ resourceSubjectId: ctx.subjectId,
866
1067
  homeLease: {
867
1068
  sandboxGroupId,
868
1069
  leaseEpoch: leaseSnapshot.leaseEpoch,
@@ -964,6 +1165,7 @@ async function withChannelAOperation<T>(
964
1165
  },
965
1166
  {
966
1167
  maxFreshHandleRetries: session.sandboxBackend === "modal" ? 2 : 1,
1168
+ allowOperationReplay: ctx.allowOperationReplay,
967
1169
  ...(ctx.waitSignal ? { waitSignal: ctx.waitSignal } : {}),
968
1170
  ...(ctx.retryControllerTransport
969
1171
  ? { retryableError: isRetryableControllerTransport }
@@ -990,6 +1192,7 @@ async function withChannelAOperation<T>(
990
1192
  });
991
1193
  throw mapChannelAError(error, ctx.waitSignal);
992
1194
  } finally {
1195
+ clearInterval(directHolderHeartbeat);
993
1196
  await release();
994
1197
  await dropEstablishedHandle(established);
995
1198
  }
@@ -999,6 +1202,8 @@ async function withChannelAOperation<T>(
999
1202
  * already-HTTPException unchanged. */
1000
1203
  export function mapChannelAError(error: unknown, waitSignal?: AbortSignal): unknown {
1001
1204
  if (error instanceof HTTPException) return error;
1205
+ if (error instanceof SandboxPaidComputeAdmissionError)
1206
+ return new HTTPException(402, { message: error.message, cause: error });
1002
1207
  if (isChannelARequestCancellation(error, waitSignal))
1003
1208
  return new HTTPException(499 as never, {
1004
1209
  message: "request cancelled",
@@ -1009,8 +1214,44 @@ export function mapChannelAError(error: unknown, waitSignal?: AbortSignal): unkn
1009
1214
  error instanceof SandboxResumeIdentityUnavailableError
1010
1215
  )
1011
1216
  return new HTTPException(409, { message: error.message });
1217
+ if (
1218
+ error instanceof RoutingActiveRouteChangedError ||
1219
+ error instanceof RoutingWorkspaceRootChangedError ||
1220
+ error instanceof SelfhostedWorkspaceRootChangedError ||
1221
+ error instanceof ChannelAFileSystemRouteChangedError
1222
+ )
1223
+ return new ApiHttpError(409, {
1224
+ code: "conflict",
1225
+ message: error.message,
1226
+ retryable: true,
1227
+ });
1012
1228
  if (error instanceof SandboxProviderReadLockUnavailableError)
1013
1229
  return new HTTPException(503, { message: error.message });
1230
+ if (error instanceof SandboxImageConflictError || error instanceof SandboxRigConflictError)
1231
+ return new ApiHttpError(409, {
1232
+ code: "conflict",
1233
+ message: "sandbox runtime changed while this session still has active operations; retry",
1234
+ retryable: true,
1235
+ });
1236
+ if (error instanceof SelfhostedControlError && error.agentOffline)
1237
+ return new HTTPException(409, { message: error.message, cause: error });
1238
+ if (error instanceof SelfhostedControlError && error.payloadTooLarge) {
1239
+ const outbound = error.detail.direction === "request";
1240
+ // Project only the bounded direction. Native free-form diagnostics can
1241
+ // contain file contents or private paths. A large reply is not evidence
1242
+ // that the operation failed before execution, and must not invite replay.
1243
+ return new ApiHttpError(outbound ? 413 : 502, {
1244
+ code: "limit_exceeded",
1245
+ message: outbound
1246
+ ? "The request exceeds the connected machine's per-message size limit. Large file content requires a machine that supports bounded file transfers."
1247
+ : "The connected machine's reply exceeds its per-message size limit. The operation may have completed; inspect its result before repeating it. Read large files in bounded ranges.",
1248
+ retryable: false,
1249
+ details: {
1250
+ code: "machine_transport_payload_too_large",
1251
+ direction: outbound ? "request" : "response",
1252
+ },
1253
+ });
1254
+ }
1014
1255
  if (error instanceof ChannelAUnavailableError)
1015
1256
  return new HTTPException(503, { message: error.message });
1016
1257
  if (error instanceof ChannelAValidationError)
@@ -1021,9 +1262,31 @@ export function mapChannelAError(error: unknown, waitSignal?: AbortSignal): unkn
1021
1262
  return new HTTPException(409, { message: error.message });
1022
1263
  if (error instanceof ChannelAUnsupportedError)
1023
1264
  return new HTTPException(409, { message: error.message });
1265
+ const authorityFence = workspaceMutationAuthorityFenceCode(error);
1266
+ // A revoked grant is an authorization outcome, not a server fault; an
1267
+ // unattributed pre-0277 writer is a conflict the caller resolves by starting
1268
+ // fresh work. Both must be visible instead of surfacing as a 500.
1269
+ if (authorityFence === "authority_revoked")
1270
+ return new HTTPException(403, { message: (error as Error).message });
1271
+ if (authorityFence === "authority_unattributed")
1272
+ return new HTTPException(409, { message: (error as Error).message });
1024
1273
  return error;
1025
1274
  }
1026
1275
 
1276
+ /** Structural check: the fence type lives in `@opengeni/db` and is raised deep
1277
+ * inside admission, so match it the same way the worker does. */
1278
+ function workspaceMutationAuthorityFenceCode(error: unknown): string | null {
1279
+ if (
1280
+ !(error instanceof Error) ||
1281
+ (error.name !== "SandboxWorkspaceMutationFencedError" &&
1282
+ error.name !== "SandboxRetainedProcessPromotionFencedError")
1283
+ ) {
1284
+ return null;
1285
+ }
1286
+ const code = (error as Error & { code?: unknown }).code;
1287
+ return typeof code === "string" ? code : null;
1288
+ }
1289
+
1027
1290
  export function isChannelARequestCancellation(error: unknown, waitSignal?: AbortSignal): boolean {
1028
1291
  if (waitSignal?.aborted !== true) return false;
1029
1292
  const isSignalReason = waitSignal.reason !== undefined && error === waitSignal.reason;
@@ -1053,7 +1316,21 @@ export function channelAOperationFailureDiagnostic(
1053
1316
  errorCode: "sandbox_channel_a_provider_busy",
1054
1317
  };
1055
1318
  }
1056
- if (error instanceof ChannelAUnavailableError) {
1319
+ if (error instanceof SelfhostedControlError && error.payloadTooLarge) {
1320
+ return {
1321
+ reason: error.detail.direction === "request" ? "request_rejected" : "provider_unavailable",
1322
+ status: error.detail.direction === "request" ? 413 : 502,
1323
+ errorCode: "sandbox_channel_a_operation_failed",
1324
+ };
1325
+ }
1326
+ if (error instanceof SandboxImageConflictError || error instanceof SandboxRigConflictError) {
1327
+ return {
1328
+ reason: "lifecycle_conflict",
1329
+ status: 409,
1330
+ errorCode: "sandbox_channel_a_lifecycle_conflict",
1331
+ };
1332
+ }
1333
+ if (error instanceof ChannelAUnavailableError || error instanceof BrowserControlTransportError) {
1057
1334
  return {
1058
1335
  reason: "provider_unavailable",
1059
1336
  status: 503,
@@ -1063,6 +1340,10 @@ export function channelAOperationFailureDiagnostic(
1063
1340
  if (
1064
1341
  error instanceof SandboxResumeIdentityMismatchError ||
1065
1342
  error instanceof SandboxResumeIdentityUnavailableError ||
1343
+ error instanceof RoutingActiveRouteChangedError ||
1344
+ error instanceof RoutingWorkspaceRootChangedError ||
1345
+ error instanceof SelfhostedWorkspaceRootChangedError ||
1346
+ error instanceof ChannelAFileSystemRouteChangedError ||
1066
1347
  (error instanceof HTTPException && error.status === 409)
1067
1348
  ) {
1068
1349
  return {
@@ -1091,6 +1372,16 @@ export function channelAOperationFailureDiagnostic(
1091
1372
  errorCode: "sandbox_channel_a_operation_failed",
1092
1373
  };
1093
1374
  }
1375
+ // An authority fence is a deliberate rejection, not a fault: keep it out of
1376
+ // the unexpected-failure signal that operators page on.
1377
+ const authorityFence = workspaceMutationAuthorityFenceCode(error);
1378
+ if (authorityFence === "authority_revoked" || authorityFence === "authority_unattributed") {
1379
+ return {
1380
+ reason: "request_rejected",
1381
+ status: authorityFence === "authority_revoked" ? 403 : 409,
1382
+ errorCode: "sandbox_channel_a_operation_failed",
1383
+ };
1384
+ }
1094
1385
  return {
1095
1386
  reason: "unexpected",
1096
1387
  status: 500,
@@ -1098,7 +1389,8 @@ export function channelAOperationFailureDiagnostic(
1098
1389
  };
1099
1390
  }
1100
1391
 
1101
- function observeChannelAOperationFailure(
1392
+ /** Exported for the telemetry contract tests; not a route surface. */
1393
+ export function observeChannelAOperationFailure(
1102
1394
  services: ChannelAServices,
1103
1395
  input: {
1104
1396
  workspaceId: string;
@@ -1111,6 +1403,13 @@ function observeChannelAOperationFailure(
1111
1403
  },
1112
1404
  ): void {
1113
1405
  if (!services.observability) return;
1406
+ // A writer with no recorded authority is a compatibility lane, not a fault:
1407
+ // count the lane itself so an operator can see whether it is still live,
1408
+ // separately from the structural failure signal operators page on below.
1409
+ // Lane name only - never the workspace, sandbox group, backend, or operation.
1410
+ if (workspaceMutationAuthorityFenceCode(input.error) === "authority_unattributed") {
1411
+ recordTenancyCompatibilityLaneUse(services.observability, "workspace_writer_unattributed");
1412
+ }
1114
1413
  const diagnostic = channelAOperationFailureDiagnostic(input.error, input.waitSignal);
1115
1414
  const attributes = {
1116
1415
  sandboxLeaseKey: sandboxLeaseTelemetryKey(input.workspaceId, input.sandboxGroupId),
@@ -0,0 +1,3 @@
1
+ /** Five-second heartbeats get four missed intervals before another daemon may
2
+ * claim the enrollment. Server time is authoritative. */
3
+ export const AGENT_CONNECTION_LEASE_MS = 20_000;