@opengeni/api-router 0.30.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/dist/access-grant-rls.d.ts +3 -0
  2. package/dist/admission-trace.d.ts +8 -0
  3. package/dist/api-websocket.d.ts +18 -0
  4. package/dist/app.d.ts +50 -2
  5. package/dist/app.js +12 -1
  6. package/dist/artifact-catalog-cursor.d.ts +27 -0
  7. package/dist/auth/managed-auth-attempt-context.d.ts +10 -0
  8. package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
  9. package/dist/auth/managed-auth-session-adapter.d.ts +6 -0
  10. package/dist/auth/managed-auth.d.ts +102 -3
  11. package/dist/auth/managed-email.d.ts +29 -0
  12. package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
  13. package/dist/auth/new-signups-gate.d.ts +23 -0
  14. package/dist/auth/organization-user-setup.d.ts +80 -0
  15. package/dist/auth/signup-funnel-metrics.d.ts +44 -0
  16. package/dist/browser-controller-authority.d.ts +1 -61
  17. package/dist/browser-ephemeral.d.ts +5 -0
  18. package/dist/browser-state-authority.d.ts +1 -27
  19. package/dist/chunk-6TZ5LG3O.js +123948 -0
  20. package/dist/chunk-6TZ5LG3O.js.map +1 -0
  21. package/dist/chunk-OGQDXVXY.js +18 -0
  22. package/dist/chunk-OGQDXVXY.js.map +1 -0
  23. package/dist/claude-subscription-account-conflicts.d.ts +1 -0
  24. package/dist/claude-subscription-account-usage.d.ts +39 -0
  25. package/dist/claude-subscription-oauth.d.ts +25 -0
  26. package/dist/claude-subscription-profile.d.ts +9 -0
  27. package/dist/claude-subscription-usage.d.ts +44 -0
  28. package/dist/claude-workspace-connection.d.ts +15 -0
  29. package/dist/codemode.d.ts +32 -1
  30. package/dist/company-brain-okf.d.ts +24 -0
  31. package/dist/connected-machine-computer-access.d.ts +11 -0
  32. package/dist/connection-ownership.d.ts +54 -0
  33. package/dist/controller-data-plane.d.ts +32 -0
  34. package/dist/editable-artifact-source-session.d.ts +3 -0
  35. package/dist/editable-artifact-websocket.d.ts +10 -18
  36. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  37. package/dist/fatal-process-boundary.d.ts +25 -0
  38. package/dist/github-access.d.ts +31 -2
  39. package/dist/http/acting-person.d.ts +24 -0
  40. package/dist/http/api-contract-compat.d.ts +19 -0
  41. package/dist/http/api-error.d.ts +27 -1
  42. package/dist/http/cors.d.ts +17 -0
  43. package/dist/http/deprecation.d.ts +42 -0
  44. package/dist/http/interaction-control-error.d.ts +13 -0
  45. package/dist/http/keyed-admission.d.ts +12 -0
  46. package/dist/http/local-browser-boundary.d.ts +72 -0
  47. package/dist/http/metrics-listener.d.ts +22 -0
  48. package/dist/http/path-identifier.d.ts +17 -0
  49. package/dist/http/registered-route-label.d.ts +16 -0
  50. package/dist/http/request-body.d.ts +27 -0
  51. package/dist/http/request-source.d.ts +52 -0
  52. package/dist/http/sse.d.ts +17 -6
  53. package/dist/http/unmatched-route.d.ts +18 -0
  54. package/dist/http/user-content.d.ts +36 -0
  55. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  56. package/dist/index.d.ts +10 -3
  57. package/dist/index.js +1091 -162
  58. package/dist/index.js.map +1 -1
  59. package/dist/integration-endpoint-test.d.ts +20 -0
  60. package/dist/integrations/api-integrations.d.ts +2 -2
  61. package/dist/integrations/atlassian.d.ts +29 -3
  62. package/dist/integrations/connect-authority.d.ts +1 -0
  63. package/dist/integrations/connect-callback-return.d.ts +6 -0
  64. package/dist/integrations/fiken.d.ts +16 -2
  65. package/dist/integrations/github-app-connect.d.ts +47 -0
  66. package/dist/integrations/github-installation-proof.d.ts +3 -0
  67. package/dist/integrations/github-lens-connect.d.ts +116 -0
  68. package/dist/integrations/github-skill-source.d.ts +1 -5
  69. package/dist/integrations/google-drive.d.ts +24 -0
  70. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  71. package/dist/integrations/marketplace-plugin.d.ts +2691 -0
  72. package/dist/integrations/oauth-client.d.ts +178 -18
  73. package/dist/integrations/oauth-profiles.d.ts +222 -0
  74. package/dist/integrations/oauth-return-path.d.ts +1 -0
  75. package/dist/integrations/personal-github-repositories.d.ts +84 -0
  76. package/dist/integrations/personal-github.d.ts +42 -0
  77. package/dist/integrations/pr-review-provider.d.ts +22 -0
  78. package/dist/integrations/provider-oauth.d.ts +19 -1
  79. package/dist/integrations/slack-app-home.d.ts +24 -0
  80. package/dist/integrations/slack-bot.d.ts +367 -12
  81. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  82. package/dist/integrations/slack-install.d.ts +20 -0
  83. package/dist/integrations/slack-interactions.d.ts +107 -9
  84. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  85. package/dist/integrations/slack-routing.d.ts +120 -0
  86. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  87. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  88. package/dist/integrations/social-oauth.d.ts +7 -0
  89. package/dist/interaction-agent-access.d.ts +15 -0
  90. package/dist/interaction-frame-proxy.d.ts +68 -0
  91. package/dist/interaction-metrics.d.ts +2 -0
  92. package/dist/mcp/action-catalog-types.d.ts +9 -0
  93. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  94. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  95. package/dist/mcp/child-read-evidence.d.ts +9 -0
  96. package/dist/mcp/command-read.d.ts +24 -0
  97. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  98. package/dist/mcp/contract-input.d.ts +11 -0
  99. package/dist/mcp/documents.d.ts +7 -5
  100. package/dist/mcp/files.d.ts +2 -2
  101. package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
  102. package/dist/mcp/knowledge-entries.d.ts +5 -0
  103. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  104. package/dist/mcp/receipts.d.ts +9 -0
  105. package/dist/mcp/request-abort.d.ts +19 -0
  106. package/dist/mcp/scheduled-task-input.d.ts +1189 -0
  107. package/dist/mcp/scheduled-task-view.d.ts +22 -4
  108. package/dist/mcp/server.d.ts +255 -3
  109. package/dist/mcp/session-event-view.d.ts +94 -0
  110. package/dist/mcp/session-view.d.ts +66 -2
  111. package/dist/mcp/session-wait.d.ts +174 -0
  112. package/dist/mcp-oauth.d.ts +52 -0
  113. package/dist/model-catalog.d.ts +11 -31
  114. package/dist/observability.d.ts +3 -1
  115. package/dist/organization-mcp.d.ts +52 -0
  116. package/dist/organization-recovery-notifications.d.ts +41 -0
  117. package/dist/routes/analytics-consent.d.ts +26 -0
  118. package/dist/routes/api-integrations.d.ts +25 -0
  119. package/dist/routes/api-keys.d.ts +17 -0
  120. package/dist/routes/artifact-catalog.d.ts +6 -0
  121. package/dist/routes/automations.d.ts +19 -0
  122. package/dist/routes/billing.d.ts +49 -0
  123. package/dist/routes/browser-sessions.d.ts +59 -2
  124. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  125. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  126. package/dist/routes/client-errors.d.ts +146 -0
  127. package/dist/routes/codex.d.ts +76 -2
  128. package/dist/routes/company-brain.d.ts +3 -0
  129. package/dist/routes/company-profile.d.ts +2 -1
  130. package/dist/routes/computer-sessions.d.ts +14 -0
  131. package/dist/routes/connect.d.ts +5 -0
  132. package/dist/routes/editable-artifacts.d.ts +2 -0
  133. package/dist/routes/external-identity-links.d.ts +6 -0
  134. package/dist/routes/feedback.d.ts +3 -0
  135. package/dist/routes/github-browser-pages.d.ts +12 -0
  136. package/dist/routes/github.d.ts +2 -0
  137. package/dist/routes/insights-response-cache.d.ts +10 -0
  138. package/dist/routes/insights-usage.d.ts +12 -0
  139. package/dist/routes/insights.d.ts +30 -1
  140. package/dist/routes/knowledge.d.ts +3 -0
  141. package/dist/routes/managed-auth-session-sets.d.ts +26 -0
  142. package/dist/routes/managed-onboarding.d.ts +29 -0
  143. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  144. package/dist/routes/model-connection-access.d.ts +3 -0
  145. package/dist/routes/organization-integration-policy.d.ts +3 -0
  146. package/dist/routes/organization-integrations.d.ts +6 -0
  147. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  148. package/dist/routes/organization-model-providers.d.ts +3 -0
  149. package/dist/routes/organization-recovery.d.ts +19 -0
  150. package/dist/routes/organization-service-accounts.d.ts +3 -0
  151. package/dist/routes/organization-sessions.d.ts +26 -0
  152. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  153. package/dist/routes/personal-github.d.ts +3 -0
  154. package/dist/routes/pr-review-github.d.ts +3 -0
  155. package/dist/routes/pr-review.d.ts +3 -0
  156. package/dist/routes/session-artifact-associations.d.ts +4 -0
  157. package/dist/routes/session-history-imports.d.ts +9 -0
  158. package/dist/routes/sessions.d.ts +44 -6
  159. package/dist/routes/skill-content.d.ts +4 -0
  160. package/dist/routes/skill-install-authority.d.ts +6 -0
  161. package/dist/routes/subscription-account-pools.d.ts +34 -0
  162. package/dist/routes/subscription-pool-access.d.ts +16 -0
  163. package/dist/routes/supergrok.d.ts +6 -1
  164. package/dist/routes/usage-allowances.d.ts +12 -0
  165. package/dist/routes/user-resource-authorities.d.ts +3 -0
  166. package/dist/routes/workspace-artifacts.d.ts +2 -1
  167. package/dist/routes/workspace-capture.d.ts +10 -2
  168. package/dist/routes/workspace-integrations.d.ts +35 -0
  169. package/dist/routes/workspace-learning.d.ts +3 -0
  170. package/dist/routes/workspace-model-providers.d.ts +4 -0
  171. package/dist/routes/workspaces.d.ts +29 -0
  172. package/dist/sandbox/auth-callout.d.ts +8 -0
  173. package/dist/sandbox/channel-a.d.ts +19 -1
  174. package/dist/sandbox/connection-authority.d.ts +3 -0
  175. package/dist/sandbox/enrollment.d.ts +9 -1
  176. package/dist/sandbox/machines.d.ts +5 -2
  177. package/dist/sandbox/metrics-ingestion.d.ts +28 -20
  178. package/dist/sandbox/rematerialize.d.ts +2 -0
  179. package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
  180. package/dist/sandbox/viewer.d.ts +26 -1
  181. package/dist/sandbox-file-artifacts.d.ts +50 -0
  182. package/dist/scheduled-task-deletion.d.ts +13 -0
  183. package/dist/session-create-observability.d.ts +5 -0
  184. package/dist/session-event-view-MPS2OZD3.js +292 -0
  185. package/dist/session-event-view-MPS2OZD3.js.map +1 -0
  186. package/dist/site-session-origin.d.ts +13 -0
  187. package/dist/site-uploads.d.ts +41 -0
  188. package/dist/slack-reaction-files.d.ts +1 -1
  189. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  190. package/dist/temporal-schedule-sync.d.ts +26 -0
  191. package/dist/transcription/providers/xai-subscription.d.ts +1 -0
  192. package/dist/transcription/service.d.ts +2 -1
  193. package/dist/work-discovery-observability.d.ts +33 -0
  194. package/dist/workspace-artifact-content.d.ts +28 -0
  195. package/dist/workspace-artifact-provenance.d.ts +7 -0
  196. package/dist/workspace-delete-observability.d.ts +10 -0
  197. package/dist/workspace-deletion.d.ts +6 -0
  198. package/dist/workspace-state-projection.d.ts +3 -5
  199. package/dist/workspace-tool-gateway-observability.d.ts +17 -0
  200. package/dist/workspace-tool-gateway.d.ts +123 -0
  201. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  202. package/package.json +23 -19
  203. package/src/access-grant-rls.ts +75 -0
  204. package/src/admission-trace.ts +14 -0
  205. package/src/api-websocket.ts +23 -0
  206. package/src/app.ts +1967 -252
  207. package/src/artifact-catalog-cursor.ts +60 -0
  208. package/src/auth/managed-auth-attempt-context.ts +70 -0
  209. package/src/auth/managed-auth-rate-limits.ts +252 -0
  210. package/src/auth/managed-auth-session-adapter.ts +222 -0
  211. package/src/auth/managed-auth.ts +536 -60
  212. package/src/auth/managed-email.ts +174 -0
  213. package/src/auth/managed-sign-in-notifications.ts +81 -0
  214. package/src/auth/new-signups-gate.ts +49 -0
  215. package/src/auth/organization-user-setup.ts +307 -0
  216. package/src/auth/signup-funnel-metrics.ts +164 -0
  217. package/src/browser-controller-authority.ts +1 -186
  218. package/src/browser-ephemeral.ts +39 -0
  219. package/src/browser-state-authority.ts +1 -236
  220. package/src/claude-subscription-account-conflicts.ts +12 -0
  221. package/src/claude-subscription-account-usage.ts +48 -0
  222. package/src/claude-subscription-oauth.ts +362 -0
  223. package/src/claude-subscription-profile.ts +73 -0
  224. package/src/claude-subscription-usage.ts +97 -0
  225. package/src/claude-workspace-connection.ts +82 -0
  226. package/src/codemode.ts +194 -30
  227. package/src/codex-realtime.ts +8 -2
  228. package/src/company-brain-okf.ts +340 -0
  229. package/src/connected-machine-computer-access.ts +33 -0
  230. package/src/connection-ownership.ts +199 -0
  231. package/src/controller-data-plane.ts +81 -0
  232. package/src/editable-artifact-native-kernel.ts +26 -15
  233. package/src/editable-artifact-office-import.ts +28 -3
  234. package/src/editable-artifact-production.ts +23 -7
  235. package/src/editable-artifact-source-session.ts +123 -0
  236. package/src/editable-artifact-websocket.ts +27 -21
  237. package/src/editable-artifact-workspace-files.ts +31 -6
  238. package/src/fatal-process-boundary.ts +246 -0
  239. package/src/gateway-realtime.ts +1 -1
  240. package/src/github-access.ts +147 -5
  241. package/src/http/acting-person.ts +71 -0
  242. package/src/http/api-contract-compat.ts +49 -0
  243. package/src/http/api-error.ts +115 -1
  244. package/src/http/auth.ts +48 -0
  245. package/src/http/cors.ts +67 -0
  246. package/src/http/deprecation.ts +118 -0
  247. package/src/http/interaction-control-error.ts +164 -0
  248. package/src/http/keyed-admission.ts +29 -0
  249. package/src/http/local-browser-boundary.ts +343 -0
  250. package/src/http/metrics-listener.ts +57 -0
  251. package/src/http/path-identifier.ts +54 -0
  252. package/src/http/registered-route-label.ts +34 -0
  253. package/src/http/request-body.ts +127 -0
  254. package/src/http/request-source.ts +178 -0
  255. package/src/http/sse.ts +486 -132
  256. package/src/http/unmatched-route.ts +60 -0
  257. package/src/http/user-content.ts +158 -0
  258. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  259. package/src/index.ts +157 -52
  260. package/src/integration-endpoint-test.ts +291 -0
  261. package/src/integrations/api-integrations.ts +98 -11
  262. package/src/integrations/atlassian.ts +474 -136
  263. package/src/integrations/connect-authority.ts +2 -0
  264. package/src/integrations/connect-callback-return.ts +86 -0
  265. package/src/integrations/fiken.ts +354 -64
  266. package/src/integrations/github-app-connect.ts +435 -0
  267. package/src/integrations/github-installation-proof.ts +60 -0
  268. package/src/integrations/github-lens-connect.ts +76 -0
  269. package/src/integrations/github-skill-source.ts +2 -142
  270. package/src/integrations/google-drive.ts +717 -225
  271. package/src/integrations/integration-commit-authority.ts +69 -0
  272. package/src/integrations/marketplace-plugin.ts +48 -0
  273. package/src/integrations/oauth-client.ts +1356 -459
  274. package/src/integrations/oauth-profiles.ts +537 -0
  275. package/src/integrations/oauth-return-path.ts +18 -0
  276. package/src/integrations/personal-github-repositories.ts +674 -0
  277. package/src/integrations/personal-github.ts +825 -0
  278. package/src/integrations/pr-review-provider.ts +246 -0
  279. package/src/integrations/provider-oauth.ts +250 -22
  280. package/src/integrations/slack-app-home.ts +300 -0
  281. package/src/integrations/slack-bot.ts +963 -239
  282. package/src/integrations/slack-file-upload-flow.ts +147 -0
  283. package/src/integrations/slack-install.ts +83 -0
  284. package/src/integrations/slack-interactions.ts +3167 -474
  285. package/src/integrations/slack-mrkdwn.ts +193 -0
  286. package/src/integrations/slack-routing.ts +337 -0
  287. package/src/integrations/slack-session-defaults.ts +224 -0
  288. package/src/integrations/slack-task-file-upload.ts +323 -0
  289. package/src/integrations/social-oauth.ts +213 -15
  290. package/src/interaction-agent-access.ts +48 -0
  291. package/src/interaction-frame-proxy.ts +409 -0
  292. package/src/interaction-metrics.ts +30 -0
  293. package/src/mcp/action-catalog-types.ts +9 -0
  294. package/src/mcp/action-catalog.gen.ts +6696 -0
  295. package/src/mcp/capability-account-readiness.ts +17 -0
  296. package/src/mcp/child-read-evidence.ts +19 -0
  297. package/src/mcp/command-read.ts +109 -0
  298. package/src/mcp/company-profile-agent-admin.ts +198 -0
  299. package/src/mcp/contract-input.ts +141 -0
  300. package/src/mcp/documents.ts +65 -377
  301. package/src/mcp/editable-artifacts.ts +12 -6
  302. package/src/mcp/files.ts +80 -43
  303. package/src/mcp/first-party-tool-permissions.ts +305 -0
  304. package/src/mcp/knowledge-entries.ts +322 -0
  305. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  306. package/src/mcp/receipts.ts +34 -0
  307. package/src/mcp/request-abort.ts +44 -0
  308. package/src/mcp/scheduled-task-input.ts +76 -0
  309. package/src/mcp/scheduled-task-view.ts +44 -3
  310. package/src/mcp/server.ts +3030 -1267
  311. package/src/mcp/session-event-view.ts +383 -0
  312. package/src/mcp/session-view.ts +84 -3
  313. package/src/mcp/session-wait.ts +665 -0
  314. package/src/mcp-oauth.ts +1123 -0
  315. package/src/model-catalog.ts +91 -333
  316. package/src/observability.ts +15 -1
  317. package/src/organization-mcp.ts +397 -0
  318. package/src/organization-recovery-notifications.ts +103 -0
  319. package/src/routes/analytics-consent.ts +123 -0
  320. package/src/routes/api-integrations.ts +364 -74
  321. package/src/routes/api-keys.ts +336 -10
  322. package/src/routes/artifact-catalog.ts +279 -0
  323. package/src/routes/automations.ts +768 -0
  324. package/src/routes/billing.ts +461 -46
  325. package/src/routes/browser-sessions.ts +780 -112
  326. package/src/routes/canonical-human-identities.ts +90 -14
  327. package/src/routes/capabilities.ts +107 -6
  328. package/src/routes/channels.ts +20 -3
  329. package/src/routes/claude-subscription-accounts.ts +334 -0
  330. package/src/routes/claude-subscription-oauth.ts +142 -0
  331. package/src/routes/client-errors.ts +362 -0
  332. package/src/routes/codex.ts +833 -116
  333. package/src/routes/company-brain.ts +322 -0
  334. package/src/routes/company-profile.ts +65 -1
  335. package/src/routes/computer-sessions.ts +557 -106
  336. package/src/routes/connect.ts +1938 -0
  337. package/src/routes/connections.ts +1039 -349
  338. package/src/routes/documents.ts +488 -287
  339. package/src/routes/editable-artifacts.ts +79 -9
  340. package/src/routes/enrollments.ts +135 -39
  341. package/src/routes/environments.ts +154 -58
  342. package/src/routes/external-identity-links.ts +201 -0
  343. package/src/routes/feedback.ts +113 -0
  344. package/src/routes/files.ts +267 -33
  345. package/src/routes/github-browser-pages.ts +162 -0
  346. package/src/routes/github.ts +446 -144
  347. package/src/routes/insights-response-cache.ts +83 -0
  348. package/src/routes/insights-usage.ts +345 -0
  349. package/src/routes/insights.ts +153 -19
  350. package/src/routes/install.ts +133 -38
  351. package/src/routes/integration-facets.ts +107 -33
  352. package/src/routes/interaction-resources.ts +30 -3
  353. package/src/routes/knowledge.ts +488 -0
  354. package/src/routes/machines.ts +313 -15
  355. package/src/routes/managed-auth-session-sets.ts +1218 -0
  356. package/src/routes/managed-onboarding.ts +337 -0
  357. package/src/routes/managed-sign-in-methods.ts +433 -0
  358. package/src/routes/memory-slack-publications.ts +3 -2
  359. package/src/routes/model-connection-access.ts +208 -0
  360. package/src/routes/organization-integration-policy.ts +116 -0
  361. package/src/routes/organization-integrations.ts +326 -0
  362. package/src/routes/organization-mcp-connections.ts +178 -0
  363. package/src/routes/organization-memberships.ts +1019 -27
  364. package/src/routes/organization-model-providers.ts +293 -0
  365. package/src/routes/organization-recovery.ts +325 -0
  366. package/src/routes/organization-service-accounts.ts +128 -0
  367. package/src/routes/organization-sessions.ts +350 -0
  368. package/src/routes/personal-github-git-broker.ts +785 -0
  369. package/src/routes/personal-github.ts +370 -0
  370. package/src/routes/plugins.ts +251 -22
  371. package/src/routes/pr-review-github.ts +881 -0
  372. package/src/routes/pr-review.ts +622 -0
  373. package/src/routes/preference-registry.ts +12 -93
  374. package/src/routes/rigs.ts +167 -50
  375. package/src/routes/scheduled-tasks.ts +346 -41
  376. package/src/routes/session-artifact-associations.ts +87 -0
  377. package/src/routes/session-history-imports.ts +280 -0
  378. package/src/routes/sessions.ts +2306 -264
  379. package/src/routes/skill-content.ts +297 -0
  380. package/src/routes/skill-install-authority.ts +64 -0
  381. package/src/routes/skills.ts +62 -9
  382. package/src/routes/social.ts +46 -18
  383. package/src/routes/subscription-account-pools.ts +436 -0
  384. package/src/routes/subscription-pool-access.ts +126 -0
  385. package/src/routes/supergrok.ts +219 -303
  386. package/src/routes/transcription-recordings.ts +38 -3
  387. package/src/routes/transcriptions.ts +4 -0
  388. package/src/routes/usage-allowances.ts +378 -0
  389. package/src/routes/user-resource-authorities.ts +138 -0
  390. package/src/routes/video-generation.ts +14 -10
  391. package/src/routes/workspace-artifacts.ts +275 -69
  392. package/src/routes/workspace-capture.ts +21 -0
  393. package/src/routes/workspace-integrations.ts +576 -0
  394. package/src/routes/workspace-learning.ts +159 -0
  395. package/src/routes/workspace-model-providers.ts +148 -0
  396. package/src/routes/workspace-state.ts +38 -25
  397. package/src/routes/workspaces.ts +1004 -127
  398. package/src/sandbox/auth-callout.ts +96 -19
  399. package/src/sandbox/channel-a.ts +323 -24
  400. package/src/sandbox/connection-authority.ts +3 -0
  401. package/src/sandbox/enrollment.ts +81 -6
  402. package/src/sandbox/machines.ts +218 -76
  403. package/src/sandbox/metrics-ingestion.ts +411 -62
  404. package/src/sandbox/rematerialize.ts +121 -19
  405. package/src/sandbox/session-attach-variable-sets.ts +131 -0
  406. package/src/sandbox/viewer.ts +280 -25
  407. package/src/sandbox-file-artifacts.ts +413 -0
  408. package/src/scheduled-task-deletion.ts +138 -0
  409. package/src/session-create-observability.ts +46 -0
  410. package/src/session-realtime-context.ts +6 -3
  411. package/src/site-session-origin.ts +48 -0
  412. package/src/site-uploads.ts +224 -0
  413. package/src/slack-reaction-files.ts +16 -5
  414. package/src/temporal-schedule-cleanup.ts +13 -0
  415. package/src/temporal-schedule-sync.ts +74 -0
  416. package/src/transcription/providers/codex-subscription.ts +2 -0
  417. package/src/transcription/providers/openai.ts +1 -0
  418. package/src/transcription/providers/xai-subscription.ts +49 -3
  419. package/src/transcription/segmenter.ts +8 -2
  420. package/src/transcription/service.ts +43 -6
  421. package/src/work-discovery-observability.ts +121 -0
  422. package/src/workspace-artifact-content.ts +144 -0
  423. package/src/workspace-artifact-provenance.ts +104 -0
  424. package/src/workspace-delete-observability.ts +75 -0
  425. package/src/workspace-deletion.ts +73 -0
  426. package/src/workspace-state-projection.ts +18 -148
  427. package/src/workspace-tool-gateway-observability.ts +100 -0
  428. package/src/workspace-tool-gateway.ts +870 -0
  429. package/src/workspace-webhook-dispatch.ts +190 -0
  430. package/src/xai-subscription-auth.ts +9 -2
  431. package/dist/chunk-WCXHI3FF.js +0 -49920
  432. package/dist/chunk-WCXHI3FF.js.map +0 -1
  433. package/dist/routes/packs.d.ts +0 -3
  434. package/src/routes/packs.ts +0 -729
