@opengeni/api-router 0.30.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/dist/access-grant-rls.d.ts +3 -0
  2. package/dist/admission-trace.d.ts +8 -0
  3. package/dist/api-websocket.d.ts +18 -0
  4. package/dist/app.d.ts +50 -2
  5. package/dist/app.js +12 -1
  6. package/dist/artifact-catalog-cursor.d.ts +27 -0
  7. package/dist/auth/managed-auth-attempt-context.d.ts +10 -0
  8. package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
  9. package/dist/auth/managed-auth-session-adapter.d.ts +6 -0
  10. package/dist/auth/managed-auth.d.ts +102 -3
  11. package/dist/auth/managed-email.d.ts +29 -0
  12. package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
  13. package/dist/auth/new-signups-gate.d.ts +23 -0
  14. package/dist/auth/organization-user-setup.d.ts +80 -0
  15. package/dist/auth/signup-funnel-metrics.d.ts +44 -0
  16. package/dist/browser-controller-authority.d.ts +1 -61
  17. package/dist/browser-ephemeral.d.ts +5 -0
  18. package/dist/browser-state-authority.d.ts +1 -27
  19. package/dist/chunk-6TZ5LG3O.js +123948 -0
  20. package/dist/chunk-6TZ5LG3O.js.map +1 -0
  21. package/dist/chunk-OGQDXVXY.js +18 -0
  22. package/dist/chunk-OGQDXVXY.js.map +1 -0
  23. package/dist/claude-subscription-account-conflicts.d.ts +1 -0
  24. package/dist/claude-subscription-account-usage.d.ts +39 -0
  25. package/dist/claude-subscription-oauth.d.ts +25 -0
  26. package/dist/claude-subscription-profile.d.ts +9 -0
  27. package/dist/claude-subscription-usage.d.ts +44 -0
  28. package/dist/claude-workspace-connection.d.ts +15 -0
  29. package/dist/codemode.d.ts +32 -1
  30. package/dist/company-brain-okf.d.ts +24 -0
  31. package/dist/connected-machine-computer-access.d.ts +11 -0
  32. package/dist/connection-ownership.d.ts +54 -0
  33. package/dist/controller-data-plane.d.ts +32 -0
  34. package/dist/editable-artifact-source-session.d.ts +3 -0
  35. package/dist/editable-artifact-websocket.d.ts +10 -18
  36. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  37. package/dist/fatal-process-boundary.d.ts +25 -0
  38. package/dist/github-access.d.ts +31 -2
  39. package/dist/http/acting-person.d.ts +24 -0
  40. package/dist/http/api-contract-compat.d.ts +19 -0
  41. package/dist/http/api-error.d.ts +27 -1
  42. package/dist/http/cors.d.ts +17 -0
  43. package/dist/http/deprecation.d.ts +42 -0
  44. package/dist/http/interaction-control-error.d.ts +13 -0
  45. package/dist/http/keyed-admission.d.ts +12 -0
  46. package/dist/http/local-browser-boundary.d.ts +72 -0
  47. package/dist/http/metrics-listener.d.ts +22 -0
  48. package/dist/http/path-identifier.d.ts +17 -0
  49. package/dist/http/registered-route-label.d.ts +16 -0
  50. package/dist/http/request-body.d.ts +27 -0
  51. package/dist/http/request-source.d.ts +52 -0
  52. package/dist/http/sse.d.ts +17 -6
  53. package/dist/http/unmatched-route.d.ts +18 -0
  54. package/dist/http/user-content.d.ts +36 -0
  55. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  56. package/dist/index.d.ts +10 -3
  57. package/dist/index.js +1091 -162
  58. package/dist/index.js.map +1 -1
  59. package/dist/integration-endpoint-test.d.ts +20 -0
  60. package/dist/integrations/api-integrations.d.ts +2 -2
  61. package/dist/integrations/atlassian.d.ts +29 -3
  62. package/dist/integrations/connect-authority.d.ts +1 -0
  63. package/dist/integrations/connect-callback-return.d.ts +6 -0
  64. package/dist/integrations/fiken.d.ts +16 -2
  65. package/dist/integrations/github-app-connect.d.ts +47 -0
  66. package/dist/integrations/github-installation-proof.d.ts +3 -0
  67. package/dist/integrations/github-lens-connect.d.ts +116 -0
  68. package/dist/integrations/github-skill-source.d.ts +1 -5
  69. package/dist/integrations/google-drive.d.ts +24 -0
  70. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  71. package/dist/integrations/marketplace-plugin.d.ts +2691 -0
  72. package/dist/integrations/oauth-client.d.ts +178 -18
  73. package/dist/integrations/oauth-profiles.d.ts +222 -0
  74. package/dist/integrations/oauth-return-path.d.ts +1 -0
  75. package/dist/integrations/personal-github-repositories.d.ts +84 -0
  76. package/dist/integrations/personal-github.d.ts +42 -0
  77. package/dist/integrations/pr-review-provider.d.ts +22 -0
  78. package/dist/integrations/provider-oauth.d.ts +19 -1
  79. package/dist/integrations/slack-app-home.d.ts +24 -0
  80. package/dist/integrations/slack-bot.d.ts +367 -12
  81. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  82. package/dist/integrations/slack-install.d.ts +20 -0
  83. package/dist/integrations/slack-interactions.d.ts +107 -9
  84. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  85. package/dist/integrations/slack-routing.d.ts +120 -0
  86. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  87. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  88. package/dist/integrations/social-oauth.d.ts +7 -0
  89. package/dist/interaction-agent-access.d.ts +15 -0
  90. package/dist/interaction-frame-proxy.d.ts +68 -0
  91. package/dist/interaction-metrics.d.ts +2 -0
  92. package/dist/mcp/action-catalog-types.d.ts +9 -0
  93. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  94. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  95. package/dist/mcp/child-read-evidence.d.ts +9 -0
  96. package/dist/mcp/command-read.d.ts +24 -0
  97. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  98. package/dist/mcp/contract-input.d.ts +11 -0
  99. package/dist/mcp/documents.d.ts +7 -5
  100. package/dist/mcp/files.d.ts +2 -2
  101. package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
  102. package/dist/mcp/knowledge-entries.d.ts +5 -0
  103. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  104. package/dist/mcp/receipts.d.ts +9 -0
  105. package/dist/mcp/request-abort.d.ts +19 -0
  106. package/dist/mcp/scheduled-task-input.d.ts +1189 -0
  107. package/dist/mcp/scheduled-task-view.d.ts +22 -4
  108. package/dist/mcp/server.d.ts +255 -3
  109. package/dist/mcp/session-event-view.d.ts +94 -0
  110. package/dist/mcp/session-view.d.ts +66 -2
  111. package/dist/mcp/session-wait.d.ts +174 -0
  112. package/dist/mcp-oauth.d.ts +52 -0
  113. package/dist/model-catalog.d.ts +11 -31
  114. package/dist/observability.d.ts +3 -1
  115. package/dist/organization-mcp.d.ts +52 -0
  116. package/dist/organization-recovery-notifications.d.ts +41 -0
  117. package/dist/routes/analytics-consent.d.ts +26 -0
  118. package/dist/routes/api-integrations.d.ts +25 -0
  119. package/dist/routes/api-keys.d.ts +17 -0
  120. package/dist/routes/artifact-catalog.d.ts +6 -0
  121. package/dist/routes/automations.d.ts +19 -0
  122. package/dist/routes/billing.d.ts +49 -0
  123. package/dist/routes/browser-sessions.d.ts +59 -2
  124. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  125. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  126. package/dist/routes/client-errors.d.ts +146 -0
  127. package/dist/routes/codex.d.ts +76 -2
  128. package/dist/routes/company-brain.d.ts +3 -0
  129. package/dist/routes/company-profile.d.ts +2 -1
  130. package/dist/routes/computer-sessions.d.ts +14 -0
  131. package/dist/routes/connect.d.ts +5 -0
  132. package/dist/routes/editable-artifacts.d.ts +2 -0
  133. package/dist/routes/external-identity-links.d.ts +6 -0
  134. package/dist/routes/feedback.d.ts +3 -0
  135. package/dist/routes/github-browser-pages.d.ts +12 -0
  136. package/dist/routes/github.d.ts +2 -0
  137. package/dist/routes/insights-response-cache.d.ts +10 -0
  138. package/dist/routes/insights-usage.d.ts +12 -0
  139. package/dist/routes/insights.d.ts +30 -1
  140. package/dist/routes/knowledge.d.ts +3 -0
  141. package/dist/routes/managed-auth-session-sets.d.ts +26 -0
  142. package/dist/routes/managed-onboarding.d.ts +29 -0
  143. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  144. package/dist/routes/model-connection-access.d.ts +3 -0
  145. package/dist/routes/organization-integration-policy.d.ts +3 -0
  146. package/dist/routes/organization-integrations.d.ts +6 -0
  147. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  148. package/dist/routes/organization-model-providers.d.ts +3 -0
  149. package/dist/routes/organization-recovery.d.ts +19 -0
  150. package/dist/routes/organization-service-accounts.d.ts +3 -0
  151. package/dist/routes/organization-sessions.d.ts +26 -0
  152. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  153. package/dist/routes/personal-github.d.ts +3 -0
  154. package/dist/routes/pr-review-github.d.ts +3 -0
  155. package/dist/routes/pr-review.d.ts +3 -0
  156. package/dist/routes/session-artifact-associations.d.ts +4 -0
  157. package/dist/routes/session-history-imports.d.ts +9 -0
  158. package/dist/routes/sessions.d.ts +44 -6
  159. package/dist/routes/skill-content.d.ts +4 -0
  160. package/dist/routes/skill-install-authority.d.ts +6 -0
  161. package/dist/routes/subscription-account-pools.d.ts +34 -0
  162. package/dist/routes/subscription-pool-access.d.ts +16 -0
  163. package/dist/routes/supergrok.d.ts +6 -1
  164. package/dist/routes/usage-allowances.d.ts +12 -0
  165. package/dist/routes/user-resource-authorities.d.ts +3 -0
  166. package/dist/routes/workspace-artifacts.d.ts +2 -1
  167. package/dist/routes/workspace-capture.d.ts +10 -2
  168. package/dist/routes/workspace-integrations.d.ts +35 -0
  169. package/dist/routes/workspace-learning.d.ts +3 -0
  170. package/dist/routes/workspace-model-providers.d.ts +4 -0
  171. package/dist/routes/workspaces.d.ts +29 -0
  172. package/dist/sandbox/auth-callout.d.ts +8 -0
  173. package/dist/sandbox/channel-a.d.ts +19 -1
  174. package/dist/sandbox/connection-authority.d.ts +3 -0
  175. package/dist/sandbox/enrollment.d.ts +9 -1
  176. package/dist/sandbox/machines.d.ts +5 -2
  177. package/dist/sandbox/metrics-ingestion.d.ts +28 -20
  178. package/dist/sandbox/rematerialize.d.ts +2 -0
  179. package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
  180. package/dist/sandbox/viewer.d.ts +26 -1
  181. package/dist/sandbox-file-artifacts.d.ts +50 -0
  182. package/dist/scheduled-task-deletion.d.ts +13 -0
  183. package/dist/session-create-observability.d.ts +5 -0
  184. package/dist/session-event-view-MPS2OZD3.js +292 -0
  185. package/dist/session-event-view-MPS2OZD3.js.map +1 -0
  186. package/dist/site-session-origin.d.ts +13 -0
  187. package/dist/site-uploads.d.ts +41 -0
  188. package/dist/slack-reaction-files.d.ts +1 -1
  189. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  190. package/dist/temporal-schedule-sync.d.ts +26 -0
  191. package/dist/transcription/providers/xai-subscription.d.ts +1 -0
  192. package/dist/transcription/service.d.ts +2 -1
  193. package/dist/work-discovery-observability.d.ts +33 -0
  194. package/dist/workspace-artifact-content.d.ts +28 -0
  195. package/dist/workspace-artifact-provenance.d.ts +7 -0
  196. package/dist/workspace-delete-observability.d.ts +10 -0
  197. package/dist/workspace-deletion.d.ts +6 -0
  198. package/dist/workspace-state-projection.d.ts +3 -5
  199. package/dist/workspace-tool-gateway-observability.d.ts +17 -0
  200. package/dist/workspace-tool-gateway.d.ts +123 -0
  201. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  202. package/package.json +23 -19
  203. package/src/access-grant-rls.ts +75 -0
  204. package/src/admission-trace.ts +14 -0
  205. package/src/api-websocket.ts +23 -0
  206. package/src/app.ts +1967 -252
  207. package/src/artifact-catalog-cursor.ts +60 -0
  208. package/src/auth/managed-auth-attempt-context.ts +70 -0
  209. package/src/auth/managed-auth-rate-limits.ts +252 -0
  210. package/src/auth/managed-auth-session-adapter.ts +222 -0
  211. package/src/auth/managed-auth.ts +536 -60
  212. package/src/auth/managed-email.ts +174 -0
  213. package/src/auth/managed-sign-in-notifications.ts +81 -0
  214. package/src/auth/new-signups-gate.ts +49 -0
  215. package/src/auth/organization-user-setup.ts +307 -0
  216. package/src/auth/signup-funnel-metrics.ts +164 -0
  217. package/src/browser-controller-authority.ts +1 -186
  218. package/src/browser-ephemeral.ts +39 -0
  219. package/src/browser-state-authority.ts +1 -236
  220. package/src/claude-subscription-account-conflicts.ts +12 -0
  221. package/src/claude-subscription-account-usage.ts +48 -0
  222. package/src/claude-subscription-oauth.ts +362 -0
  223. package/src/claude-subscription-profile.ts +73 -0
  224. package/src/claude-subscription-usage.ts +97 -0
  225. package/src/claude-workspace-connection.ts +82 -0
  226. package/src/codemode.ts +194 -30
  227. package/src/codex-realtime.ts +8 -2
  228. package/src/company-brain-okf.ts +340 -0
  229. package/src/connected-machine-computer-access.ts +33 -0
  230. package/src/connection-ownership.ts +199 -0
  231. package/src/controller-data-plane.ts +81 -0
  232. package/src/editable-artifact-native-kernel.ts +26 -15
  233. package/src/editable-artifact-office-import.ts +28 -3
  234. package/src/editable-artifact-production.ts +23 -7
  235. package/src/editable-artifact-source-session.ts +123 -0
  236. package/src/editable-artifact-websocket.ts +27 -21
  237. package/src/editable-artifact-workspace-files.ts +31 -6
  238. package/src/fatal-process-boundary.ts +246 -0
  239. package/src/gateway-realtime.ts +1 -1
  240. package/src/github-access.ts +147 -5
  241. package/src/http/acting-person.ts +71 -0
  242. package/src/http/api-contract-compat.ts +49 -0
  243. package/src/http/api-error.ts +115 -1
  244. package/src/http/auth.ts +48 -0
  245. package/src/http/cors.ts +67 -0
  246. package/src/http/deprecation.ts +118 -0
  247. package/src/http/interaction-control-error.ts +164 -0
  248. package/src/http/keyed-admission.ts +29 -0
  249. package/src/http/local-browser-boundary.ts +343 -0
  250. package/src/http/metrics-listener.ts +57 -0
  251. package/src/http/path-identifier.ts +54 -0
  252. package/src/http/registered-route-label.ts +34 -0
  253. package/src/http/request-body.ts +127 -0
  254. package/src/http/request-source.ts +178 -0
  255. package/src/http/sse.ts +486 -132
  256. package/src/http/unmatched-route.ts +60 -0
  257. package/src/http/user-content.ts +158 -0
  258. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  259. package/src/index.ts +157 -52
  260. package/src/integration-endpoint-test.ts +291 -0
  261. package/src/integrations/api-integrations.ts +98 -11
  262. package/src/integrations/atlassian.ts +474 -136
  263. package/src/integrations/connect-authority.ts +2 -0
  264. package/src/integrations/connect-callback-return.ts +86 -0
  265. package/src/integrations/fiken.ts +354 -64
  266. package/src/integrations/github-app-connect.ts +435 -0
  267. package/src/integrations/github-installation-proof.ts +60 -0
  268. package/src/integrations/github-lens-connect.ts +76 -0
  269. package/src/integrations/github-skill-source.ts +2 -142
  270. package/src/integrations/google-drive.ts +717 -225
  271. package/src/integrations/integration-commit-authority.ts +69 -0
  272. package/src/integrations/marketplace-plugin.ts +48 -0
  273. package/src/integrations/oauth-client.ts +1356 -459
  274. package/src/integrations/oauth-profiles.ts +537 -0
  275. package/src/integrations/oauth-return-path.ts +18 -0
  276. package/src/integrations/personal-github-repositories.ts +674 -0
  277. package/src/integrations/personal-github.ts +825 -0
  278. package/src/integrations/pr-review-provider.ts +246 -0
  279. package/src/integrations/provider-oauth.ts +250 -22
  280. package/src/integrations/slack-app-home.ts +300 -0
  281. package/src/integrations/slack-bot.ts +963 -239
  282. package/src/integrations/slack-file-upload-flow.ts +147 -0
  283. package/src/integrations/slack-install.ts +83 -0
  284. package/src/integrations/slack-interactions.ts +3167 -474
  285. package/src/integrations/slack-mrkdwn.ts +193 -0
  286. package/src/integrations/slack-routing.ts +337 -0
  287. package/src/integrations/slack-session-defaults.ts +224 -0
  288. package/src/integrations/slack-task-file-upload.ts +323 -0
  289. package/src/integrations/social-oauth.ts +213 -15
  290. package/src/interaction-agent-access.ts +48 -0
  291. package/src/interaction-frame-proxy.ts +409 -0
  292. package/src/interaction-metrics.ts +30 -0
  293. package/src/mcp/action-catalog-types.ts +9 -0
  294. package/src/mcp/action-catalog.gen.ts +6696 -0
  295. package/src/mcp/capability-account-readiness.ts +17 -0
  296. package/src/mcp/child-read-evidence.ts +19 -0
  297. package/src/mcp/command-read.ts +109 -0
  298. package/src/mcp/company-profile-agent-admin.ts +198 -0
  299. package/src/mcp/contract-input.ts +141 -0
  300. package/src/mcp/documents.ts +65 -377
  301. package/src/mcp/editable-artifacts.ts +12 -6
  302. package/src/mcp/files.ts +80 -43
  303. package/src/mcp/first-party-tool-permissions.ts +305 -0
  304. package/src/mcp/knowledge-entries.ts +322 -0
  305. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  306. package/src/mcp/receipts.ts +34 -0
  307. package/src/mcp/request-abort.ts +44 -0
  308. package/src/mcp/scheduled-task-input.ts +76 -0
  309. package/src/mcp/scheduled-task-view.ts +44 -3
  310. package/src/mcp/server.ts +3030 -1267
  311. package/src/mcp/session-event-view.ts +383 -0
  312. package/src/mcp/session-view.ts +84 -3
  313. package/src/mcp/session-wait.ts +665 -0
  314. package/src/mcp-oauth.ts +1123 -0
  315. package/src/model-catalog.ts +91 -333
  316. package/src/observability.ts +15 -1
  317. package/src/organization-mcp.ts +397 -0
  318. package/src/organization-recovery-notifications.ts +103 -0
  319. package/src/routes/analytics-consent.ts +123 -0
  320. package/src/routes/api-integrations.ts +364 -74
  321. package/src/routes/api-keys.ts +336 -10
  322. package/src/routes/artifact-catalog.ts +279 -0
  323. package/src/routes/automations.ts +768 -0
  324. package/src/routes/billing.ts +461 -46
  325. package/src/routes/browser-sessions.ts +780 -112
  326. package/src/routes/canonical-human-identities.ts +90 -14
  327. package/src/routes/capabilities.ts +107 -6
  328. package/src/routes/channels.ts +20 -3
  329. package/src/routes/claude-subscription-accounts.ts +334 -0
  330. package/src/routes/claude-subscription-oauth.ts +142 -0
  331. package/src/routes/client-errors.ts +362 -0
  332. package/src/routes/codex.ts +833 -116
  333. package/src/routes/company-brain.ts +322 -0
  334. package/src/routes/company-profile.ts +65 -1
  335. package/src/routes/computer-sessions.ts +557 -106
  336. package/src/routes/connect.ts +1938 -0
  337. package/src/routes/connections.ts +1039 -349
  338. package/src/routes/documents.ts +488 -287
  339. package/src/routes/editable-artifacts.ts +79 -9
  340. package/src/routes/enrollments.ts +135 -39
  341. package/src/routes/environments.ts +154 -58
  342. package/src/routes/external-identity-links.ts +201 -0
  343. package/src/routes/feedback.ts +113 -0
  344. package/src/routes/files.ts +267 -33
  345. package/src/routes/github-browser-pages.ts +162 -0
  346. package/src/routes/github.ts +446 -144
  347. package/src/routes/insights-response-cache.ts +83 -0
  348. package/src/routes/insights-usage.ts +345 -0
  349. package/src/routes/insights.ts +153 -19
  350. package/src/routes/install.ts +133 -38
  351. package/src/routes/integration-facets.ts +107 -33
  352. package/src/routes/interaction-resources.ts +30 -3
  353. package/src/routes/knowledge.ts +488 -0
  354. package/src/routes/machines.ts +313 -15
  355. package/src/routes/managed-auth-session-sets.ts +1218 -0
  356. package/src/routes/managed-onboarding.ts +337 -0
  357. package/src/routes/managed-sign-in-methods.ts +433 -0
  358. package/src/routes/memory-slack-publications.ts +3 -2
  359. package/src/routes/model-connection-access.ts +208 -0
  360. package/src/routes/organization-integration-policy.ts +116 -0
  361. package/src/routes/organization-integrations.ts +326 -0
  362. package/src/routes/organization-mcp-connections.ts +178 -0
  363. package/src/routes/organization-memberships.ts +1019 -27
  364. package/src/routes/organization-model-providers.ts +293 -0
  365. package/src/routes/organization-recovery.ts +325 -0
  366. package/src/routes/organization-service-accounts.ts +128 -0
  367. package/src/routes/organization-sessions.ts +350 -0
  368. package/src/routes/personal-github-git-broker.ts +785 -0
  369. package/src/routes/personal-github.ts +370 -0
  370. package/src/routes/plugins.ts +251 -22
  371. package/src/routes/pr-review-github.ts +881 -0
  372. package/src/routes/pr-review.ts +622 -0
  373. package/src/routes/preference-registry.ts +12 -93
  374. package/src/routes/rigs.ts +167 -50
  375. package/src/routes/scheduled-tasks.ts +346 -41
  376. package/src/routes/session-artifact-associations.ts +87 -0
  377. package/src/routes/session-history-imports.ts +280 -0
  378. package/src/routes/sessions.ts +2306 -264
  379. package/src/routes/skill-content.ts +297 -0
  380. package/src/routes/skill-install-authority.ts +64 -0
  381. package/src/routes/skills.ts +62 -9
  382. package/src/routes/social.ts +46 -18
  383. package/src/routes/subscription-account-pools.ts +436 -0
  384. package/src/routes/subscription-pool-access.ts +126 -0
  385. package/src/routes/supergrok.ts +219 -303
  386. package/src/routes/transcription-recordings.ts +38 -3
  387. package/src/routes/transcriptions.ts +4 -0
  388. package/src/routes/usage-allowances.ts +378 -0
  389. package/src/routes/user-resource-authorities.ts +138 -0
  390. package/src/routes/video-generation.ts +14 -10
  391. package/src/routes/workspace-artifacts.ts +275 -69
  392. package/src/routes/workspace-capture.ts +21 -0
  393. package/src/routes/workspace-integrations.ts +576 -0
  394. package/src/routes/workspace-learning.ts +159 -0
  395. package/src/routes/workspace-model-providers.ts +148 -0
  396. package/src/routes/workspace-state.ts +38 -25
  397. package/src/routes/workspaces.ts +1004 -127
  398. package/src/sandbox/auth-callout.ts +96 -19
  399. package/src/sandbox/channel-a.ts +323 -24
  400. package/src/sandbox/connection-authority.ts +3 -0
  401. package/src/sandbox/enrollment.ts +81 -6
  402. package/src/sandbox/machines.ts +218 -76
  403. package/src/sandbox/metrics-ingestion.ts +411 -62
  404. package/src/sandbox/rematerialize.ts +121 -19
  405. package/src/sandbox/session-attach-variable-sets.ts +131 -0
  406. package/src/sandbox/viewer.ts +280 -25
  407. package/src/sandbox-file-artifacts.ts +413 -0
  408. package/src/scheduled-task-deletion.ts +138 -0
  409. package/src/session-create-observability.ts +46 -0
  410. package/src/session-realtime-context.ts +6 -3
  411. package/src/site-session-origin.ts +48 -0
  412. package/src/site-uploads.ts +224 -0
  413. package/src/slack-reaction-files.ts +16 -5
  414. package/src/temporal-schedule-cleanup.ts +13 -0
  415. package/src/temporal-schedule-sync.ts +74 -0
  416. package/src/transcription/providers/codex-subscription.ts +2 -0
  417. package/src/transcription/providers/openai.ts +1 -0
  418. package/src/transcription/providers/xai-subscription.ts +49 -3
  419. package/src/transcription/segmenter.ts +8 -2
  420. package/src/transcription/service.ts +43 -6
  421. package/src/work-discovery-observability.ts +121 -0
  422. package/src/workspace-artifact-content.ts +144 -0
  423. package/src/workspace-artifact-provenance.ts +104 -0
  424. package/src/workspace-delete-observability.ts +75 -0
  425. package/src/workspace-deletion.ts +73 -0
  426. package/src/workspace-state-projection.ts +18 -148
  427. package/src/workspace-tool-gateway-observability.ts +100 -0
  428. package/src/workspace-tool-gateway.ts +870 -0
  429. package/src/workspace-webhook-dispatch.ts +190 -0
  430. package/src/xai-subscription-auth.ts +9 -2
  431. package/dist/chunk-WCXHI3FF.js +0 -49920
  432. package/dist/chunk-WCXHI3FF.js.map +0 -1
  433. package/dist/routes/packs.d.ts +0 -3
  434. package/src/routes/packs.ts +0 -729
