@opengeni/api-router 0.30.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-grant-rls.d.ts +3 -0
- package/dist/admission-trace.d.ts +8 -0
- package/dist/api-websocket.d.ts +18 -0
- package/dist/app.d.ts +50 -2
- package/dist/app.js +12 -1
- package/dist/artifact-catalog-cursor.d.ts +27 -0
- package/dist/auth/managed-auth-attempt-context.d.ts +10 -0
- package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
- package/dist/auth/managed-auth-session-adapter.d.ts +6 -0
- package/dist/auth/managed-auth.d.ts +102 -3
- package/dist/auth/managed-email.d.ts +29 -0
- package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
- package/dist/auth/new-signups-gate.d.ts +23 -0
- package/dist/auth/organization-user-setup.d.ts +80 -0
- package/dist/auth/signup-funnel-metrics.d.ts +44 -0
- package/dist/browser-controller-authority.d.ts +1 -61
- package/dist/browser-ephemeral.d.ts +5 -0
- package/dist/browser-state-authority.d.ts +1 -27
- package/dist/chunk-6TZ5LG3O.js +123948 -0
- package/dist/chunk-6TZ5LG3O.js.map +1 -0
- package/dist/chunk-OGQDXVXY.js +18 -0
- package/dist/chunk-OGQDXVXY.js.map +1 -0
- package/dist/claude-subscription-account-conflicts.d.ts +1 -0
- package/dist/claude-subscription-account-usage.d.ts +39 -0
- package/dist/claude-subscription-oauth.d.ts +25 -0
- package/dist/claude-subscription-profile.d.ts +9 -0
- package/dist/claude-subscription-usage.d.ts +44 -0
- package/dist/claude-workspace-connection.d.ts +15 -0
- package/dist/codemode.d.ts +32 -1
- package/dist/company-brain-okf.d.ts +24 -0
- package/dist/connected-machine-computer-access.d.ts +11 -0
- package/dist/connection-ownership.d.ts +54 -0
- package/dist/controller-data-plane.d.ts +32 -0
- package/dist/editable-artifact-source-session.d.ts +3 -0
- package/dist/editable-artifact-websocket.d.ts +10 -18
- package/dist/editable-artifact-workspace-files.d.ts +1 -1
- package/dist/fatal-process-boundary.d.ts +25 -0
- package/dist/github-access.d.ts +31 -2
- package/dist/http/acting-person.d.ts +24 -0
- package/dist/http/api-contract-compat.d.ts +19 -0
- package/dist/http/api-error.d.ts +27 -1
- package/dist/http/cors.d.ts +17 -0
- package/dist/http/deprecation.d.ts +42 -0
- package/dist/http/interaction-control-error.d.ts +13 -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/request-body.d.ts +27 -0
- package/dist/http/request-source.d.ts +52 -0
- package/dist/http/sse.d.ts +17 -6
- package/dist/http/unmatched-route.d.ts +18 -0
- package/dist/http/user-content.d.ts +36 -0
- package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.js +1091 -162
- package/dist/index.js.map +1 -1
- package/dist/integration-endpoint-test.d.ts +20 -0
- package/dist/integrations/api-integrations.d.ts +2 -2
- package/dist/integrations/atlassian.d.ts +29 -3
- package/dist/integrations/connect-authority.d.ts +1 -0
- package/dist/integrations/connect-callback-return.d.ts +6 -0
- package/dist/integrations/fiken.d.ts +16 -2
- package/dist/integrations/github-app-connect.d.ts +47 -0
- package/dist/integrations/github-installation-proof.d.ts +3 -0
- package/dist/integrations/github-lens-connect.d.ts +116 -0
- package/dist/integrations/github-skill-source.d.ts +1 -5
- package/dist/integrations/google-drive.d.ts +24 -0
- package/dist/integrations/integration-commit-authority.d.ts +13 -0
- package/dist/integrations/marketplace-plugin.d.ts +2691 -0
- package/dist/integrations/oauth-client.d.ts +178 -18
- package/dist/integrations/oauth-profiles.d.ts +222 -0
- package/dist/integrations/oauth-return-path.d.ts +1 -0
- package/dist/integrations/personal-github-repositories.d.ts +84 -0
- package/dist/integrations/personal-github.d.ts +42 -0
- package/dist/integrations/pr-review-provider.d.ts +22 -0
- package/dist/integrations/provider-oauth.d.ts +19 -1
- package/dist/integrations/slack-app-home.d.ts +24 -0
- package/dist/integrations/slack-bot.d.ts +367 -12
- package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
- package/dist/integrations/slack-install.d.ts +20 -0
- package/dist/integrations/slack-interactions.d.ts +107 -9
- package/dist/integrations/slack-mrkdwn.d.ts +41 -0
- package/dist/integrations/slack-routing.d.ts +120 -0
- package/dist/integrations/slack-session-defaults.d.ts +58 -0
- package/dist/integrations/slack-task-file-upload.d.ts +36 -0
- package/dist/integrations/social-oauth.d.ts +7 -0
- package/dist/interaction-agent-access.d.ts +15 -0
- package/dist/interaction-frame-proxy.d.ts +68 -0
- package/dist/interaction-metrics.d.ts +2 -0
- package/dist/mcp/action-catalog-types.d.ts +9 -0
- package/dist/mcp/action-catalog.gen.d.ts +2 -0
- package/dist/mcp/capability-account-readiness.d.ts +7 -0
- package/dist/mcp/child-read-evidence.d.ts +9 -0
- package/dist/mcp/command-read.d.ts +24 -0
- package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
- package/dist/mcp/contract-input.d.ts +11 -0
- package/dist/mcp/documents.d.ts +7 -5
- package/dist/mcp/files.d.ts +2 -2
- package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
- package/dist/mcp/knowledge-entries.d.ts +5 -0
- package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
- package/dist/mcp/receipts.d.ts +9 -0
- package/dist/mcp/request-abort.d.ts +19 -0
- package/dist/mcp/scheduled-task-input.d.ts +1189 -0
- package/dist/mcp/scheduled-task-view.d.ts +22 -4
- package/dist/mcp/server.d.ts +255 -3
- package/dist/mcp/session-event-view.d.ts +94 -0
- package/dist/mcp/session-view.d.ts +66 -2
- package/dist/mcp/session-wait.d.ts +174 -0
- package/dist/mcp-oauth.d.ts +52 -0
- package/dist/model-catalog.d.ts +11 -31
- package/dist/observability.d.ts +3 -1
- package/dist/organization-mcp.d.ts +52 -0
- package/dist/organization-recovery-notifications.d.ts +41 -0
- package/dist/routes/analytics-consent.d.ts +26 -0
- package/dist/routes/api-integrations.d.ts +25 -0
- package/dist/routes/api-keys.d.ts +17 -0
- package/dist/routes/artifact-catalog.d.ts +6 -0
- package/dist/routes/automations.d.ts +19 -0
- package/dist/routes/billing.d.ts +49 -0
- package/dist/routes/browser-sessions.d.ts +59 -2
- 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 +146 -0
- package/dist/routes/codex.d.ts +76 -2
- package/dist/routes/company-brain.d.ts +3 -0
- package/dist/routes/company-profile.d.ts +2 -1
- package/dist/routes/computer-sessions.d.ts +14 -0
- package/dist/routes/connect.d.ts +5 -0
- package/dist/routes/editable-artifacts.d.ts +2 -0
- package/dist/routes/external-identity-links.d.ts +6 -0
- package/dist/routes/feedback.d.ts +3 -0
- package/dist/routes/github-browser-pages.d.ts +12 -0
- package/dist/routes/github.d.ts +2 -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 +30 -1
- package/dist/routes/knowledge.d.ts +3 -0
- package/dist/routes/managed-auth-session-sets.d.ts +26 -0
- package/dist/routes/managed-onboarding.d.ts +29 -0
- package/dist/routes/managed-sign-in-methods.d.ts +6 -0
- package/dist/routes/model-connection-access.d.ts +3 -0
- package/dist/routes/organization-integration-policy.d.ts +3 -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-providers.d.ts +3 -0
- package/dist/routes/organization-recovery.d.ts +19 -0
- package/dist/routes/organization-service-accounts.d.ts +3 -0
- package/dist/routes/organization-sessions.d.ts +26 -0
- package/dist/routes/personal-github-git-broker.d.ts +29 -0
- package/dist/routes/personal-github.d.ts +3 -0
- package/dist/routes/pr-review-github.d.ts +3 -0
- package/dist/routes/pr-review.d.ts +3 -0
- package/dist/routes/session-artifact-associations.d.ts +4 -0
- package/dist/routes/session-history-imports.d.ts +9 -0
- package/dist/routes/sessions.d.ts +44 -6
- package/dist/routes/skill-content.d.ts +4 -0
- package/dist/routes/skill-install-authority.d.ts +6 -0
- package/dist/routes/subscription-account-pools.d.ts +34 -0
- package/dist/routes/subscription-pool-access.d.ts +16 -0
- package/dist/routes/supergrok.d.ts +6 -1
- package/dist/routes/usage-allowances.d.ts +12 -0
- package/dist/routes/user-resource-authorities.d.ts +3 -0
- package/dist/routes/workspace-artifacts.d.ts +2 -1
- package/dist/routes/workspace-capture.d.ts +10 -2
- package/dist/routes/workspace-integrations.d.ts +35 -0
- package/dist/routes/workspace-learning.d.ts +3 -0
- package/dist/routes/workspace-model-providers.d.ts +4 -0
- package/dist/routes/workspaces.d.ts +29 -0
- package/dist/sandbox/auth-callout.d.ts +8 -0
- package/dist/sandbox/channel-a.d.ts +19 -1
- package/dist/sandbox/connection-authority.d.ts +3 -0
- package/dist/sandbox/enrollment.d.ts +9 -1
- package/dist/sandbox/machines.d.ts +5 -2
- package/dist/sandbox/metrics-ingestion.d.ts +28 -20
- package/dist/sandbox/rematerialize.d.ts +2 -0
- package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
- package/dist/sandbox/viewer.d.ts +26 -1
- package/dist/sandbox-file-artifacts.d.ts +50 -0
- package/dist/scheduled-task-deletion.d.ts +13 -0
- package/dist/session-create-observability.d.ts +5 -0
- package/dist/session-event-view-MPS2OZD3.js +292 -0
- package/dist/session-event-view-MPS2OZD3.js.map +1 -0
- package/dist/site-session-origin.d.ts +13 -0
- package/dist/site-uploads.d.ts +41 -0
- package/dist/slack-reaction-files.d.ts +1 -1
- package/dist/temporal-schedule-cleanup.d.ts +1 -0
- package/dist/temporal-schedule-sync.d.ts +26 -0
- package/dist/transcription/providers/xai-subscription.d.ts +1 -0
- package/dist/transcription/service.d.ts +2 -1
- package/dist/work-discovery-observability.d.ts +33 -0
- package/dist/workspace-artifact-content.d.ts +28 -0
- package/dist/workspace-artifact-provenance.d.ts +7 -0
- package/dist/workspace-delete-observability.d.ts +10 -0
- package/dist/workspace-deletion.d.ts +6 -0
- package/dist/workspace-state-projection.d.ts +3 -5
- package/dist/workspace-tool-gateway-observability.d.ts +17 -0
- package/dist/workspace-tool-gateway.d.ts +123 -0
- package/dist/workspace-webhook-dispatch.d.ts +26 -0
- package/package.json +23 -19
- package/src/access-grant-rls.ts +75 -0
- package/src/admission-trace.ts +14 -0
- package/src/api-websocket.ts +23 -0
- package/src/app.ts +1967 -252
- package/src/artifact-catalog-cursor.ts +60 -0
- package/src/auth/managed-auth-attempt-context.ts +70 -0
- package/src/auth/managed-auth-rate-limits.ts +252 -0
- package/src/auth/managed-auth-session-adapter.ts +222 -0
- package/src/auth/managed-auth.ts +536 -60
- package/src/auth/managed-email.ts +174 -0
- 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 +307 -0
- package/src/auth/signup-funnel-metrics.ts +164 -0
- package/src/browser-controller-authority.ts +1 -186
- package/src/browser-ephemeral.ts +39 -0
- package/src/browser-state-authority.ts +1 -236
- package/src/claude-subscription-account-conflicts.ts +12 -0
- package/src/claude-subscription-account-usage.ts +48 -0
- package/src/claude-subscription-oauth.ts +362 -0
- package/src/claude-subscription-profile.ts +73 -0
- package/src/claude-subscription-usage.ts +97 -0
- package/src/claude-workspace-connection.ts +82 -0
- package/src/codemode.ts +194 -30
- package/src/codex-realtime.ts +8 -2
- package/src/company-brain-okf.ts +340 -0
- package/src/connected-machine-computer-access.ts +33 -0
- package/src/connection-ownership.ts +199 -0
- package/src/controller-data-plane.ts +81 -0
- package/src/editable-artifact-native-kernel.ts +26 -15
- package/src/editable-artifact-office-import.ts +28 -3
- package/src/editable-artifact-production.ts +23 -7
- package/src/editable-artifact-source-session.ts +123 -0
- package/src/editable-artifact-websocket.ts +27 -21
- package/src/editable-artifact-workspace-files.ts +31 -6
- package/src/fatal-process-boundary.ts +246 -0
- package/src/gateway-realtime.ts +1 -1
- package/src/github-access.ts +147 -5
- package/src/http/acting-person.ts +71 -0
- package/src/http/api-contract-compat.ts +49 -0
- package/src/http/api-error.ts +115 -1
- package/src/http/auth.ts +48 -0
- package/src/http/cors.ts +67 -0
- package/src/http/deprecation.ts +118 -0
- package/src/http/interaction-control-error.ts +164 -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/request-body.ts +127 -0
- package/src/http/request-source.ts +178 -0
- package/src/http/sse.ts +486 -132
- package/src/http/unmatched-route.ts +60 -0
- package/src/http/user-content.ts +158 -0
- package/src/http/websocket-upgrade-dispatch.ts +29 -0
- package/src/index.ts +157 -52
- package/src/integration-endpoint-test.ts +291 -0
- package/src/integrations/api-integrations.ts +98 -11
- package/src/integrations/atlassian.ts +474 -136
- package/src/integrations/connect-authority.ts +2 -0
- package/src/integrations/connect-callback-return.ts +86 -0
- package/src/integrations/fiken.ts +354 -64
- package/src/integrations/github-app-connect.ts +435 -0
- package/src/integrations/github-installation-proof.ts +60 -0
- package/src/integrations/github-lens-connect.ts +76 -0
- package/src/integrations/github-skill-source.ts +2 -142
- package/src/integrations/google-drive.ts +717 -225
- package/src/integrations/integration-commit-authority.ts +69 -0
- package/src/integrations/marketplace-plugin.ts +48 -0
- package/src/integrations/oauth-client.ts +1356 -459
- package/src/integrations/oauth-profiles.ts +537 -0
- package/src/integrations/oauth-return-path.ts +18 -0
- package/src/integrations/personal-github-repositories.ts +674 -0
- package/src/integrations/personal-github.ts +825 -0
- package/src/integrations/pr-review-provider.ts +246 -0
- package/src/integrations/provider-oauth.ts +250 -22
- package/src/integrations/slack-app-home.ts +300 -0
- package/src/integrations/slack-bot.ts +963 -239
- package/src/integrations/slack-file-upload-flow.ts +147 -0
- package/src/integrations/slack-install.ts +83 -0
- package/src/integrations/slack-interactions.ts +3167 -474
- package/src/integrations/slack-mrkdwn.ts +193 -0
- package/src/integrations/slack-routing.ts +337 -0
- package/src/integrations/slack-session-defaults.ts +224 -0
- package/src/integrations/slack-task-file-upload.ts +323 -0
- package/src/integrations/social-oauth.ts +213 -15
- package/src/interaction-agent-access.ts +48 -0
- package/src/interaction-frame-proxy.ts +409 -0
- package/src/interaction-metrics.ts +30 -0
- package/src/mcp/action-catalog-types.ts +9 -0
- package/src/mcp/action-catalog.gen.ts +6696 -0
- package/src/mcp/capability-account-readiness.ts +17 -0
- package/src/mcp/child-read-evidence.ts +19 -0
- package/src/mcp/command-read.ts +109 -0
- package/src/mcp/company-profile-agent-admin.ts +198 -0
- package/src/mcp/contract-input.ts +141 -0
- package/src/mcp/documents.ts +65 -377
- package/src/mcp/editable-artifacts.ts +12 -6
- package/src/mcp/files.ts +80 -43
- package/src/mcp/first-party-tool-permissions.ts +305 -0
- package/src/mcp/knowledge-entries.ts +322 -0
- package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
- package/src/mcp/receipts.ts +34 -0
- package/src/mcp/request-abort.ts +44 -0
- package/src/mcp/scheduled-task-input.ts +76 -0
- package/src/mcp/scheduled-task-view.ts +44 -3
- package/src/mcp/server.ts +3030 -1267
- package/src/mcp/session-event-view.ts +383 -0
- package/src/mcp/session-view.ts +84 -3
- package/src/mcp/session-wait.ts +665 -0
- package/src/mcp-oauth.ts +1123 -0
- package/src/model-catalog.ts +91 -333
- package/src/observability.ts +15 -1
- package/src/organization-mcp.ts +397 -0
- package/src/organization-recovery-notifications.ts +103 -0
- package/src/routes/analytics-consent.ts +123 -0
- package/src/routes/api-integrations.ts +364 -74
- package/src/routes/api-keys.ts +336 -10
- package/src/routes/artifact-catalog.ts +279 -0
- package/src/routes/automations.ts +768 -0
- package/src/routes/billing.ts +461 -46
- package/src/routes/browser-sessions.ts +780 -112
- package/src/routes/canonical-human-identities.ts +90 -14
- package/src/routes/capabilities.ts +107 -6
- package/src/routes/channels.ts +20 -3
- package/src/routes/claude-subscription-accounts.ts +334 -0
- package/src/routes/claude-subscription-oauth.ts +142 -0
- package/src/routes/client-errors.ts +362 -0
- package/src/routes/codex.ts +833 -116
- package/src/routes/company-brain.ts +322 -0
- package/src/routes/company-profile.ts +65 -1
- package/src/routes/computer-sessions.ts +557 -106
- package/src/routes/connect.ts +1938 -0
- package/src/routes/connections.ts +1039 -349
- package/src/routes/documents.ts +488 -287
- package/src/routes/editable-artifacts.ts +79 -9
- package/src/routes/enrollments.ts +135 -39
- package/src/routes/environments.ts +154 -58
- package/src/routes/external-identity-links.ts +201 -0
- package/src/routes/feedback.ts +113 -0
- package/src/routes/files.ts +267 -33
- package/src/routes/github-browser-pages.ts +162 -0
- package/src/routes/github.ts +446 -144
- package/src/routes/insights-response-cache.ts +83 -0
- package/src/routes/insights-usage.ts +345 -0
- package/src/routes/insights.ts +153 -19
- package/src/routes/install.ts +133 -38
- package/src/routes/integration-facets.ts +107 -33
- package/src/routes/interaction-resources.ts +30 -3
- package/src/routes/knowledge.ts +488 -0
- package/src/routes/machines.ts +313 -15
- package/src/routes/managed-auth-session-sets.ts +1218 -0
- package/src/routes/managed-onboarding.ts +337 -0
- package/src/routes/managed-sign-in-methods.ts +433 -0
- package/src/routes/memory-slack-publications.ts +3 -2
- package/src/routes/model-connection-access.ts +208 -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 +178 -0
- package/src/routes/organization-memberships.ts +1019 -27
- package/src/routes/organization-model-providers.ts +293 -0
- package/src/routes/organization-recovery.ts +325 -0
- package/src/routes/organization-service-accounts.ts +128 -0
- package/src/routes/organization-sessions.ts +350 -0
- package/src/routes/personal-github-git-broker.ts +785 -0
- package/src/routes/personal-github.ts +370 -0
- package/src/routes/plugins.ts +251 -22
- package/src/routes/pr-review-github.ts +881 -0
- package/src/routes/pr-review.ts +622 -0
- package/src/routes/preference-registry.ts +12 -93
- package/src/routes/rigs.ts +167 -50
- package/src/routes/scheduled-tasks.ts +346 -41
- package/src/routes/session-artifact-associations.ts +87 -0
- package/src/routes/session-history-imports.ts +280 -0
- package/src/routes/sessions.ts +2306 -264
- package/src/routes/skill-content.ts +297 -0
- package/src/routes/skill-install-authority.ts +64 -0
- package/src/routes/skills.ts +62 -9
- package/src/routes/social.ts +46 -18
- package/src/routes/subscription-account-pools.ts +436 -0
- package/src/routes/subscription-pool-access.ts +126 -0
- package/src/routes/supergrok.ts +219 -303
- package/src/routes/transcription-recordings.ts +38 -3
- package/src/routes/transcriptions.ts +4 -0
- package/src/routes/usage-allowances.ts +378 -0
- package/src/routes/user-resource-authorities.ts +138 -0
- package/src/routes/video-generation.ts +14 -10
- package/src/routes/workspace-artifacts.ts +275 -69
- package/src/routes/workspace-capture.ts +21 -0
- package/src/routes/workspace-integrations.ts +576 -0
- package/src/routes/workspace-learning.ts +159 -0
- package/src/routes/workspace-model-providers.ts +148 -0
- package/src/routes/workspace-state.ts +38 -25
- package/src/routes/workspaces.ts +1004 -127
- package/src/sandbox/auth-callout.ts +96 -19
- package/src/sandbox/channel-a.ts +323 -24
- package/src/sandbox/connection-authority.ts +3 -0
- package/src/sandbox/enrollment.ts +81 -6
- package/src/sandbox/machines.ts +218 -76
- package/src/sandbox/metrics-ingestion.ts +411 -62
- package/src/sandbox/rematerialize.ts +121 -19
- package/src/sandbox/session-attach-variable-sets.ts +131 -0
- package/src/sandbox/viewer.ts +280 -25
- package/src/sandbox-file-artifacts.ts +413 -0
- package/src/scheduled-task-deletion.ts +138 -0
- package/src/session-create-observability.ts +46 -0
- package/src/session-realtime-context.ts +6 -3
- package/src/site-session-origin.ts +48 -0
- package/src/site-uploads.ts +224 -0
- package/src/slack-reaction-files.ts +16 -5
- package/src/temporal-schedule-cleanup.ts +13 -0
- package/src/temporal-schedule-sync.ts +74 -0
- package/src/transcription/providers/codex-subscription.ts +2 -0
- package/src/transcription/providers/openai.ts +1 -0
- package/src/transcription/providers/xai-subscription.ts +49 -3
- package/src/transcription/segmenter.ts +8 -2
- package/src/transcription/service.ts +43 -6
- package/src/work-discovery-observability.ts +121 -0
- package/src/workspace-artifact-content.ts +144 -0
- package/src/workspace-artifact-provenance.ts +104 -0
- package/src/workspace-delete-observability.ts +75 -0
- package/src/workspace-deletion.ts +73 -0
- package/src/workspace-state-projection.ts +18 -148
- package/src/workspace-tool-gateway-observability.ts +100 -0
- package/src/workspace-tool-gateway.ts +870 -0
- package/src/workspace-webhook-dispatch.ts +190 -0
- package/src/xai-subscription-auth.ts +9 -2
- package/dist/chunk-WCXHI3FF.js +0 -49920
- package/dist/chunk-WCXHI3FF.js.map +0 -1
- package/dist/routes/packs.d.ts +0 -3
- package/src/routes/packs.ts +0 -729
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { posix } from "node:path";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
SANDBOX_FILE_ARTIFACT_MAX_BYTES,
|
|
6
|
+
SandboxFileArtifactReceipt,
|
|
7
|
+
retainedArtifactReferenceFromFile,
|
|
8
|
+
type AccessGrant,
|
|
9
|
+
type Session,
|
|
10
|
+
} from "@opengeni/contracts";
|
|
11
|
+
import {
|
|
12
|
+
fileOwnerContextForAccess,
|
|
13
|
+
fileOwnerContextForAgent,
|
|
14
|
+
recordWorkspaceUsage,
|
|
15
|
+
requireLimit,
|
|
16
|
+
type ApiRouteDeps,
|
|
17
|
+
type AccessGrantAuthorization,
|
|
18
|
+
} from "@opengeni/core";
|
|
19
|
+
import {
|
|
20
|
+
completeFileUpload,
|
|
21
|
+
getFile,
|
|
22
|
+
prepareGeneratedWorkspaceFile,
|
|
23
|
+
getSessionAuthorityProjection,
|
|
24
|
+
requireWorkspace,
|
|
25
|
+
recordSandboxFilePublication,
|
|
26
|
+
withSessionRlsActorContext,
|
|
27
|
+
} from "@opengeni/db";
|
|
28
|
+
import { retryWhileMissing, type ObjectHead, type ObjectStorage } from "@opengeni/storage";
|
|
29
|
+
import { HTTPException } from "hono/http-exception";
|
|
30
|
+
import {
|
|
31
|
+
isConnectedMachineAbsolutePath,
|
|
32
|
+
relativeConnectedMachinePath,
|
|
33
|
+
resolveConnectedMachinePath,
|
|
34
|
+
type SandboxChannelAService,
|
|
35
|
+
} from "@opengeni/runtime/sandbox";
|
|
36
|
+
|
|
37
|
+
import { withChannelARead } from "./sandbox/channel-a";
|
|
38
|
+
import { sanitizeFilename } from "./routes/files";
|
|
39
|
+
|
|
40
|
+
const FILE_READ_SENTINEL_BYTES = 1;
|
|
41
|
+
const UPLOAD_INTENT_TTL_MS = 60 * 60_000;
|
|
42
|
+
const SANDBOX_ARTIFACT_ABSOLUTE_PATH_MAX_CHARS = 4_096;
|
|
43
|
+
const SANDBOX_ARTIFACT_SAFE_FILENAME_MAX_CHARS = 200;
|
|
44
|
+
|
|
45
|
+
/** Original bytes inherit the already-authorized source session's ownership. */
|
|
46
|
+
export async function publishSandboxFileArtifact(
|
|
47
|
+
deps: ApiRouteDeps,
|
|
48
|
+
input: Parameters<typeof publishSandboxFileArtifactInScope>[1],
|
|
49
|
+
): Promise<SandboxFileArtifactReceipt> {
|
|
50
|
+
const actor = input.authorization
|
|
51
|
+
? await fileOwnerContextForAccess(deps, input.authorization, "files:upload")
|
|
52
|
+
: input.grant.principalKind === "agent_attempt"
|
|
53
|
+
? await fileOwnerContextForAgent(deps, input.grant, "files:upload")
|
|
54
|
+
: { subjectId: input.grant.subjectId, privateFileOwnerSubjectId: null };
|
|
55
|
+
return withSessionRlsActorContext(actor, async () => {
|
|
56
|
+
const [authority, workspace] = await Promise.all([
|
|
57
|
+
getSessionAuthorityProjection(deps.db, input.grant.workspaceId, input.session.id),
|
|
58
|
+
requireWorkspace(deps.db, input.grant.workspaceId),
|
|
59
|
+
]);
|
|
60
|
+
if (!authority) throw new HTTPException(404, { message: "Source session is unavailable" });
|
|
61
|
+
const personal =
|
|
62
|
+
authority.visibility === "user_private" ||
|
|
63
|
+
authority.memoryScope === "user" ||
|
|
64
|
+
workspace.kind === "personal";
|
|
65
|
+
const expectedOwner =
|
|
66
|
+
authority.visibility === "user_private"
|
|
67
|
+
? authority.ownerSubjectId
|
|
68
|
+
: authority.memoryScope === "user"
|
|
69
|
+
? authority.scopeSubjectId
|
|
70
|
+
: actor.privateFileOwnerSubjectId;
|
|
71
|
+
if (personal && (!expectedOwner || actor.privateFileOwnerSubjectId !== expectedOwner))
|
|
72
|
+
throw new HTTPException(403, {
|
|
73
|
+
message: "Personal file publication requires the session owner's authority",
|
|
74
|
+
});
|
|
75
|
+
return withSessionRlsActorContext(
|
|
76
|
+
{ ...actor, privateFileOwnerSubjectId: personal ? (expectedOwner ?? null) : null },
|
|
77
|
+
() => publishSandboxFileArtifactInScope(deps, input),
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function publishSandboxFileArtifactInScope(
|
|
83
|
+
deps: ApiRouteDeps,
|
|
84
|
+
input: {
|
|
85
|
+
grant: AccessGrant;
|
|
86
|
+
authorization?: AccessGrantAuthorization;
|
|
87
|
+
session: Session;
|
|
88
|
+
path: string;
|
|
89
|
+
signal?: AbortSignal | undefined;
|
|
90
|
+
},
|
|
91
|
+
): Promise<SandboxFileArtifactReceipt> {
|
|
92
|
+
if (!deps.settings.sandboxOwnershipEnabled) {
|
|
93
|
+
throw new HTTPException(404, {
|
|
94
|
+
message: "sandbox ownership is not enabled for this deployment",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const storage = deps.objectStorage;
|
|
98
|
+
if (!storage) {
|
|
99
|
+
throw new HTTPException(503, { message: "object storage is not configured" });
|
|
100
|
+
}
|
|
101
|
+
if (!storage.headObject) {
|
|
102
|
+
throw new HTTPException(503, {
|
|
103
|
+
message: "object storage cannot verify immutable artifact files",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const maxArtifactBytes = Math.min(SANDBOX_FILE_ARTIFACT_MAX_BYTES, storage.maxSinglePutSizeBytes);
|
|
108
|
+
if (maxArtifactBytes < 1) {
|
|
109
|
+
throw new HTTPException(503, { message: "object storage cannot accept artifact files" });
|
|
110
|
+
}
|
|
111
|
+
const readLimit = Math.min(25 * 1024 * 1024, maxArtifactBytes + FILE_READ_SENTINEL_BYTES);
|
|
112
|
+
const { path, sandboxPath, read } = await withChannelARead(
|
|
113
|
+
{
|
|
114
|
+
db: deps.db,
|
|
115
|
+
settings: deps.settings,
|
|
116
|
+
bus: deps.bus,
|
|
117
|
+
...(deps.observability ? { observability: deps.observability } : {}),
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
accountId: input.grant.accountId,
|
|
121
|
+
workspaceId: input.grant.workspaceId,
|
|
122
|
+
session: input.session,
|
|
123
|
+
subjectId: input.grant.subjectId,
|
|
124
|
+
...(input.signal ? { waitSignal: input.signal } : {}),
|
|
125
|
+
operation: "artifact.publish",
|
|
126
|
+
},
|
|
127
|
+
({ service }) => readSandboxArtifactFile(service, input.path, readLimit),
|
|
128
|
+
);
|
|
129
|
+
if (read.truncated || read.sizeBytes > maxArtifactBytes) {
|
|
130
|
+
throw new HTTPException(413, {
|
|
131
|
+
message: `sandbox file exceeds the ${maxArtifactBytes}-byte artifact publication limit`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (read.sizeBytes === 0) {
|
|
135
|
+
throw new HTTPException(422, { message: "sandbox artifact file is empty" });
|
|
136
|
+
}
|
|
137
|
+
if (read.encoding !== "base64") {
|
|
138
|
+
throw new HTTPException(502, { message: "sandbox returned an invalid binary file response" });
|
|
139
|
+
}
|
|
140
|
+
const bytes = Buffer.from(read.content, "base64");
|
|
141
|
+
if (bytes.byteLength !== read.sizeBytes) {
|
|
142
|
+
throw new HTTPException(502, { message: "sandbox returned an invalid file length" });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const filename = posix.basename(path);
|
|
146
|
+
if (filename.length > 1_024) {
|
|
147
|
+
throw new HTTPException(422, { message: "sandbox artifact filename is too long" });
|
|
148
|
+
}
|
|
149
|
+
const safeFilename = sandboxArtifactSafeFilename(filename);
|
|
150
|
+
const contentType = sandboxFileContentType(filename);
|
|
151
|
+
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
|
152
|
+
const identity = sandboxArtifactIdentity({
|
|
153
|
+
workspaceId: input.grant.workspaceId,
|
|
154
|
+
sessionId: input.session.id,
|
|
155
|
+
path,
|
|
156
|
+
sha256,
|
|
157
|
+
});
|
|
158
|
+
const objectKey = `workspaces/${input.grant.workspaceId}/files/${identity.fileId}/sandbox/${safeFilename}`;
|
|
159
|
+
const existing = await getFile(deps.db, input.grant.workspaceId, identity.fileId);
|
|
160
|
+
let file = existing;
|
|
161
|
+
|
|
162
|
+
if (!file) {
|
|
163
|
+
await requireLimit(deps, {
|
|
164
|
+
accountId: input.grant.accountId,
|
|
165
|
+
workspaceId: input.grant.workspaceId,
|
|
166
|
+
action: "file:upload",
|
|
167
|
+
quantity: bytes.byteLength,
|
|
168
|
+
});
|
|
169
|
+
const prepared = await prepareGeneratedWorkspaceFile(deps.db, {
|
|
170
|
+
accountId: input.grant.accountId,
|
|
171
|
+
workspaceId: input.grant.workspaceId,
|
|
172
|
+
fileId: identity.fileId,
|
|
173
|
+
uploadId: identity.uploadId,
|
|
174
|
+
filename,
|
|
175
|
+
safeFilename,
|
|
176
|
+
contentType,
|
|
177
|
+
sizeBytes: bytes.byteLength,
|
|
178
|
+
sha256,
|
|
179
|
+
bucket: storage.bucket,
|
|
180
|
+
objectKey,
|
|
181
|
+
expiresAt: new Date(Date.now() + UPLOAD_INTENT_TTL_MS),
|
|
182
|
+
});
|
|
183
|
+
file = prepared.file;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
assertSandboxArtifactFile(file, {
|
|
187
|
+
filename,
|
|
188
|
+
safeFilename,
|
|
189
|
+
contentType,
|
|
190
|
+
sizeBytes: bytes.byteLength,
|
|
191
|
+
sha256,
|
|
192
|
+
bucket: storage.bucket,
|
|
193
|
+
objectKey,
|
|
194
|
+
});
|
|
195
|
+
if (file.status !== "ready") {
|
|
196
|
+
const existingObject = await storage.headObject(file.objectKey);
|
|
197
|
+
if (existingObject) {
|
|
198
|
+
assertStoredSandboxArtifact(existingObject, file);
|
|
199
|
+
} else {
|
|
200
|
+
const put = {
|
|
201
|
+
key: file.objectKey,
|
|
202
|
+
contentType: file.contentType,
|
|
203
|
+
body: bytes,
|
|
204
|
+
sha256,
|
|
205
|
+
};
|
|
206
|
+
if (storage.putObjectIfAbsent) {
|
|
207
|
+
const created = await storage.putObjectIfAbsent(put);
|
|
208
|
+
if (!created) await assertVisibleSandboxArtifact(storage, file);
|
|
209
|
+
} else {
|
|
210
|
+
await storage.putObject(put);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
file = await completeFileUpload(deps.db, input.grant.workspaceId, identity.uploadId);
|
|
214
|
+
} else {
|
|
215
|
+
await assertVisibleSandboxArtifact(storage, file);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
await recordWorkspaceUsage(deps, {
|
|
219
|
+
accountId: input.grant.accountId,
|
|
220
|
+
workspaceId: input.grant.workspaceId,
|
|
221
|
+
subjectId: input.grant.subjectId,
|
|
222
|
+
eventType: "file.uploaded",
|
|
223
|
+
quantity: file.sizeBytes,
|
|
224
|
+
unit: "byte",
|
|
225
|
+
sourceResourceType: "file",
|
|
226
|
+
sourceResourceId: file.id,
|
|
227
|
+
idempotencyKey: `file.uploaded:${input.grant.workspaceId}:${file.id}`,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const artifact = retainedArtifactReferenceFromFile(file, "file");
|
|
231
|
+
if (!artifact) {
|
|
232
|
+
throw new HTTPException(502, { message: "published sandbox artifact is not ready" });
|
|
233
|
+
}
|
|
234
|
+
await recordSandboxFilePublication(deps.db, {
|
|
235
|
+
accountId: input.grant.accountId,
|
|
236
|
+
workspaceId: input.grant.workspaceId,
|
|
237
|
+
fileId: file.id,
|
|
238
|
+
sourceSessionId: input.session.id,
|
|
239
|
+
});
|
|
240
|
+
return SandboxFileArtifactReceipt.parse({
|
|
241
|
+
type: "sandbox_file",
|
|
242
|
+
sandboxPath,
|
|
243
|
+
filename,
|
|
244
|
+
artifact,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Use the root captured by the same fenced Channel-A service that reads bytes,
|
|
249
|
+
* not the session's placement-home label or a caller-supplied root. */
|
|
250
|
+
export async function readSandboxArtifactFile(
|
|
251
|
+
service: Pick<SandboxChannelAService, "capabilities" | "fsRead">,
|
|
252
|
+
value: string,
|
|
253
|
+
maxBytes: number,
|
|
254
|
+
) {
|
|
255
|
+
const root = service.capabilities().FileSystem.root;
|
|
256
|
+
const path = sandboxArtifactRelativePath(value, root);
|
|
257
|
+
const sandboxPath = resolveConnectedMachinePath(root, path);
|
|
258
|
+
const read = await service.fsRead({ path, encoding: "base64", maxBytes });
|
|
259
|
+
return { path, sandboxPath, read };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function sandboxArtifactRelativePath(value: string, workspaceRoot = "/workspace"): string {
|
|
263
|
+
let path = value.trim();
|
|
264
|
+
if (path.startsWith("sandbox:")) {
|
|
265
|
+
path = path.slice("sandbox:".length);
|
|
266
|
+
}
|
|
267
|
+
if (!path || /[\\/]$/.test(path)) {
|
|
268
|
+
throw new HTTPException(400, { message: "sandbox artifact path must name a file" });
|
|
269
|
+
}
|
|
270
|
+
let absolute: string;
|
|
271
|
+
let relative: string | null;
|
|
272
|
+
try {
|
|
273
|
+
if (!isConnectedMachineAbsolutePath(workspaceRoot)) throw new Error("Missing workspace root");
|
|
274
|
+
absolute = resolveConnectedMachinePath(workspaceRoot, path);
|
|
275
|
+
relative = relativeConnectedMachinePath(workspaceRoot, absolute);
|
|
276
|
+
} catch {
|
|
277
|
+
throw new HTTPException(400, {
|
|
278
|
+
message: "sandbox artifact path is invalid for this workspace",
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
if (!relative) {
|
|
282
|
+
throw new HTTPException(400, {
|
|
283
|
+
message: "sandbox artifact path must name a file inside the active workspace root",
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
if (absolute.length > SANDBOX_ARTIFACT_ABSOLUTE_PATH_MAX_CHARS) {
|
|
287
|
+
throw new HTTPException(400, { message: "sandbox artifact path is too long" });
|
|
288
|
+
}
|
|
289
|
+
return relative;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export function sandboxArtifactSafeFilename(filename: string): string {
|
|
293
|
+
return sanitizeFilename(filename).slice(0, SANDBOX_ARTIFACT_SAFE_FILENAME_MAX_CHARS);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function sandboxFileContentType(filename: string): string {
|
|
297
|
+
const extension = posix.extname(filename).toLowerCase();
|
|
298
|
+
return (
|
|
299
|
+
{
|
|
300
|
+
".csv": "text/csv",
|
|
301
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
302
|
+
".gz": "application/gzip",
|
|
303
|
+
".html": "text/html",
|
|
304
|
+
".htm": "text/html",
|
|
305
|
+
".jpeg": "image/jpeg",
|
|
306
|
+
".jpg": "image/jpeg",
|
|
307
|
+
".json": "application/json",
|
|
308
|
+
".md": "text/markdown",
|
|
309
|
+
".mp4": "video/mp4",
|
|
310
|
+
".webm": "video/webm",
|
|
311
|
+
".ogv": "video/ogg",
|
|
312
|
+
".mp3": "audio/mpeg",
|
|
313
|
+
".m4a": "audio/mp4",
|
|
314
|
+
".ogg": "audio/ogg",
|
|
315
|
+
".wav": "audio/wav",
|
|
316
|
+
".flac": "audio/flac",
|
|
317
|
+
".pdf": "application/pdf",
|
|
318
|
+
".png": "image/png",
|
|
319
|
+
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
320
|
+
".tar": "application/x-tar",
|
|
321
|
+
".txt": "text/plain",
|
|
322
|
+
".webp": "image/webp",
|
|
323
|
+
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
324
|
+
".zip": "application/zip",
|
|
325
|
+
}[extension] ?? "application/octet-stream"
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export function sandboxArtifactIdentity(input: {
|
|
330
|
+
workspaceId: string;
|
|
331
|
+
sessionId: string;
|
|
332
|
+
path: string;
|
|
333
|
+
sha256: string;
|
|
334
|
+
}): { fileId: string; uploadId: string } {
|
|
335
|
+
const digest = createHash("sha256")
|
|
336
|
+
// Newly classified media must not collide with old binary-typed publications.
|
|
337
|
+
// Preserve the v1 identity for every previously supported format.
|
|
338
|
+
.update(
|
|
339
|
+
/^(audio|video)\//.test(sandboxFileContentType(input.path))
|
|
340
|
+
? "opengeni-sandbox-media-artifact-v1\0"
|
|
341
|
+
: "opengeni-sandbox-file-artifact-v1\0",
|
|
342
|
+
)
|
|
343
|
+
.update(input.workspaceId)
|
|
344
|
+
.update("\0")
|
|
345
|
+
.update(input.sessionId)
|
|
346
|
+
.update("\0")
|
|
347
|
+
.update(input.path)
|
|
348
|
+
.update("\0")
|
|
349
|
+
.update(input.sha256)
|
|
350
|
+
.digest("hex");
|
|
351
|
+
return {
|
|
352
|
+
fileId: uuidFromDigest(digest, 0),
|
|
353
|
+
uploadId: uuidFromDigest(digest, 16),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function uuidFromDigest(digest: string, startByte: number): string {
|
|
358
|
+
const bytes = Buffer.from(digest, "hex").subarray(startByte, startByte + 16);
|
|
359
|
+
bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;
|
|
360
|
+
bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;
|
|
361
|
+
const hex = bytes.toString("hex");
|
|
362
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export function assertSandboxArtifactFile(
|
|
366
|
+
file: NonNullable<Awaited<ReturnType<typeof getFile>>>,
|
|
367
|
+
expected: {
|
|
368
|
+
filename: string;
|
|
369
|
+
safeFilename: string;
|
|
370
|
+
contentType: string;
|
|
371
|
+
sizeBytes: number;
|
|
372
|
+
sha256: string;
|
|
373
|
+
bucket: string;
|
|
374
|
+
objectKey: string;
|
|
375
|
+
},
|
|
376
|
+
): void {
|
|
377
|
+
if (
|
|
378
|
+
!["pending_upload", "ready"].includes(file.status) ||
|
|
379
|
+
file.filename !== expected.filename ||
|
|
380
|
+
file.safeFilename !== expected.safeFilename ||
|
|
381
|
+
file.contentType !== expected.contentType ||
|
|
382
|
+
file.sizeBytes !== expected.sizeBytes ||
|
|
383
|
+
file.sha256 !== expected.sha256 ||
|
|
384
|
+
file.bucket !== expected.bucket ||
|
|
385
|
+
file.objectKey !== expected.objectKey
|
|
386
|
+
) {
|
|
387
|
+
throw new HTTPException(409, { message: "sandbox artifact identity is unavailable" });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async function assertVisibleSandboxArtifact(
|
|
392
|
+
storage: ObjectStorage,
|
|
393
|
+
file: NonNullable<Awaited<ReturnType<typeof getFile>>>,
|
|
394
|
+
): Promise<void> {
|
|
395
|
+
const head = await retryWhileMissing(async () => await storage.headObject!(file.objectKey));
|
|
396
|
+
assertStoredSandboxArtifact(head, file);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function assertStoredSandboxArtifact(
|
|
400
|
+
head: ObjectHead | null,
|
|
401
|
+
file: NonNullable<Awaited<ReturnType<typeof getFile>>>,
|
|
402
|
+
): void {
|
|
403
|
+
if (
|
|
404
|
+
!head ||
|
|
405
|
+
head.ContentLength !== file.sizeBytes ||
|
|
406
|
+
head.ContentType !== file.contentType ||
|
|
407
|
+
(file.sha256 !== null && head.Metadata?.sha256 !== file.sha256) ||
|
|
408
|
+
typeof head.VersionToken !== "string" ||
|
|
409
|
+
head.VersionToken.length < 1
|
|
410
|
+
) {
|
|
411
|
+
throw new HTTPException(502, { message: "sandbox artifact failed storage verification" });
|
|
412
|
+
}
|
|
413
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { scheduledTaskKnowledgeSource } from "@opengeni/contracts";
|
|
2
|
+
import type { AccessGrant, ScheduledTask as ScheduledTaskValue } from "@opengeni/contracts";
|
|
3
|
+
import {
|
|
4
|
+
assertScheduledTaskMutationOwner,
|
|
5
|
+
deleteScheduledTaskLifecycle,
|
|
6
|
+
type ApiRouteDeps,
|
|
7
|
+
} from "@opengeni/core";
|
|
8
|
+
import type { TemporalScheduleCleanupClaim } from "@opengeni/db";
|
|
9
|
+
import { HTTPException } from "hono/http-exception";
|
|
10
|
+
import * as z4 from "zod/v4";
|
|
11
|
+
import {
|
|
12
|
+
cleanupAtlassianScheduleAuthorization,
|
|
13
|
+
preflightAtlassianScheduleAuthorization,
|
|
14
|
+
revokeAtlassianScheduleAuthorization,
|
|
15
|
+
} from "./integrations/atlassian";
|
|
16
|
+
import {
|
|
17
|
+
cleanupKnowledgeSourceScheduleAuthorization,
|
|
18
|
+
preflightKnowledgeSourceScheduleAuthorization,
|
|
19
|
+
revokeKnowledgeSourceScheduleAuthorization,
|
|
20
|
+
} from "./integrations/google-drive";
|
|
21
|
+
import { processTemporalScheduleCleanupClaims } from "./temporal-schedule-cleanup";
|
|
22
|
+
|
|
23
|
+
const ScheduledConnectorCleanupV1 = z4.object({
|
|
24
|
+
version: z4.literal(1),
|
|
25
|
+
taskId: z4.string().uuid(),
|
|
26
|
+
accountId: z4.string().uuid(),
|
|
27
|
+
workspaceId: z4.string().uuid(),
|
|
28
|
+
connectorKind: z4.enum(["google_drive", "atlassian"]),
|
|
29
|
+
connectionId: z4.string().uuid(),
|
|
30
|
+
connectionVersion: z4.number().int().positive(),
|
|
31
|
+
sourceId: z4.string().uuid(),
|
|
32
|
+
sourceLifecycleGeneration: z4.number().int().positive(),
|
|
33
|
+
sourceConfigGeneration: z4.number().int().positive(),
|
|
34
|
+
externalSourceId: z4.string().min(1).max(512),
|
|
35
|
+
subjectId: z4.string().min(1).max(1024),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
async function preflightConnectorAuthorization(
|
|
39
|
+
deps: ApiRouteDeps,
|
|
40
|
+
task: ScheduledTaskValue,
|
|
41
|
+
subjectId: string,
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
if (!scheduledTaskKnowledgeSource(task)) return;
|
|
44
|
+
if (task.metadata.connectorKind === "atlassian") {
|
|
45
|
+
await preflightAtlassianScheduleAuthorization(deps, { task, subjectId });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (task.metadata.connectorKind === "google_drive") {
|
|
49
|
+
await preflightKnowledgeSourceScheduleAuthorization(deps, { task, subjectId });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
throw new HTTPException(409, {
|
|
53
|
+
message: "knowledge source schedule connector cannot be durably disabled",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function revokeConnectorAuthorization(
|
|
58
|
+
deps: ApiRouteDeps,
|
|
59
|
+
task: ScheduledTaskValue,
|
|
60
|
+
subjectId: string,
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
if (!scheduledTaskKnowledgeSource(task)) return;
|
|
63
|
+
if (task.metadata.connectorKind === "atlassian") {
|
|
64
|
+
await revokeAtlassianScheduleAuthorization(deps, { task, subjectId });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (task.metadata.connectorKind === "google_drive") {
|
|
68
|
+
await revokeKnowledgeSourceScheduleAuthorization(deps, { task, subjectId });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
throw new HTTPException(409, {
|
|
72
|
+
message: "knowledge source schedule connector cannot be durably disabled",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Execute one exact connector obligation frozen into the tombstone outbox row. */
|
|
77
|
+
export async function cleanupScheduledTaskConnectorAuthorization(
|
|
78
|
+
deps: ApiRouteDeps,
|
|
79
|
+
claim: TemporalScheduleCleanupClaim,
|
|
80
|
+
): Promise<void> {
|
|
81
|
+
if (!claim.connectorCleanupSnapshot) return;
|
|
82
|
+
const cleanup = ScheduledConnectorCleanupV1.parse(claim.connectorCleanupSnapshot);
|
|
83
|
+
const subjectId = claim.connectorCleanupSubjectId;
|
|
84
|
+
if (
|
|
85
|
+
!subjectId ||
|
|
86
|
+
claim.scheduledTaskId !== cleanup.taskId ||
|
|
87
|
+
claim.accountId !== cleanup.accountId ||
|
|
88
|
+
claim.workspaceId !== cleanup.workspaceId ||
|
|
89
|
+
cleanup.subjectId !== subjectId
|
|
90
|
+
) {
|
|
91
|
+
throw new Error("scheduled connector cleanup receipt is contradictory");
|
|
92
|
+
}
|
|
93
|
+
if (cleanup.connectorKind === "atlassian") {
|
|
94
|
+
await cleanupAtlassianScheduleAuthorization(deps, cleanup);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (cleanup.connectorKind === "google_drive") {
|
|
98
|
+
await cleanupKnowledgeSourceScheduleAuthorization(deps, cleanup);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
throw new Error("scheduled connector cleanup receipt has an unsupported connector");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Shared HTTP/MCP domain operation: authorize, tombstone, persist, then accelerate cleanup. */
|
|
105
|
+
export async function deleteScheduledTaskWithDurableCleanup(
|
|
106
|
+
deps: ApiRouteDeps,
|
|
107
|
+
request: { grant: AccessGrant; taskId: string },
|
|
108
|
+
): Promise<{ task: ScheduledTaskValue; changed: boolean }> {
|
|
109
|
+
const input = {
|
|
110
|
+
workspaceId: request.grant.workspaceId,
|
|
111
|
+
subjectId: request.grant.subjectId,
|
|
112
|
+
taskId: request.taskId,
|
|
113
|
+
};
|
|
114
|
+
const result = await deleteScheduledTaskLifecycle({
|
|
115
|
+
db: deps.db,
|
|
116
|
+
workspaceId: input.workspaceId,
|
|
117
|
+
taskId: input.taskId,
|
|
118
|
+
subjectId: input.subjectId,
|
|
119
|
+
beforeDeleteCommit: (tx) => assertScheduledTaskMutationOwner(tx, request.grant, request.taskId),
|
|
120
|
+
preflightConnectorAuthorization: async (task) =>
|
|
121
|
+
await preflightConnectorAuthorization(deps, task, input.subjectId),
|
|
122
|
+
cleanupConnectorAuthorization: async (db, task) =>
|
|
123
|
+
await revokeConnectorAuthorization({ ...deps, db }, task, input.subjectId),
|
|
124
|
+
processCleanupClaims: async (claims) => {
|
|
125
|
+
await processTemporalScheduleCleanupClaims(
|
|
126
|
+
{
|
|
127
|
+
db: deps.db,
|
|
128
|
+
cleanupConnectorAuthorization: async (claim) =>
|
|
129
|
+
await cleanupScheduledTaskConnectorAuthorization(deps, claim),
|
|
130
|
+
deleteSchedule: async (temporalScheduleId) =>
|
|
131
|
+
await deps.workflowClient.deleteScheduledTaskSchedule({ temporalScheduleId }),
|
|
132
|
+
},
|
|
133
|
+
claims,
|
|
134
|
+
);
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
return { task: result.task, changed: result.changed };
|
|
138
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { withTraceContext, type Observability, type Span } from "@opengeni/observability";
|
|
2
|
+
|
|
3
|
+
type SessionCreatePhase =
|
|
4
|
+
| "authorization"
|
|
5
|
+
| "body_read"
|
|
6
|
+
| "site_origin"
|
|
7
|
+
| "core_create"
|
|
8
|
+
| "response_projection";
|
|
9
|
+
|
|
10
|
+
/** Content-free child boundaries within the existing HTTP request span. */
|
|
11
|
+
export async function measureSessionCreatePhase<T>(
|
|
12
|
+
observability: Pick<Observability, "startSpan"> | null | undefined,
|
|
13
|
+
phase: SessionCreatePhase,
|
|
14
|
+
work: () => Promise<T>,
|
|
15
|
+
): Promise<T> {
|
|
16
|
+
let span: Span | undefined;
|
|
17
|
+
try {
|
|
18
|
+
span = observability?.startSpan(`api.session_create.${phase}`);
|
|
19
|
+
} catch {
|
|
20
|
+
// Diagnostics cannot replace authenticated request authority.
|
|
21
|
+
}
|
|
22
|
+
const end = (outcome: "completed" | "failed") => {
|
|
23
|
+
try {
|
|
24
|
+
void Promise.resolve(span?.end({ attributes: { outcome } })).catch(() => undefined);
|
|
25
|
+
} catch {
|
|
26
|
+
// Do not export errors, request content, or credentials.
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
try {
|
|
30
|
+
const result = span ? withTraceContext(span, work) : work();
|
|
31
|
+
if (!span) return result;
|
|
32
|
+
return result.then(
|
|
33
|
+
(value) => {
|
|
34
|
+
end("completed");
|
|
35
|
+
return value;
|
|
36
|
+
},
|
|
37
|
+
(error) => {
|
|
38
|
+
end("failed");
|
|
39
|
+
throw error;
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
end("failed");
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -82,11 +82,14 @@ function projectHistoryMessage(item: Record<string, unknown>): CodexRealtimeInit
|
|
|
82
82
|
const role = item.role;
|
|
83
83
|
if (role !== "user" && role !== "developer" && role !== "assistant") return null;
|
|
84
84
|
if (item.status !== undefined && item.status !== "completed") return null;
|
|
85
|
-
const text = messageText(item.content);
|
|
85
|
+
const text = messageText(item.content, role === "assistant" ? "" : "\n");
|
|
86
86
|
return text ? { role, text } : null;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
// User and developer parts are separate blocks (application context, the
|
|
90
|
+
// message time, the prompt), so each keeps its own line. Assistant output parts
|
|
91
|
+
// are pieces of one answer and join directly.
|
|
92
|
+
function messageText(content: unknown, separator: string): string {
|
|
90
93
|
if (typeof content === "string") return content;
|
|
91
94
|
if (!Array.isArray(content)) return "";
|
|
92
95
|
return content
|
|
@@ -101,7 +104,7 @@ function messageText(content: unknown): string {
|
|
|
101
104
|
}
|
|
102
105
|
return [];
|
|
103
106
|
})
|
|
104
|
-
.join(
|
|
107
|
+
.join(separator);
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
function estimatedTokens(text: string): number {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getWorkspaceSiteSessionOrigin, WorkspaceArtifactNotFoundError } from "@opengeni/db";
|
|
2
|
+
import { withSiteSessionOrigin, type ApiRouteDeps } from "@opengeni/core";
|
|
3
|
+
import { HTTPException } from "hono/http-exception";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
/** Validates a caller-asserted Site association, not browser execution or authority. */
|
|
7
|
+
export async function resolveSiteSessionOrigin(
|
|
8
|
+
db: ApiRouteDeps["db"],
|
|
9
|
+
workspaceId: string,
|
|
10
|
+
siteId?: string,
|
|
11
|
+
versionId?: string,
|
|
12
|
+
) {
|
|
13
|
+
if (!siteId && !versionId) return null;
|
|
14
|
+
if (
|
|
15
|
+
!z.string().uuid().safeParse(siteId).success ||
|
|
16
|
+
!z.string().uuid().safeParse(versionId).success
|
|
17
|
+
)
|
|
18
|
+
throw new HTTPException(400, { message: "Invalid Site origin" });
|
|
19
|
+
try {
|
|
20
|
+
// Provenance is not a live-version fence: a response-loss retry still belongs
|
|
21
|
+
// to the same Site after it publishes a new version or is archived.
|
|
22
|
+
return await getWorkspaceSiteSessionOrigin(db, workspaceId, siteId!, versionId!);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (error instanceof WorkspaceArtifactNotFoundError)
|
|
25
|
+
throw new HTTPException(404, { message: "Site origin not found" });
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Run a follow-up command (Send or Steer) inside the request's Site scope when
|
|
32
|
+
* the published Site bridge supplied a valid origin, so its turn records the
|
|
33
|
+
* `site` surface. Provenance only: a missing or unverifiable origin leaves the
|
|
34
|
+
* command unscoped instead of rejecting a message that is otherwise valid.
|
|
35
|
+
*/
|
|
36
|
+
export async function withOptionalSiteCommandOrigin<T>(
|
|
37
|
+
db: ApiRouteDeps["db"],
|
|
38
|
+
workspaceId: string,
|
|
39
|
+
siteId: string | undefined,
|
|
40
|
+
versionId: string | undefined,
|
|
41
|
+
run: () => Promise<T>,
|
|
42
|
+
): Promise<T> {
|
|
43
|
+
if (!siteId && !versionId) return await run();
|
|
44
|
+
const origin = await resolveSiteSessionOrigin(db, workspaceId, siteId, versionId).catch(
|
|
45
|
+
() => null,
|
|
46
|
+
);
|
|
47
|
+
return origin ? await withSiteSessionOrigin(origin, run) : await run();
|
|
48
|
+
}
|