@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
@@ -26,6 +26,7 @@ import {
26
26
  hasGitHubRepositorySelection,
27
27
  resolveStreamTokenSecret,
28
28
  sandboxLifecycleTransitionWaitMs,
29
+ sandboxWarmRateMicrosPerSecond,
29
30
  stableSandboxEnvironmentForRun,
30
31
  } from "@opengeni/config";
31
32
  import type { Settings } from "@opengeni/config";
@@ -33,10 +34,10 @@ import { githubAppBotIdentity } from "@opengeni/github";
33
34
  import { type Session, type StreamUrlRotatedPayload } from "@opengeni/contracts";
34
35
  import {
35
36
  acquireLease,
37
+ getLiveEnrollmentConnection,
36
38
  getSandbox,
37
39
  getSandboxSessionEnvelope,
38
- heartbeatLeaseHolder,
39
- loadWorkspaceEnvironmentForRun,
40
+ heartbeatLeaseHolderStatus,
40
41
  markSandboxProviderReady,
41
42
  markWarmLeaseInstanceLost,
42
43
  readLease,
@@ -45,12 +46,16 @@ import {
45
46
  releaseLeaseHolder,
46
47
  SandboxLeaseSupersededError,
47
48
  SandboxViewerAdmissionBlockedError,
49
+ SandboxPaidComputeAdmissionError,
48
50
  type Database,
49
51
  type LeaseSnapshot,
50
52
  type SandboxRecord,
53
+ getSessionAuthorityEpoch,
54
+ namedSubjectHasLiveWorkspaceAuthority,
51
55
  } from "@opengeni/db";
52
56
  import { appendAndPublishEvents, type EventBus } from "@opengeni/events";
53
57
  import { HTTPException } from "hono/http-exception";
58
+ import type { ObjectStorage } from "@opengeni/storage";
54
59
 
55
60
  // The leaf — agent-loop-free. apps/api imports sandbox symbols ONLY from here
56
61
  // (enforced by sandbox-access-import-guard.test.ts).
@@ -71,13 +76,21 @@ import {
71
76
  TerminalServerUnsupportedError,
72
77
  verifySandboxExecReadiness,
73
78
  StreamPortUnavailableError,
79
+ renewSandboxProviderExpiration,
74
80
  type ControlRpc,
75
81
  type EstablishedSandboxSession,
76
82
  type NatsRequestConnection,
77
83
  } from "@opengeni/runtime/sandbox";
78
- import { relayConfigFromSettings } from "@opengeni/core";
84
+ import {
85
+ managedSessionGroupBackend,
86
+ managedSessionGroupOs,
87
+ providerSettingsForSessionSandboxRuntime,
88
+ relayConfigFromSettings,
89
+ resolveSessionSandboxRuntime,
90
+ } from "@opengeni/core";
79
91
  import { establishApiSandboxSpawner } from "./rematerialize";
80
92
  import { establishCachedChannelAHandle } from "./channel-a";
93
+ import { loadSessionAttachVariableSetValues } from "./session-attach-variable-sets";
81
94
 
82
95
  /** The minimal services a viewer op needs: the DB + settings (lease cadence +
83
96
  * the sandbox client construction the leaf reads from settings). The bus is
@@ -87,6 +100,7 @@ export type ViewerServices = {
87
100
  db: Database;
88
101
  settings: Settings;
89
102
  bus?: EventBus;
103
+ objectStorage?: ObjectStorage | null;
90
104
  /** Provider-establish dependency used by API-direct readiness and stream
91
105
  * operations. Production uses the runtime leaf; isolated tests may supply a
92
106
  * deterministic provider without replacing a process-global module. */
@@ -137,12 +151,14 @@ export async function sessionAttachEnvironment(
137
151
  services: ViewerServices,
138
152
  workspaceId: string,
139
153
  session: Session,
154
+ /** The authenticated route subject driving this attach (0282); recorded on
155
+ * the materialization audit fact. Null records the legacy service sentinel. */
156
+ attachSubjectId: string | null,
140
157
  ): Promise<Record<string, string>> {
141
- const workspaceEnvironment = await loadWorkspaceEnvironmentForRun(
158
+ const workspaceEnvironmentValues = await loadSessionAttachVariableSetValues(
142
159
  services.db,
143
160
  services.settings,
144
- workspaceId,
145
- session.environmentId,
161
+ { accountId: session.accountId, workspaceId, session, subjectId: attachSubjectId },
146
162
  );
147
163
  // Build the env with the SESSION's backend, not the deployment default: the
148
164
  // stable base is backend-aware (HOME = the descriptor workspaceRoot, and the
@@ -158,7 +174,7 @@ export async function sessionAttachEnvironment(
158
174
  : services.settings;
159
175
  const environment = stableSandboxEnvironmentForRun(
160
176
  settingsForSession,
161
- workspaceEnvironment?.values ?? {},
177
+ workspaceEnvironmentValues,
162
178
  { workspaceId },
163
179
  );
164
180
  if (hasGitCredentialRepositorySelection(session.resources)) {
@@ -187,15 +203,40 @@ export async function attachViewer(
187
203
  workspaceId: string;
188
204
  session: Session;
189
205
  viewerId?: string;
206
+ /** The authenticated subject attaching this viewer (0281): recorded on
207
+ * the holder row together with the live session authority epoch. */
208
+ viewerSubjectId?: string;
190
209
  /** Cancel lifecycle waiting when the originating HTTP request disconnects. */
191
210
  waitSignal?: AbortSignal;
192
211
  },
193
212
  ): Promise<ViewerAttachResult> {
194
213
  const { db, settings } = services;
195
- const { accountId, workspaceId, session } = input;
214
+ const { accountId, workspaceId } = input;
215
+ const groupBackend = managedSessionGroupBackend(
216
+ settings.sandboxBackend,
217
+ input.session.sandboxBackend,
218
+ );
219
+ if (!groupBackend) {
220
+ throw new HTTPException(409, {
221
+ message: "session has no managed sandbox group to attach",
222
+ });
223
+ }
224
+ const session =
225
+ groupBackend === input.session.sandboxBackend
226
+ ? input.session
227
+ : {
228
+ ...input.session,
229
+ sandboxBackend: groupBackend,
230
+ sandboxOs: managedSessionGroupOs(input.session.sandboxBackend, input.session.sandboxOs),
231
+ };
196
232
  const viewerId = input.viewerId ?? crypto.randomUUID();
233
+ const attachSubjectId = claimableSubjectId(input.viewerSubjectId ?? null);
234
+ const attachAuthorityEpoch = attachSubjectId
235
+ ? await getSessionAuthorityEpoch(db, { accountId, workspaceId, sessionId: session.id })
236
+ : null;
197
237
  const leaseTtlMs = settings.sandboxLeaseTtlMs;
198
238
  const sandboxGroupId = session.sandboxGroupId;
239
+ const sandboxRuntime = await resolveSessionSandboxRuntime(db, settings, session);
199
240
 
200
241
  const release = async (): Promise<void> => {
201
242
  await releaseLeaseHolder(db, {
@@ -217,19 +258,31 @@ export async function attachViewer(
217
258
  kind: "viewer",
218
259
  holderId: viewerId,
219
260
  subjectId: session.id,
261
+ ...(attachSubjectId ? { viewerSubjectId: attachSubjectId } : {}),
262
+ ...(attachAuthorityEpoch !== null ? { viewerAuthorityEpoch: attachAuthorityEpoch } : {}),
220
263
  backend: session.sandboxBackend,
264
+ warmBilling: {
265
+ mode: settings.sandboxWarmBillingMode,
266
+ rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond(settings, session.sandboxBackend),
267
+ },
221
268
  os: session.sandboxOs,
269
+ image: sandboxRuntime.image,
270
+ imagePolicy: "new_creates_only",
271
+ rigVersionId: session.rigVersionId,
222
272
  leaseTtlMs,
223
273
  warmingLeaseTtlMs: settings.sandboxWarmingTimeoutMs,
224
274
  captureWaitMs: sandboxLifecycleTransitionWaitMs(settings),
225
275
  ...(input.waitSignal ? { waitSignal: input.waitSignal } : {}),
226
276
  });
227
277
  } catch (error) {
278
+ if (error instanceof SandboxPaidComputeAdmissionError) {
279
+ throw new HTTPException(402, { message: error.message, cause: error });
280
+ }
228
281
  if (error instanceof SandboxViewerAdmissionBlockedError) {
229
282
  throw new HTTPException(error.reason === "balance" ? 402 : 429, {
230
283
  message:
231
284
  error.reason === "balance"
232
- ? "insufficient OpenGeni credits for an idle sandbox viewer"
285
+ ? "insufficient Opengeni credits for an idle sandbox viewer"
233
286
  : "workspace sandbox warm allowance exhausted",
234
287
  cause: error,
235
288
  });
@@ -270,7 +323,16 @@ export async function attachViewer(
270
323
  // so the next turn's agent-manifest apply finds an EMPTY environment delta in
271
324
  // the SDK's validateNoEnvironmentDelta (otherwise: "Live sandbox sessions
272
325
  // cannot change manifest environment variables").
273
- const environment = await sessionAttachEnvironment(services, workspaceId, session);
326
+ const environment = await sessionAttachEnvironment(
327
+ services,
328
+ workspaceId,
329
+ session,
330
+ input.viewerSubjectId ?? null,
331
+ );
332
+ const providerSettings = await providerSettingsForSessionSandboxRuntime(
333
+ sandboxRuntime,
334
+ session.sandboxBackend,
335
+ );
274
336
  // Prefer the COLD lease's preserved resume_state when it carries a persisted
275
337
  // /workspace snapshot (confirmDrainCold keeps a minimal archive-only envelope
276
338
  // across draining->cold). establishSandboxSessionFromEnvelope cold-creates a
@@ -279,7 +341,7 @@ export async function attachViewer(
279
341
  // session envelope (a never-warmed cold start).
280
342
  const result = await establishApiSandboxSpawner({
281
343
  db,
282
- settings,
344
+ settings: providerSettings,
283
345
  accountId,
284
346
  workspaceId,
285
347
  sandboxGroupId,
@@ -290,6 +352,7 @@ export async function attachViewer(
290
352
  acquiredLease: acquired.lease,
291
353
  fallbackEnvelope: envelope,
292
354
  dataPlaneUrl: null,
355
+ ...(services.objectStorage !== undefined ? { objectStorage: services.objectStorage } : {}),
293
356
  });
294
357
  established = result.established;
295
358
  return {
@@ -353,11 +416,16 @@ export async function attachViewer(
353
416
  message: `sandbox is ${live.recovery.restore.status} at epoch ${live.leaseEpoch}`,
354
417
  });
355
418
  }
356
- const environment = await sessionAttachEnvironment(services, workspaceId, session);
419
+ const environment = await sessionAttachEnvironment(
420
+ services,
421
+ workspaceId,
422
+ session,
423
+ input.viewerSubjectId ?? null,
424
+ );
357
425
  let observed: EstablishedSandboxSession | undefined;
358
426
  try {
359
427
  const establish = services.establishSandboxSession ?? establishSandboxSessionFromEnvelope;
360
- observed = await establish(settings, live.resumeState, {
428
+ observed = await establish(sandboxRuntime.settings, live.resumeState, {
361
429
  sessionId: session.id,
362
430
  recovery: "resume-only",
363
431
  backendOverride: session.sandboxBackend,
@@ -430,13 +498,26 @@ export type SessionGroupReadinessHold = {
430
498
  * it. */
431
499
  export async function ensureSessionGroupReady(
432
500
  services: ViewerServices,
433
- input: { accountId: string; workspaceId: string; session: Session },
501
+ input: {
502
+ accountId: string;
503
+ workspaceId: string;
504
+ session: Session;
505
+ /** The authenticated subject driving the fleet attach/swap (0282): recorded
506
+ * on the viewer holder and the materialization audit fact. Omitting it
507
+ * records the explicit service sentinel, so forward the route subject. */
508
+ subjectId?: string | null;
509
+ },
434
510
  ): Promise<SessionGroupReadinessHold> {
435
511
  let lastError: unknown;
436
512
  for (let attempt = 0; attempt < 2; attempt += 1) {
437
513
  let release: (() => Promise<void>) | undefined;
438
514
  try {
439
- const attached = await attachViewer(services, input);
515
+ const attached = await attachViewer(services, {
516
+ accountId: input.accountId,
517
+ workspaceId: input.workspaceId,
518
+ session: input.session,
519
+ ...(input.subjectId ? { viewerSubjectId: input.subjectId } : {}),
520
+ });
440
521
  let releasePromise: Promise<void> | undefined;
441
522
  release = () =>
442
523
  (releasePromise ??= detachViewer(services, {
@@ -480,7 +561,7 @@ export async function heartbeatViewer(
480
561
  expectedEpoch: number;
481
562
  },
482
563
  ): Promise<boolean> {
483
- return await heartbeatLeaseHolder(services.db, {
564
+ const status = await heartbeatLeaseHolderStatus(services.db, {
484
565
  accountId: input.accountId,
485
566
  workspaceId: input.workspaceId,
486
567
  sandboxGroupId: input.sandboxGroupId,
@@ -488,7 +569,21 @@ export async function heartbeatViewer(
488
569
  holderId: input.viewerId,
489
570
  leaseTtlMs: services.settings.sandboxLeaseTtlMs,
490
571
  expectedEpoch: input.expectedEpoch,
572
+ billingMode: services.settings.sandboxWarmBillingMode,
491
573
  });
574
+ // A funding fence stops renewing paid provider time, but the holder is
575
+ // deliberately kept alive while the viewer winds down or adds funds. Other
576
+ // fences (epoch/rotation/drain) still require the client to re-attach.
577
+ if (!status.leaseExtended) return status.holderAlive && status.fence === "funding";
578
+ const lease = await readLease(services.db, input.workspaceId, input.sandboxGroupId);
579
+ if (lease?.liveness === "warm" && lease.leaseEpoch === input.expectedEpoch && lease.instanceId) {
580
+ await renewSandboxProviderExpiration({
581
+ backend: lease.backend as Settings["sandboxBackend"],
582
+ settings: services.settings,
583
+ instanceId: lease.instanceId,
584
+ }).catch(() => false);
585
+ }
586
+ return true;
492
587
  }
493
588
 
494
589
  /**
@@ -498,7 +593,12 @@ export async function heartbeatViewer(
498
593
  */
499
594
  export async function detachViewer(
500
595
  services: ViewerServices,
501
- input: { accountId: string; workspaceId: string; sandboxGroupId: string; viewerId: string },
596
+ input: {
597
+ accountId: string;
598
+ workspaceId: string;
599
+ sandboxGroupId: string;
600
+ viewerId: string;
601
+ },
502
602
  ): Promise<{ liveness: LeaseSnapshot["liveness"]; refcount: number } | null> {
503
603
  return await releaseLeaseHolder(services.db, {
504
604
  accountId: input.accountId,
@@ -625,7 +725,11 @@ export function resolveActiveDesktopTransport(
625
725
  if (selfhostedActive) {
626
726
  return { transport: "relay-frames", client: "frames", mode: "read-only" };
627
727
  }
628
- return { transport: "vnc-ws", client: "novnc", mode: interactive ? "interactive" : "read-only" };
728
+ return {
729
+ transport: "vnc-ws",
730
+ client: "novnc",
731
+ mode: interactive ? "interactive" : "read-only",
732
+ };
629
733
  }
630
734
 
631
735
  /** The minted pixel cell the handshake/attach folds into the DesktopStream
@@ -639,9 +743,73 @@ export type DesktopStreamMint = {
639
743
  leaseEpoch: number;
640
744
  };
641
745
 
746
+ /** A subject claim must satisfy the StreamTokenPayload bounds and the 0281
747
+ * holder CHECK (non-blank, <= 512). An out-of-bounds subject (possible only
748
+ * from a host-signed delegated token) is omitted from the claims rather than
749
+ * turning the mint into a 500. */
750
+ function claimableSubjectId(subjectId: string | null): string | null {
751
+ if (!subjectId) return null;
752
+ const trimmed = subjectId.trim();
753
+ return trimmed.length >= 1 && subjectId.length <= 512 ? subjectId : null;
754
+ }
755
+
756
+ /**
757
+ * Resolve the viewer-facing authority claims stamped into a scoped stream
758
+ * token and recorded on the viewer holder (0281): the authenticated viewer
759
+ * subject and the session's LIVE authority epoch. Re-verifies a human
760
+ * (`user:`) subject's current workspace authority at mint time through the
761
+ * same model the route-time access builder uses - a membership row with an
762
+ * active owning organization membership, or an active organization
763
+ * membership's personal-workspace pointer - so a viewer whose authority was
764
+ * revoked since the route authorized them degrades to null (transport:null)
765
+ * instead of receiving a fresh token. Delegated token-borne grants
766
+ * (`subjectDelegated`) are authorized by their signed token, not by rows this
767
+ * check can see; they keep their route authorization, as do API-key and
768
+ * service principals. Identity and epoch only - never a secret value.
769
+ */
770
+ async function resolveViewerAuthorityClaims(
771
+ db: ViewerServices["db"],
772
+ input: {
773
+ accountId: string;
774
+ workspaceId: string;
775
+ sessionId: string;
776
+ subjectId: string | null;
777
+ subjectDelegated?: boolean;
778
+ },
779
+ ): Promise<{ subjectId?: string; authorityEpoch: number } | null> {
780
+ const authorityEpoch = await getSessionAuthorityEpoch(db, {
781
+ accountId: input.accountId,
782
+ workspaceId: input.workspaceId,
783
+ sessionId: input.sessionId,
784
+ });
785
+ if (authorityEpoch === null) {
786
+ return null;
787
+ }
788
+ if (input.subjectId?.startsWith("user:") && input.subjectDelegated !== true) {
789
+ const live = await namedSubjectHasLiveWorkspaceAuthority(db, {
790
+ accountId: input.accountId,
791
+ workspaceId: input.workspaceId,
792
+ subjectId: input.subjectId,
793
+ });
794
+ if (!live) {
795
+ return null;
796
+ }
797
+ }
798
+ const subjectId = claimableSubjectId(input.subjectId);
799
+ return {
800
+ ...(subjectId ? { subjectId } : {}),
801
+ authorityEpoch,
802
+ };
803
+ }
804
+
642
805
  export type MintDesktopStreamInput = {
643
806
  accountId: string;
644
807
  workspaceId: string;
808
+ resourceSubjectId?: string;
809
+ /** True when the route grant is a signed delegated token (metadata.delegated):
810
+ * its authority is the token, not membership rows, so the mint-time
811
+ * live-authority recheck does not apply. */
812
+ resourceSubjectDelegated?: boolean;
645
813
  session: Session;
646
814
  /** The viewer holder id the scoped token is minted for. */
647
815
  viewerId: string;
@@ -704,20 +872,44 @@ export async function mintDesktopStream(
704
872
  return null;
705
873
  }
706
874
 
875
+ // 0281: the viewer's authority claims. A missing epoch (session not
876
+ // visible) or a removed human membership degrades the mint instead of
877
+ // issuing a fresh token.
878
+ const viewerAuthority = await resolveViewerAuthorityClaims(db, {
879
+ accountId,
880
+ workspaceId,
881
+ sessionId: session.id,
882
+ subjectId: input.resourceSubjectId ?? null,
883
+ ...(input.resourceSubjectDelegated !== undefined
884
+ ? { subjectDelegated: input.resourceSubjectDelegated }
885
+ : {}),
886
+ });
887
+ if (!viewerAuthority) {
888
+ return null;
889
+ }
890
+
707
891
  // SELFHOSTED ACTIVE: when the session's active sandbox is a selfhosted machine,
708
892
  // route to the relay (NOT the Modal group-box path — it would resume the wrong
709
893
  // box and return a Modal URL). No Modal lease required.
710
894
  if (session.activeSandboxId) {
711
- const active = await getSandbox(db, workspaceId, session.activeSandboxId);
895
+ const active = await getSandbox(
896
+ db,
897
+ input.resourceSubjectId
898
+ ? { accountId, workspaceId, subjectId: input.resourceSubjectId }
899
+ : workspaceId,
900
+ session.activeSandboxId,
901
+ );
712
902
  if (active?.kind === "selfhosted") {
713
903
  const m = await tryMintActiveSelfhostedStream(
714
904
  services,
715
905
  {
716
906
  session,
717
907
  viewerId: input.viewerId,
718
- workspaceId,
908
+ workspaceId: active.workspaceId,
909
+ ...(input.resourceSubjectId ? { resourceSubjectId: input.resourceSubjectId } : {}),
719
910
  port: DESKTOP_STREAM_PORT,
720
911
  sandbox: active,
912
+ viewerAuthority,
721
913
  },
722
914
  input.resolveSelfhostedSession,
723
915
  );
@@ -749,7 +941,12 @@ export async function mintDesktopStream(
749
941
  try {
750
942
  // On a cold-restore (the lease's box is gone) this create() must carry the
751
943
  // SAME stable run-env the turn declares, so a later turn finds no env delta.
752
- const environment = await sessionAttachEnvironment(services, workspaceId, session);
944
+ const environment = await sessionAttachEnvironment(
945
+ services,
946
+ workspaceId,
947
+ session,
948
+ input.resourceSubjectId ?? null,
949
+ );
753
950
  try {
754
951
  const establish = () =>
755
952
  (services.establishSandboxSession ?? establishSandboxSessionFromEnvelope)(
@@ -799,6 +996,7 @@ export async function mintDesktopStream(
799
996
  leaseEpoch: lease.leaseEpoch,
800
997
  streamTokenSecret: secret,
801
998
  resolution: defaultResolution(settings),
999
+ ...viewerAuthority,
802
1000
  });
803
1001
  } catch (error) {
804
1002
  // A transient/headless provider failure degrades the desktop cell.
@@ -899,6 +1097,9 @@ type SelfhostedStreamMint = Omit<TerminalStreamMint, "transport">;
899
1097
  export type MintTerminalStreamInput = {
900
1098
  accountId: string;
901
1099
  workspaceId: string;
1100
+ resourceSubjectId?: string;
1101
+ /** See MintDesktopStreamInput.resourceSubjectDelegated. */
1102
+ resourceSubjectDelegated?: boolean;
902
1103
  session: Session;
903
1104
  /** The viewer holder / principal id the scoped token is minted for. */
904
1105
  viewerId: string;
@@ -947,20 +1148,44 @@ export async function mintTerminalStream(
947
1148
  return null;
948
1149
  }
949
1150
 
1151
+ // 0281: the viewer's authority claims. A missing epoch (session not
1152
+ // visible) or a removed human membership degrades the mint instead of
1153
+ // issuing a fresh token.
1154
+ const viewerAuthority = await resolveViewerAuthorityClaims(db, {
1155
+ accountId,
1156
+ workspaceId,
1157
+ sessionId: session.id,
1158
+ subjectId: input.resourceSubjectId ?? null,
1159
+ ...(input.resourceSubjectDelegated !== undefined
1160
+ ? { subjectDelegated: input.resourceSubjectDelegated }
1161
+ : {}),
1162
+ });
1163
+ if (!viewerAuthority) {
1164
+ return null;
1165
+ }
1166
+
950
1167
  // SELFHOSTED ACTIVE: when the session's active sandbox is a selfhosted machine,
951
1168
  // route to the relay. NEVER fall through to the Modal group-box path (it would
952
1169
  // resume the wrong box / return a Modal URL).
953
1170
  if (session.activeSandboxId) {
954
- const active = await getSandbox(db, workspaceId, session.activeSandboxId);
1171
+ const active = await getSandbox(
1172
+ db,
1173
+ input.resourceSubjectId
1174
+ ? { accountId, workspaceId, subjectId: input.resourceSubjectId }
1175
+ : workspaceId,
1176
+ session.activeSandboxId,
1177
+ );
955
1178
  if (active?.kind === "selfhosted") {
956
1179
  const stream = await tryMintActiveSelfhostedStream(
957
1180
  services,
958
1181
  {
959
1182
  session,
960
1183
  viewerId: input.viewerId,
961
- workspaceId,
1184
+ workspaceId: active.workspaceId,
1185
+ ...(input.resourceSubjectId ? { resourceSubjectId: input.resourceSubjectId } : {}),
962
1186
  port: TERMINAL_STREAM_PORT,
963
1187
  sandbox: active,
1188
+ viewerAuthority,
964
1189
  },
965
1190
  input.resolveSelfhostedSession,
966
1191
  );
@@ -982,7 +1207,12 @@ export async function mintTerminalStream(
982
1207
  try {
983
1208
  // On a cold-restore this create() must carry the SAME stable run-env the turn
984
1209
  // declares, so a later turn finds no manifest-env delta.
985
- const environment = await sessionAttachEnvironment(services, workspaceId, session);
1210
+ const environment = await sessionAttachEnvironment(
1211
+ services,
1212
+ workspaceId,
1213
+ session,
1214
+ input.resourceSubjectId ?? null,
1215
+ );
986
1216
  try {
987
1217
  const establish = () =>
988
1218
  (services.establishSandboxSession ?? establishSandboxSessionFromEnvelope)(
@@ -1008,7 +1238,9 @@ export async function mintTerminalStream(
1008
1238
  // Idempotent ttyd launch (flock-guarded; a no-op when already up). A box that
1009
1239
  // genuinely can't run it degrades to the sse-events firehose, not a throw.
1010
1240
  try {
1011
- await ensureTerminalServer(established.session, { port: TERMINAL_STREAM_PORT });
1241
+ await ensureTerminalServer(established.session, {
1242
+ port: TERMINAL_STREAM_PORT,
1243
+ });
1012
1244
  } catch (error) {
1013
1245
  if (error instanceof TerminalServerUnsupportedError) {
1014
1246
  return null;
@@ -1029,6 +1261,7 @@ export async function mintTerminalStream(
1029
1261
  leaseEpoch: lease.leaseEpoch,
1030
1262
  streamTokenSecret: secret,
1031
1263
  port: TERMINAL_STREAM_PORT,
1264
+ ...viewerAuthority,
1032
1265
  });
1033
1266
  } catch (error) {
1034
1267
  if (error instanceof StreamPortUnavailableError) {
@@ -1104,8 +1337,11 @@ async function tryMintActiveSelfhostedStream(
1104
1337
  session: Session;
1105
1338
  viewerId: string;
1106
1339
  workspaceId: string;
1340
+ resourceSubjectId?: string;
1107
1341
  port: number;
1108
1342
  sandbox: SandboxRecord;
1343
+ /** 0281 viewer authority claims stamped into the relay stream token. */
1344
+ viewerAuthority?: { subjectId?: string; authorityEpoch: number };
1109
1345
  },
1110
1346
  // optional test seam (mirrors the existing `establish?` seam pattern): inject a
1111
1347
  // fake relay-resolving session; production NEVER passes it.
@@ -1127,11 +1363,26 @@ async function tryMintActiveSelfhostedStream(
1127
1363
  if (resolveSelfhostedSession) {
1128
1364
  shSession = await resolveSelfhostedSession(sandbox);
1129
1365
  } else {
1366
+ const enrollment = await getLiveEnrollmentConnection(
1367
+ services.db,
1368
+ input.resourceSubjectId
1369
+ ? {
1370
+ accountId: input.session.accountId,
1371
+ workspaceId: input.session.workspaceId,
1372
+ subjectId: input.resourceSubjectId,
1373
+ }
1374
+ : workspaceId,
1375
+ sandbox.enrollmentId,
1376
+ );
1377
+ if (!enrollment?.connectionInstanceId) return null;
1378
+ if (!enrollment.workspaceRoot) return null;
1130
1379
  const client = new SelfhostedSandboxClient({
1131
1380
  workspaceId,
1381
+ workspaceRoot: enrollment.workspaceRoot,
1132
1382
  relay: relayConfigFromSettings(settings),
1133
1383
  controlRpcFactory: () => controlRpc(bus),
1134
1384
  agentId: sandbox.enrollmentId,
1385
+ connectionInstanceId: enrollment.connectionInstanceId,
1135
1386
  epoch: session.activeEpoch,
1136
1387
  // Stream authority rotates; terminal process identity does not.
1137
1388
  terminalScopeId: session.id,
@@ -1151,6 +1402,7 @@ async function tryMintActiveSelfhostedStream(
1151
1402
  sessionId: session.id,
1152
1403
  viewerId: input.viewerId,
1153
1404
  activeEpoch: session.activeEpoch,
1405
+ ...(input.viewerAuthority ? { viewerAuthority: input.viewerAuthority } : {}),
1154
1406
  port,
1155
1407
  session: shSession,
1156
1408
  });
@@ -1170,6 +1422,8 @@ export type MintSelfhostedStreamInput = {
1170
1422
  * THIS as its leaseEpoch claim so the relay rejects a stale-epoch (swapped-away)
1171
1423
  * viewer. */
1172
1424
  activeEpoch: number;
1425
+ /** 0281 viewer authority claims stamped into the relay stream token. */
1426
+ viewerAuthority?: { subjectId?: string; authorityEpoch: number };
1173
1427
  /** The exposed stream port (6080 desktop / 7681 terminal). */
1174
1428
  port: number;
1175
1429
  /** The resolvable selfhosted session (the routing proxy resolves the active
@@ -1213,6 +1467,7 @@ export async function mintSelfhostedStream(
1213
1467
  leaseEpoch: input.activeEpoch,
1214
1468
  streamTokenSecret: secret,
1215
1469
  port: input.port,
1470
+ ...(input.viewerAuthority ?? {}),
1216
1471
  });
1217
1472
  return {
1218
1473
  url: exposed.url,