@@ -0,0 +1,674 @@
1
+ import {
2
+ PERSONAL_GITHUB_API_ORIGIN,
3
+ PERSONAL_GITHUB_PROVIDER_DOMAIN,
4
+ PERSONAL_GITHUB_REPOSITORY_CATALOG_MAX,
5
+ PersonalGitHubRepository,
6
+ canonicalPersonalGitHubRepositoryUrl,
7
+ isPersonalGitHubConnection,
8
+ type PersonalGitHubRepository as PersonalGitHubRepositoryContract,
9
+ type PersonalGitHubRepositorySelectionInput,
10
+ } from "@opengeni/contracts/personal-github";
11
+ import {
12
+ GitHubRepositoryBranchesResponse,
13
+ type GitHubRepositoryBranchesResponse as GitHubRepositoryBranchesResponseContract,
14
+ type ListGitHubRepositoryBranchesQuery,
15
+ } from "@opengeni/contracts/github-repository-contracts";
16
+ import type { ApiRouteDeps } from "@opengeni/core";
17
+ import {
18
+ buildConnectionTokenResolver,
19
+ getConnectionMetadata,
20
+ getPersonalGitHubRepositorySelectionState,
21
+ type PersonalGitHubRepositorySelectionState as DbPersonalGitHubRepositorySelectionState,
22
+ } from "@opengeni/db";
23
+ import { readResponseTextBounded } from "@opengeni/network";
24
+ import { HTTPException } from "hono/http-exception";
25
+ import JSONBig from "json-bigint";
26
+
27
+ const GITHUB_API_VERSION = "2022-11-28";
28
+ const GITHUB_REQUEST_TIMEOUT_MS = 10_000;
29
+ const GITHUB_REPOSITORIES_RESPONSE_MAX_BYTES = 1024 * 1024;
30
+ const GITHUB_BRANCHES_RESPONSE_MAX_BYTES = 256 * 1024;
31
+ const personalGitHubProviderJsonParser = JSONBig({
32
+ storeAsString: true,
33
+ protoAction: "error",
34
+ constructorAction: "error",
35
+ });
36
+
37
+ export type PersonalGitHubRepositoryConnection = NonNullable<
38
+ Awaited<ReturnType<typeof getConnectionMetadata>>
39
+ >;
40
+
41
+ type PersonalGitHubRepositoryProviderOperation =
42
+ | "repositories_list"
43
+ | "repository_branches_list"
44
+ | "repository_verify";
45
+
46
+ type ExpectedPersonalGitHubRepositoryAuthority = {
47
+ selectionGeneration: number;
48
+ repositoryId: string;
49
+ fullName: string;
50
+ };
51
+
52
+ type PersonalGitHubProviderJsonOptions = {
53
+ operation: PersonalGitHubRepositoryProviderOperation;
54
+ expectedRepositoryAuthority?: ExpectedPersonalGitHubRepositoryAuthority;
55
+ responseLabel?: string;
56
+ responseMaxBytes?: number;
57
+ };
58
+
59
+ export type PersonalGitHubRepositoryBranchServices = {
60
+ requireConnection: typeof requirePersonalGitHubRepositoryConnection;
61
+ getSelectionState: (
62
+ deps: ApiRouteDeps,
63
+ input: {
64
+ accountId: string;
65
+ originWorkspaceId: string;
66
+ subjectId: string;
67
+ connectionId: string;
68
+ },
69
+ ) => Promise<DbPersonalGitHubRepositorySelectionState | null>;
70
+ providerJson: (input: {
71
+ deps: ApiRouteDeps;
72
+ connection: PersonalGitHubRepositoryConnection;
73
+ subjectId: string;
74
+ url: URL;
75
+ expectedConnectionAuthorityGeneration: number;
76
+ options: PersonalGitHubProviderJsonOptions;
77
+ }) => Promise<unknown>;
78
+ };
79
+
80
+ const personalGitHubRepositoryBranchServices: PersonalGitHubRepositoryBranchServices = {
81
+ requireConnection: requirePersonalGitHubRepositoryConnection,
82
+ getSelectionState: async (deps, input) =>
83
+ await getPersonalGitHubRepositorySelectionState(deps.db, input),
84
+ providerJson: async (input) =>
85
+ await personalGitHubProviderJson(
86
+ input.deps,
87
+ input.connection,
88
+ input.subjectId,
89
+ input.url,
90
+ input.expectedConnectionAuthorityGeneration,
91
+ input.options,
92
+ ),
93
+ };
94
+
95
+ export type PersonalGitHubRepositoryProviderErrorCode =
96
+ | "connection_changed"
97
+ | "connection_inactive"
98
+ | "invalid_provider_response"
99
+ | "provider_denied"
100
+ | "provider_rate_limited"
101
+ | "provider_unavailable"
102
+ | "repository_archived"
103
+ | "repository_not_found"
104
+ | "repository_not_selected"
105
+ | "repository_read_denied"
106
+ | "repository_selection_changed"
107
+ | "repository_write_denied";
108
+
109
+ export class PersonalGitHubRepositoryProviderError extends Error {
110
+ constructor(readonly code: PersonalGitHubRepositoryProviderErrorCode) {
111
+ super(code);
112
+ this.name = "PersonalGitHubRepositoryProviderError";
113
+ }
114
+ }
115
+
116
+ export async function requirePersonalGitHubRepositoryConnection(
117
+ deps: ApiRouteDeps,
118
+ input: { accountId: string; workspaceId: string; subjectId: string; connectionId: string },
119
+ ): Promise<PersonalGitHubRepositoryConnection> {
120
+ if (!deps.settings.githubPersonalOauthEnabled) {
121
+ throw new HTTPException(404, {
122
+ message: "personal GitHub repository discovery is not enabled",
123
+ });
124
+ }
125
+ const connection = await getConnectionMetadata(
126
+ deps.db,
127
+ input.workspaceId,
128
+ input.connectionId,
129
+ input.subjectId,
130
+ );
131
+ if (
132
+ !connection ||
133
+ connection.accountId !== input.accountId ||
134
+ connection.subjectId !== input.subjectId ||
135
+ !isPersonalGitHubConnection(connection)
136
+ ) {
137
+ throw new HTTPException(404, { message: "personal GitHub connection not found" });
138
+ }
139
+ if (connection.status !== "active") {
140
+ throw new HTTPException(409, { message: "personal GitHub connection must be reconnected" });
141
+ }
142
+ return connection;
143
+ }
144
+
145
+ export async function listLivePersonalGitHubRepositories(
146
+ deps: ApiRouteDeps,
147
+ input: {
148
+ workspaceId: string;
149
+ accountId: string;
150
+ subjectId: string;
151
+ connectionId: string;
152
+ expectedConnectionAuthorityGeneration: number;
153
+ page: number;
154
+ limit: number;
155
+ },
156
+ ): Promise<{ repositories: PersonalGitHubRepositoryContract[]; nextPage: number | null }> {
157
+ const connection = await requirePersonalGitHubRepositoryConnection(deps, input);
158
+ const url = new URL("/user/repos", PERSONAL_GITHUB_API_ORIGIN);
159
+ url.searchParams.set("affiliation", "owner,collaborator,organization_member");
160
+ url.searchParams.set("direction", "asc");
161
+ url.searchParams.set("page", String(input.page));
162
+ url.searchParams.set("per_page", String(input.limit));
163
+ url.searchParams.set("sort", "full_name");
164
+ const payload = await personalGitHubProviderJson(
165
+ deps,
166
+ connection,
167
+ input.subjectId,
168
+ url,
169
+ input.expectedConnectionAuthorityGeneration,
170
+ { operation: "repositories_list" },
171
+ );
172
+ if (!Array.isArray(payload) || payload.length > PERSONAL_GITHUB_REPOSITORY_CATALOG_MAX) {
173
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
174
+ }
175
+ const repositories: PersonalGitHubRepositoryContract[] = [];
176
+ const seen = new Set<string>();
177
+ for (const value of payload) {
178
+ const repository = parsePersonalGitHubRepository(value);
179
+ if (seen.has(repository.repositoryId)) {
180
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
181
+ }
182
+ seen.add(repository.repositoryId);
183
+ if (personalGitHubRepositoryCanRead(repository.permissions)) repositories.push(repository);
184
+ }
185
+ return {
186
+ repositories,
187
+ nextPage: payload.length === input.limit && input.page < 10_000 ? input.page + 1 : null,
188
+ };
189
+ }
190
+
191
+ export async function listLivePersonalGitHubRepositoryBranches(
192
+ deps: ApiRouteDeps,
193
+ input: {
194
+ workspaceId: string;
195
+ accountId: string;
196
+ subjectId: string;
197
+ connectionId: string;
198
+ repositoryId: string;
199
+ query: ListGitHubRepositoryBranchesQuery;
200
+ },
201
+ services: PersonalGitHubRepositoryBranchServices = personalGitHubRepositoryBranchServices,
202
+ ): Promise<GitHubRepositoryBranchesResponseContract> {
203
+ const connection = await services.requireConnection(deps, input);
204
+ const current = await requireSelectedPersonalGitHubRepository(
205
+ deps,
206
+ connection,
207
+ input,
208
+ null,
209
+ services.getSelectionState,
210
+ );
211
+ const [owner, repositoryName] = current.repository.fullName.split("/");
212
+ if (!owner || !repositoryName) {
213
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
214
+ }
215
+ const url = new URL(
216
+ `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repositoryName)}/branches`,
217
+ PERSONAL_GITHUB_API_ORIGIN,
218
+ );
219
+ url.searchParams.set("page", String(input.query.cursor));
220
+ url.searchParams.set("per_page", String(input.query.limit));
221
+ const expectedRepositoryAuthority = {
222
+ selectionGeneration: current.selectionGeneration,
223
+ repositoryId: current.repository.repositoryId,
224
+ fullName: current.repository.fullName,
225
+ };
226
+ const payload = await services.providerJson({
227
+ deps,
228
+ connection,
229
+ subjectId: input.subjectId,
230
+ url,
231
+ expectedConnectionAuthorityGeneration: current.connectionAuthorityGeneration,
232
+ options: {
233
+ operation: "repository_branches_list",
234
+ expectedRepositoryAuthority,
235
+ responseLabel: "GitHub repository branches response",
236
+ responseMaxBytes: GITHUB_BRANCHES_RESPONSE_MAX_BYTES,
237
+ },
238
+ });
239
+ if (!Array.isArray(payload) || payload.length > input.query.limit) {
240
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
241
+ }
242
+ const branches: string[] = [];
243
+ const seen = new Set<string>();
244
+ for (const value of payload) {
245
+ const name =
246
+ value && typeof value === "object" && !Array.isArray(value)
247
+ ? (value as Record<string, unknown>).name
248
+ : null;
249
+ if (typeof name !== "string" || name.length === 0 || name.length > 1024 || seen.has(name)) {
250
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
251
+ }
252
+ seen.add(name);
253
+ branches.push(name);
254
+ }
255
+ await requireSelectedPersonalGitHubRepository(
256
+ deps,
257
+ connection,
258
+ input,
259
+ expectedRepositoryAuthority,
260
+ services.getSelectionState,
261
+ );
262
+ const response = GitHubRepositoryBranchesResponse.safeParse({
263
+ branches: branches.map((name) => ({
264
+ name,
265
+ isDefault: name === current.repository.defaultBranch,
266
+ })),
267
+ nextCursor:
268
+ branches.length === input.query.limit && input.query.cursor < 10_000
269
+ ? input.query.cursor + 1
270
+ : null,
271
+ });
272
+ if (!response.success) {
273
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
274
+ }
275
+ return response.data;
276
+ }
277
+
278
+ /** Serial by design: one bounded provider request and one authority check at a time. */
279
+ export async function verifyLivePersonalGitHubRepositories(
280
+ deps: ApiRouteDeps,
281
+ input: {
282
+ workspaceId: string;
283
+ accountId: string;
284
+ subjectId: string;
285
+ connectionId: string;
286
+ expectedConnectionAuthorityGeneration: number;
287
+ repositories: PersonalGitHubRepositorySelectionInput[];
288
+ },
289
+ ): Promise<Array<PersonalGitHubRepositoryContract & { selectedAccess: "read" | "write" }>> {
290
+ const connection = await requirePersonalGitHubRepositoryConnection(deps, input);
291
+ const verified: Array<PersonalGitHubRepositoryContract & { selectedAccess: "read" | "write" }> =
292
+ [];
293
+ for (const selection of input.repositories) {
294
+ const [owner, repositoryName] = selection.fullName.split("/");
295
+ if (!owner || !repositoryName) {
296
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
297
+ }
298
+ const url = new URL(
299
+ `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repositoryName)}`,
300
+ PERSONAL_GITHUB_API_ORIGIN,
301
+ );
302
+ const payload = await personalGitHubProviderJson(
303
+ deps,
304
+ connection,
305
+ input.subjectId,
306
+ url,
307
+ input.expectedConnectionAuthorityGeneration,
308
+ { operation: "repository_verify" },
309
+ );
310
+ const repository = parsePersonalGitHubRepository(payload);
311
+ if (
312
+ repository.repositoryId !== selection.repositoryId ||
313
+ repository.fullName.toLowerCase() !== selection.fullName.toLowerCase()
314
+ ) {
315
+ throw new PersonalGitHubRepositoryProviderError("repository_not_found");
316
+ }
317
+ if (!personalGitHubRepositoryCanRead(repository.permissions)) {
318
+ throw new PersonalGitHubRepositoryProviderError("repository_read_denied");
319
+ }
320
+ if (selection.access === "write") {
321
+ if (repository.archived || repository.disabled) {
322
+ throw new PersonalGitHubRepositoryProviderError("repository_archived");
323
+ }
324
+ if (!personalGitHubRepositoryCanWrite(repository.permissions)) {
325
+ throw new PersonalGitHubRepositoryProviderError("repository_write_denied");
326
+ }
327
+ }
328
+ verified.push({ ...repository, selectedAccess: selection.access });
329
+ }
330
+ return verified;
331
+ }
332
+
333
+ async function requireSelectedPersonalGitHubRepository(
334
+ deps: ApiRouteDeps,
335
+ connection: PersonalGitHubRepositoryConnection,
336
+ input: {
337
+ accountId: string;
338
+ subjectId: string;
339
+ connectionId: string;
340
+ repositoryId: string;
341
+ },
342
+ expected: ExpectedPersonalGitHubRepositoryAuthority | null,
343
+ getSelectionState: PersonalGitHubRepositoryBranchServices["getSelectionState"],
344
+ ): Promise<{
345
+ connectionAuthorityGeneration: number;
346
+ selectionGeneration: number;
347
+ repository: NonNullable<
348
+ Awaited<ReturnType<typeof getPersonalGitHubRepositorySelectionState>>
349
+ >["repositories"][number];
350
+ }> {
351
+ const selection = await getSelectionState(deps, {
352
+ accountId: input.accountId,
353
+ originWorkspaceId: connection.workspaceId,
354
+ subjectId: input.subjectId,
355
+ connectionId: input.connectionId,
356
+ });
357
+ if (!selection) {
358
+ throw new PersonalGitHubRepositoryProviderError(
359
+ expected ? "repository_selection_changed" : "repository_not_selected",
360
+ );
361
+ }
362
+ const repository = selection.repositories.find(
363
+ (candidate) => candidate.repositoryId === input.repositoryId,
364
+ );
365
+ if (!repository) {
366
+ throw new PersonalGitHubRepositoryProviderError(
367
+ expected ? "repository_selection_changed" : "repository_not_selected",
368
+ );
369
+ }
370
+ if (
371
+ expected &&
372
+ (selection.selectionGeneration !== expected.selectionGeneration ||
373
+ repository.repositoryId !== expected.repositoryId ||
374
+ repository.fullName !== expected.fullName)
375
+ ) {
376
+ throw new PersonalGitHubRepositoryProviderError("repository_selection_changed");
377
+ }
378
+ return {
379
+ connectionAuthorityGeneration: selection.connectionAuthorityGeneration,
380
+ selectionGeneration: selection.selectionGeneration,
381
+ repository,
382
+ };
383
+ }
384
+
385
+ export function personalGitHubRepositoryProviderHttpError(
386
+ error: PersonalGitHubRepositoryProviderError,
387
+ ): HTTPException {
388
+ switch (error.code) {
389
+ case "connection_changed":
390
+ return new HTTPException(409, {
391
+ message: "personal GitHub connection changed; refresh and try again",
392
+ });
393
+ case "connection_inactive":
394
+ case "provider_denied":
395
+ return new HTTPException(401, { message: "personal GitHub must be reconnected" });
396
+ case "provider_rate_limited":
397
+ return new HTTPException(503, { message: "GitHub is temporarily rate limited" });
398
+ case "repository_not_found":
399
+ return new HTTPException(422, { message: "a selected GitHub repository is unavailable" });
400
+ case "repository_not_selected":
401
+ return new HTTPException(404, {
402
+ message: "personal GitHub repository is not selected for this connection",
403
+ });
404
+ case "repository_selection_changed":
405
+ return new HTTPException(409, {
406
+ message: "personal GitHub repository selection changed; refresh and try again",
407
+ });
408
+ case "repository_archived":
409
+ return new HTTPException(422, {
410
+ message: "an archived or disabled GitHub repository cannot be selected for write access",
411
+ });
412
+ case "repository_read_denied":
413
+ return new HTTPException(422, {
414
+ message: "a selected GitHub repository is not readable",
415
+ });
416
+ case "repository_write_denied":
417
+ return new HTTPException(422, {
418
+ message: "a selected GitHub repository does not allow writes",
419
+ });
420
+ case "invalid_provider_response":
421
+ case "provider_unavailable":
422
+ return new HTTPException(502, { message: "GitHub repository discovery is unavailable" });
423
+ }
424
+ }
425
+
426
+ async function personalGitHubProviderJson(
427
+ deps: ApiRouteDeps,
428
+ connection: PersonalGitHubRepositoryConnection,
429
+ subjectId: string,
430
+ url: URL,
431
+ expectedConnectionAuthorityGeneration: number,
432
+ options: PersonalGitHubProviderJsonOptions,
433
+ ): Promise<unknown> {
434
+ if (url.origin !== PERSONAL_GITHUB_API_ORIGIN) {
435
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
436
+ }
437
+ let response = await personalGitHubProviderFetch(
438
+ deps,
439
+ connection,
440
+ subjectId,
441
+ url,
442
+ expectedConnectionAuthorityGeneration,
443
+ options.operation,
444
+ options.expectedRepositoryAuthority,
445
+ false,
446
+ );
447
+ if (response.status === 401) {
448
+ await cancelResponse(response);
449
+ response = await personalGitHubProviderFetch(
450
+ deps,
451
+ connection,
452
+ subjectId,
453
+ url,
454
+ expectedConnectionAuthorityGeneration,
455
+ options.operation,
456
+ options.expectedRepositoryAuthority,
457
+ true,
458
+ );
459
+ }
460
+ if (response.status >= 300 && response.status < 400) {
461
+ await cancelResponse(response);
462
+ throw new PersonalGitHubRepositoryProviderError("provider_unavailable");
463
+ }
464
+ if (!response.ok) {
465
+ const status = response.status;
466
+ const rateLimited =
467
+ status === 429 ||
468
+ (status === 403 &&
469
+ (response.headers.get("x-ratelimit-remaining") === "0" ||
470
+ response.headers.has("retry-after")));
471
+ await cancelResponse(response);
472
+ if (status === 401 || status === 403) {
473
+ throw new PersonalGitHubRepositoryProviderError(
474
+ rateLimited ? "provider_rate_limited" : "provider_denied",
475
+ );
476
+ }
477
+ if (status === 429) {
478
+ throw new PersonalGitHubRepositoryProviderError("provider_rate_limited");
479
+ }
480
+ if (status === 404 && options.operation !== "repositories_list") {
481
+ throw new PersonalGitHubRepositoryProviderError("repository_not_found");
482
+ }
483
+ throw new PersonalGitHubRepositoryProviderError("provider_unavailable");
484
+ }
485
+ try {
486
+ return parsePersonalGitHubProviderJson(
487
+ await readResponseTextBounded(
488
+ response,
489
+ options.responseMaxBytes ?? GITHUB_REPOSITORIES_RESPONSE_MAX_BYTES,
490
+ options.responseLabel ??
491
+ (options.operation === "repositories_list"
492
+ ? "GitHub repositories response"
493
+ : "GitHub repository response"),
494
+ ),
495
+ );
496
+ } catch {
497
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
498
+ }
499
+ }
500
+
501
+ /** Keep provider integer lexemes exact before repository IDs become bigint-backed strings. */
502
+ export function parsePersonalGitHubProviderJson(value: string): unknown {
503
+ return personalGitHubProviderJsonParser.parse(value) as unknown;
504
+ }
505
+
506
+ async function personalGitHubProviderFetch(
507
+ deps: ApiRouteDeps,
508
+ connection: PersonalGitHubRepositoryConnection,
509
+ subjectId: string,
510
+ url: URL,
511
+ expectedConnectionAuthorityGeneration: number,
512
+ operation: PersonalGitHubRepositoryProviderOperation,
513
+ expectedRepositoryAuthority: ExpectedPersonalGitHubRepositoryAuthority | undefined,
514
+ forceRefresh: boolean,
515
+ ): Promise<Response> {
516
+ const resolver = buildConnectionTokenResolver(deps.db, deps.settings, undefined, {
517
+ ...(deps.githubPersonalFetch
518
+ ? { refreshTransport: { fetchImpl: deps.githubPersonalFetch } }
519
+ : {}),
520
+ });
521
+ const credential = await resolver({
522
+ workspaceId: connection.workspaceId,
523
+ subjectId,
524
+ serverId: "github-personal-repository-picker",
525
+ toolName: operation,
526
+ connectionRef: {
527
+ connectionId: connection.id,
528
+ providerDomain: PERSONAL_GITHUB_PROVIDER_DOMAIN,
529
+ kind: "oauth2",
530
+ subjectScope: "subject",
531
+ scopes: ["repo"],
532
+ },
533
+ destinationUrl: url.toString(),
534
+ credentialTarget: "http_api",
535
+ forceRefresh,
536
+ });
537
+ if (credential.status !== "ok") {
538
+ throw new PersonalGitHubRepositoryProviderError("connection_inactive");
539
+ }
540
+ if (credential.connectionId !== connection.id || credential.connectionVersion === undefined) {
541
+ throw new PersonalGitHubRepositoryProviderError("connection_changed");
542
+ }
543
+ const current = await getConnectionMetadata(
544
+ deps.db,
545
+ connection.workspaceId,
546
+ connection.id,
547
+ subjectId,
548
+ );
549
+ if (
550
+ !current ||
551
+ current.version !== credential.connectionVersion ||
552
+ current.subjectId !== subjectId ||
553
+ current.status !== "active" ||
554
+ !isPersonalGitHubConnection(current)
555
+ ) {
556
+ throw new PersonalGitHubRepositoryProviderError("connection_changed");
557
+ }
558
+ const authority = await getPersonalGitHubRepositorySelectionState(deps.db, {
559
+ accountId: connection.accountId,
560
+ originWorkspaceId: connection.workspaceId,
561
+ subjectId,
562
+ connectionId: connection.id,
563
+ });
564
+ if (
565
+ !authority ||
566
+ authority.connectionAuthorityGeneration !== expectedConnectionAuthorityGeneration
567
+ ) {
568
+ throw new PersonalGitHubRepositoryProviderError("connection_changed");
569
+ }
570
+ if (expectedRepositoryAuthority) {
571
+ const repository = authority.repositories.find(
572
+ (candidate) => candidate.repositoryId === expectedRepositoryAuthority.repositoryId,
573
+ );
574
+ if (
575
+ authority.selectionGeneration !== expectedRepositoryAuthority.selectionGeneration ||
576
+ !repository ||
577
+ repository.fullName !== expectedRepositoryAuthority.fullName
578
+ ) {
579
+ throw new PersonalGitHubRepositoryProviderError("repository_selection_changed");
580
+ }
581
+ }
582
+ const authorization = Object.entries(credential.headers).find(
583
+ ([name]) => name.toLowerCase() === "authorization",
584
+ )?.[1];
585
+ if (!authorization) {
586
+ throw new PersonalGitHubRepositoryProviderError("connection_inactive");
587
+ }
588
+ try {
589
+ return await (deps.githubPersonalFetch ?? fetch)(url, {
590
+ method: "GET",
591
+ redirect: "manual",
592
+ headers: {
593
+ accept: "application/vnd.github+json",
594
+ authorization,
595
+ "user-agent": "OpenGeni",
596
+ "x-github-api-version": GITHUB_API_VERSION,
597
+ },
598
+ signal: AbortSignal.timeout(GITHUB_REQUEST_TIMEOUT_MS),
599
+ });
600
+ } catch {
601
+ throw new PersonalGitHubRepositoryProviderError("provider_unavailable");
602
+ }
603
+ }
604
+
605
+ export function personalGitHubRepositoryCanRead(
606
+ permissions: PersonalGitHubRepositoryContract["permissions"],
607
+ ): boolean {
608
+ return (
609
+ permissions.pull ||
610
+ permissions.triage ||
611
+ permissions.push ||
612
+ permissions.maintain ||
613
+ permissions.admin
614
+ );
615
+ }
616
+
617
+ export function personalGitHubRepositoryCanWrite(
618
+ permissions: PersonalGitHubRepositoryContract["permissions"],
619
+ ): boolean {
620
+ return permissions.push || permissions.maintain || permissions.admin;
621
+ }
622
+
623
+ export function parsePersonalGitHubRepository(value: unknown): PersonalGitHubRepositoryContract {
624
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
625
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
626
+ }
627
+ const payload = value as Record<string, unknown>;
628
+ const repositoryId = providerRepositoryId(payload.id);
629
+ const fullName = requiredProviderString(payload.full_name, 255);
630
+ const defaultBranch = requiredProviderString(payload.default_branch, 255);
631
+ const permissions = payload.permissions;
632
+ if (!permissions || typeof permissions !== "object" || Array.isArray(permissions)) {
633
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
634
+ }
635
+ const permissionRecord = permissions as Record<string, unknown>;
636
+ const parsed = PersonalGitHubRepository.safeParse({
637
+ repositoryId,
638
+ fullName,
639
+ canonicalUrl: canonicalPersonalGitHubRepositoryUrl(fullName),
640
+ defaultBranch,
641
+ visibility: payload.visibility,
642
+ private: payload.private,
643
+ archived: payload.archived,
644
+ disabled: payload.disabled,
645
+ permissions: {
646
+ pull: permissionRecord.pull,
647
+ push: permissionRecord.push,
648
+ admin: permissionRecord.admin,
649
+ maintain: permissionRecord.maintain,
650
+ triage: permissionRecord.triage,
651
+ },
652
+ });
653
+ if (!parsed.success) {
654
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
655
+ }
656
+ return parsed.data;
657
+ }
658
+
659
+ function providerRepositoryId(value: unknown): string {
660
+ if (typeof value === "number" && Number.isSafeInteger(value) && value > 0) return String(value);
661
+ if (typeof value === "string" && /^[1-9]\d*$/u.test(value)) return value;
662
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
663
+ }
664
+
665
+ function requiredProviderString(value: unknown, maxLength: number): string {
666
+ if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
667
+ throw new PersonalGitHubRepositoryProviderError("invalid_provider_response");
668
+ }
669
+ return value;
670
+ }
671
+
672
+ async function cancelResponse(response: Response): Promise<void> {
673
+ await response.body?.cancel().catch(() => undefined);
674
+ }