@opengeni/api-router 3.0.1 → 3.0.2-canary.38894290271001
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.
- package/dist/access-grant-rls.d.ts +8 -1
- package/dist/admission-trace.d.ts +8 -0
- package/dist/app.d.ts +50 -3
- package/dist/app.js +10 -1
- package/dist/artifact-catalog-cursor.d.ts +1 -0
- package/dist/attached-browser-viewer.d.ts +11 -0
- package/dist/auth/managed-auth-attempt-context.d.ts +2 -0
- package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
- package/dist/auth/managed-auth-session-adapter.d.ts +9 -1
- package/dist/auth/managed-auth.d.ts +72 -5
- package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
- package/dist/auth/new-signups-gate.d.ts +23 -0
- package/dist/auth/signup-funnel-metrics.d.ts +44 -0
- package/dist/azure-live.d.ts +28 -0
- package/dist/browser-action-fences.d.ts +13 -0
- package/dist/browser-controller-authority.d.ts +1 -61
- package/dist/browser-ephemeral.d.ts +5 -0
- package/dist/browser-lost-runtime-end.d.ts +24 -0
- package/dist/browser-state-authority.d.ts +1 -27
- package/dist/{chunk-AJ62T5QN.js → chunk-GBUJ2DYZ.js} +80507 -39878
- package/dist/chunk-GBUJ2DYZ.js.map +1 -0
- package/dist/chunk-OGQDXVXY.js +18 -0
- package/dist/chunk-OGQDXVXY.js.map +1 -0
- package/dist/claude-default-models.d.ts +19 -0
- package/dist/claude-subscription-core.d.ts +50 -0
- package/dist/claude-subscription-oauth.d.ts +36 -0
- package/dist/claude-subscription-profile.d.ts +9 -0
- package/dist/claude-subscription-usage.d.ts +6 -0
- package/dist/claude-workspace-connection.d.ts +15 -0
- package/dist/codemode.d.ts +40 -5
- package/dist/codex-realtime.d.ts +29 -3
- package/dist/codex-session-pointers.d.ts +19 -0
- package/dist/connection-ownership.d.ts +6 -3
- package/dist/controller-data-plane.d.ts +16 -0
- package/dist/credit-promotion-snapshot.d.ts +6 -0
- package/dist/editable-artifact-source-session.d.ts +3 -0
- package/dist/editable-artifact-websocket.d.ts +5 -3
- package/dist/fatal-process-boundary.d.ts +9 -1
- package/dist/github-access.d.ts +7 -1
- package/dist/github-browser-flow.d.ts +1 -1
- package/dist/http/acting-person.d.ts +36 -0
- package/dist/http/api-contract-compat.d.ts +19 -0
- package/dist/http/api-error.d.ts +50 -1
- package/dist/http/auth.d.ts +8 -1
- package/dist/http/cors.d.ts +12 -0
- package/dist/http/deprecation.d.ts +42 -0
- package/dist/http/keyed-admission.d.ts +12 -0
- package/dist/http/local-browser-boundary.d.ts +72 -0
- package/dist/http/metrics-listener.d.ts +22 -0
- package/dist/http/path-identifier.d.ts +17 -0
- package/dist/http/registered-route-label.d.ts +16 -0
- package/dist/http/rejection-telemetry.d.ts +34 -0
- package/dist/http/request-body.d.ts +27 -0
- package/dist/http/request-source.d.ts +41 -3
- package/dist/http/sse.d.ts +12 -1
- package/dist/http/unmatched-route.d.ts +18 -0
- package/dist/http/user-content.d.ts +36 -0
- package/dist/http/variable-sets-removed.d.ts +41 -0
- package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
- package/dist/index.js +1279 -108
- package/dist/index.js.map +1 -1
- package/dist/integration-connect-metrics.d.ts +35 -0
- package/dist/integration-endpoint-test.d.ts +20 -0
- package/dist/integrations/api-integrations.d.ts +2 -2
- package/dist/integrations/atlassian.d.ts +8 -3
- package/dist/integrations/fiken.d.ts +3 -1
- package/dist/integrations/github-lens-connect.d.ts +37 -66
- package/dist/integrations/google-drive.d.ts +2 -0
- package/dist/integrations/integration-commit-authority.d.ts +13 -0
- package/dist/integrations/marketplace-plugin.d.ts +43 -43
- package/dist/integrations/oauth-client.d.ts +171 -12
- package/dist/integrations/oauth-profiles.d.ts +42 -13
- package/dist/integrations/onepassword-vault-provider.d.ts +9 -0
- package/dist/integrations/slack-bot.d.ts +285 -7
- package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
- package/dist/integrations/slack-interactions.d.ts +89 -10
- package/dist/integrations/slack-mrkdwn.d.ts +41 -0
- package/dist/integrations/slack-routing.d.ts +1 -1
- package/dist/integrations/slack-session-defaults.d.ts +58 -0
- package/dist/integrations/slack-task-file-upload.d.ts +36 -0
- package/dist/integrations/slack-tool-review.d.ts +5 -0
- package/dist/interaction-agent-access.d.ts +13 -8
- package/dist/interaction-agent-version.d.ts +21 -0
- package/dist/interaction-holder-heartbeat.d.ts +5 -0
- package/dist/interaction-metrics.d.ts +27 -2
- package/dist/interaction-route-stages.d.ts +25 -0
- package/dist/interaction-secrets-vault.d.ts +20 -0
- package/dist/interaction-secrets.d.ts +103 -0
- package/dist/mcp/action-catalog-types.d.ts +14 -0
- package/dist/mcp/action-catalog.gen.d.ts +2 -0
- package/dist/mcp/action-descriptions.d.ts +4 -0
- package/dist/mcp/action-schema-imports.gen.d.ts +1 -0
- package/dist/mcp/capability-account-readiness.d.ts +7 -0
- package/dist/mcp/child-read-evidence.d.ts +9 -0
- package/dist/mcp/company-profile-agent-admin.d.ts +12 -0
- package/dist/mcp/contract-input.d.ts +13 -0
- package/dist/mcp/documents.d.ts +2 -0
- package/dist/mcp/first-party-tool-permissions.d.ts +3 -606
- package/dist/mcp/notification-tools.d.ts +26 -0
- package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
- package/dist/mcp/scheduled-task-input.d.ts +1309 -0
- package/dist/mcp/scheduled-task-view.d.ts +217 -3
- package/dist/mcp/secret-tools.d.ts +14 -0
- package/dist/mcp/server.d.ts +108 -5
- package/dist/mcp/session-admin-access-tools.d.ts +33 -0
- package/dist/mcp/session-event-errors.d.ts +28 -0
- package/dist/mcp/session-event-view.d.ts +62 -0
- package/dist/mcp/session-view.d.ts +15 -0
- package/dist/mcp/session-wait.d.ts +18 -0
- package/dist/mcp/site-agent-clamp-tools.d.ts +38 -0
- package/dist/mcp/site-data-tools.d.ts +22 -0
- package/dist/mcp/site-publication-tools.d.ts +19 -0
- package/dist/mcp/site-sql-tools.d.ts +27 -0
- package/dist/mcp-oauth.d.ts +37 -4
- package/dist/model-calls/chat-completions.d.ts +87 -0
- package/dist/model-calls/pending-usage-settlements.d.ts +57 -0
- package/dist/model-calls/service.d.ts +36 -0
- package/dist/model-catalog.d.ts +9 -3
- package/dist/native-push-dispatch.d.ts +69 -0
- package/dist/observability.d.ts +3 -1
- package/dist/organization-mcp.d.ts +82 -0
- package/dist/prepared-mcp-actor.d.ts +77 -0
- package/dist/prepared-mcp-permissions.d.ts +8 -0
- package/dist/routes/analytics-consent.d.ts +26 -0
- package/dist/routes/api-integrations.d.ts +11 -0
- package/dist/routes/api-keys.d.ts +7 -7
- package/dist/routes/automations.d.ts +2 -0
- package/dist/routes/billing.d.ts +59 -0
- package/dist/routes/browser-sessions.d.ts +65 -2
- package/dist/routes/chat-completions.d.ts +11 -0
- package/dist/routes/claude-core-usage.d.ts +20 -0
- package/dist/routes/claude-subscription-accounts.d.ts +3 -0
- package/dist/routes/claude-subscription-oauth.d.ts +3 -0
- package/dist/routes/client-errors.d.ts +182 -0
- package/dist/routes/codex-core.d.ts +401 -0
- package/dist/routes/codex.d.ts +64 -2
- package/dist/routes/computer-sessions.d.ts +6 -1
- package/dist/routes/desktop-distribution.d.ts +32 -0
- package/dist/routes/github-browser-fonts.gen.d.ts +2 -0
- package/dist/routes/github-browser-pages.d.ts +27 -0
- package/dist/routes/inbox.d.ts +13 -0
- package/dist/routes/insights-response-cache.d.ts +10 -0
- package/dist/routes/insights-usage.d.ts +12 -0
- package/dist/routes/insights.d.ts +28 -0
- package/dist/routes/interaction-placement-message.d.ts +7 -0
- package/dist/routes/managed-sign-in-methods.d.ts +6 -0
- package/dist/routes/model-account-choice.d.ts +13 -0
- package/dist/routes/model-account-settings.d.ts +19 -0
- package/dist/routes/native-app-auth.d.ts +12 -0
- package/dist/routes/organization-integration-policy.d.ts +8 -0
- package/dist/routes/organization-integrations.d.ts +6 -0
- package/dist/routes/organization-mcp-connections.d.ts +3 -0
- package/dist/routes/organization-model-defaults.d.ts +9 -0
- package/dist/routes/organization-service-accounts.d.ts +3 -0
- package/dist/routes/personal-api-keys.d.ts +3 -0
- package/dist/routes/session-admin-access.d.ts +3 -0
- package/dist/routes/session-artifact-associations.d.ts +4 -0
- package/dist/routes/session-history-imports.d.ts +20 -0
- package/dist/routes/sessions.d.ts +38 -2
- package/dist/routes/site-data.d.ts +18 -0
- package/dist/routes/site-publishing.d.ts +5 -0
- package/dist/routes/site-runtime.d.ts +31 -0
- package/dist/routes/site-sql.d.ts +16 -0
- package/dist/routes/slack-bot-access.d.ts +3 -0
- package/dist/routes/subscription-account-pools.d.ts +21 -0
- package/dist/routes/subscription-core-http.d.ts +5 -0
- package/dist/routes/subscription-pool-access.d.ts +37 -0
- package/dist/routes/subscription-pool-core.d.ts +153 -0
- package/dist/routes/supergrok.d.ts +6 -6
- package/dist/routes/usage-allowances.d.ts +12 -0
- package/dist/routes/variable-sets-removed.d.ts +2 -0
- package/dist/routes/vault-providers.d.ts +34 -0
- package/dist/routes/vaults.d.ts +3 -0
- package/dist/routes/workspace-integrations.d.ts +35 -0
- package/dist/routes/workspace-model-providers.d.ts +4 -0
- package/dist/routes/workspaces.d.ts +11 -2
- package/dist/sandbox/agent-update.d.ts +64 -0
- package/dist/sandbox/auth-callout.d.ts +8 -0
- package/dist/sandbox/channel-a.d.ts +15 -1
- package/dist/sandbox/enrollment.d.ts +26 -4
- package/dist/sandbox/machine-audience.d.ts +29 -0
- package/dist/sandbox/machines.d.ts +15 -2
- package/dist/sandbox/metrics-ingestion.d.ts +6 -2
- package/dist/sandbox/screen-control.d.ts +85 -0
- package/dist/sandbox/viewer.d.ts +5 -1
- package/dist/sandbox-file-artifacts.d.ts +17 -1
- package/dist/scheduled-task-blockers.d.ts +39 -0
- package/dist/scheduled-task-deletion.d.ts +3 -4
- package/dist/scheduled-task-lifecycle.d.ts +14 -0
- package/dist/secret-answers.d.ts +40 -0
- package/dist/session-create-observability.d.ts +5 -0
- package/dist/session-event-view-36GO3IL7.js +528 -0
- package/dist/session-event-view-36GO3IL7.js.map +1 -0
- package/dist/signed-state-secret.d.ts +18 -0
- package/dist/site-agent-guard.d.ts +53 -0
- package/dist/site-data/operations.d.ts +103 -0
- package/dist/site-data/service.d.ts +203 -0
- package/dist/site-frame-guard.d.ts +32 -0
- package/dist/site-publishing/agent-data-tools.d.ts +84 -0
- package/dist/site-publishing/agent-model.d.ts +58 -0
- package/dist/site-publishing/agent-session.d.ts +16 -0
- package/dist/site-publishing/content-scanner.d.ts +31 -0
- package/dist/site-publishing/edge-sync.d.ts +48 -0
- package/dist/site-publishing/gateway-signature.d.ts +56 -0
- package/dist/site-publishing/limits.d.ts +63 -0
- package/dist/site-publishing/page-tool-authority.d.ts +30 -0
- package/dist/site-publishing/platform-usage.d.ts +113 -0
- package/dist/site-publishing/platform.d.ts +21 -0
- package/dist/site-publishing/readiness.d.ts +62 -0
- package/dist/site-publishing/runtime.d.ts +179 -0
- package/dist/site-publishing/service.d.ts +264 -0
- package/dist/site-publishing/session-events.d.ts +22 -0
- package/dist/site-publishing/session-views.d.ts +36 -0
- package/dist/site-publishing/viewer.d.ts +40 -0
- package/dist/site-session-origin.d.ts +31 -6
- package/dist/site-sql/format.d.ts +47 -0
- package/dist/site-sql/gateway.d.ts +50 -0
- package/dist/site-sql/service.d.ts +213 -0
- package/dist/temporal-schedule-sync.d.ts +26 -0
- package/dist/transcription/billing-refusal.d.ts +8 -0
- package/dist/transcription/normalize.d.ts +23 -0
- package/dist/transcription/providers/azure-mai.d.ts +12 -0
- package/dist/transcription/providers/azure-openai.d.ts +4 -0
- package/dist/transcription/providers/openai.d.ts +16 -0
- package/dist/transcription/providers/subscription-core.d.ts +39 -0
- package/dist/transcription/service.d.ts +10 -1
- package/dist/transcription/wav-duration.d.ts +8 -0
- package/dist/workspace-tool-gateway-attestations.d.ts +37 -0
- package/dist/workspace-tool-gateway-observability.d.ts +16 -0
- package/dist/workspace-tool-gateway-secrets.d.ts +27 -0
- package/dist/workspace-tool-gateway.d.ts +102 -6
- package/dist/workspace-tool-target-fence.d.ts +116 -0
- package/dist/workspace-tool-target.d.ts +225 -0
- package/dist/workspace-webhook-dispatch.d.ts +26 -0
- package/dist/xai-subscription-core.d.ts +60 -0
- package/package.json +25 -20
- package/src/access-grant-rls.ts +64 -14
- package/src/admission-trace.ts +14 -0
- package/src/app.ts +1684 -252
- package/src/artifact-catalog-cursor.ts +1 -0
- package/src/attached-browser-viewer.ts +26 -0
- package/src/auth/managed-auth-attempt-context.ts +9 -0
- package/src/auth/managed-auth-rate-limits.ts +252 -0
- package/src/auth/managed-auth-session-adapter.ts +64 -29
- package/src/auth/managed-auth.ts +303 -35
- package/src/auth/managed-email.ts +18 -1
- package/src/auth/managed-sign-in-notifications.ts +81 -0
- package/src/auth/new-signups-gate.ts +49 -0
- package/src/auth/organization-user-setup.ts +3 -3
- package/src/auth/signup-funnel-metrics.ts +164 -0
- package/src/azure-live.ts +103 -0
- package/src/browser-action-fences.ts +45 -0
- package/src/browser-controller-authority.ts +1 -186
- package/src/browser-ephemeral.ts +39 -0
- package/src/browser-lost-runtime-end.ts +71 -0
- package/src/browser-state-authority.ts +1 -236
- package/src/claude-default-models.ts +37 -0
- package/src/claude-subscription-core.ts +154 -0
- package/src/claude-subscription-oauth.ts +352 -0
- package/src/claude-subscription-profile.ts +73 -0
- package/src/claude-subscription-usage.ts +51 -0
- package/src/claude-workspace-connection.ts +82 -0
- package/src/codemode.ts +236 -39
- package/src/codex-realtime.ts +181 -53
- package/src/codex-session-pointers.ts +80 -0
- package/src/company-brain-okf.ts +1 -1
- package/src/connected-machine-computer-access.ts +2 -1
- package/src/connection-ownership.ts +19 -13
- package/src/controller-data-plane.ts +34 -0
- package/src/credit-promotion-snapshot.ts +36 -0
- package/src/editable-artifact-production.ts +10 -0
- package/src/editable-artifact-source-session.ts +123 -0
- package/src/editable-artifact-websocket.ts +16 -3
- package/src/fatal-process-boundary.ts +67 -3
- package/src/gateway-realtime.ts +12 -8
- package/src/github-access.ts +31 -5
- package/src/github-browser-flow.ts +1 -1
- package/src/http/acting-person.ts +105 -0
- package/src/http/api-contract-compat.ts +49 -0
- package/src/http/api-error.ts +210 -2
- package/src/http/auth.ts +68 -4
- package/src/http/cors.ts +37 -5
- package/src/http/deprecation.ts +118 -0
- package/src/http/keyed-admission.ts +29 -0
- package/src/http/local-browser-boundary.ts +343 -0
- package/src/http/metrics-listener.ts +57 -0
- package/src/http/path-identifier.ts +54 -0
- package/src/http/registered-route-label.ts +34 -0
- package/src/http/rejection-telemetry.ts +120 -0
- package/src/http/request-body.ts +127 -0
- package/src/http/request-source.ts +154 -13
- package/src/http/sse.ts +88 -28
- package/src/http/unmatched-route.ts +60 -0
- package/src/http/user-content.ts +158 -0
- package/src/http/variable-sets-removed.ts +122 -0
- package/src/http/websocket-upgrade-dispatch.ts +29 -0
- package/src/index.ts +107 -57
- package/src/integration-connect-metrics.ts +228 -0
- package/src/integration-endpoint-test.ts +291 -0
- package/src/integrations/api-integrations.ts +81 -7
- package/src/integrations/atlassian.ts +202 -83
- package/src/integrations/fiken.ts +66 -38
- package/src/integrations/github-app-connect.ts +64 -18
- package/src/integrations/github-lens-connect.ts +8 -29
- package/src/integrations/google-drive.ts +448 -152
- package/src/integrations/integration-commit-authority.ts +69 -0
- package/src/integrations/marketplace-plugin.ts +1 -1
- package/src/integrations/oauth-client.ts +733 -193
- package/src/integrations/oauth-profiles.ts +116 -45
- package/src/integrations/onepassword-vault-provider.ts +16 -0
- package/src/integrations/personal-github-repositories.ts +1 -1
- package/src/integrations/personal-github.ts +61 -35
- package/src/integrations/provider-oauth.ts +67 -85
- package/src/integrations/slack-app-home.ts +5 -5
- package/src/integrations/slack-bot.ts +893 -201
- package/src/integrations/slack-file-upload-flow.ts +147 -0
- package/src/integrations/slack-install.ts +7 -7
- package/src/integrations/slack-interactions.ts +1589 -299
- package/src/integrations/slack-mrkdwn.ts +193 -0
- package/src/integrations/slack-routing.ts +2 -2
- package/src/integrations/slack-session-defaults.ts +224 -0
- package/src/integrations/slack-task-file-upload.ts +323 -0
- package/src/integrations/slack-tool-review.ts +65 -0
- package/src/integrations/social-oauth.ts +90 -58
- package/src/interaction-agent-access.ts +40 -20
- package/src/interaction-agent-version.ts +85 -0
- package/src/interaction-holder-heartbeat.ts +24 -8
- package/src/interaction-metrics.ts +164 -2
- package/src/interaction-route-stages.ts +94 -0
- package/src/interaction-secrets-vault.ts +213 -0
- package/src/interaction-secrets.ts +426 -0
- package/src/mcp/action-catalog-types.ts +14 -0
- package/src/mcp/action-catalog.gen.ts +8014 -0
- package/src/mcp/action-descriptions.ts +299 -0
- package/src/mcp/action-schema-imports.gen.ts +304 -0
- package/src/mcp/capability-account-readiness.ts +17 -0
- package/src/mcp/child-read-evidence.ts +19 -0
- package/src/mcp/company-profile-agent-admin.ts +13 -0
- package/src/mcp/contract-input.ts +165 -0
- package/src/mcp/documents.ts +9 -2
- package/src/mcp/editable-artifacts.ts +29 -11
- package/src/mcp/files.ts +5 -1
- package/src/mcp/first-party-tool-permissions.ts +7 -285
- package/src/mcp/knowledge-entries.ts +108 -34
- package/src/mcp/notification-tools.ts +480 -0
- package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
- package/src/mcp/scheduled-task-input.ts +89 -0
- package/src/mcp/scheduled-task-view.ts +63 -3
- package/src/mcp/secret-tools.ts +185 -0
- package/src/mcp/server.ts +2213 -1116
- package/src/mcp/session-admin-access-tools.ts +163 -0
- package/src/mcp/session-event-errors.ts +123 -0
- package/src/mcp/session-event-view.ts +395 -13
- package/src/mcp/session-view.ts +3 -0
- package/src/mcp/session-wait.ts +67 -7
- package/src/mcp/site-agent-clamp-tools.ts +140 -0
- package/src/mcp/site-data-tools.ts +339 -0
- package/src/mcp/site-publication-tools.ts +201 -0
- package/src/mcp/site-sql-tools.ts +427 -0
- package/src/mcp-oauth.ts +635 -45
- package/src/model-calls/chat-completions.ts +352 -0
- package/src/model-calls/pending-usage-settlements.ts +125 -0
- package/src/model-calls/service.ts +694 -0
- package/src/model-catalog.ts +68 -17
- package/src/native-push-dispatch.ts +457 -0
- package/src/observability.ts +15 -1
- package/src/organization-mcp.ts +485 -0
- package/src/prepared-mcp-actor.ts +154 -0
- package/src/prepared-mcp-permissions.ts +38 -0
- package/src/routes/analytics-consent.ts +123 -0
- package/src/routes/api-integrations.ts +268 -9
- package/src/routes/api-keys.ts +164 -25
- package/src/routes/artifact-catalog.ts +111 -0
- package/src/routes/automations.ts +163 -90
- package/src/routes/billing.ts +535 -59
- package/src/routes/browser-sessions.ts +966 -342
- package/src/routes/canonical-human-identities.ts +61 -0
- package/src/routes/capabilities.ts +112 -5
- package/src/routes/channels.ts +4 -3
- package/src/routes/chat-completions.ts +235 -0
- package/src/routes/claude-core-usage.ts +147 -0
- package/src/routes/claude-subscription-accounts.ts +233 -0
- package/src/routes/claude-subscription-oauth.ts +175 -0
- package/src/routes/client-errors.ts +394 -0
- package/src/routes/codex-core.ts +687 -0
- package/src/routes/codex.ts +1277 -1119
- package/src/routes/company-brain.ts +4 -0
- package/src/routes/computer-sessions.ts +319 -85
- package/src/routes/connect.ts +277 -175
- package/src/routes/connections.ts +690 -363
- package/src/routes/desktop-distribution.ts +217 -0
- package/src/routes/documents.ts +13 -7
- package/src/routes/editable-artifacts.ts +74 -4
- package/src/routes/enrollments.ts +110 -16
- package/src/routes/external-identity-links.ts +13 -12
- package/src/routes/files.ts +41 -16
- package/src/routes/github-browser-fonts.gen.ts +12 -0
- package/src/routes/github-browser-pages.ts +258 -0
- package/src/routes/github.ts +200 -75
- package/src/routes/inbox.ts +353 -0
- package/src/routes/insights-response-cache.ts +83 -0
- package/src/routes/insights-usage.ts +345 -0
- package/src/routes/insights.ts +103 -8
- package/src/routes/install.ts +51 -10
- package/src/routes/integration-facets.ts +70 -28
- package/src/routes/interaction-placement-message.ts +12 -0
- package/src/routes/knowledge.ts +136 -27
- package/src/routes/machines.ts +189 -135
- package/src/routes/managed-auth-session-sets.ts +43 -10
- package/src/routes/managed-onboarding.ts +39 -19
- package/src/routes/managed-sign-in-methods.ts +433 -0
- package/src/routes/memory-slack-publications.ts +3 -2
- package/src/routes/model-account-choice.ts +194 -0
- package/src/routes/model-account-settings.ts +235 -0
- package/src/routes/model-connection-access.ts +210 -48
- package/src/routes/native-app-auth.ts +296 -0
- package/src/routes/organization-integration-policy.ts +116 -0
- package/src/routes/organization-integrations.ts +326 -0
- package/src/routes/organization-mcp-connections.ts +183 -0
- package/src/routes/organization-memberships.ts +205 -19
- package/src/routes/organization-model-defaults.ts +110 -0
- package/src/routes/organization-model-providers.ts +74 -3
- package/src/routes/organization-service-accounts.ts +128 -0
- package/src/routes/organization-sessions.ts +21 -5
- package/src/routes/personal-api-keys.ts +184 -0
- package/src/routes/personal-github-git-broker.ts +2 -2
- package/src/routes/personal-github.ts +9 -4
- package/src/routes/plugins.ts +46 -7
- package/src/routes/pr-review-github.ts +105 -118
- package/src/routes/pr-review.ts +88 -82
- package/src/routes/preference-registry.ts +18 -0
- package/src/routes/rigs.ts +48 -13
- package/src/routes/scheduled-tasks.ts +347 -27
- package/src/routes/session-admin-access.ts +271 -0
- package/src/routes/session-artifact-associations.ts +164 -0
- package/src/routes/session-history-imports.ts +305 -0
- package/src/routes/sessions.ts +1682 -363
- package/src/routes/site-data.ts +340 -0
- package/src/routes/site-publishing.ts +584 -0
- package/src/routes/site-runtime.ts +1944 -0
- package/src/routes/site-sql.ts +263 -0
- package/src/routes/skill-content.ts +72 -7
- package/src/routes/skills.ts +5 -4
- package/src/routes/slack-bot-access.ts +108 -0
- package/src/routes/social.ts +27 -15
- package/src/routes/subscription-account-pools.ts +209 -0
- package/src/routes/subscription-core-http.ts +18 -0
- package/src/routes/subscription-pool-access.ts +180 -0
- package/src/routes/subscription-pool-core.ts +552 -0
- package/src/routes/supergrok.ts +174 -655
- package/src/routes/transcription-recordings.ts +71 -4
- package/src/routes/transcriptions.ts +26 -2
- package/src/routes/usage-allowances.ts +381 -0
- package/src/routes/variable-sets-removed.ts +19 -0
- package/src/routes/vault-providers.ts +782 -0
- package/src/routes/vaults.ts +421 -0
- package/src/routes/video-generation.ts +30 -12
- package/src/routes/workspace-artifacts.ts +165 -53
- package/src/routes/workspace-integrations.ts +576 -0
- package/src/routes/workspace-model-providers.ts +148 -0
- package/src/routes/workspace-state.ts +4 -0
- package/src/routes/workspaces.ts +625 -117
- package/src/sandbox/agent-update.ts +315 -0
- package/src/sandbox/auth-callout.ts +104 -21
- package/src/sandbox/channel-a.ts +150 -49
- package/src/sandbox/enrollment.ts +131 -22
- package/src/sandbox/machine-audience.ts +192 -0
- package/src/sandbox/machines.ts +75 -31
- package/src/sandbox/metrics-ingestion.ts +133 -2
- package/src/sandbox/rematerialize.ts +51 -21
- package/src/sandbox/screen-control.ts +289 -0
- package/src/sandbox/viewer.ts +33 -58
- package/src/sandbox-file-artifacts.ts +53 -27
- package/src/scheduled-task-blockers.ts +293 -0
- package/src/scheduled-task-deletion.ts +13 -3
- package/src/scheduled-task-lifecycle.ts +84 -0
- package/src/secret-answers.ts +119 -0
- package/src/session-create-observability.ts +46 -0
- package/src/session-realtime-context.ts +26 -4
- package/src/signed-state-secret.ts +58 -0
- package/src/site-agent-guard.ts +261 -0
- package/src/site-data/operations.ts +777 -0
- package/src/site-data/service.ts +1043 -0
- package/src/site-frame-guard.ts +107 -0
- package/src/site-publishing/agent-data-tools.ts +250 -0
- package/src/site-publishing/agent-model.ts +127 -0
- package/src/site-publishing/agent-session.ts +148 -0
- package/src/site-publishing/content-scanner.ts +93 -0
- package/src/site-publishing/edge-sync.ts +148 -0
- package/src/site-publishing/gateway-signature.ts +198 -0
- package/src/site-publishing/limits.ts +315 -0
- package/src/site-publishing/page-tool-authority.ts +111 -0
- package/src/site-publishing/platform-usage.ts +479 -0
- package/src/site-publishing/platform.ts +98 -0
- package/src/site-publishing/readiness.ts +330 -0
- package/src/site-publishing/runtime.ts +831 -0
- package/src/site-publishing/service.ts +1282 -0
- package/src/site-publishing/session-events.ts +262 -0
- package/src/site-publishing/session-views.ts +262 -0
- package/src/site-publishing/viewer.ts +75 -0
- package/src/site-session-origin.ts +91 -6
- package/src/site-sql/format.ts +134 -0
- package/src/site-sql/gateway.ts +168 -0
- package/src/site-sql/service.ts +1636 -0
- package/src/site-uploads.ts +27 -5
- package/src/temporal-schedule-sync.ts +74 -0
- package/src/transcription/billing-refusal.ts +14 -0
- package/src/transcription/normalize.ts +77 -0
- package/src/transcription/providers/azure-mai.ts +98 -0
- package/src/transcription/providers/azure-openai.ts +16 -7
- package/src/transcription/providers/codex-subscription.ts +190 -67
- package/src/transcription/providers/openai.ts +79 -5
- package/src/transcription/providers/subscription-core.ts +125 -0
- package/src/transcription/providers/xai-subscription.ts +81 -83
- package/src/transcription/segmenter.ts +7 -1
- package/src/transcription/service.ts +239 -10
- package/src/transcription/wav-duration.ts +39 -0
- package/src/workspace-deletion.ts +25 -1
- package/src/workspace-tool-gateway-attestations.ts +133 -0
- package/src/workspace-tool-gateway-observability.ts +64 -0
- package/src/workspace-tool-gateway-secrets.ts +104 -0
- package/src/workspace-tool-gateway.ts +921 -103
- package/src/workspace-tool-target-fence.ts +380 -0
- package/src/workspace-tool-target.ts +554 -0
- package/src/workspace-webhook-dispatch.ts +225 -0
- package/src/xai-realtime.ts +85 -81
- package/src/xai-subscription-core.ts +172 -0
- package/dist/browser-auth-broker.d.ts +0 -20
- package/dist/chunk-AJ62T5QN.js.map +0 -1
- package/dist/connection-authority-owner.d.ts +0 -59
- package/dist/routes/connection-authorities.d.ts +0 -3
- package/dist/routes/environments.d.ts +0 -5
- package/dist/routes/host-mcp-bindings.d.ts +0 -5
- package/dist/routes/host-mcp-resolvers.d.ts +0 -3
- package/dist/routes/packs.d.ts +0 -3
- package/dist/session-event-view-MU3HMNV3.js +0 -264
- package/dist/session-event-view-MU3HMNV3.js.map +0 -1
- package/dist/xai-subscription-auth.d.ts +0 -23
- package/src/browser-auth-broker.ts +0 -155
- package/src/connection-authority-owner.ts +0 -61
- package/src/routes/connection-authorities.ts +0 -139
- package/src/routes/environments.ts +0 -388
- package/src/routes/host-mcp-bindings.ts +0 -122
- package/src/routes/host-mcp-resolvers.ts +0 -41
- package/src/routes/packs.ts +0 -784
- package/src/xai-subscription-auth.ts +0 -139
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { Settings } from "@opengeni/config";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pluggable content scanning for published Sites. `none` is the default; the
|
|
5
|
+
* Google Web Risk scanner runs only with OPENGENI_SITES_WEB_RISK_API_KEY. A
|
|
6
|
+
* scan looks up the absolute URLs found in a Site's HTML when it is published
|
|
7
|
+
* and records findings for moderation. It never blocks publishing, and a
|
|
8
|
+
* disabled or failing scanner records nothing that blocks either.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export type SiteContentScanFinding = { url: string; threatTypes: string[] };
|
|
12
|
+
export type SiteContentScanResult = {
|
|
13
|
+
status: "none" | "clean" | "flagged" | "error";
|
|
14
|
+
findings: SiteContentScanFinding[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type SiteContentScanner = {
|
|
18
|
+
readonly name: "none" | "web_risk";
|
|
19
|
+
scanHtml(html: string): Promise<SiteContentScanResult>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** Most distinct URLs one scan looks up (bounds cost per publish). */
|
|
23
|
+
export const SITE_SCAN_MAX_URLS = 20;
|
|
24
|
+
|
|
25
|
+
/** Distinct absolute http(s) URLs in the HTML, first seen first, at most `limit`. */
|
|
26
|
+
export function siteHtmlUrls(html: string, limit = SITE_SCAN_MAX_URLS): string[] {
|
|
27
|
+
const found = new Set<string>();
|
|
28
|
+
for (const match of html.matchAll(/https?:\/\/[^\s"'<>`()\\]{1,2000}/giu)) {
|
|
29
|
+
let url: URL;
|
|
30
|
+
try {
|
|
31
|
+
url = new URL(match[0]);
|
|
32
|
+
} catch {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
found.add(url.toString());
|
|
36
|
+
if (found.size >= limit) break;
|
|
37
|
+
}
|
|
38
|
+
return [...found];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const noneSiteContentScanner: SiteContentScanner = Object.freeze({
|
|
42
|
+
name: "none" as const,
|
|
43
|
+
scanHtml: async () => ({ status: "none" as const, findings: [] }),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const WEB_RISK_THREATS = ["MALWARE", "SOCIAL_ENGINEERING", "UNWANTED_SOFTWARE"];
|
|
47
|
+
|
|
48
|
+
export function createWebRiskSiteContentScanner(
|
|
49
|
+
apiKey: string,
|
|
50
|
+
options: { fetch?: typeof fetch } = {},
|
|
51
|
+
): SiteContentScanner {
|
|
52
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
53
|
+
return {
|
|
54
|
+
name: "web_risk",
|
|
55
|
+
async scanHtml(html) {
|
|
56
|
+
const urls = siteHtmlUrls(html);
|
|
57
|
+
if (urls.length === 0) return { status: "clean", findings: [] };
|
|
58
|
+
const findings: SiteContentScanFinding[] = [];
|
|
59
|
+
try {
|
|
60
|
+
for (const url of urls) {
|
|
61
|
+
const query = new URLSearchParams();
|
|
62
|
+
for (const threat of WEB_RISK_THREATS) query.append("threatTypes", threat);
|
|
63
|
+
query.set("uri", url);
|
|
64
|
+
query.set("key", apiKey);
|
|
65
|
+
const response = await fetchImpl(
|
|
66
|
+
`https://webrisk.googleapis.com/v1/uris:search?${query.toString()}`,
|
|
67
|
+
{ method: "GET" },
|
|
68
|
+
);
|
|
69
|
+
if (!response.ok) throw new Error(`Web Risk lookup failed with ${response.status}`);
|
|
70
|
+
const body = (await response.json().catch(() => ({}))) as {
|
|
71
|
+
threat?: { threatTypes?: unknown };
|
|
72
|
+
};
|
|
73
|
+
const types = Array.isArray(body.threat?.threatTypes)
|
|
74
|
+
? body.threat.threatTypes.filter((type): type is string => typeof type === "string")
|
|
75
|
+
: [];
|
|
76
|
+
if (types.length > 0) findings.push({ url, threatTypes: types });
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
return { status: "error", findings };
|
|
80
|
+
}
|
|
81
|
+
return { status: findings.length > 0 ? "flagged" : "clean", findings };
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function createSiteContentScanner(
|
|
87
|
+
settings: Pick<Settings, "sitesWebRiskApiKey">,
|
|
88
|
+
options: { fetch?: typeof fetch } = {},
|
|
89
|
+
): SiteContentScanner {
|
|
90
|
+
return settings.sitesWebRiskApiKey
|
|
91
|
+
? createWebRiskSiteContentScanner(settings.sitesWebRiskApiKey, options)
|
|
92
|
+
: noneSiteContentScanner;
|
|
93
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { SiteHostMapRecord, siteHostMapKey } from "@opengeni/contracts";
|
|
2
|
+
import type { Settings } from "@opengeni/config";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Optional Cloudflare edge sync for published Sites. Postgres is the source
|
|
6
|
+
* of truth; the KV host map and the edge cache are rebuildable copies. With
|
|
7
|
+
* no Cloudflare settings every call is a no-op.
|
|
8
|
+
*
|
|
9
|
+
* Writes go through the Cloudflare REST API with plain fetch (no SDK, each
|
|
10
|
+
* call bounded by a 10 s timeout) and never block the database write: callers
|
|
11
|
+
* schedule them after commit, each is retried a few times and then logged.
|
|
12
|
+
* The caller reads what a hostname should hold in a short transaction under
|
|
13
|
+
* the hostname's lock and commits before any of these calls, so no database
|
|
14
|
+
* transaction or lock waits on Cloudflare; after writing it re-reads the
|
|
15
|
+
* hostname and writes again if it moved meanwhile. One process runs at most
|
|
16
|
+
* one sync per hostname at a time. A writer never replaces a newer
|
|
17
|
+
* generation (read, compare, write; KV has no compare-and-set, so writers in
|
|
18
|
+
* two processes racing within one round trip can still land out of order,
|
|
19
|
+
* until the entry's TTL ends it). Generations come from one database
|
|
20
|
+
* sequence shared by every hostname, so a later change to a label (a move,
|
|
21
|
+
* an unpublish tombstone, a takedown) always carries a higher generation
|
|
22
|
+
* than anything written before.
|
|
23
|
+
*
|
|
24
|
+
* Staleness bound: the API itself refuses a suspended or unpublished Site on
|
|
25
|
+
* the very next site-runtime call (it re-checks publication status and access
|
|
26
|
+
* every time). The edge copies lag behind: Cloudflare KV propagates a write
|
|
27
|
+
* to other locations within about 60 s, every KV entry expires after
|
|
28
|
+
* `sitesHostMapTtlSeconds` (default 300 s), and the gateway caches host
|
|
29
|
+
* lookups for up to 60 s and access checks for 30 s. A takedown also purges
|
|
30
|
+
* the host's edge cache when a zone id is configured. The after-commit sync
|
|
31
|
+
* runs in process, so a restart can lose a pending write; the next signed
|
|
32
|
+
* host lookup for that label re-syncs a stale record, and the TTL bounds the
|
|
33
|
+
* rest. A missed sync is therefore corrected within TTL + 60 s at worst.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export type SiteEdgeSyncSettings = Pick<
|
|
37
|
+
Settings,
|
|
38
|
+
| "sitesCloudflareApiToken"
|
|
39
|
+
| "sitesCloudflareAccountId"
|
|
40
|
+
| "sitesCloudflareKvNamespaceId"
|
|
41
|
+
| "sitesCloudflareZoneId"
|
|
42
|
+
| "sitesHostMapTtlSeconds"
|
|
43
|
+
>;
|
|
44
|
+
|
|
45
|
+
export type SiteEdgeSync = {
|
|
46
|
+
readonly kvEnabled: boolean;
|
|
47
|
+
readonly purgeEnabled: boolean;
|
|
48
|
+
/** Write the host-map record unless the edge already holds a newer generation. */
|
|
49
|
+
putHostRecord(record: SiteHostMapRecord): Promise<"written" | "skipped_newer" | "disabled">;
|
|
50
|
+
/** Purge the edge cache for one hostname. */
|
|
51
|
+
purgeHost(hostname: string): Promise<"purged" | "disabled">;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type SiteEdgeSyncOptions = {
|
|
55
|
+
fetch?: typeof fetch;
|
|
56
|
+
attempts?: number;
|
|
57
|
+
backoffMs?: number;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const API = "https://api.cloudflare.com/client/v4";
|
|
61
|
+
const FETCH_TIMEOUT_MS = 10_000;
|
|
62
|
+
|
|
63
|
+
async function withRetries<T>(attempts: number, backoffMs: number, run: () => Promise<T>) {
|
|
64
|
+
let last: unknown;
|
|
65
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
66
|
+
try {
|
|
67
|
+
return await run();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
last = error;
|
|
70
|
+
if (attempt < attempts - 1)
|
|
71
|
+
await new Promise((resolve) => setTimeout(resolve, backoffMs * 2 ** attempt));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
throw last;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function createSiteEdgeSync(
|
|
78
|
+
settings: SiteEdgeSyncSettings,
|
|
79
|
+
options: SiteEdgeSyncOptions = {},
|
|
80
|
+
): SiteEdgeSync {
|
|
81
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
82
|
+
const attempts = Math.max(1, options.attempts ?? 3);
|
|
83
|
+
const backoffMs = Math.max(0, options.backoffMs ?? 250);
|
|
84
|
+
const token = settings.sitesCloudflareApiToken;
|
|
85
|
+
const account = settings.sitesCloudflareAccountId;
|
|
86
|
+
const namespace = settings.sitesCloudflareKvNamespaceId;
|
|
87
|
+
const zone = settings.sitesCloudflareZoneId;
|
|
88
|
+
const kvEnabled = Boolean(token && account && namespace);
|
|
89
|
+
const purgeEnabled = Boolean(token && zone);
|
|
90
|
+
const headers = { authorization: `Bearer ${token ?? ""}` };
|
|
91
|
+
const valueUrl = (key: string) =>
|
|
92
|
+
`${API}/accounts/${encodeURIComponent(account ?? "")}/storage/kv/namespaces/${encodeURIComponent(
|
|
93
|
+
namespace ?? "",
|
|
94
|
+
)}/values/${encodeURIComponent(key)}`;
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
kvEnabled,
|
|
98
|
+
purgeEnabled,
|
|
99
|
+
async putHostRecord(record) {
|
|
100
|
+
if (!kvEnabled) return "disabled";
|
|
101
|
+
const parsed = SiteHostMapRecord.parse(record);
|
|
102
|
+
const key = siteHostMapKey(parsed.hostname);
|
|
103
|
+
return await withRetries(attempts, backoffMs, async () => {
|
|
104
|
+
const current = await fetchImpl(valueUrl(key), {
|
|
105
|
+
method: "GET",
|
|
106
|
+
headers,
|
|
107
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
108
|
+
});
|
|
109
|
+
if (current.ok) {
|
|
110
|
+
const existing = SiteHostMapRecord.safeParse(await current.json().catch(() => null));
|
|
111
|
+
if (existing.success && existing.data.generation > parsed.generation)
|
|
112
|
+
return "skipped_newer" as const;
|
|
113
|
+
} else if (current.status !== 404) {
|
|
114
|
+
throw new Error(`Cloudflare KV read failed with ${current.status}`);
|
|
115
|
+
} else {
|
|
116
|
+
await current.body?.cancel().catch(() => undefined);
|
|
117
|
+
}
|
|
118
|
+
const ttl = Math.max(60, settings.sitesHostMapTtlSeconds);
|
|
119
|
+
const written = await fetchImpl(`${valueUrl(key)}?expiration_ttl=${ttl}`, {
|
|
120
|
+
method: "PUT",
|
|
121
|
+
headers: { ...headers, "content-type": "application/json" },
|
|
122
|
+
body: JSON.stringify(parsed),
|
|
123
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
124
|
+
});
|
|
125
|
+
if (!written.ok) throw new Error(`Cloudflare KV write failed with ${written.status}`);
|
|
126
|
+
await written.body?.cancel().catch(() => undefined);
|
|
127
|
+
return "written" as const;
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
async purgeHost(hostname) {
|
|
131
|
+
if (!purgeEnabled) return "disabled";
|
|
132
|
+
return await withRetries(attempts, backoffMs, async () => {
|
|
133
|
+
const response = await fetchImpl(
|
|
134
|
+
`${API}/zones/${encodeURIComponent(zone ?? "")}/purge_cache`,
|
|
135
|
+
{
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: { ...headers, "content-type": "application/json" },
|
|
138
|
+
body: JSON.stringify({ hosts: [hostname.toLowerCase()] }),
|
|
139
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
140
|
+
},
|
|
141
|
+
);
|
|
142
|
+
if (!response.ok) throw new Error(`Cloudflare cache purge failed with ${response.status}`);
|
|
143
|
+
await response.body?.cancel().catch(() => undefined);
|
|
144
|
+
return "purged" as const;
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
siteGatewayCanonicalString,
|
|
4
|
+
SITE_GATEWAY_BODY_SHA256_HEADER,
|
|
5
|
+
SITE_GATEWAY_CLIENT_IP_HEADER,
|
|
6
|
+
SITE_GATEWAY_HOST_HEADER,
|
|
7
|
+
SITE_GATEWAY_HUMAN_HEADER,
|
|
8
|
+
SITE_GATEWAY_MAX_SKEW_SECONDS,
|
|
9
|
+
SITE_GATEWAY_SESSION_HEADER,
|
|
10
|
+
SITE_GATEWAY_SIGNATURE_HEADER,
|
|
11
|
+
SITE_GATEWAY_SIGNATURE_VERSION,
|
|
12
|
+
SITE_GATEWAY_TIMESTAMP_HEADER,
|
|
13
|
+
SITE_GATEWAY_VISITOR_HEADER,
|
|
14
|
+
} from "@opengeni/contracts";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Verification of gateway-signed site-runtime requests. The gateway HMACs
|
|
18
|
+
* `siteGatewayCanonicalString` with the shared secret; the API accepts the
|
|
19
|
+
* current or the previous secret (rotation), within 30 s of its clock. The
|
|
20
|
+
* signed body hash travels in its own header, so the signature is checked
|
|
21
|
+
* from the headers alone, before the body is read; the route then hashes the
|
|
22
|
+
* body as it reads it and refuses a body that does not match. Nothing else
|
|
23
|
+
* about the request is trusted before this passes.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
export type SiteGatewayFields = {
|
|
27
|
+
host: string;
|
|
28
|
+
session: string;
|
|
29
|
+
visitor: string;
|
|
30
|
+
clientIp: string;
|
|
31
|
+
human: boolean;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type SiteGatewayVerification =
|
|
35
|
+
| {
|
|
36
|
+
ok: true;
|
|
37
|
+
fields: SiteGatewayFields;
|
|
38
|
+
/** The signed hex SHA-256 the body read afterwards must match. */
|
|
39
|
+
bodySha256: string;
|
|
40
|
+
}
|
|
41
|
+
| {
|
|
42
|
+
ok: false;
|
|
43
|
+
reason:
|
|
44
|
+
| "not_configured"
|
|
45
|
+
| "missing_headers"
|
|
46
|
+
| "bad_timestamp"
|
|
47
|
+
| "skew"
|
|
48
|
+
| "bad_body_hash"
|
|
49
|
+
| "bad_signature"
|
|
50
|
+
| "body_mismatch"
|
|
51
|
+
| "credentials";
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const SHA256_HEX = /^[0-9a-f]{64}$/u;
|
|
55
|
+
|
|
56
|
+
/** Request headers that carry Opengeni app credentials; site-runtime refuses them. */
|
|
57
|
+
export const SITE_RUNTIME_REFUSED_HEADERS: readonly string[] = Object.freeze([
|
|
58
|
+
"authorization",
|
|
59
|
+
"proxy-authorization",
|
|
60
|
+
"cookie",
|
|
61
|
+
"x-api-key",
|
|
62
|
+
"x-opengeni-external-actor",
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
export function sha256Hex(bytes: Uint8Array): string {
|
|
66
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function siteGatewaySignature(secret: string, canonical: string): string {
|
|
70
|
+
return `${SITE_GATEWAY_SIGNATURE_VERSION}=${createHmac("sha256", secret)
|
|
71
|
+
.update(canonical, "utf8")
|
|
72
|
+
.digest("base64url")}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function sameText(expected: string, presented: string): boolean {
|
|
76
|
+
const a = Buffer.from(expected, "utf8");
|
|
77
|
+
const b = Buffer.from(presented, "utf8");
|
|
78
|
+
// Equal-length compare; a length mismatch still spends a compare.
|
|
79
|
+
if (a.length !== b.length) {
|
|
80
|
+
timingSafeEqual(a, a);
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return timingSafeEqual(a, b);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Bounded header value: the gateway never sends long values here. */
|
|
87
|
+
function header(headers: Headers, name: string, max = 512): string | null {
|
|
88
|
+
const value = headers.get(name);
|
|
89
|
+
if (value === null) return null;
|
|
90
|
+
return value.length > max ? null : value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Verify a signed request from its headers alone; the body is not needed.
|
|
95
|
+
* On success the caller reads the body (capped) and checks it against
|
|
96
|
+
* `bodySha256` with `sameSha256Hex`, refusing a mismatch as `body_mismatch`.
|
|
97
|
+
*/
|
|
98
|
+
export function verifySiteGatewayRequest(input: {
|
|
99
|
+
method: string;
|
|
100
|
+
pathWithQuery: string;
|
|
101
|
+
headers: Headers;
|
|
102
|
+
secrets: readonly (string | undefined)[];
|
|
103
|
+
nowMs?: number;
|
|
104
|
+
}): SiteGatewayVerification {
|
|
105
|
+
const secrets = input.secrets.filter((secret): secret is string => Boolean(secret));
|
|
106
|
+
if (secrets.length === 0) return { ok: false, reason: "not_configured" };
|
|
107
|
+
const signature = header(input.headers, SITE_GATEWAY_SIGNATURE_HEADER, 128);
|
|
108
|
+
const timestampText = header(input.headers, SITE_GATEWAY_TIMESTAMP_HEADER, 16);
|
|
109
|
+
const host = header(input.headers, SITE_GATEWAY_HOST_HEADER, 253);
|
|
110
|
+
const bodySha256 = input.headers.get(SITE_GATEWAY_BODY_SHA256_HEADER);
|
|
111
|
+
if (!signature || !timestampText || !host || bodySha256 === null)
|
|
112
|
+
return { ok: false, reason: "missing_headers" };
|
|
113
|
+
if (!/^\d{1,12}$/u.test(timestampText)) return { ok: false, reason: "bad_timestamp" };
|
|
114
|
+
const timestamp = Number(timestampText);
|
|
115
|
+
const now = Math.floor((input.nowMs ?? Date.now()) / 1000);
|
|
116
|
+
if (Math.abs(now - timestamp) > SITE_GATEWAY_MAX_SKEW_SECONDS)
|
|
117
|
+
return { ok: false, reason: "skew" };
|
|
118
|
+
// The hash must be lowercase hex, exactly as the gateway signs it.
|
|
119
|
+
if (!SHA256_HEX.test(bodySha256)) return { ok: false, reason: "bad_body_hash" };
|
|
120
|
+
const session = header(input.headers, SITE_GATEWAY_SESSION_HEADER) ?? "";
|
|
121
|
+
const visitor = header(input.headers, SITE_GATEWAY_VISITOR_HEADER) ?? "";
|
|
122
|
+
const clientIp = header(input.headers, SITE_GATEWAY_CLIENT_IP_HEADER, 64) ?? "";
|
|
123
|
+
const human = header(input.headers, SITE_GATEWAY_HUMAN_HEADER, 8) ?? "";
|
|
124
|
+
const canonical = siteGatewayCanonicalString({
|
|
125
|
+
method: input.method,
|
|
126
|
+
host,
|
|
127
|
+
pathWithQuery: input.pathWithQuery,
|
|
128
|
+
timestamp,
|
|
129
|
+
bodySha256,
|
|
130
|
+
session,
|
|
131
|
+
visitor,
|
|
132
|
+
clientIp,
|
|
133
|
+
human,
|
|
134
|
+
});
|
|
135
|
+
// Check every configured secret, so timing does not reveal which one matched.
|
|
136
|
+
let matched = false;
|
|
137
|
+
for (const secret of secrets)
|
|
138
|
+
matched = sameText(siteGatewaySignature(secret, canonical), signature) || matched;
|
|
139
|
+
if (!matched) return { ok: false, reason: "bad_signature" };
|
|
140
|
+
// Signed requests never carry app credentials; a request that does is refused.
|
|
141
|
+
if (SITE_RUNTIME_REFUSED_HEADERS.some((name) => input.headers.has(name)))
|
|
142
|
+
return { ok: false, reason: "credentials" };
|
|
143
|
+
return {
|
|
144
|
+
ok: true,
|
|
145
|
+
fields: { host: host.toLowerCase(), session, visitor, clientIp, human: human === "1" },
|
|
146
|
+
bodySha256,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Whether two hex digests are equal, compared in constant time. */
|
|
151
|
+
export function sameSha256Hex(actual: string, signed: string): boolean {
|
|
152
|
+
return sameText(actual, signed);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Sign a request as the gateway does (tests and local tools). */
|
|
156
|
+
export function signSiteGatewayRequest(input: {
|
|
157
|
+
secret: string;
|
|
158
|
+
method: string;
|
|
159
|
+
pathWithQuery: string;
|
|
160
|
+
host: string;
|
|
161
|
+
body?: Uint8Array | string;
|
|
162
|
+
session?: string;
|
|
163
|
+
visitor?: string;
|
|
164
|
+
clientIp?: string;
|
|
165
|
+
human?: boolean;
|
|
166
|
+
nowMs?: number;
|
|
167
|
+
}): Record<string, string> {
|
|
168
|
+
const body =
|
|
169
|
+
typeof input.body === "string"
|
|
170
|
+
? new TextEncoder().encode(input.body)
|
|
171
|
+
: (input.body ?? new Uint8Array());
|
|
172
|
+
const timestamp = Math.floor((input.nowMs ?? Date.now()) / 1000);
|
|
173
|
+
const fields = {
|
|
174
|
+
session: input.session ?? "",
|
|
175
|
+
visitor: input.visitor ?? "",
|
|
176
|
+
clientIp: input.clientIp ?? "",
|
|
177
|
+
human: input.human ? "1" : "",
|
|
178
|
+
};
|
|
179
|
+
const bodySha256 = sha256Hex(body);
|
|
180
|
+
const canonical = siteGatewayCanonicalString({
|
|
181
|
+
method: input.method,
|
|
182
|
+
host: input.host,
|
|
183
|
+
pathWithQuery: input.pathWithQuery,
|
|
184
|
+
timestamp,
|
|
185
|
+
bodySha256,
|
|
186
|
+
...fields,
|
|
187
|
+
});
|
|
188
|
+
return {
|
|
189
|
+
[SITE_GATEWAY_BODY_SHA256_HEADER]: bodySha256,
|
|
190
|
+
[SITE_GATEWAY_TIMESTAMP_HEADER]: String(timestamp),
|
|
191
|
+
[SITE_GATEWAY_SIGNATURE_HEADER]: siteGatewaySignature(input.secret, canonical),
|
|
192
|
+
[SITE_GATEWAY_HOST_HEADER]: input.host,
|
|
193
|
+
...(fields.session ? { [SITE_GATEWAY_SESSION_HEADER]: fields.session } : {}),
|
|
194
|
+
...(fields.visitor ? { [SITE_GATEWAY_VISITOR_HEADER]: fields.visitor } : {}),
|
|
195
|
+
...(fields.clientIp ? { [SITE_GATEWAY_CLIENT_IP_HEADER]: fields.clientIp } : {}),
|
|
196
|
+
...(fields.human ? { [SITE_GATEWAY_HUMAN_HEADER]: fields.human } : {}),
|
|
197
|
+
};
|
|
198
|
+
}
|