@@ -28,7 +28,7 @@
28
28
  // FLAG GATE: the whole feature is behind sandboxSelfhostedEnabled (default OFF) —
29
29
  // when off the routes 404 (the surface is invisible) and boot is unaffected.
30
30
 
31
- import { randomBytes } from "node:crypto";
31
+ import { createPublicKey, randomBytes, verify } from "node:crypto";
32
32
  import {
33
33
  resolveEnrollmentSigningSecret,
34
34
  resolveRelayTokenSecret,
@@ -36,10 +36,13 @@ import {
36
36
  } from "@opengeni/config";
37
37
  import {
38
38
  DeviceEnrollmentState,
39
+ enrollmentRenewalProof,
39
40
  signEnrollmentBearer,
40
41
  signEnrollToken,
41
42
  signRelayToken,
42
43
  verifyEnrollToken,
44
+ verifyEnrollmentBearer,
45
+ type RenewEnrollmentRequest,
43
46
  type DeviceEnrollmentLookupResponse,
44
47
  type DeviceEnrollmentPollResponse,
45
48
  type DeviceEnrollmentStartResponse,
@@ -71,7 +74,8 @@ export const DEVICE_POLL_INTERVAL_SECONDS = 5;
71
74
  // The bearer the agent presents to the NATS auth-callout. A bring-your-own-compute
72
75
  // machine is PERSISTENT (unlike an ephemeral Modal box, whose lifetime ~= an agent
73
76
  // token's hour), so this is long-lived — 30 days, matching the relay token below —
74
- // and re-minted on every poll/re-enroll. The old 1-hour value (sized for a Modal
77
+ // and renewed automatically by install-key proof, or re-minted on poll/re-enroll.
78
+ // The old 1-hour value (sized for a Modal
75
79
  // box) caused a self-hosted agent to drop PERMANENTLY one hour after connecting: the
76
80
  // bearer expired and the auth-callout rejected every reconnect ("re-enroll may be
77
81
  // required"). A long-lived bearer is safe because the auth-callout RE-CHECKS the
@@ -83,10 +87,69 @@ export const ENROLLMENT_BEARER_TTL_SECONDS = 30 * 24 * 3600;
83
87
  // NOT per-stream: the agent presents it on every channel registration for the life
84
88
  // of its run, and the producer side has no per-viewer epoch fence (that is the
85
89
  // VIEWER's `ogs_` token's job). So it is long-lived — 30 days — re-minted on every
86
- // poll/re-enroll. The relay re-verifies it (authenticity + the channel-key ws+agent
90
+ // renewal/poll/re-enroll. The relay re-verifies it (authenticity + the channel-key ws+agent
87
91
  // scope) on every StreamOpen; a revoked enrollment's machine goes offline at the
88
92
  // control plane regardless, so a long-lived relay token cannot reach a dead agent.
89
93
  export const RELAY_TOKEN_TTL_SECONDS = 30 * 24 * 3600;
94
+
95
+ /** Renew an existing grant, including after a long offline interval. The expired
96
+ * bearer is only an authenticated enrollment/generation locator here: current
97
+ * install-key possession and live enrollment authority are both required. Normal
98
+ * NATS/relay authentication continues to reject expired transport credentials.
99
+ * Nothing creates/reactivates an enrollment or changes its consent or scope. */
100
+ export async function renewEnrollmentCredentials(
101
+ services: EnrollmentServices,
102
+ input: RenewEnrollmentRequest,
103
+ nowSeconds = Math.floor(Date.now() / 1000),
104
+ ): Promise<EnrollmentCredentialsResponse | null> {
105
+ if (Math.abs(nowSeconds - input.signedAt) > 120) return null;
106
+ const secret = resolveEnrollmentSigningSecret(services.settings);
107
+ if (!secret) return null;
108
+ const claims = await verifyEnrollmentBearer(secret, input.bearer, 0);
109
+ if (
110
+ !claims ||
111
+ claims.agentId !== claims.enrollmentId ||
112
+ claims.subjectPrefix !== `agent.${claims.workspaceId}.${claims.agentId}`
113
+ )
114
+ return null;
115
+ const enrollment = await getEnrollment(services.db, claims.workspaceId, claims.enrollmentId);
116
+ if (
117
+ !enrollment ||
118
+ enrollment.status !== "active" ||
119
+ enrollment.credentialGeneration !== claims.credentialGeneration
120
+ )
121
+ return null;
122
+ try {
123
+ const rawKey = Buffer.from(enrollment.pubkey, "base64");
124
+ const signature = Buffer.from(input.signature, "base64");
125
+ if (rawKey.length !== 32 || signature.length !== 64) return null;
126
+ const key = createPublicKey({
127
+ key: Buffer.concat([Buffer.from("302a300506032b6570032100", "hex"), rawKey]),
128
+ format: "der",
129
+ type: "spki",
130
+ });
131
+ if (
132
+ !verify(
133
+ null,
134
+ Buffer.from(enrollmentRenewalProof(input.bearer, input.signedAt)),
135
+ key,
136
+ signature,
137
+ )
138
+ )
139
+ return null;
140
+ } catch {
141
+ return null;
142
+ }
143
+ // A concurrent revoke/re-enrollment still wins: issued credentials retain the
144
+ // captured generation, which the control-plane claim rechecks transactionally.
145
+ return buildEnrollmentCredentials(services, {
146
+ secret,
147
+ workspaceId: enrollment.workspaceId,
148
+ agentId: enrollment.id,
149
+ credentialGeneration: enrollment.credentialGeneration,
150
+ consentedScreenControl: enrollment.allowScreenControl,
151
+ });
152
+ }
90
153
  // The headless enroll token (`oget_`; design 11 §A2.1) TTL. 1h: long enough to
91
154
  // script a fleet rollout, short enough to bound exposure of a workspace-scoped
92
155
  // secret that IS the grant (no human approve). Re-mintable by an authorized user.
@@ -172,7 +235,7 @@ export async function startDeviceEnrollment(
172
235
  throw lastError instanceof Error ? lastError : new Error("failed to start device enrollment");
173
236
  }
174
237
 
175
- const base = input.verificationOrigin.replace(/\/$/, "");
238
+ const base = input.verificationOrigin.replace(/\/+$/, "");
176
239
  const verificationUri = `${base}/device`;
177
240
  const verificationUriComplete = `${verificationUri}?user_code=${encodeURIComponent(request.userCode)}`;
178
241
  return {
@@ -193,12 +256,18 @@ export async function approveDeviceEnrollment(
193
256
  input: {
194
257
  accountId: string;
195
258
  workspaceId: string;
259
+ scope?: "organization" | "workspace" | "user";
260
+ allowOrganization?: boolean;
196
261
  userCode: string;
197
262
  allowScreenControl: boolean;
198
263
  approvedBySubjectId: string;
199
264
  approvedBySubjectLabel?: string | null;
200
265
  },
201
- ): Promise<{ enrollmentId: string; sandboxId: string; allowScreenControl: boolean } | null> {
266
+ ): Promise<{
267
+ enrollmentId: string;
268
+ sandboxId: string;
269
+ allowScreenControl: boolean;
270
+ } | null> {
202
271
  const { db } = services;
203
272
  const pending = await getPendingDeviceEnrollmentRequestByUserCode(
204
273
  db,
@@ -213,6 +282,8 @@ export async function approveDeviceEnrollment(
213
282
  const result = await approveDeviceEnrollmentRequest(db, {
214
283
  accountId: input.accountId,
215
284
  workspaceId: input.workspaceId,
285
+ ...(input.scope ? { scope: input.scope } : {}),
286
+ allowOrganization: input.allowOrganization === true,
216
287
  requestId: pending.id,
217
288
  allowScreenControl: input.allowScreenControl,
218
289
  approvedBySubjectId: input.approvedBySubjectId,
@@ -291,7 +362,11 @@ export async function denyDeviceEnrollment(
291
362
  * mirror poll's "disabled" handling. The token value is NEVER logged. */
292
363
  export async function mintEnrollToken(
293
364
  services: EnrollmentServices,
294
- input: { accountId: string; workspaceId: string; allowScreenControl: boolean },
365
+ input: {
366
+ accountId: string;
367
+ workspaceId: string;
368
+ allowScreenControl: boolean;
369
+ },
295
370
  ): Promise<MintEnrollTokenResponse | null> {
296
371
  const { settings } = services;
297
372
  const secret = resolveEnrollmentSigningSecret(settings);
@@ -1,16 +1,17 @@
1
1
  // apps/api/src/sandbox/machines.ts — the M10 Machines-DASHBOARD service (design
2
2
  // §10.7). Builds the `MachinesResponse` the dashboard renders: the workspace's
3
3
  // enrolled selfhosted machines, each enriched with
4
- // * STATE — the M3 liveness (online/reconnecting/offline) overlaid with the
5
- // enrollment-derived consent/display reasons (consent_required /
6
- // display_unavailable) — a real ControlRpc ping (the subject IS the registry),
7
- // reusing the M7 fleet probe;
4
+ // * STATE — heartbeat + goodbye liveness (online/offline) overlaid with the
5
+ // enrollment-derived display reason (display_unavailable). This list does
6
+ // not ControlRpc-ping; attach, capability negotiation, and fleet tools
7
+ // still probe when they need a live responder.
8
8
  // * METRICS — the latest machine_metrics_latest row (or null before a first
9
9
  // heartbeat), projected to the contract's MetricSample;
10
10
  // * sharedSessionCount — the lease refcount (how many sessions share this one
11
11
  // whole machine, the maxSandboxes:1 disclosure).
12
- // PLUS, when a session context is supplied, the session's synthetic Modal group
13
- // box (isSessionGroup:true) + the active-sandbox pointer (activeSandboxId/Epoch).
12
+ // PLUS, when a session context is supplied, the session's synthetic managed
13
+ // group box (isSessionGroup:true) + the active-sandbox pointer
14
+ // (activeSandboxId/Epoch).
14
15
  //
15
16
  // This is workspace-scoped (perm enrollments:read) and flag-gated upstream
16
17
  // (sandboxSelfhostedEnabled). It deliberately does NOT depend on a FleetContext
@@ -21,6 +22,7 @@
21
22
  import type { Settings } from "@opengeni/config";
22
23
  import {
23
24
  getSession,
25
+ getLiveEnrollmentConnection,
24
26
  listEnrollments,
25
27
  listSandboxes,
26
28
  readActiveSandbox,
@@ -30,32 +32,129 @@ import {
30
32
  type EnrollmentRecord,
31
33
  type MachineMetricsRow,
32
34
  } from "@opengeni/db";
33
- import type { EventBus } from "@opengeni/events";
34
35
  import { MachineView, MetricSample, type MachinesResponse } from "@opengeni/contracts";
35
- import {
36
- NatsControlRpc,
37
- selfhostedLiveness,
38
- SelfhostedSession,
39
- type ControlRpc,
40
- type NatsRequestConnection,
41
- } from "@opengeni/runtime/sandbox";
42
- import { relayConfigFromSettings } from "@opengeni/core";
36
+ import { managedSessionGroupBackend, sessionGroupMachinePresentation } from "@opengeni/core";
37
+ import { selfhostedHeartbeatLiveness } from "@opengeni/runtime/sandbox";
43
38
 
44
39
  export type MachinesServices = {
45
40
  db: Database;
46
41
  settings: Settings;
47
- bus?: EventBus;
48
42
  };
49
43
 
50
- const PROBE_TIMEOUT_MS = 5_000;
44
+ const ACTIVE_UPDATE_STATUSES = new Set([
45
+ "requested",
46
+ "accepted",
47
+ "waiting_for_idle",
48
+ "downloading",
49
+ "verifying",
50
+ "applying",
51
+ "restarting",
52
+ ]);
51
53
 
52
- function controlRpc(bus: EventBus | undefined): ControlRpc {
53
- return new NatsControlRpc(async (): Promise<NatsRequestConnection | null> => {
54
- if (!bus) {
55
- return null;
56
- }
57
- return bus.getRequestConnection();
58
- });
54
+ function compareAgentVersions(left: string, right: string): number | null {
55
+ const parse = (value: string): { core: number[]; prerelease: string | null } | null => {
56
+ const match = /^(?:v)?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(value.trim());
57
+ if (!match) return null;
58
+ return {
59
+ core: [Number(match[1]), Number(match[2]), Number(match[3])],
60
+ prerelease: match[4] ?? null,
61
+ };
62
+ };
63
+ const a = parse(left);
64
+ const b = parse(right);
65
+ if (!a || !b) return null;
66
+ for (let index = 0; index < 3; index += 1) {
67
+ const delta = a.core[index]! - b.core[index]!;
68
+ if (delta !== 0) return Math.sign(delta);
69
+ }
70
+ if (a.prerelease === b.prerelease) return 0;
71
+ if (a.prerelease === null) return 1;
72
+ if (b.prerelease === null) return -1;
73
+ return a.prerelease.localeCompare(b.prerelease);
74
+ }
75
+
76
+ /** Older Mac updaters replace a single file inside a sealed app. They must
77
+ * bootstrap once through the official whole-app installer, never an RPC swap. */
78
+ export function machineUpdateBlockedReason(os: string, version: string | null): string | null {
79
+ if (os !== "macos") return null;
80
+ const order = version ? compareAgentVersions(version, "0.1.29") : null;
81
+ return order !== null && order >= 0
82
+ ? null
83
+ : "Install Opengeni Agent 0.1.29 or newer with the official Mac installer first. This older updater cannot preserve the signed application.";
84
+ }
85
+
86
+ function runtimeFor(settings: Settings, enrollment: EnrollmentRecord): MachineView["runtime"] {
87
+ const desiredVersion =
88
+ enrollment.agentUpdateChannel === "beta"
89
+ ? (settings.agentBetaVersion ?? settings.agentStableVersion)
90
+ : settings.agentStableVersion;
91
+ const update = enrollment.agentUpdate;
92
+ const activeUpdate = update ? ACTIVE_UPDATE_STATUSES.has(update.status) : false;
93
+ const order =
94
+ enrollment.agentVersion && desiredVersion
95
+ ? compareAgentVersions(enrollment.agentVersion, desiredVersion)
96
+ : null;
97
+ const versionState = activeUpdate
98
+ ? "updating"
99
+ : update?.status === "failed"
100
+ ? "update_failed"
101
+ : order === null
102
+ ? "unknown"
103
+ : order === 0
104
+ ? "current"
105
+ : order < 0
106
+ ? "outdated"
107
+ : "ahead";
108
+ const capability = (name: string): boolean => enrollment.agentCapabilities[name] === true;
109
+ return {
110
+ installedVersion: enrollment.agentVersion,
111
+ binarySha256: enrollment.agentBinarySha256,
112
+ updateChannel: enrollment.agentUpdateChannel,
113
+ desiredVersion,
114
+ versionState,
115
+ updateBlockedReason: machineUpdateBlockedReason(enrollment.os, enrollment.agentVersion),
116
+ capabilities: {
117
+ exec: capability("exec"),
118
+ filesystem: capability("filesystem"),
119
+ git: capability("git"),
120
+ pty: capability("pty"),
121
+ desktop: capability("desktop"),
122
+ opStream: capability("opStream"),
123
+ browserBridge: capability("browserBridge"),
124
+ operationResourcePolicy: capability("operationResourcePolicy"),
125
+ operationCpuQuota: capability("operationCpuQuota"),
126
+ transactionalFsWrite: capability("transactionalFsWrite"),
127
+ },
128
+ update,
129
+ };
130
+ }
131
+
132
+ function connectionAuthorityFor(
133
+ enrollment: EnrollmentRecord | null,
134
+ liveConnection: EnrollmentRecord | null,
135
+ ): MachineView["connectionAuthority"] {
136
+ if (!enrollment) {
137
+ return {
138
+ state: "not_applicable",
139
+ generation: 0,
140
+ supersededCount: 0,
141
+ leaseExpiresAt: null,
142
+ duplicateRunnerDeniedCount: 0,
143
+ duplicateRunnerDeniedAt: null,
144
+ };
145
+ }
146
+ return {
147
+ state: liveConnection
148
+ ? "active"
149
+ : enrollment.connectionInstanceId && enrollment.connectionLeaseExpiresAt
150
+ ? "expired"
151
+ : "unclaimed",
152
+ generation: enrollment.connectionGeneration,
153
+ supersededCount: Math.max(0, enrollment.connectionGeneration - 1),
154
+ leaseExpiresAt: enrollment.connectionLeaseExpiresAt,
155
+ duplicateRunnerDeniedCount: enrollment.connectionDuplicateDeniedCount,
156
+ duplicateRunnerDeniedAt: enrollment.connectionDuplicateDeniedAt,
157
+ };
59
158
  }
60
159
 
61
160
  /**
@@ -83,36 +182,8 @@ export function metricRowToSample(row: MachineMetricsRow): MetricSample {
83
182
  });
84
183
  }
85
184
 
86
- /** Probe an enrolled machine's liveness — a real ControlRpc ping mapped through
87
- * `selfhostedLiveness` (the enrollment status/consent/display + lastSeenAt
88
- * disambiguate a probe-miss into reconnecting vs offline). Mirrors the M7 fleet
89
- * probe. A non-active enrollment is offline without a probe. */
90
- async function probeEnrollment(
91
- services: MachinesServices,
92
- workspaceId: string,
93
- enrollment: EnrollmentRecord,
94
- ): Promise<{
95
- state: "online" | "reconnecting" | "offline";
96
- consented: boolean;
97
- hasDisplay: boolean;
98
- }> {
99
- const { settings, bus } = services;
100
- let probeResponded = false;
101
- if (enrollment.status === "active") {
102
- const session = new SelfhostedSession({
103
- workspaceId,
104
- agentId: enrollment.id,
105
- controlRpc: controlRpc(bus),
106
- relay: relayConfigFromSettings(settings),
107
- timeoutMs: PROBE_TIMEOUT_MS,
108
- });
109
- try {
110
- probeResponded = await session.ping();
111
- } catch {
112
- probeResponded = false;
113
- }
114
- }
115
- const derived = selfhostedLiveness({
185
+ function enrollmentLiveness(enrollment: EnrollmentRecord) {
186
+ return selfhostedHeartbeatLiveness({
116
187
  enrollment: {
117
188
  status: enrollment.status,
118
189
  exposure: enrollment.exposure,
@@ -122,16 +193,15 @@ async function probeEnrollment(
122
193
  wentOfflineAt: enrollment.wentOfflineAt,
123
194
  wentOfflineReason: enrollment.wentOfflineReason,
124
195
  },
125
- probeResponded,
126
196
  });
127
- return { state: derived.state, consented: derived.consented, hasDisplay: derived.hasDisplay };
128
197
  }
129
198
 
130
199
  /**
131
200
  * Resolve the dashboard STATE of a machine. State reflects REACHABILITY + the
132
201
  * VIEW plane only: an online machine with no display → `display_unavailable` (no
133
202
  * desktop stream, but compute — exec/fs/git/terminal — still works); otherwise
134
- * the liveness state (online/reconnecting/offline). It deliberately does NOT fold
203
+ * the liveness state (online/offline; list heartbeat never yields reconnecting).
204
+ * It deliberately does NOT fold
135
205
  * in screen-control consent: a displayed machine can be VIEWED (read-only) and
136
206
  * used for compute regardless of `allowScreenControl` — only INPUT (ComputerUse /
137
207
  * an interactive stream) needs that consent, which is a per-capability concern
@@ -163,7 +233,12 @@ function machineStateFor(
163
233
  */
164
234
  export async function listMachines(
165
235
  services: MachinesServices,
166
- input: { workspaceId: string; sessionId?: string | null },
236
+ input: {
237
+ accountId?: string;
238
+ workspaceId: string;
239
+ subjectId?: string;
240
+ sessionId?: string | null;
241
+ },
167
242
  ): Promise<MachinesResponse> {
168
243
  const { db } = services;
169
244
  const { workspaceId } = input;
@@ -183,45 +258,92 @@ export async function listMachines(
183
258
  }
184
259
 
185
260
  const machines: MachineView[] = [];
261
+ const groupBackend = session
262
+ ? managedSessionGroupBackend(services.settings.sandboxBackend, session.sandboxBackend)
263
+ : null;
186
264
 
187
- // The session's own group box (synthetic): the default/home sandbox a null
188
- // active pointer routes to. A backend:none session has no home box.
189
- if (session && session.sandboxBackend !== "none") {
265
+ // The session's own managed group box (synthetic): the sandbox a null active
266
+ // pointer routes to. A machine-home session uses the deployment's managed
267
+ // backend only after an explicit switch; none/selfhosted-only deployments do
268
+ // not invent a group they cannot establish.
269
+ if (session && groupBackend) {
190
270
  const groupActive = activeSandboxId === null;
191
271
  const groupLease = await readLease(db, workspaceId, session.sandboxGroupId);
272
+ const presentation = sessionGroupMachinePresentation(groupBackend);
273
+ const localHost = groupBackend === "local";
192
274
  machines.push(
193
275
  MachineView.parse({
194
276
  sandboxId: session.sandboxGroupId,
195
277
  enrollmentId: null,
196
- name: "session sandbox",
197
- kind: session.sandboxBackend === "selfhosted" ? "selfhosted" : "modal",
278
+ name: presentation.name,
279
+ kind: presentation.kind,
198
280
  state: "online",
199
281
  active: groupActive,
200
282
  isSessionGroup: true,
201
283
  workspaceGeneration: groupLease?.workspaceGeneration ?? null,
202
284
  archiveGeneration: groupLease?.archiveGeneration ?? null,
203
285
  archiveComplete: groupLease?.archiveComplete ?? false,
204
- // The Modal group box is a cloud Linux box; its precise OS/arch is not
205
- // surfaced as a metric, so the dashboard shows the canonical linux/x86_64.
206
- os: "linux",
207
- arch: "x86_64",
208
- hasDisplay: false,
286
+ // A local sandbox is this machine. Other managed providers run a Linux box.
287
+ os: localHost ? process.platform : "linux",
288
+ arch: localHost ? process.arch : "x86_64",
289
+ hasDisplay: localHost,
209
290
  desktopUnavailableReason: null,
210
291
  allowScreenControl: false,
211
292
  sharedSessionCount: 1,
212
293
  lastSeenAt: null,
294
+ connectionAuthority: connectionAuthorityFor(null, null),
295
+ runtime: null,
296
+ operationPolicy: null,
213
297
  metrics: null,
214
298
  }),
215
299
  );
216
300
  }
217
301
 
218
302
  // The workspace's enrolled selfhosted machines. One bulk metrics read joined
219
- // onto the machines (no N+1). Each machine is probed for liveness.
220
- const [sandboxes, enrollments, metricsByEnrollment] = await Promise.all([
303
+ // onto the machines (no N+1). Liveness is the durable heartbeat cursor.
304
+ const [legacySandboxes, enrollments] = await Promise.all([
221
305
  listSandboxes(db, workspaceId),
222
- listEnrollments(db, workspaceId, { status: "active" }),
223
- readMachineMetricsLatestForWorkspace(db, workspaceId),
306
+ listEnrollments(
307
+ db,
308
+ input.accountId && input.subjectId
309
+ ? {
310
+ accountId: input.accountId,
311
+ workspaceId,
312
+ subjectId: input.subjectId,
313
+ }
314
+ : workspaceId,
315
+ { status: "active" },
316
+ ),
224
317
  ]);
318
+ const metricsByEnrollment = new Map<string, MachineMetricsRow>();
319
+ for (const originWorkspaceId of new Set(enrollments.map((entry) => entry.workspaceId))) {
320
+ const originMetrics = await readMachineMetricsLatestForWorkspace(db, originWorkspaceId);
321
+ for (const [enrollmentId, metrics] of originMetrics) {
322
+ metricsByEnrollment.set(enrollmentId, metrics);
323
+ }
324
+ }
325
+ const scopedSandboxes = enrollments.flatMap((enrollment) =>
326
+ enrollment.sandboxId
327
+ ? [
328
+ {
329
+ id: enrollment.sandboxId,
330
+ accountId: enrollment.accountId,
331
+ workspaceId: enrollment.workspaceId,
332
+ kind: "selfhosted" as const,
333
+ name: enrollment.sandboxName ?? `${enrollment.os} machine`,
334
+ enrollmentId: enrollment.id,
335
+ createdAt: enrollment.createdAt,
336
+ updatedAt: enrollment.updatedAt,
337
+ },
338
+ ]
339
+ : [],
340
+ );
341
+ const sandboxes = [
342
+ ...legacySandboxes.filter(
343
+ (sandbox) => !scopedSandboxes.some((scoped) => scoped.id === sandbox.id),
344
+ ),
345
+ ...scopedSandboxes,
346
+ ];
225
347
  const enrollmentById = new Map(enrollments.map((e) => [e.id, e]));
226
348
 
227
349
  const machineViews = await Promise.all(
@@ -233,11 +355,26 @@ export async function listMachines(
233
355
  if (!enrollment) {
234
356
  return null;
235
357
  }
236
- const [probe, lease] = await Promise.all([
237
- probeEnrollment(services, workspaceId, enrollment),
238
- readLease(db, workspaceId, sandbox.id),
358
+ const [liveConnection, lease] = await Promise.all([
359
+ enrollment.connectionInstanceId &&
360
+ enrollment.connectionLeaseExpiresAt &&
361
+ Date.parse(enrollment.connectionLeaseExpiresAt) > Date.now()
362
+ ? Promise.resolve(enrollment)
363
+ : getLiveEnrollmentConnection(
364
+ db,
365
+ input.accountId && input.subjectId
366
+ ? {
367
+ accountId: input.accountId,
368
+ workspaceId,
369
+ subjectId: input.subjectId,
370
+ }
371
+ : enrollment.workspaceId,
372
+ enrollment.id,
373
+ ),
374
+ readLease(db, enrollment.workspaceId, sandbox.id),
239
375
  ]);
240
- const state = machineStateFor(probe.state, probe.hasDisplay);
376
+ const liveness = enrollmentLiveness(enrollment);
377
+ const state = machineStateFor(liveness.state, liveness.hasDisplay);
241
378
 
242
379
  // sharedSessionCount = the lease refcount for this machine's group. The
243
380
  // selfhosted sandbox id IS the lease group key (maxSandboxes:1, N sessions
@@ -248,6 +385,8 @@ export async function listMachines(
248
385
  return MachineView.parse({
249
386
  sandboxId: sandbox.id,
250
387
  enrollmentId: enrollment.id,
388
+ scope: enrollment.scope,
389
+ generation: enrollment.generation,
251
390
  name: sandbox.name,
252
391
  kind: "selfhosted",
253
392
  state,
@@ -263,6 +402,9 @@ export async function listMachines(
263
402
  allowScreenControl: enrollment.allowScreenControl,
264
403
  sharedSessionCount,
265
404
  lastSeenAt: enrollment.lastSeenAt,
405
+ connectionAuthority: connectionAuthorityFor(enrollment, liveConnection),
406
+ runtime: runtimeFor(services.settings, enrollment),
407
+ operationPolicy: enrollment.operationPolicy,
266
408
  metrics: metricsRow ? metricRowToSample(metricsRow) : null,
267
409
  });
268
410
  }),