@opengeni/api-router 3.0.1 → 3.1.2

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 (546) hide show
  1. package/dist/access-grant-rls.d.ts +8 -1
  2. package/dist/admission-trace.d.ts +8 -0
  3. package/dist/app.d.ts +50 -3
  4. package/dist/app.js +10 -1
  5. package/dist/artifact-catalog-cursor.d.ts +1 -0
  6. package/dist/attached-browser-viewer.d.ts +11 -0
  7. package/dist/auth/managed-auth-attempt-context.d.ts +2 -0
  8. package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
  9. package/dist/auth/managed-auth-session-adapter.d.ts +9 -1
  10. package/dist/auth/managed-auth.d.ts +72 -5
  11. package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
  12. package/dist/auth/new-signups-gate.d.ts +23 -0
  13. package/dist/auth/signup-funnel-metrics.d.ts +44 -0
  14. package/dist/azure-live.d.ts +28 -0
  15. package/dist/browser-action-fences.d.ts +13 -0
  16. package/dist/browser-controller-authority.d.ts +1 -61
  17. package/dist/browser-ephemeral.d.ts +5 -0
  18. package/dist/browser-lost-runtime-end.d.ts +24 -0
  19. package/dist/browser-state-authority.d.ts +1 -27
  20. package/dist/chunk-OGQDXVXY.js +18 -0
  21. package/dist/chunk-OGQDXVXY.js.map +1 -0
  22. package/dist/{chunk-AJ62T5QN.js → chunk-OT56OY4V.js} +80503 -39869
  23. package/dist/chunk-OT56OY4V.js.map +1 -0
  24. package/dist/claude-default-models.d.ts +19 -0
  25. package/dist/claude-subscription-core.d.ts +50 -0
  26. package/dist/claude-subscription-oauth.d.ts +36 -0
  27. package/dist/claude-subscription-profile.d.ts +9 -0
  28. package/dist/claude-subscription-usage.d.ts +6 -0
  29. package/dist/claude-workspace-connection.d.ts +15 -0
  30. package/dist/codemode.d.ts +40 -5
  31. package/dist/codex-realtime.d.ts +29 -3
  32. package/dist/codex-session-pointers.d.ts +19 -0
  33. package/dist/connection-ownership.d.ts +6 -3
  34. package/dist/controller-data-plane.d.ts +16 -0
  35. package/dist/credit-promotion-snapshot.d.ts +6 -0
  36. package/dist/editable-artifact-source-session.d.ts +3 -0
  37. package/dist/editable-artifact-websocket.d.ts +5 -3
  38. package/dist/fatal-process-boundary.d.ts +9 -1
  39. package/dist/github-access.d.ts +7 -1
  40. package/dist/github-browser-flow.d.ts +1 -1
  41. package/dist/http/acting-person.d.ts +36 -0
  42. package/dist/http/api-contract-compat.d.ts +19 -0
  43. package/dist/http/api-error.d.ts +50 -1
  44. package/dist/http/auth.d.ts +8 -1
  45. package/dist/http/cors.d.ts +12 -0
  46. package/dist/http/deprecation.d.ts +42 -0
  47. package/dist/http/keyed-admission.d.ts +12 -0
  48. package/dist/http/local-browser-boundary.d.ts +72 -0
  49. package/dist/http/metrics-listener.d.ts +22 -0
  50. package/dist/http/path-identifier.d.ts +17 -0
  51. package/dist/http/registered-route-label.d.ts +16 -0
  52. package/dist/http/rejection-telemetry.d.ts +34 -0
  53. package/dist/http/request-body.d.ts +27 -0
  54. package/dist/http/request-source.d.ts +41 -3
  55. package/dist/http/sse.d.ts +12 -1
  56. package/dist/http/unmatched-route.d.ts +18 -0
  57. package/dist/http/user-content.d.ts +36 -0
  58. package/dist/http/variable-sets-removed.d.ts +41 -0
  59. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  60. package/dist/index.js +1279 -108
  61. package/dist/index.js.map +1 -1
  62. package/dist/integration-connect-metrics.d.ts +35 -0
  63. package/dist/integration-endpoint-test.d.ts +20 -0
  64. package/dist/integrations/api-integrations.d.ts +2 -2
  65. package/dist/integrations/atlassian.d.ts +8 -3
  66. package/dist/integrations/fiken.d.ts +3 -1
  67. package/dist/integrations/github-lens-connect.d.ts +37 -66
  68. package/dist/integrations/google-drive.d.ts +2 -0
  69. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  70. package/dist/integrations/marketplace-plugin.d.ts +43 -43
  71. package/dist/integrations/oauth-client.d.ts +171 -12
  72. package/dist/integrations/oauth-profiles.d.ts +42 -13
  73. package/dist/integrations/onepassword-vault-provider.d.ts +9 -0
  74. package/dist/integrations/slack-bot.d.ts +285 -7
  75. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  76. package/dist/integrations/slack-interactions.d.ts +89 -10
  77. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  78. package/dist/integrations/slack-routing.d.ts +1 -1
  79. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  80. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  81. package/dist/integrations/slack-tool-review.d.ts +5 -0
  82. package/dist/interaction-agent-access.d.ts +13 -8
  83. package/dist/interaction-agent-version.d.ts +21 -0
  84. package/dist/interaction-holder-heartbeat.d.ts +5 -0
  85. package/dist/interaction-metrics.d.ts +27 -2
  86. package/dist/interaction-route-stages.d.ts +25 -0
  87. package/dist/interaction-secrets-vault.d.ts +20 -0
  88. package/dist/interaction-secrets.d.ts +103 -0
  89. package/dist/mcp/action-catalog-types.d.ts +14 -0
  90. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  91. package/dist/mcp/action-descriptions.d.ts +4 -0
  92. package/dist/mcp/action-schema-imports.gen.d.ts +1 -0
  93. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  94. package/dist/mcp/child-read-evidence.d.ts +9 -0
  95. package/dist/mcp/company-profile-agent-admin.d.ts +12 -0
  96. package/dist/mcp/contract-input.d.ts +13 -0
  97. package/dist/mcp/documents.d.ts +2 -0
  98. package/dist/mcp/first-party-tool-permissions.d.ts +3 -606
  99. package/dist/mcp/notification-tools.d.ts +26 -0
  100. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  101. package/dist/mcp/scheduled-task-input.d.ts +1309 -0
  102. package/dist/mcp/scheduled-task-view.d.ts +217 -3
  103. package/dist/mcp/secret-tools.d.ts +14 -0
  104. package/dist/mcp/server.d.ts +108 -5
  105. package/dist/mcp/session-admin-access-tools.d.ts +33 -0
  106. package/dist/mcp/session-event-errors.d.ts +28 -0
  107. package/dist/mcp/session-event-view.d.ts +62 -0
  108. package/dist/mcp/session-view.d.ts +15 -0
  109. package/dist/mcp/session-wait.d.ts +18 -0
  110. package/dist/mcp/site-agent-clamp-tools.d.ts +38 -0
  111. package/dist/mcp/site-data-tools.d.ts +22 -0
  112. package/dist/mcp/site-publication-tools.d.ts +19 -0
  113. package/dist/mcp/site-sql-tools.d.ts +27 -0
  114. package/dist/mcp-oauth.d.ts +37 -4
  115. package/dist/model-calls/chat-completions.d.ts +87 -0
  116. package/dist/model-calls/pending-usage-settlements.d.ts +57 -0
  117. package/dist/model-calls/service.d.ts +36 -0
  118. package/dist/model-catalog.d.ts +9 -3
  119. package/dist/native-push-dispatch.d.ts +69 -0
  120. package/dist/observability.d.ts +3 -1
  121. package/dist/organization-mcp.d.ts +82 -0
  122. package/dist/prepared-mcp-actor.d.ts +77 -0
  123. package/dist/prepared-mcp-permissions.d.ts +8 -0
  124. package/dist/routes/analytics-consent.d.ts +26 -0
  125. package/dist/routes/api-integrations.d.ts +11 -0
  126. package/dist/routes/api-keys.d.ts +7 -7
  127. package/dist/routes/automations.d.ts +2 -0
  128. package/dist/routes/billing.d.ts +59 -0
  129. package/dist/routes/browser-sessions.d.ts +65 -2
  130. package/dist/routes/chat-completions.d.ts +11 -0
  131. package/dist/routes/claude-core-usage.d.ts +20 -0
  132. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  133. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  134. package/dist/routes/client-errors.d.ts +182 -0
  135. package/dist/routes/codex-core.d.ts +401 -0
  136. package/dist/routes/codex.d.ts +64 -2
  137. package/dist/routes/computer-sessions.d.ts +6 -1
  138. package/dist/routes/desktop-distribution.d.ts +32 -0
  139. package/dist/routes/github-browser-fonts.gen.d.ts +2 -0
  140. package/dist/routes/github-browser-pages.d.ts +27 -0
  141. package/dist/routes/inbox.d.ts +13 -0
  142. package/dist/routes/insights-response-cache.d.ts +10 -0
  143. package/dist/routes/insights-usage.d.ts +12 -0
  144. package/dist/routes/insights.d.ts +28 -0
  145. package/dist/routes/interaction-placement-message.d.ts +7 -0
  146. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  147. package/dist/routes/model-account-choice.d.ts +13 -0
  148. package/dist/routes/model-account-settings.d.ts +19 -0
  149. package/dist/routes/native-app-auth.d.ts +12 -0
  150. package/dist/routes/organization-integration-policy.d.ts +8 -0
  151. package/dist/routes/organization-integrations.d.ts +6 -0
  152. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  153. package/dist/routes/organization-model-defaults.d.ts +9 -0
  154. package/dist/routes/organization-service-accounts.d.ts +3 -0
  155. package/dist/routes/personal-api-keys.d.ts +3 -0
  156. package/dist/routes/session-admin-access.d.ts +3 -0
  157. package/dist/routes/session-artifact-associations.d.ts +4 -0
  158. package/dist/routes/session-history-imports.d.ts +20 -0
  159. package/dist/routes/sessions.d.ts +38 -2
  160. package/dist/routes/site-data.d.ts +18 -0
  161. package/dist/routes/site-publishing.d.ts +5 -0
  162. package/dist/routes/site-runtime.d.ts +31 -0
  163. package/dist/routes/site-sql.d.ts +16 -0
  164. package/dist/routes/slack-bot-access.d.ts +3 -0
  165. package/dist/routes/subscription-account-pools.d.ts +21 -0
  166. package/dist/routes/subscription-core-http.d.ts +5 -0
  167. package/dist/routes/subscription-pool-access.d.ts +37 -0
  168. package/dist/routes/subscription-pool-core.d.ts +153 -0
  169. package/dist/routes/supergrok.d.ts +6 -6
  170. package/dist/routes/usage-allowances.d.ts +12 -0
  171. package/dist/routes/variable-sets-removed.d.ts +2 -0
  172. package/dist/routes/vault-providers.d.ts +34 -0
  173. package/dist/routes/vaults.d.ts +3 -0
  174. package/dist/routes/workspace-integrations.d.ts +35 -0
  175. package/dist/routes/workspace-model-providers.d.ts +4 -0
  176. package/dist/routes/workspaces.d.ts +11 -2
  177. package/dist/sandbox/agent-update.d.ts +64 -0
  178. package/dist/sandbox/auth-callout.d.ts +8 -0
  179. package/dist/sandbox/channel-a.d.ts +15 -1
  180. package/dist/sandbox/enrollment.d.ts +26 -4
  181. package/dist/sandbox/machine-audience.d.ts +29 -0
  182. package/dist/sandbox/machines.d.ts +15 -2
  183. package/dist/sandbox/metrics-ingestion.d.ts +6 -2
  184. package/dist/sandbox/screen-control.d.ts +85 -0
  185. package/dist/sandbox/viewer.d.ts +5 -1
  186. package/dist/sandbox-file-artifacts.d.ts +17 -1
  187. package/dist/scheduled-task-blockers.d.ts +39 -0
  188. package/dist/scheduled-task-deletion.d.ts +3 -4
  189. package/dist/scheduled-task-lifecycle.d.ts +14 -0
  190. package/dist/secret-answers.d.ts +40 -0
  191. package/dist/session-create-observability.d.ts +5 -0
  192. package/dist/session-event-view-36GO3IL7.js +528 -0
  193. package/dist/session-event-view-36GO3IL7.js.map +1 -0
  194. package/dist/signed-state-secret.d.ts +18 -0
  195. package/dist/site-agent-guard.d.ts +53 -0
  196. package/dist/site-data/operations.d.ts +103 -0
  197. package/dist/site-data/service.d.ts +203 -0
  198. package/dist/site-frame-guard.d.ts +32 -0
  199. package/dist/site-publishing/agent-data-tools.d.ts +84 -0
  200. package/dist/site-publishing/agent-model.d.ts +58 -0
  201. package/dist/site-publishing/agent-session.d.ts +16 -0
  202. package/dist/site-publishing/content-scanner.d.ts +31 -0
  203. package/dist/site-publishing/edge-sync.d.ts +48 -0
  204. package/dist/site-publishing/gateway-signature.d.ts +56 -0
  205. package/dist/site-publishing/limits.d.ts +63 -0
  206. package/dist/site-publishing/page-tool-authority.d.ts +30 -0
  207. package/dist/site-publishing/platform-usage.d.ts +113 -0
  208. package/dist/site-publishing/platform.d.ts +21 -0
  209. package/dist/site-publishing/readiness.d.ts +62 -0
  210. package/dist/site-publishing/runtime.d.ts +179 -0
  211. package/dist/site-publishing/service.d.ts +264 -0
  212. package/dist/site-publishing/session-events.d.ts +22 -0
  213. package/dist/site-publishing/session-views.d.ts +36 -0
  214. package/dist/site-publishing/viewer.d.ts +40 -0
  215. package/dist/site-session-origin.d.ts +31 -6
  216. package/dist/site-sql/format.d.ts +47 -0
  217. package/dist/site-sql/gateway.d.ts +50 -0
  218. package/dist/site-sql/service.d.ts +213 -0
  219. package/dist/temporal-schedule-sync.d.ts +26 -0
  220. package/dist/transcription/billing-refusal.d.ts +8 -0
  221. package/dist/transcription/normalize.d.ts +23 -0
  222. package/dist/transcription/providers/azure-mai.d.ts +12 -0
  223. package/dist/transcription/providers/azure-openai.d.ts +4 -0
  224. package/dist/transcription/providers/openai.d.ts +16 -0
  225. package/dist/transcription/providers/subscription-core.d.ts +39 -0
  226. package/dist/transcription/service.d.ts +10 -1
  227. package/dist/transcription/wav-duration.d.ts +8 -0
  228. package/dist/workspace-tool-gateway-attestations.d.ts +37 -0
  229. package/dist/workspace-tool-gateway-observability.d.ts +16 -0
  230. package/dist/workspace-tool-gateway-secrets.d.ts +27 -0
  231. package/dist/workspace-tool-gateway.d.ts +102 -6
  232. package/dist/workspace-tool-target-fence.d.ts +116 -0
  233. package/dist/workspace-tool-target.d.ts +225 -0
  234. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  235. package/dist/xai-subscription-core.d.ts +60 -0
  236. package/package.json +25 -20
  237. package/src/access-grant-rls.ts +64 -14
  238. package/src/admission-trace.ts +14 -0
  239. package/src/app.ts +1684 -252
  240. package/src/artifact-catalog-cursor.ts +1 -0
  241. package/src/attached-browser-viewer.ts +26 -0
  242. package/src/auth/managed-auth-attempt-context.ts +9 -0
  243. package/src/auth/managed-auth-rate-limits.ts +252 -0
  244. package/src/auth/managed-auth-session-adapter.ts +64 -29
  245. package/src/auth/managed-auth.ts +303 -35
  246. package/src/auth/managed-email.ts +18 -1
  247. package/src/auth/managed-sign-in-notifications.ts +81 -0
  248. package/src/auth/new-signups-gate.ts +49 -0
  249. package/src/auth/organization-user-setup.ts +3 -3
  250. package/src/auth/signup-funnel-metrics.ts +164 -0
  251. package/src/azure-live.ts +103 -0
  252. package/src/browser-action-fences.ts +45 -0
  253. package/src/browser-controller-authority.ts +1 -186
  254. package/src/browser-ephemeral.ts +39 -0
  255. package/src/browser-lost-runtime-end.ts +71 -0
  256. package/src/browser-state-authority.ts +1 -236
  257. package/src/claude-default-models.ts +37 -0
  258. package/src/claude-subscription-core.ts +154 -0
  259. package/src/claude-subscription-oauth.ts +352 -0
  260. package/src/claude-subscription-profile.ts +73 -0
  261. package/src/claude-subscription-usage.ts +51 -0
  262. package/src/claude-workspace-connection.ts +82 -0
  263. package/src/codemode.ts +236 -39
  264. package/src/codex-realtime.ts +181 -53
  265. package/src/codex-session-pointers.ts +80 -0
  266. package/src/company-brain-okf.ts +1 -1
  267. package/src/connected-machine-computer-access.ts +2 -1
  268. package/src/connection-ownership.ts +19 -13
  269. package/src/controller-data-plane.ts +34 -0
  270. package/src/credit-promotion-snapshot.ts +36 -0
  271. package/src/editable-artifact-production.ts +10 -0
  272. package/src/editable-artifact-source-session.ts +123 -0
  273. package/src/editable-artifact-websocket.ts +16 -3
  274. package/src/fatal-process-boundary.ts +67 -3
  275. package/src/gateway-realtime.ts +12 -8
  276. package/src/github-access.ts +31 -5
  277. package/src/github-browser-flow.ts +1 -1
  278. package/src/http/acting-person.ts +105 -0
  279. package/src/http/api-contract-compat.ts +49 -0
  280. package/src/http/api-error.ts +210 -2
  281. package/src/http/auth.ts +68 -4
  282. package/src/http/cors.ts +37 -5
  283. package/src/http/deprecation.ts +118 -0
  284. package/src/http/keyed-admission.ts +29 -0
  285. package/src/http/local-browser-boundary.ts +343 -0
  286. package/src/http/metrics-listener.ts +57 -0
  287. package/src/http/path-identifier.ts +54 -0
  288. package/src/http/registered-route-label.ts +34 -0
  289. package/src/http/rejection-telemetry.ts +120 -0
  290. package/src/http/request-body.ts +127 -0
  291. package/src/http/request-source.ts +154 -13
  292. package/src/http/sse.ts +88 -28
  293. package/src/http/unmatched-route.ts +60 -0
  294. package/src/http/user-content.ts +158 -0
  295. package/src/http/variable-sets-removed.ts +122 -0
  296. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  297. package/src/index.ts +107 -57
  298. package/src/integration-connect-metrics.ts +228 -0
  299. package/src/integration-endpoint-test.ts +291 -0
  300. package/src/integrations/api-integrations.ts +81 -7
  301. package/src/integrations/atlassian.ts +202 -83
  302. package/src/integrations/fiken.ts +66 -38
  303. package/src/integrations/github-app-connect.ts +64 -18
  304. package/src/integrations/github-lens-connect.ts +8 -29
  305. package/src/integrations/google-drive.ts +448 -152
  306. package/src/integrations/integration-commit-authority.ts +69 -0
  307. package/src/integrations/marketplace-plugin.ts +1 -1
  308. package/src/integrations/oauth-client.ts +733 -193
  309. package/src/integrations/oauth-profiles.ts +116 -45
  310. package/src/integrations/onepassword-vault-provider.ts +16 -0
  311. package/src/integrations/personal-github-repositories.ts +1 -1
  312. package/src/integrations/personal-github.ts +61 -35
  313. package/src/integrations/provider-oauth.ts +67 -85
  314. package/src/integrations/slack-app-home.ts +5 -5
  315. package/src/integrations/slack-bot.ts +893 -201
  316. package/src/integrations/slack-file-upload-flow.ts +147 -0
  317. package/src/integrations/slack-install.ts +7 -7
  318. package/src/integrations/slack-interactions.ts +1589 -299
  319. package/src/integrations/slack-mrkdwn.ts +193 -0
  320. package/src/integrations/slack-routing.ts +2 -2
  321. package/src/integrations/slack-session-defaults.ts +224 -0
  322. package/src/integrations/slack-task-file-upload.ts +323 -0
  323. package/src/integrations/slack-tool-review.ts +65 -0
  324. package/src/integrations/social-oauth.ts +90 -58
  325. package/src/interaction-agent-access.ts +40 -20
  326. package/src/interaction-agent-version.ts +85 -0
  327. package/src/interaction-holder-heartbeat.ts +24 -8
  328. package/src/interaction-metrics.ts +164 -2
  329. package/src/interaction-route-stages.ts +94 -0
  330. package/src/interaction-secrets-vault.ts +213 -0
  331. package/src/interaction-secrets.ts +426 -0
  332. package/src/mcp/action-catalog-types.ts +14 -0
  333. package/src/mcp/action-catalog.gen.ts +8014 -0
  334. package/src/mcp/action-descriptions.ts +299 -0
  335. package/src/mcp/action-schema-imports.gen.ts +304 -0
  336. package/src/mcp/capability-account-readiness.ts +17 -0
  337. package/src/mcp/child-read-evidence.ts +19 -0
  338. package/src/mcp/company-profile-agent-admin.ts +13 -0
  339. package/src/mcp/contract-input.ts +165 -0
  340. package/src/mcp/documents.ts +9 -2
  341. package/src/mcp/editable-artifacts.ts +29 -11
  342. package/src/mcp/files.ts +5 -1
  343. package/src/mcp/first-party-tool-permissions.ts +7 -285
  344. package/src/mcp/knowledge-entries.ts +108 -34
  345. package/src/mcp/notification-tools.ts +480 -0
  346. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  347. package/src/mcp/scheduled-task-input.ts +89 -0
  348. package/src/mcp/scheduled-task-view.ts +63 -3
  349. package/src/mcp/secret-tools.ts +185 -0
  350. package/src/mcp/server.ts +2213 -1116
  351. package/src/mcp/session-admin-access-tools.ts +163 -0
  352. package/src/mcp/session-event-errors.ts +123 -0
  353. package/src/mcp/session-event-view.ts +395 -13
  354. package/src/mcp/session-view.ts +3 -0
  355. package/src/mcp/session-wait.ts +67 -7
  356. package/src/mcp/site-agent-clamp-tools.ts +140 -0
  357. package/src/mcp/site-data-tools.ts +339 -0
  358. package/src/mcp/site-publication-tools.ts +201 -0
  359. package/src/mcp/site-sql-tools.ts +427 -0
  360. package/src/mcp-oauth.ts +635 -45
  361. package/src/model-calls/chat-completions.ts +352 -0
  362. package/src/model-calls/pending-usage-settlements.ts +125 -0
  363. package/src/model-calls/service.ts +694 -0
  364. package/src/model-catalog.ts +68 -17
  365. package/src/native-push-dispatch.ts +457 -0
  366. package/src/observability.ts +15 -1
  367. package/src/organization-mcp.ts +485 -0
  368. package/src/prepared-mcp-actor.ts +154 -0
  369. package/src/prepared-mcp-permissions.ts +38 -0
  370. package/src/routes/analytics-consent.ts +123 -0
  371. package/src/routes/api-integrations.ts +268 -9
  372. package/src/routes/api-keys.ts +164 -25
  373. package/src/routes/artifact-catalog.ts +111 -0
  374. package/src/routes/automations.ts +163 -90
  375. package/src/routes/billing.ts +535 -59
  376. package/src/routes/browser-sessions.ts +966 -342
  377. package/src/routes/canonical-human-identities.ts +61 -0
  378. package/src/routes/capabilities.ts +112 -5
  379. package/src/routes/channels.ts +4 -3
  380. package/src/routes/chat-completions.ts +235 -0
  381. package/src/routes/claude-core-usage.ts +147 -0
  382. package/src/routes/claude-subscription-accounts.ts +233 -0
  383. package/src/routes/claude-subscription-oauth.ts +175 -0
  384. package/src/routes/client-errors.ts +394 -0
  385. package/src/routes/codex-core.ts +687 -0
  386. package/src/routes/codex.ts +1277 -1119
  387. package/src/routes/company-brain.ts +4 -0
  388. package/src/routes/computer-sessions.ts +319 -85
  389. package/src/routes/connect.ts +277 -175
  390. package/src/routes/connections.ts +690 -363
  391. package/src/routes/desktop-distribution.ts +217 -0
  392. package/src/routes/documents.ts +13 -7
  393. package/src/routes/editable-artifacts.ts +74 -4
  394. package/src/routes/enrollments.ts +110 -16
  395. package/src/routes/external-identity-links.ts +13 -12
  396. package/src/routes/files.ts +41 -16
  397. package/src/routes/github-browser-fonts.gen.ts +12 -0
  398. package/src/routes/github-browser-pages.ts +258 -0
  399. package/src/routes/github.ts +200 -75
  400. package/src/routes/inbox.ts +353 -0
  401. package/src/routes/insights-response-cache.ts +83 -0
  402. package/src/routes/insights-usage.ts +345 -0
  403. package/src/routes/insights.ts +103 -8
  404. package/src/routes/install.ts +51 -10
  405. package/src/routes/integration-facets.ts +70 -28
  406. package/src/routes/interaction-placement-message.ts +12 -0
  407. package/src/routes/knowledge.ts +136 -27
  408. package/src/routes/machines.ts +189 -135
  409. package/src/routes/managed-auth-session-sets.ts +43 -10
  410. package/src/routes/managed-onboarding.ts +39 -19
  411. package/src/routes/managed-sign-in-methods.ts +433 -0
  412. package/src/routes/memory-slack-publications.ts +3 -2
  413. package/src/routes/model-account-choice.ts +194 -0
  414. package/src/routes/model-account-settings.ts +235 -0
  415. package/src/routes/model-connection-access.ts +210 -48
  416. package/src/routes/native-app-auth.ts +296 -0
  417. package/src/routes/organization-integration-policy.ts +116 -0
  418. package/src/routes/organization-integrations.ts +326 -0
  419. package/src/routes/organization-mcp-connections.ts +183 -0
  420. package/src/routes/organization-memberships.ts +205 -19
  421. package/src/routes/organization-model-defaults.ts +110 -0
  422. package/src/routes/organization-model-providers.ts +74 -3
  423. package/src/routes/organization-service-accounts.ts +128 -0
  424. package/src/routes/organization-sessions.ts +21 -5
  425. package/src/routes/personal-api-keys.ts +184 -0
  426. package/src/routes/personal-github-git-broker.ts +2 -2
  427. package/src/routes/personal-github.ts +9 -4
  428. package/src/routes/plugins.ts +46 -7
  429. package/src/routes/pr-review-github.ts +105 -118
  430. package/src/routes/pr-review.ts +88 -82
  431. package/src/routes/preference-registry.ts +18 -0
  432. package/src/routes/rigs.ts +48 -13
  433. package/src/routes/scheduled-tasks.ts +347 -27
  434. package/src/routes/session-admin-access.ts +271 -0
  435. package/src/routes/session-artifact-associations.ts +164 -0
  436. package/src/routes/session-history-imports.ts +305 -0
  437. package/src/routes/sessions.ts +1682 -363
  438. package/src/routes/site-data.ts +340 -0
  439. package/src/routes/site-publishing.ts +584 -0
  440. package/src/routes/site-runtime.ts +1944 -0
  441. package/src/routes/site-sql.ts +263 -0
  442. package/src/routes/skill-content.ts +72 -7
  443. package/src/routes/skills.ts +5 -4
  444. package/src/routes/slack-bot-access.ts +108 -0
  445. package/src/routes/social.ts +27 -15
  446. package/src/routes/subscription-account-pools.ts +209 -0
  447. package/src/routes/subscription-core-http.ts +18 -0
  448. package/src/routes/subscription-pool-access.ts +180 -0
  449. package/src/routes/subscription-pool-core.ts +552 -0
  450. package/src/routes/supergrok.ts +174 -655
  451. package/src/routes/transcription-recordings.ts +71 -4
  452. package/src/routes/transcriptions.ts +26 -2
  453. package/src/routes/usage-allowances.ts +381 -0
  454. package/src/routes/variable-sets-removed.ts +19 -0
  455. package/src/routes/vault-providers.ts +782 -0
  456. package/src/routes/vaults.ts +421 -0
  457. package/src/routes/video-generation.ts +30 -12
  458. package/src/routes/workspace-artifacts.ts +165 -53
  459. package/src/routes/workspace-integrations.ts +576 -0
  460. package/src/routes/workspace-model-providers.ts +148 -0
  461. package/src/routes/workspace-state.ts +4 -0
  462. package/src/routes/workspaces.ts +625 -117
  463. package/src/sandbox/agent-update.ts +315 -0
  464. package/src/sandbox/auth-callout.ts +104 -21
  465. package/src/sandbox/channel-a.ts +165 -55
  466. package/src/sandbox/enrollment.ts +131 -22
  467. package/src/sandbox/machine-audience.ts +192 -0
  468. package/src/sandbox/machines.ts +75 -31
  469. package/src/sandbox/metrics-ingestion.ts +133 -2
  470. package/src/sandbox/rematerialize.ts +51 -21
  471. package/src/sandbox/screen-control.ts +289 -0
  472. package/src/sandbox/viewer.ts +33 -58
  473. package/src/sandbox-file-artifacts.ts +53 -27
  474. package/src/scheduled-task-blockers.ts +293 -0
  475. package/src/scheduled-task-deletion.ts +13 -3
  476. package/src/scheduled-task-lifecycle.ts +84 -0
  477. package/src/secret-answers.ts +119 -0
  478. package/src/session-create-observability.ts +46 -0
  479. package/src/session-realtime-context.ts +26 -4
  480. package/src/signed-state-secret.ts +58 -0
  481. package/src/site-agent-guard.ts +261 -0
  482. package/src/site-data/operations.ts +777 -0
  483. package/src/site-data/service.ts +1043 -0
  484. package/src/site-frame-guard.ts +107 -0
  485. package/src/site-publishing/agent-data-tools.ts +250 -0
  486. package/src/site-publishing/agent-model.ts +127 -0
  487. package/src/site-publishing/agent-session.ts +148 -0
  488. package/src/site-publishing/content-scanner.ts +93 -0
  489. package/src/site-publishing/edge-sync.ts +148 -0
  490. package/src/site-publishing/gateway-signature.ts +198 -0
  491. package/src/site-publishing/limits.ts +315 -0
  492. package/src/site-publishing/page-tool-authority.ts +111 -0
  493. package/src/site-publishing/platform-usage.ts +479 -0
  494. package/src/site-publishing/platform.ts +98 -0
  495. package/src/site-publishing/readiness.ts +330 -0
  496. package/src/site-publishing/runtime.ts +831 -0
  497. package/src/site-publishing/service.ts +1282 -0
  498. package/src/site-publishing/session-events.ts +262 -0
  499. package/src/site-publishing/session-views.ts +262 -0
  500. package/src/site-publishing/viewer.ts +75 -0
  501. package/src/site-session-origin.ts +91 -6
  502. package/src/site-sql/format.ts +134 -0
  503. package/src/site-sql/gateway.ts +168 -0
  504. package/src/site-sql/service.ts +1636 -0
  505. package/src/site-uploads.ts +27 -5
  506. package/src/temporal-schedule-sync.ts +74 -0
  507. package/src/transcription/billing-refusal.ts +14 -0
  508. package/src/transcription/normalize.ts +77 -0
  509. package/src/transcription/providers/azure-mai.ts +98 -0
  510. package/src/transcription/providers/azure-openai.ts +16 -7
  511. package/src/transcription/providers/codex-subscription.ts +190 -67
  512. package/src/transcription/providers/openai.ts +79 -5
  513. package/src/transcription/providers/subscription-core.ts +125 -0
  514. package/src/transcription/providers/xai-subscription.ts +81 -83
  515. package/src/transcription/segmenter.ts +7 -1
  516. package/src/transcription/service.ts +239 -10
  517. package/src/transcription/wav-duration.ts +39 -0
  518. package/src/workspace-deletion.ts +25 -1
  519. package/src/workspace-tool-gateway-attestations.ts +133 -0
  520. package/src/workspace-tool-gateway-observability.ts +64 -0
  521. package/src/workspace-tool-gateway-secrets.ts +104 -0
  522. package/src/workspace-tool-gateway.ts +921 -103
  523. package/src/workspace-tool-target-fence.ts +380 -0
  524. package/src/workspace-tool-target.ts +554 -0
  525. package/src/workspace-webhook-dispatch.ts +225 -0
  526. package/src/xai-realtime.ts +85 -81
  527. package/src/xai-subscription-core.ts +172 -0
  528. package/dist/browser-auth-broker.d.ts +0 -20
  529. package/dist/chunk-AJ62T5QN.js.map +0 -1
  530. package/dist/connection-authority-owner.d.ts +0 -59
  531. package/dist/routes/connection-authorities.d.ts +0 -3
  532. package/dist/routes/environments.d.ts +0 -5
  533. package/dist/routes/host-mcp-bindings.d.ts +0 -5
  534. package/dist/routes/host-mcp-resolvers.d.ts +0 -3
  535. package/dist/routes/packs.d.ts +0 -3
  536. package/dist/session-event-view-MU3HMNV3.js +0 -264
  537. package/dist/session-event-view-MU3HMNV3.js.map +0 -1
  538. package/dist/xai-subscription-auth.d.ts +0 -23
  539. package/src/browser-auth-broker.ts +0 -155
  540. package/src/connection-authority-owner.ts +0 -61
  541. package/src/routes/connection-authorities.ts +0 -139
  542. package/src/routes/environments.ts +0 -388
  543. package/src/routes/host-mcp-bindings.ts +0 -122
  544. package/src/routes/host-mcp-resolvers.ts +0 -41
  545. package/src/routes/packs.ts +0 -784
  546. package/src/xai-subscription-auth.ts +0 -139
@@ -0,0 +1,831 @@
1
+ import { createHash } from "node:crypto";
2
+ import { isIP } from "node:net";
3
+ import {
4
+ parseSiteHostname,
5
+ siteHostname,
6
+ SITE_NOT_AVAILABLE_FOR_VIEWER_ERROR_CODE,
7
+ type Permission,
8
+ type SiteLimitProfileKind,
9
+ type SiteLimits,
10
+ type SiteViewerCapabilities,
11
+ } from "@opengeni/contracts";
12
+ import { sessionUsageLimitsProducerEnabled, type ApiRouteDeps } from "@opengeni/core";
13
+ import {
14
+ consumeSiteRuntimeRate,
15
+ findSiteHostname,
16
+ findSiteViewerSession,
17
+ getPublishedSite,
18
+ getSession,
19
+ getSitePublication,
20
+ isSiteWorkspaceMember,
21
+ claimSiteRuntimeReservationSweep,
22
+ readSessionUsageLimit,
23
+ recordUsageEvent,
24
+ releaseSiteRuntimeConversationStart,
25
+ setSessionUsageLimitInTransaction,
26
+ siteRuntimeFundedLimitInTransaction,
27
+ settleSiteRuntimeConversationSpend,
28
+ SITE_RUNTIME_ABANDONED_START_MINUTES,
29
+ SITE_RUNTIME_MEMBERS_PRINCIPAL,
30
+ SITE_RUNTIME_SITE_PRINCIPAL,
31
+ withRlsContext,
32
+ withWorkspaceSessionActivityRls,
33
+ type PublishedSiteRecord,
34
+ type SitePublicationRecord,
35
+ type SitePublishingScope,
36
+ type SiteRuntimeBudget,
37
+ type SiteRuntimeBudgetLimits,
38
+ type SiteRuntimeConversationRecord,
39
+ type SiteRuntimeRateBucket,
40
+ type SiteRuntimeReservation,
41
+ } from "@opengeni/db";
42
+ import type { SiteGatewayFields } from "./gateway-signature";
43
+ import { effectiveSiteLimits, siteViewerLimits, sourceSiteLimitProfile } from "./limits";
44
+ import {
45
+ siteLimitInputs,
46
+ sitePublishingError,
47
+ siteServable,
48
+ siteServiceSessionRequest,
49
+ SITE_RUNTIME_AGENT_PERMISSIONS,
50
+ } from "./service";
51
+ import {
52
+ effectiveSiteAccess,
53
+ signedInSiteViewerKind,
54
+ siteGuestsAllowed,
55
+ SITE_VISITOR_ID,
56
+ type SiteRuntimeViewer,
57
+ } from "./viewer";
58
+
59
+ /**
60
+ * Site-runtime: the narrow API a Site gateway calls for one published Site
61
+ * host, after the gateway signature passed. Everything here works for exactly
62
+ * one Site: the host names it, the viewer is resolved for it, and the agent
63
+ * principal is `site:<siteId>`.
64
+ */
65
+
66
+ export type SiteRuntimeDeps = Pick<ApiRouteDeps, "db" | "settings" | "objectStorage">;
67
+
68
+ export type SiteRuntimeHost = {
69
+ domain: string;
70
+ label: string;
71
+ hostname: string;
72
+ scope: SitePublishingScope;
73
+ publication: SitePublicationRecord;
74
+ site: PublishedSiteRecord;
75
+ };
76
+
77
+ /** The Site behind a host, whatever its status (null when the host names no Site). */
78
+ export async function findSiteRuntimeHost(
79
+ deps: SiteRuntimeDeps,
80
+ domain: string,
81
+ host: string,
82
+ ): Promise<SiteRuntimeHost | null> {
83
+ // parseSiteHostname lowercases and drops a port and one trailing dot.
84
+ const label = parseSiteHostname(host, domain);
85
+ if (!label) return null;
86
+ const record = await findSiteHostname(deps.db, label);
87
+ if (!record || record.releasedAt !== null) return null;
88
+ const scope = { accountId: record.accountId, workspaceId: record.workspaceId };
89
+ const [publication, site] = await Promise.all([
90
+ getSitePublication(deps.db, scope, record.siteId),
91
+ getPublishedSite(deps.db, scope, record.siteId),
92
+ ]);
93
+ if (!publication || !site || publication.label !== label) return null;
94
+ return { domain, label, hostname: siteHostname(label, domain), scope, publication, site };
95
+ }
96
+
97
+ /** The Site behind a host when it is served: 404 for no Site, 410 when not served. */
98
+ export async function requireServedSiteRuntimeHost(
99
+ deps: SiteRuntimeDeps,
100
+ domain: string,
101
+ host: string,
102
+ ): Promise<SiteRuntimeHost & { versionId: string }> {
103
+ const found = await findSiteRuntimeHost(deps, domain, host);
104
+ if (!found)
105
+ throw sitePublishingError(404, "not_found", "site_not_found", "This Site does not exist");
106
+ const { publication, site } = found;
107
+ if (publication.status !== "active" || !siteServable(site) || !site.currentVersionId)
108
+ throw sitePublishingError(410, "not_found", "site_unavailable", "This Site is not available", {
109
+ status: publication.status === "suspended" ? "suspended" : "unpublished",
110
+ });
111
+ return { ...found, versionId: site.currentVersionId };
112
+ }
113
+
114
+ export function sha256Text(value: string): string {
115
+ return createHash("sha256").update(value, "utf8").digest("hex");
116
+ }
117
+
118
+ /**
119
+ * Who is viewing: a live site-session of this Site whose person the Site
120
+ * still admits (membership and invitations are re-read every call), else an
121
+ * anonymous guest of a public Site, else sign-in is required.
122
+ *
123
+ * "View as visitor": a workspace member whose site-session previews another
124
+ * role is resolved as exactly that role, and only ever downgraded: `public`
125
+ * is an anonymous guest (refused where guests are not admitted), `invited`
126
+ * a signed-in person outside the workspace (refused on members-only Sites).
127
+ * A preview role on the session of anyone who is not a member is ignored, so
128
+ * it can never grant more than the person already has. `ignoreViewAs`
129
+ * resolves the real viewer (to start or end a preview).
130
+ */
131
+ export async function resolveSiteRuntimeViewer(
132
+ deps: SiteRuntimeDeps,
133
+ host: SiteRuntimeHost,
134
+ fields: SiteGatewayFields,
135
+ options: { ignoreViewAs?: boolean } = {},
136
+ ): Promise<SiteRuntimeViewer> {
137
+ const { scope, publication, site } = host;
138
+ const denied = () =>
139
+ sitePublishingError(
140
+ 403,
141
+ "forbidden",
142
+ "site_access_denied",
143
+ "You do not have access to this Site",
144
+ );
145
+ const access = effectiveSiteAccess(publication.access, deps.settings);
146
+ if (fields.session) {
147
+ const session = await findSiteViewerSession(deps.db, scope, {
148
+ siteId: site.id,
149
+ tokenHash: sha256Text(fields.session),
150
+ idleSeconds: deps.settings.sitesViewerSessionIdleSeconds,
151
+ });
152
+ if (session) {
153
+ const member = await isSiteWorkspaceMember(deps.db, scope, session.subjectId);
154
+ const kind = signedInSiteViewerKind({
155
+ access,
156
+ member,
157
+ email: session.email,
158
+ invitedEmails: publication.invitedEmails,
159
+ });
160
+ if (!kind) throw denied();
161
+ const viewAs = !options.ignoreViewAs && kind === "member" ? (session.viewAs ?? null) : null;
162
+ if (viewAs === "public") {
163
+ if (
164
+ !siteGuestsAllowed(publication.access, deps.settings) ||
165
+ !SITE_VISITOR_ID.test(fields.visitor)
166
+ )
167
+ throw denied();
168
+ return {
169
+ kind: "guest",
170
+ principal: `guest:${fields.visitor}`,
171
+ subjectId: null,
172
+ name: null,
173
+ email: null,
174
+ sessionId: null,
175
+ viewAs,
176
+ };
177
+ }
178
+ if (viewAs === "invited") {
179
+ if (access === "members") throw denied();
180
+ return {
181
+ kind: "invited",
182
+ principal: `user:${session.subjectId}`,
183
+ subjectId: session.subjectId,
184
+ name: session.displayName,
185
+ email: session.email,
186
+ sessionId: session.id,
187
+ viewAs,
188
+ };
189
+ }
190
+ return {
191
+ kind,
192
+ principal: `user:${session.subjectId}`,
193
+ subjectId: session.subjectId,
194
+ name: session.displayName,
195
+ email: session.email,
196
+ sessionId: session.id,
197
+ viewAs: null,
198
+ };
199
+ }
200
+ }
201
+ if (siteGuestsAllowed(publication.access, deps.settings) && SITE_VISITOR_ID.test(fields.visitor))
202
+ return {
203
+ kind: "guest",
204
+ principal: `guest:${fields.visitor}`,
205
+ subjectId: null,
206
+ name: null,
207
+ email: null,
208
+ sessionId: null,
209
+ viewAs: null,
210
+ };
211
+ throw sitePublishingError(
212
+ 401,
213
+ "unauthenticated",
214
+ "site_sign_in_required",
215
+ "Sign in to view this Site",
216
+ );
217
+ }
218
+
219
+ /** What a viewer cannot do on a Site: 403 with `details.code` `not_available_for_viewer`. */
220
+ export type SiteViewerFeature =
221
+ | "agent"
222
+ | "agent_model"
223
+ | "workspace_tools"
224
+ | "site_data"
225
+ | "site_sql";
226
+
227
+ /**
228
+ * The `details.code` each feature answered before `not_available_for_viewer`,
229
+ * retained as `details.legacyCode` for migration. Clients matching
230
+ * `details.code` must adopt the new code; the alias is not automatic compatibility.
231
+ */
232
+ const SITE_VIEWER_FEATURE_LEGACY_CODES: Partial<Record<SiteViewerFeature, string>> = {
233
+ agent: "site_agents_unavailable",
234
+ workspace_tools: "site_tools_unavailable",
235
+ site_data: "forbidden",
236
+ site_sql: "forbidden",
237
+ };
238
+
239
+ export function siteNotAvailableForViewer(
240
+ feature: SiteViewerFeature,
241
+ message: string,
242
+ extra: Record<string, unknown> = {},
243
+ ) {
244
+ const legacyCode = SITE_VIEWER_FEATURE_LEGACY_CODES[feature];
245
+ return sitePublishingError(403, "forbidden", SITE_NOT_AVAILABLE_FOR_VIEWER_ERROR_CODE, message, {
246
+ ...extra,
247
+ feature,
248
+ ...(legacyCode ? { legacyCode } : {}),
249
+ });
250
+ }
251
+
252
+ /** The viewer capabilities a page reads from `site.config` to hide what won't work. */
253
+ export function siteViewerCapabilities(
254
+ deps: SiteRuntimeDeps,
255
+ host: SiteRuntimeHost,
256
+ viewer: SiteRuntimeViewer,
257
+ limits: SiteLimits,
258
+ ): SiteViewerCapabilities {
259
+ return {
260
+ agent: siteAgentRefusal(deps, host, viewer, limits) === null,
261
+ // The route intersects this with the immutable page declarations and live grant.
262
+ workspaceTools: viewer.kind === "member",
263
+ siteData: viewer.kind === "guest" ? "guest" : "viewer",
264
+ sqlQueryAudiences: viewer.kind === "guest" ? ["everyone"] : ["everyone", "signed_in"],
265
+ viewAs: viewer.viewAs ?? null,
266
+ };
267
+ }
268
+
269
+ export async function siteRuntimeLimits(
270
+ deps: SiteRuntimeDeps,
271
+ host: SiteRuntimeHost,
272
+ viewer?: Pick<SiteRuntimeViewer, "kind">,
273
+ ): Promise<SiteLimits> {
274
+ return (await siteRuntimeLimitProfile(deps, host, viewer)).limits;
275
+ }
276
+
277
+ /**
278
+ * The limits that govern a viewer and the kind of limit profile they come
279
+ * from: workspace members are never limited by Site limits (flood brakes
280
+ * only); everyone else gets the Site's limits (siteViewerLimits). Without a
281
+ * viewer: the Site's limits.
282
+ */
283
+ export async function siteRuntimeLimitProfile(
284
+ deps: SiteRuntimeDeps,
285
+ host: SiteRuntimeHost,
286
+ viewer?: Pick<SiteRuntimeViewer, "kind">,
287
+ ): Promise<{ limits: SiteLimits; kind: SiteLimitProfileKind }> {
288
+ const profiles = await siteLimitInputs(deps, host.scope, host.publication);
289
+ const limits = effectiveSiteLimits(deps.settings, profiles.site, profiles.workspace);
290
+ return {
291
+ limits: viewer ? siteViewerLimits(limits, viewer.kind) : limits,
292
+ kind: sourceSiteLimitProfile(profiles.site, profiles.workspace).kind,
293
+ };
294
+ }
295
+
296
+ /** A guest's client address may carry this many visitors' worth of traffic. */
297
+ export const SITE_GUEST_IP_LIMIT_FACTOR = 4;
298
+
299
+ /**
300
+ * A viewer's per-minute bucket. Guests are also counted per signed client
301
+ * address (`ip:<address>`, `SITE_GUEST_IP_LIMIT_FACTOR` times the visitor
302
+ * limit), so minting new visitor ids does not reset their limits; both must
303
+ * pass.
304
+ */
305
+ export async function enforceSiteRuntimeViewerRate(
306
+ deps: SiteRuntimeDeps,
307
+ host: SiteRuntimeHost,
308
+ viewer: SiteRuntimeViewer,
309
+ fields: Pick<SiteGatewayFields, "clientIp">,
310
+ bucket: SiteRuntimeRateBucket,
311
+ limit: number | null,
312
+ ): Promise<void> {
313
+ await enforceSiteRuntimeRate(deps, host, viewer.principal, bucket, limit);
314
+ if (viewer.kind === "guest" && limit !== null)
315
+ await enforceSiteRuntimeRate(
316
+ deps,
317
+ host,
318
+ siteClientAddressPrincipal(fields),
319
+ bucket,
320
+ limit * SITE_GUEST_IP_LIMIT_FACTOR,
321
+ );
322
+ }
323
+
324
+ /**
325
+ * The rate principal of the signed client address (`ip:unknown` when the
326
+ * gateway sent none). IPv6 addresses count per /64 (one subscriber usually
327
+ * holds a whole /64, so per-address keys would be free to rotate);
328
+ * IPv4-mapped IPv6 counts as its IPv4 address.
329
+ */
330
+ export function siteClientAddressPrincipal(fields: Pick<SiteGatewayFields, "clientIp">): string {
331
+ return `ip:${siteClientAddressKey(fields.clientIp)}`;
332
+ }
333
+
334
+ /** A client address as a rate key: IPv4 as is, IPv6 as its /64 prefix. */
335
+ export function siteClientAddressKey(raw: string): string {
336
+ const value = raw
337
+ .trim()
338
+ .toLowerCase()
339
+ .replace(/^\[(.*)\]$/u, "$1")
340
+ .replace(/%.*$/u, "");
341
+ if (!value) return "unknown";
342
+ const family = isIP(value);
343
+ if (family !== 6) return value.slice(0, 64);
344
+ const halves = value.split("::");
345
+ const groups = (part: string | undefined) => (part ? part.split(":") : []);
346
+ const head = groups(halves[0]);
347
+ const tail = halves.length === 2 ? groups(halves[1]) : [];
348
+ // An embedded IPv4 tail is two hextets.
349
+ const last = halves.length === 2 ? tail : head;
350
+ const dotted = last.at(-1);
351
+ if (dotted?.includes(".")) {
352
+ const octets = dotted.split(".").map(Number);
353
+ last.splice(
354
+ -1,
355
+ 1,
356
+ ((octets[0]! << 8) | octets[1]!).toString(16),
357
+ ((octets[2]! << 8) | octets[3]!).toString(16),
358
+ );
359
+ }
360
+ const zeros = halves.length === 2 ? Math.max(0, 8 - head.length - tail.length) : 0;
361
+ const hextets = [...head, ...Array<string>(zeros).fill("0"), ...tail].map((group) =>
362
+ Number.parseInt(group, 16),
363
+ );
364
+ if (hextets.length !== 8 || hextets.some((hextet) => !Number.isInteger(hextet)))
365
+ return value.slice(0, 64);
366
+ if (hextets.slice(0, 5).every((hextet) => hextet === 0) && hextets[5] === 0xffff)
367
+ return [hextets[6]! >> 8, hextets[6]! & 255, hextets[7]! >> 8, hextets[7]! & 255].join(".");
368
+ return `${hextets
369
+ .slice(0, 4)
370
+ .map((hextet) => hextet.toString(16))
371
+ .join(":")}::/64`;
372
+ }
373
+
374
+ /** Count one operation in a per-minute bucket; 429 with Retry-After past `limit` (null: no limit). */
375
+ export async function enforceSiteRuntimeRate(
376
+ deps: SiteRuntimeDeps,
377
+ host: SiteRuntimeHost,
378
+ principal: string,
379
+ bucket: SiteRuntimeRateBucket,
380
+ limit: number | null,
381
+ ): Promise<void> {
382
+ if (limit === null) return;
383
+ const rate = await consumeSiteRuntimeRate(deps.db, host.scope, {
384
+ siteId: host.site.id,
385
+ principal,
386
+ bucket,
387
+ limit,
388
+ });
389
+ if (!rate.allowed)
390
+ throw sitePublishingError(
391
+ 429,
392
+ "limit_exceeded",
393
+ "site_rate_limited",
394
+ "Too many requests; try again shortly",
395
+ {
396
+ bucket,
397
+ retryAfterSeconds: rate.retryAfterSeconds,
398
+ },
399
+ );
400
+ }
401
+
402
+ // --- agents ---------------------------------------------------------------------
403
+
404
+ export { SITE_RUNTIME_AGENT_PERMISSIONS };
405
+
406
+ /** A short display label for the viewer, recorded as the end user of the agent's work. */
407
+ export function siteRuntimeViewerLabel(viewer: SiteRuntimeViewer): string {
408
+ if (viewer.kind === "guest") return "Site guest";
409
+ const who = viewer.name?.trim() || viewer.email || "Site viewer";
410
+ return who.slice(0, 120);
411
+ }
412
+
413
+ /** Whether this viewer may use the Site's embedded agent at all (before budgets). */
414
+ export function siteAgentRefusal(
415
+ deps: SiteRuntimeDeps,
416
+ host: SiteRuntimeHost,
417
+ viewer: SiteRuntimeViewer,
418
+ limits: SiteLimits,
419
+ ): string | null {
420
+ if (!host.publication.agent.enabled || !limits.agentsEnabled) return "agent_disabled";
421
+ // A conversation of a viewer outside the workspace is capped by its own
422
+ // task usage limit; without the producer that cap cannot be stored, so
423
+ // their Site agents stay off. Members run under the workspace's normal
424
+ // session limits and need no Site cap.
425
+ if (viewer.kind !== "member" && !sessionUsageLimitsProducerEnabled(deps.settings))
426
+ return "usage_limits_disabled";
427
+ if (viewer.kind === "guest" && !limits.guestAgentsEnabled) return "guest_agents_disabled";
428
+ if (viewer.kind === "user" && !deps.settings.sitesPublicAgentsEnabled)
429
+ return "public_agents_disabled";
430
+ return null;
431
+ }
432
+
433
+ const AGENT_REFUSAL_MESSAGES: Record<string, string> = {
434
+ agent_disabled: "This Site's assistant is not available to you",
435
+ usage_limits_disabled: "This Site's assistant is not available to you",
436
+ guest_agents_disabled: "Sign in to use this Site's assistant",
437
+ public_agents_disabled: "This Site's assistant is only available to invited people",
438
+ };
439
+
440
+ export function requireSiteAgent(
441
+ deps: SiteRuntimeDeps,
442
+ host: SiteRuntimeHost,
443
+ viewer: SiteRuntimeViewer,
444
+ limits: SiteLimits,
445
+ ): void {
446
+ const reason = siteAgentRefusal(deps, host, viewer, limits);
447
+ if (reason)
448
+ throw siteNotAvailableForViewer(
449
+ "agent",
450
+ AGENT_REFUSAL_MESSAGES[reason] ?? "This Site's assistant is not available to you",
451
+ { reason },
452
+ );
453
+ }
454
+
455
+ function budgetExhausted(budget: string, message: string) {
456
+ return sitePublishingError(429, "limit_exceeded", "site_budget_exhausted", message, { budget });
457
+ }
458
+
459
+ const BUDGET_MESSAGES: Record<SiteRuntimeBudget, string> = {
460
+ conversations_per_visitor_per_day:
461
+ "You have started as many conversations as this Site allows today",
462
+ conversations_per_site_per_day:
463
+ "This Site's assistant has started as many conversations as it allows today",
464
+ turns_per_conversation: "This conversation has reached its message limit; start a new one",
465
+ agent_micros_per_conversation: "This conversation has reached its budget; start a new one",
466
+ agent_micros_per_visitor_per_day:
467
+ "You have used this Site's assistant as much as it allows today",
468
+ agent_micros_per_visitor_per_month:
469
+ "You have used this Site's assistant as much as it allows this month",
470
+ agent_micros_per_site_per_day: "This Site's assistant has reached its limit for today",
471
+ agent_micros_per_site_per_month: "This Site's assistant has reached its limit for this month",
472
+ };
473
+
474
+ /** The 429 for a refused reservation. */
475
+ export function siteBudgetExhausted(budget: SiteRuntimeBudget) {
476
+ return budgetExhausted(budget, BUDGET_MESSAGES[budget]);
477
+ }
478
+
479
+ /** Seconds a viewer waits before retrying a start or message refused as busy. */
480
+ export const SITE_BUDGET_BUSY_RETRY_SECONDS = 30;
481
+
482
+ /**
483
+ * The 429 when only other running conversations' reservations refuse a
484
+ * reservation: the budget has room once their spend settles, so it is worth
485
+ * retrying shortly (`site_budget_busy`, with `retryAfterSeconds`).
486
+ */
487
+ export function siteBudgetBusy(budget: SiteRuntimeBudget) {
488
+ return sitePublishingError(
489
+ 429,
490
+ "limit_exceeded",
491
+ "site_budget_busy",
492
+ "This Site's assistant is busy right now; try again in a moment",
493
+ { budget, retryAfterSeconds: SITE_BUDGET_BUSY_RETRY_SECONDS },
494
+ );
495
+ }
496
+
497
+ /** The 429 for a refused reservation, busy or exhausted. */
498
+ export function siteReservationRefused(result: Extract<SiteRuntimeReservation, { ok: false }>) {
499
+ return result.busy ? siteBudgetBusy(result.budget) : siteBudgetExhausted(result.budget);
500
+ }
501
+
502
+ /**
503
+ * The budgets a conversation start or message is reserved against. Members
504
+ * reserve nothing (their caps are all null). For everyone else a
505
+ * conversation is bounded by the per-conversation cap, else by the smallest
506
+ * spend limit that applies, so a session usage limit always holds it.
507
+ */
508
+ export function siteRuntimeBudgetLimits(
509
+ limits: SiteLimits,
510
+ settings: Pick<SiteRuntimeDeps["settings"], "sitesAgentReservationMicrosPerTurn">,
511
+ ): SiteRuntimeBudgetLimits {
512
+ const spend = [
513
+ limits.agentMicrosPerVisitorPerDay,
514
+ limits.agentMicrosPerVisitorPerMonth,
515
+ limits.agentMicrosPerSitePerDay,
516
+ limits.agentMicrosPerSitePerMonth,
517
+ ].filter((value): value is number => value !== null && value !== undefined);
518
+ return {
519
+ conversationsPerVisitorPerDay: limits.conversationsPerVisitorPerDay,
520
+ conversationsPerSitePerDay: limits.conversationsPerSitePerDay,
521
+ turnsPerConversation: limits.turnsPerConversation,
522
+ agentMicrosPerConversation:
523
+ limits.agentMicrosPerConversation ?? (spend.length > 0 ? Math.min(...spend) : null),
524
+ agentMicrosPerVisitorPerDay: limits.agentMicrosPerVisitorPerDay,
525
+ agentMicrosPerVisitorPerMonth: limits.agentMicrosPerVisitorPerMonth,
526
+ agentMicrosPerSitePerDay: limits.agentMicrosPerSitePerDay,
527
+ agentMicrosPerSitePerMonth: limits.agentMicrosPerSitePerMonth,
528
+ turnReservationMicros: settings.sitesAgentReservationMicrosPerTurn,
529
+ };
530
+ }
531
+
532
+ /**
533
+ * The Site-wide usage windows a viewer's conversations count in: members
534
+ * count apart (`*members`), so they never use up the Site limit.
535
+ */
536
+ export function siteRuntimeBudgetKey(viewer: Pick<SiteRuntimeViewer, "kind">): string {
537
+ return viewer.kind === "member" ? SITE_RUNTIME_MEMBERS_PRINCIPAL : SITE_RUNTIME_SITE_PRINCIPAL;
538
+ }
539
+
540
+ /** Whether a refusal is a Site-wide budget (stale reservations of others may free it). */
541
+ export function siteWideBudget(result: SiteRuntimeReservation): boolean {
542
+ return (
543
+ !result.ok &&
544
+ (result.budget === "agent_micros_per_site_per_month" ||
545
+ result.budget === "agent_micros_per_site_per_day")
546
+ );
547
+ }
548
+
549
+ const IDLE_SESSION_STATUSES = new Set(["idle", "failed", "cancelled"]);
550
+ /** A start whose session has not appeared after this long failed before its create committed. */
551
+ const ABANDONED_START_MS = SITE_RUNTIME_ABANDONED_START_MINUTES * 60_000;
552
+
553
+ /** A conversation's session usage as read while settling. */
554
+ export type SiteConversationUsage = {
555
+ usedMicros: number;
556
+ limitMicros: number | null;
557
+ version: number;
558
+ };
559
+
560
+ /**
561
+ * Bring a conversation's counted spend up to its session usage so far and
562
+ * release what it no longer needs reserved (all of it once the session is
563
+ * idle, or when `release` says so). A start whose session never appeared is
564
+ * released entirely. A read failure leaves the counters as they are; the
565
+ * session's own usage limit still caps the conversation.
566
+ */
567
+ export async function settleSiteRuntimeSpend(
568
+ deps: SiteRuntimeDeps,
569
+ host: SiteRuntimeHost,
570
+ conversation: Pick<SiteRuntimeConversationRecord, "sessionId" | "admissions"> &
571
+ Partial<Pick<SiteRuntimeConversationRecord, "createdAt">>,
572
+ options: { release?: boolean } = {},
573
+ ): Promise<SiteConversationUsage | null> {
574
+ const { sessionId } = conversation;
575
+ try {
576
+ const session = await getSession(deps.db, host.scope.workspaceId, sessionId);
577
+ if (session === null) {
578
+ if (
579
+ conversation.createdAt &&
580
+ Date.now() - conversation.createdAt.getTime() > ABANDONED_START_MS
581
+ )
582
+ await releaseSiteRuntimeConversationStart(deps.db, host.scope, { sessionId });
583
+ return null;
584
+ }
585
+ const read = await readSessionUsageLimit(deps.db, {
586
+ ...host.scope,
587
+ sessionId,
588
+ runtime: true,
589
+ });
590
+ if (read.outcome !== "ok" || read.state.usedMicros === null) return null;
591
+ const usage = {
592
+ usedMicros: read.state.usedMicros,
593
+ limitMicros: read.state.limitMicros,
594
+ version: read.state.version,
595
+ };
596
+ await settleSiteRuntimeConversationSpend(deps.db, host.scope, {
597
+ sessionId,
598
+ usedMicros: usage.usedMicros,
599
+ idle: options.release === true || IDLE_SESSION_STATUSES.has(session.status),
600
+ expected: { admissions: conversation.admissions },
601
+ });
602
+ return usage;
603
+ } catch (error) {
604
+ console.warn("[site-runtime] could not settle conversation spend", {
605
+ siteId: host.site.id,
606
+ error: error instanceof Error ? error.message : String(error),
607
+ });
608
+ return null;
609
+ }
610
+ }
611
+
612
+ /**
613
+ * Lift the session usage limit a Site stamped on a workspace member's
614
+ * conversation before members were kept out of Site limits: cleared only
615
+ * while it is still exactly the Site's cap (`siteCapMicros`), so a limit
616
+ * someone set on the session since is kept. Failure refuses admission; the
617
+ * caller retains its durable normalization marker and retries next time.
618
+ */
619
+ export async function liftSiteConversationUsageLimit(
620
+ deps: SiteRuntimeDeps,
621
+ host: SiteRuntimeHost,
622
+ sessionId: string,
623
+ siteCapMicros: number,
624
+ usage: SiteConversationUsage | null,
625
+ ): Promise<void> {
626
+ let current = usage;
627
+ if (current === null) {
628
+ const read = await readSessionUsageLimit(deps.db, {
629
+ ...host.scope,
630
+ sessionId,
631
+ runtime: true,
632
+ }).catch(() => null);
633
+ if (read?.outcome !== "ok")
634
+ throw sitePublishingError(
635
+ 503,
636
+ "upstream_unavailable",
637
+ "site_conversation_unavailable",
638
+ "The conversation cannot continue right now",
639
+ );
640
+ current = {
641
+ usedMicros: read.state.usedMicros ?? 0,
642
+ limitMicros: read.state.limitMicros,
643
+ version: read.state.version,
644
+ };
645
+ }
646
+ if (current.limitMicros !== siteCapMicros) return;
647
+ const { version } = current;
648
+ const result = await withWorkspaceSessionActivityRls(
649
+ deps.db,
650
+ host.scope.workspaceId,
651
+ async (tx) =>
652
+ await setSessionUsageLimitInTransaction(tx, {
653
+ ...host.scope,
654
+ sessionId,
655
+ limitMicros: null,
656
+ expectedVersion: version,
657
+ operationId: `site-runtime-member-uncap:${sessionId}:${version}`,
658
+ actor: { type: "host", subjectId: `site:${host.site.id}` },
659
+ producerEnabled: sessionUsageLimitsProducerEnabled(deps.settings),
660
+ }),
661
+ ).catch(() => null);
662
+ if (result?.outcome !== "ok" && result?.outcome !== "replayed")
663
+ throw sitePublishingError(
664
+ 503,
665
+ "upstream_unavailable",
666
+ "site_conversation_unavailable",
667
+ "The conversation cannot continue right now",
668
+ );
669
+ }
670
+
671
+ /**
672
+ * Stamp only funded execution: cumulative spend plus the current reservation,
673
+ * bounded by the conversation cap. Top-ups reserve atomically before this
674
+ * raises the ceiling; reread under the reservation lock so overlapping
675
+ * admissions cannot stamp a stale larger allowance. Failure refuses work.
676
+ */
677
+ export async function capSiteConversationUsageLimit(
678
+ deps: SiteRuntimeDeps,
679
+ host: SiteRuntimeHost,
680
+ sessionId: string,
681
+ usage: SiteConversationUsage | null,
682
+ ): Promise<void> {
683
+ let current = usage;
684
+ for (let attempt = 0; attempt < 2; attempt += 1) {
685
+ if (current === null) {
686
+ const read = await readSessionUsageLimit(deps.db, {
687
+ ...host.scope,
688
+ sessionId,
689
+ runtime: true,
690
+ }).catch(() => null);
691
+ current =
692
+ read?.outcome === "ok"
693
+ ? {
694
+ usedMicros: read.state.usedMicros ?? 0,
695
+ limitMicros: read.state.limitMicros,
696
+ version: read.state.version,
697
+ }
698
+ : null;
699
+ if (current === null) break;
700
+ }
701
+ const { version } = current;
702
+ const result = await withWorkspaceSessionActivityRls(
703
+ deps.db,
704
+ host.scope.workspaceId,
705
+ async (tx) => {
706
+ const funded = await siteRuntimeFundedLimitInTransaction(tx, host.scope, sessionId);
707
+ if (funded === null) throw new Error("Non-member conversation has no funded ceiling");
708
+ return await setSessionUsageLimitInTransaction(tx, {
709
+ ...host.scope,
710
+ sessionId,
711
+ limitMicros: funded,
712
+ expectedVersion: version,
713
+ operationId: `site-runtime-cap:${sessionId}:${version}:${funded}`,
714
+ actor: { type: "host", subjectId: `site:${host.site.id}` },
715
+ producerEnabled: sessionUsageLimitsProducerEnabled(deps.settings),
716
+ });
717
+ },
718
+ ).catch(() => null);
719
+ if (result?.outcome === "ok" || result?.outcome === "replayed") return;
720
+ current = null;
721
+ }
722
+ throw sitePublishingError(
723
+ 503,
724
+ "upstream_unavailable",
725
+ "site_conversation_unavailable",
726
+ "The conversation cannot continue right now",
727
+ );
728
+ }
729
+
730
+ /** Reservations claimed per sweep. */
731
+ const STALE_RESERVATION_SWEEP = 20;
732
+ /** After a sweep that found nothing, the Site is not swept again for this long (per process). */
733
+ const EMPTY_SWEEP_COOLDOWN_MS = 5_000;
734
+ const emptySweeps = new Map<string, number>();
735
+
736
+ /**
737
+ * Release reservations that conversations no longer need, so a Site-wide
738
+ * budget held by finished, abandoned or long-inactive conversations frees
739
+ * up. Claims a bounded batch of likely candidates (idle sessions, starts
740
+ * whose session never appeared, reservations inactive for six hours),
741
+ * least recently visited first and each at most every 30 seconds, and
742
+ * settles each. A sweep that finds nothing pauses sweeping the Site for a
743
+ * few seconds, so refused starts in a burst cost one cheap check at most.
744
+ * Returns whether any reservation was visited.
745
+ */
746
+ export async function sweepSiteRuntimeReservations(
747
+ deps: SiteRuntimeDeps,
748
+ host: SiteRuntimeHost,
749
+ ): Promise<boolean> {
750
+ const now = Date.now();
751
+ if ((emptySweeps.get(host.site.id) ?? 0) > now - EMPTY_SWEEP_COOLDOWN_MS) return false;
752
+ const candidates = await claimSiteRuntimeReservationSweep(deps.db, host.scope, {
753
+ siteId: host.site.id,
754
+ limit: STALE_RESERVATION_SWEEP,
755
+ });
756
+ if (candidates.length === 0) {
757
+ if (emptySweeps.size > 10_000) emptySweeps.clear();
758
+ emptySweeps.set(host.site.id, now);
759
+ return false;
760
+ }
761
+ emptySweeps.delete(host.site.id);
762
+ for (const candidate of candidates)
763
+ await settleSiteRuntimeSpend(deps, host, candidate, { release: candidate.aged });
764
+ return true;
765
+ }
766
+
767
+ /** Usage-only metering for Site runtime events (agent spend is metered by the session itself). */
768
+ export async function meterSiteRuntime(
769
+ deps: SiteRuntimeDeps,
770
+ host: SiteRuntimeHost,
771
+ event: { type: "conversation" | "sign_in" | "report"; viewer?: SiteRuntimeViewer },
772
+ ): Promise<void> {
773
+ try {
774
+ await withRlsContext(deps.db, host.scope, async (tx) => {
775
+ await recordUsageEvent(tx, {
776
+ accountId: host.scope.accountId,
777
+ workspaceId: host.scope.workspaceId,
778
+ subjectId: event.viewer?.subjectId ?? null,
779
+ eventType: `site_runtime.${event.type}`,
780
+ quantity: 1,
781
+ unit: event.type,
782
+ sourceResourceType: "site",
783
+ sourceResourceId: host.site.id,
784
+ idempotencyKey: `site_runtime.${event.type}:${crypto.randomUUID()}`,
785
+ });
786
+ });
787
+ } catch (error) {
788
+ console.warn("[site-runtime] could not meter usage", {
789
+ siteId: host.site.id,
790
+ type: event.type,
791
+ error: error instanceof Error ? error.message : String(error),
792
+ });
793
+ }
794
+ }
795
+
796
+ // --- in-process dispatch ------------------------------------------------------------
797
+
798
+ /**
799
+ * Run an ordinary session route in this process as the Site's service
800
+ * principal (`site:<siteId>`), with a 60-second delegated token carrying only
801
+ * session permissions and the viewer as its display label. The Site and the
802
+ * served version ride along as the request's Site origin, so new sessions and
803
+ * turns record where they came from. The route authorizes as usual.
804
+ */
805
+ export async function siteRuntimeSessionRequest(
806
+ deps: SiteRuntimeDeps,
807
+ host: SiteRuntimeHost & { versionId: string },
808
+ viewer: SiteRuntimeViewer,
809
+ input: {
810
+ origin: string;
811
+ method: string;
812
+ path: string;
813
+ body?: unknown;
814
+ extraPermissions?: readonly Permission[];
815
+ },
816
+ ): Promise<Request> {
817
+ return await siteServiceSessionRequest(
818
+ deps,
819
+ host.scope,
820
+ { id: host.site.id, versionId: host.versionId },
821
+ { ...input, label: `${siteRuntimeViewerLabel(viewer)} on ${host.hostname}` },
822
+ );
823
+ }
824
+
825
+ /** A forwarded response without cookies (site-runtime never sets any). */
826
+ export function siteRuntimeForwardedResponse(response: Response): Response {
827
+ const headers = new Headers(response.headers);
828
+ headers.delete("set-cookie");
829
+ headers.set("cache-control", "no-store");
830
+ return new Response(response.body, { status: response.status, headers });
831
+ }