@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,224 @@
|
|
|
1
|
+
import { WorkspaceArtifactSourceBundle, type AccessGrant } from "@opengeni/contracts";
|
|
2
|
+
import type { ApiRouteDeps, ObjectStorageDependency } from "@opengeni/core";
|
|
3
|
+
import { retryWhileMissing } from "@opengeni/storage";
|
|
4
|
+
import {
|
|
5
|
+
createWorkspaceArtifactUpload,
|
|
6
|
+
getWorkspaceArtifactUpload,
|
|
7
|
+
expireWorkspaceArtifactUploads,
|
|
8
|
+
WorkspaceArtifactOperationError,
|
|
9
|
+
} from "@opengeni/db";
|
|
10
|
+
import {
|
|
11
|
+
prepareWorkspaceArtifactContent,
|
|
12
|
+
type PreparedWorkspaceArtifactContent,
|
|
13
|
+
} from "./workspace-artifact-content";
|
|
14
|
+
import { userContentSignedGetUrlOptions } from "./http/user-content";
|
|
15
|
+
type Storage = NonNullable<ObjectStorageDependency>;
|
|
16
|
+
export const MAX_SITE_SOURCE_BYTES = 64 * 1024 * 1024;
|
|
17
|
+
|
|
18
|
+
export async function validateSiteSource(storage: Storage, key: string, sizeBytes: number) {
|
|
19
|
+
if (sizeBytes > MAX_SITE_SOURCE_BYTES) {
|
|
20
|
+
throw new WorkspaceArtifactOperationError(
|
|
21
|
+
"Editable source JSON must be at most 64 MiB. Exclude dependencies and build output; HTML has a separate storage limit.",
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
const content = await retryWhileMissing(() => storage.getObjectBytes(key));
|
|
25
|
+
if (!content) {
|
|
26
|
+
throw new WorkspaceArtifactOperationError(
|
|
27
|
+
"Site source is not available yet. Retry publication with the same upload.",
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
WorkspaceArtifactSourceBundle.parse(
|
|
32
|
+
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(content.bytes)),
|
|
33
|
+
);
|
|
34
|
+
} catch {
|
|
35
|
+
throw new WorkspaceArtifactOperationError(
|
|
36
|
+
"Source must be JSON {entrypoint, files: [{path, content}]}. Correct it and prepare a new upload.",
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function keys(workspaceId: string, id: string) {
|
|
41
|
+
const base = `workspaces/${workspaceId}/workspace-artifacts`;
|
|
42
|
+
return {
|
|
43
|
+
html: `${base}/uploads/${id}/index.html`,
|
|
44
|
+
source: `${base}/uploads/${id}/source.json`,
|
|
45
|
+
frozenHtml: `${base}/blobs/${id}.html`,
|
|
46
|
+
frozenSource: `${base}/sources/${id}.json`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function owner(grant: AccessGrant) {
|
|
50
|
+
return typeof grant.metadata?.sessionId === "string"
|
|
51
|
+
? `session:${grant.metadata.sessionId}`
|
|
52
|
+
: `subject:${grant.subjectId}`;
|
|
53
|
+
}
|
|
54
|
+
export async function prepareWorkspaceArtifactUpload(deps: ApiRouteDeps, grant: AccessGrant) {
|
|
55
|
+
const storage = deps.objectStorage;
|
|
56
|
+
if (!storage) throw new Error("Object storage is not configured");
|
|
57
|
+
const expired = await expireWorkspaceArtifactUploads(deps.db, grant.workspaceId);
|
|
58
|
+
await Promise.allSettled(
|
|
59
|
+
expired.flatMap((row) => {
|
|
60
|
+
const paths = keys(row.workspaceId, row.id);
|
|
61
|
+
return (row.status === "published" ? [paths.html, paths.source] : Object.values(paths)).map(
|
|
62
|
+
(key) => storage.deleteObject(key),
|
|
63
|
+
);
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
const row = await createWorkspaceArtifactUpload(deps.db, {
|
|
67
|
+
accountId: grant.accountId,
|
|
68
|
+
workspaceId: grant.workspaceId,
|
|
69
|
+
ownerId: owner(grant),
|
|
70
|
+
});
|
|
71
|
+
const paths = keys(grant.workspaceId, row.id);
|
|
72
|
+
const audience = grant.principalKind === "agent_attempt" ? "sandbox" : "public";
|
|
73
|
+
const [html, source] = await Promise.all([
|
|
74
|
+
storage.createPutUrl({ key: paths.html, contentType: "text/html", audience }),
|
|
75
|
+
storage.createPutUrl({ key: paths.source, contentType: "application/json", audience }),
|
|
76
|
+
]);
|
|
77
|
+
return {
|
|
78
|
+
uploadId: row.id,
|
|
79
|
+
html: { putUrl: html.url, requiredHeaders: html.requiredHeaders },
|
|
80
|
+
source: { putUrl: source.url, requiredHeaders: source.requiredHeaders },
|
|
81
|
+
expiresAt: new Date(
|
|
82
|
+
Math.min(html.expiresAt.getTime(), source.expiresAt.getTime()),
|
|
83
|
+
).toISOString(),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** Provider version-pinned reads, without Site SHA checks or full HTML buffering. */
|
|
87
|
+
export async function* readArtifactObject(
|
|
88
|
+
storage: Storage,
|
|
89
|
+
key: string,
|
|
90
|
+
expectedHead?: Awaited<ReturnType<NonNullable<Storage["headObject"]>>>,
|
|
91
|
+
) {
|
|
92
|
+
if (!storage.headObject || !storage.getObjectRange)
|
|
93
|
+
throw new Error("Object storage cannot stream Site content");
|
|
94
|
+
const head = expectedHead ?? (await storage.headObject(key));
|
|
95
|
+
if (!head || !head.VersionToken || head.ContentLength === undefined)
|
|
96
|
+
throw new Error("Site content is unavailable");
|
|
97
|
+
for (let start = 0; start < head.ContentLength; start += 1024 * 1024) {
|
|
98
|
+
const endInclusive = Math.min(head.ContentLength - 1, start + 1024 * 1024 - 1);
|
|
99
|
+
const part = await storage.getObjectRange({
|
|
100
|
+
key,
|
|
101
|
+
start,
|
|
102
|
+
endInclusive,
|
|
103
|
+
expectedVersionToken: head.VersionToken,
|
|
104
|
+
});
|
|
105
|
+
if (
|
|
106
|
+
!part ||
|
|
107
|
+
part.versionToken !== head.VersionToken ||
|
|
108
|
+
part.bytes.length !== endInclusive - start + 1
|
|
109
|
+
)
|
|
110
|
+
throw new Error("Site object changed during transfer");
|
|
111
|
+
yield part.bytes;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function freeze(
|
|
115
|
+
storage: Storage,
|
|
116
|
+
from: string,
|
|
117
|
+
to: string,
|
|
118
|
+
contentType: string,
|
|
119
|
+
optional = false,
|
|
120
|
+
) {
|
|
121
|
+
if (!storage.headObject || !storage.putObjectStreamIfAbsent)
|
|
122
|
+
throw new Error("Object storage cannot freeze Site uploads");
|
|
123
|
+
const existing = await storage.headObject(to);
|
|
124
|
+
if (existing) return existing.ContentLength!;
|
|
125
|
+
const head = await storage.headObject(from);
|
|
126
|
+
if (!head && optional) return null;
|
|
127
|
+
if (!head || !head.ContentLength)
|
|
128
|
+
throw new WorkspaceArtifactOperationError("Upload HTML before publishing the Site");
|
|
129
|
+
if (head.ContentLength > storage.maxSinglePutSizeBytes)
|
|
130
|
+
throw new Error("Site exceeds the storage upload limit");
|
|
131
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
132
|
+
async function* chunks() {
|
|
133
|
+
for await (const part of readArtifactObject(storage, from, head)) {
|
|
134
|
+
decoder.decode(part, { stream: true });
|
|
135
|
+
yield part;
|
|
136
|
+
}
|
|
137
|
+
decoder.decode();
|
|
138
|
+
}
|
|
139
|
+
const created = await storage.putObjectStreamIfAbsent({
|
|
140
|
+
key: to,
|
|
141
|
+
contentType,
|
|
142
|
+
byteSize: head.ContentLength,
|
|
143
|
+
chunks: chunks(),
|
|
144
|
+
});
|
|
145
|
+
// A successful conditional PUT is the receipt. A following visibility miss
|
|
146
|
+
// cannot invalidate it. Only a conflict needs the existing winner's metadata.
|
|
147
|
+
if (created) return head.ContentLength;
|
|
148
|
+
const stored = await retryWhileMissing(() => storage.headObject!(to));
|
|
149
|
+
if (!stored || stored.ContentLength === undefined) {
|
|
150
|
+
throw new WorkspaceArtifactOperationError(
|
|
151
|
+
"Frozen Site upload is unavailable. Retry publication with the same upload.",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
return stored.ContentLength;
|
|
155
|
+
}
|
|
156
|
+
type Input = Partial<Parameters<typeof prepareWorkspaceArtifactContent>[2]> & { uploadId?: string };
|
|
157
|
+
export async function prepareWorkspaceArtifactPublication(
|
|
158
|
+
deps: ApiRouteDeps,
|
|
159
|
+
grant: AccessGrant,
|
|
160
|
+
input: Input,
|
|
161
|
+
): Promise<PreparedWorkspaceArtifactContent & { uploadId?: string }> {
|
|
162
|
+
const storage = deps.objectStorage;
|
|
163
|
+
if (!storage) throw new Error("Object storage is not configured");
|
|
164
|
+
if (Boolean(input.uploadId) === (input.html !== undefined))
|
|
165
|
+
throw new Error("Provide either uploadId or inline html, not both");
|
|
166
|
+
if (!input.uploadId) {
|
|
167
|
+
return prepareWorkspaceArtifactContent(storage, grant.workspaceId, {
|
|
168
|
+
...input,
|
|
169
|
+
html: input.html!,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
if (input.source) throw new Error("Upload source JSON using the source upload URL");
|
|
173
|
+
const row = await getWorkspaceArtifactUpload(deps.db, grant.workspaceId, input.uploadId);
|
|
174
|
+
if (
|
|
175
|
+
!row ||
|
|
176
|
+
row.ownerId !== owner(grant) ||
|
|
177
|
+
row.status === "expired" ||
|
|
178
|
+
(row.status === "pending" && row.expiresAt.getTime() <= Date.now())
|
|
179
|
+
)
|
|
180
|
+
throw new WorkspaceArtifactOperationError("Site upload expired or unavailable");
|
|
181
|
+
const paths = keys(grant.workspaceId, row.id);
|
|
182
|
+
const sizeBytes = await freeze(storage, paths.html, paths.frozenHtml, "text/html; charset=utf-8");
|
|
183
|
+
const sourceSizeBytes =
|
|
184
|
+
row.status === "published" && !(await storage.headObject!(paths.frozenSource))
|
|
185
|
+
? null
|
|
186
|
+
: await freeze(storage, paths.source, paths.frozenSource, "application/json", true);
|
|
187
|
+
if (sourceSizeBytes !== null) {
|
|
188
|
+
await validateSiteSource(storage, paths.frozenSource, sourceSizeBytes);
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
uploadId: row.id,
|
|
192
|
+
contentKey: paths.frozenHtml,
|
|
193
|
+
contentSha256: null,
|
|
194
|
+
sizeBytes: sizeBytes!,
|
|
195
|
+
sourceKey: sourceSizeBytes === null ? null : paths.frozenSource,
|
|
196
|
+
sourceSha256: null,
|
|
197
|
+
sourceSizeBytes,
|
|
198
|
+
...(input.requestedTools === undefined ? {} : { requestedTools: input.requestedTools }),
|
|
199
|
+
persistContent: async () => {},
|
|
200
|
+
discardContent: async () => {},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
export async function workspaceArtifactDownloads(
|
|
204
|
+
storage: Storage,
|
|
205
|
+
ref: { contentKey: string; sourceKey: string | null },
|
|
206
|
+
audience: "sandbox" | "public",
|
|
207
|
+
) {
|
|
208
|
+
const [html, source] = await Promise.all([
|
|
209
|
+
// Site HTML runs publisher scripts; opened directly from storage it would
|
|
210
|
+
// render outside the console's opaque-origin frame, so it downloads.
|
|
211
|
+
storage.createGetUrl({
|
|
212
|
+
key: ref.contentKey,
|
|
213
|
+
audience,
|
|
214
|
+
...userContentSignedGetUrlOptions("text/html", "site.html"),
|
|
215
|
+
}),
|
|
216
|
+
ref.sourceKey ? storage.createGetUrl({ key: ref.sourceKey, audience }) : null,
|
|
217
|
+
]);
|
|
218
|
+
return {
|
|
219
|
+
html: { url: html.url, expiresAt: html.expiresAt },
|
|
220
|
+
source: source
|
|
221
|
+
? { url: source.url, expiresAt: source.expiresAt, format: "source-bundle-json" }
|
|
222
|
+
: null,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import type { FileResourceRef } from "@opengeni/contracts";
|
|
3
3
|
import { completeFileUpload, prepareGeneratedWorkspaceFile, type Database } from "@opengeni/db";
|
|
4
|
-
import type
|
|
4
|
+
import { retryWhileMissing, type ObjectHead, type ObjectStorage } from "@opengeni/storage";
|
|
5
5
|
import type { DownloadedSlackReactionImage } from "./integrations/slack-bot";
|
|
6
6
|
|
|
7
7
|
const IMPORT_IDENTITY_VERSION = "slack-reaction-image-v1";
|
|
@@ -77,13 +77,15 @@ export async function importSlackReactionImage(
|
|
|
77
77
|
if (existing) {
|
|
78
78
|
assertStoredSlackImage(existing, image, sha256);
|
|
79
79
|
} else if (storage.putObjectIfAbsent) {
|
|
80
|
-
await storage.putObjectIfAbsent({
|
|
80
|
+
const created = await storage.putObjectIfAbsent({
|
|
81
81
|
key: objectKey,
|
|
82
82
|
contentType: image.contentType,
|
|
83
83
|
body: image.bytes,
|
|
84
84
|
sha256,
|
|
85
85
|
});
|
|
86
|
-
|
|
86
|
+
if (!created) {
|
|
87
|
+
await assertVisibleSlackImage(storage, objectKey, image, sha256);
|
|
88
|
+
}
|
|
87
89
|
} else {
|
|
88
90
|
await storage.putObject({
|
|
89
91
|
key: objectKey,
|
|
@@ -91,7 +93,6 @@ export async function importSlackReactionImage(
|
|
|
91
93
|
body: image.bytes,
|
|
92
94
|
sha256,
|
|
93
95
|
});
|
|
94
|
-
assertStoredSlackImage(await storage.headObject(objectKey), image, sha256);
|
|
95
96
|
}
|
|
96
97
|
file = await (dependencies.completeFile ?? completeFileUpload)(
|
|
97
98
|
dependencies.db,
|
|
@@ -99,7 +100,7 @@ export async function importSlackReactionImage(
|
|
|
99
100
|
uploadId,
|
|
100
101
|
);
|
|
101
102
|
} else {
|
|
102
|
-
|
|
103
|
+
await assertVisibleSlackImage(storage, objectKey, image, sha256);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
if (
|
|
@@ -153,6 +154,16 @@ export function safeSlackImageFilename(
|
|
|
153
154
|
return `${stem}${extension}`;
|
|
154
155
|
}
|
|
155
156
|
|
|
157
|
+
async function assertVisibleSlackImage(
|
|
158
|
+
storage: ObjectStorage,
|
|
159
|
+
objectKey: string,
|
|
160
|
+
image: DownloadedSlackReactionImage,
|
|
161
|
+
sha256: string,
|
|
162
|
+
): Promise<void> {
|
|
163
|
+
const head = await retryWhileMissing(async () => await storage.headObject!(objectKey));
|
|
164
|
+
assertStoredSlackImage(head, image, sha256);
|
|
165
|
+
}
|
|
166
|
+
|
|
156
167
|
function assertStoredSlackImage(
|
|
157
168
|
head: ObjectHead | null,
|
|
158
169
|
image: DownloadedSlackReactionImage,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import {
|
|
3
3
|
claimTemporalScheduleCleanups,
|
|
4
|
+
completeTemporalScheduleConnectorCleanup,
|
|
4
5
|
settleTemporalScheduleCleanup,
|
|
5
6
|
type Database,
|
|
6
7
|
type TemporalScheduleCleanupClaim,
|
|
@@ -13,6 +14,7 @@ const CLEANUP_POLL_INTERVAL_MS = 1_000;
|
|
|
13
14
|
|
|
14
15
|
type TemporalScheduleCleanupDependencies = {
|
|
15
16
|
db: Database;
|
|
17
|
+
cleanupConnectorAuthorization?: (claim: TemporalScheduleCleanupClaim) => Promise<void>;
|
|
16
18
|
deleteSchedule: (temporalScheduleId: string) => Promise<void>;
|
|
17
19
|
observability?: Pick<Observability, "info" | "warn" | "error">;
|
|
18
20
|
};
|
|
@@ -39,6 +41,17 @@ export async function processTemporalScheduleCleanupClaims(
|
|
|
39
41
|
const results = await Promise.all(
|
|
40
42
|
claims.map(async (claim): Promise<"deleted" | "failed" | "stale"> => {
|
|
41
43
|
try {
|
|
44
|
+
if (claim.connectorCleanupSnapshot && !claim.connectorCleanupCompletedAt) {
|
|
45
|
+
if (!deps.cleanupConnectorAuthorization) {
|
|
46
|
+
throw new Error("scheduled connector cleanup dependency is unavailable");
|
|
47
|
+
}
|
|
48
|
+
await deps.cleanupConnectorAuthorization(claim);
|
|
49
|
+
const completed = await completeTemporalScheduleConnectorCleanup(deps.db, {
|
|
50
|
+
id: claim.id,
|
|
51
|
+
claimId: claim.claimId,
|
|
52
|
+
});
|
|
53
|
+
if (!completed) return "stale";
|
|
54
|
+
}
|
|
42
55
|
await deps.deleteSchedule(claim.temporalScheduleId);
|
|
43
56
|
const settled = await settleTemporalScheduleCleanup(deps.db, {
|
|
44
57
|
id: claim.id,
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { ScheduledTask } from "@opengeni/contracts";
|
|
2
|
+
import { getScheduledTaskIncludingDeleted, type Database } from "@opengeni/db";
|
|
3
|
+
import { sql } from "drizzle-orm";
|
|
4
|
+
|
|
5
|
+
const LOCK_TIMEOUT = "5s";
|
|
6
|
+
const WRITE_TIMEOUT_MS = 5_000;
|
|
7
|
+
|
|
8
|
+
type TemporalScheduleSyncDependencies = {
|
|
9
|
+
db: Database;
|
|
10
|
+
withDeadline<T>(deadline: number, work: () => Promise<T>): Promise<T>;
|
|
11
|
+
upsert(task: ScheduledTask): Promise<void>;
|
|
12
|
+
/** Idempotent: an absent Temporal schedule is already removed. */
|
|
13
|
+
remove(temporalScheduleId: string): Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Serialize external writes across API replicas, independently of task edits.
|
|
18
|
+
* A queued sync rereads the newest committed row after acquiring this lock;
|
|
19
|
+
* input snapshots never become desired state. Cleanup uses the same key, so
|
|
20
|
+
* an in-flight upsert finishes before its tombstone's external deletion.
|
|
21
|
+
* Failure compensation commits before releasing the lock, so a queued writer
|
|
22
|
+
* cannot read the row being restored and then publish that failed edit.
|
|
23
|
+
*
|
|
24
|
+
* Deadlines bound both lock admission and network occupancy. A thrown network
|
|
25
|
+
* error retains its unknown-outcome semantics; this is not durable recovery
|
|
26
|
+
* for a process crash or a lost Temporal acknowledgement.
|
|
27
|
+
*/
|
|
28
|
+
export function createTemporalScheduleSynchronizer(deps: TemporalScheduleSyncDependencies) {
|
|
29
|
+
const write = async <T>(
|
|
30
|
+
temporalScheduleId: string,
|
|
31
|
+
work: (tx: Database) => Promise<T>,
|
|
32
|
+
): Promise<T> =>
|
|
33
|
+
deps.db.transaction(async (tx) => {
|
|
34
|
+
await tx.execute(sql`select set_config('lock_timeout', ${LOCK_TIMEOUT}, true)`);
|
|
35
|
+
await tx.execute(sql`select pg_advisory_xact_lock(
|
|
36
|
+
hashtextextended(${`scheduled-task-temporal:${temporalScheduleId}`}, 0)
|
|
37
|
+
)`);
|
|
38
|
+
return await work(tx);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
async sync(
|
|
43
|
+
task: Pick<ScheduledTask, "id" | "workspaceId" | "temporalScheduleId">,
|
|
44
|
+
onFailure?: (tx: Database, error: unknown) => Promise<Error>,
|
|
45
|
+
) {
|
|
46
|
+
const result = await write(task.temporalScheduleId, async (tx) => {
|
|
47
|
+
try {
|
|
48
|
+
await deps.withDeadline(Date.now() + WRITE_TIMEOUT_MS, async () => {
|
|
49
|
+
const current = await getScheduledTaskIncludingDeleted(tx, task.workspaceId, task.id);
|
|
50
|
+
if (current && current.temporalScheduleId !== task.temporalScheduleId)
|
|
51
|
+
throw new Error("Scheduled task Temporal identity changed");
|
|
52
|
+
if (!current || current.deletedAt !== null || current.schedule.type === "manual") {
|
|
53
|
+
await deps.remove(task.temporalScheduleId);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const { deletedAt: _deletedAt, ...latest } = current;
|
|
57
|
+
await deps.upsert(latest);
|
|
58
|
+
});
|
|
59
|
+
return { ok: true as const };
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return { ok: false as const, error: onFailure ? await onFailure(tx, error) : error };
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
// Throw after commit: throwing inside the transaction would also undo a
|
|
65
|
+
// successful compensation. A failed commit cannot claim that receipt.
|
|
66
|
+
if (!result.ok) throw result.error;
|
|
67
|
+
},
|
|
68
|
+
async remove(temporalScheduleId: string) {
|
|
69
|
+
await write(temporalScheduleId, async () =>
|
|
70
|
+
deps.withDeadline(Date.now() + WRITE_TIMEOUT_MS, () => deps.remove(temporalScheduleId)),
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -45,6 +45,7 @@ export function createCodexSubscriptionTranscriptionProvider(input: {
|
|
|
45
45
|
);
|
|
46
46
|
if (!account) {
|
|
47
47
|
throw new TranscriptionServiceError({
|
|
48
|
+
fallbackSafe: true,
|
|
48
49
|
code: "unavailable",
|
|
49
50
|
message: "Transcription is unavailable.",
|
|
50
51
|
});
|
|
@@ -55,6 +56,7 @@ export function createCodexSubscriptionTranscriptionProvider(input: {
|
|
|
55
56
|
token = await resolver.getToken();
|
|
56
57
|
} catch {
|
|
57
58
|
throw new TranscriptionServiceError({
|
|
59
|
+
fallbackSafe: true,
|
|
58
60
|
code: "unavailable",
|
|
59
61
|
message: "Transcription is unavailable.",
|
|
60
62
|
});
|
|
@@ -53,6 +53,7 @@ function audioBlob(audio: Uint8Array, mimeType: string): Blob {
|
|
|
53
53
|
export function responseError(status: number): TranscriptionServiceError {
|
|
54
54
|
if (status === 401 || status === 403) {
|
|
55
55
|
return new TranscriptionServiceError({
|
|
56
|
+
fallbackSafe: true,
|
|
56
57
|
code: "unavailable",
|
|
57
58
|
message: "Transcription is unavailable.",
|
|
58
59
|
});
|
|
@@ -62,6 +62,7 @@ export function createXaiSubscriptionTranscriptionProvider(input: {
|
|
|
62
62
|
} catch {
|
|
63
63
|
throw new TranscriptionServiceError({
|
|
64
64
|
code: "unavailable",
|
|
65
|
+
fallbackSafe: true,
|
|
65
66
|
message: "Transcription is unavailable.",
|
|
66
67
|
});
|
|
67
68
|
}
|
|
@@ -86,16 +87,28 @@ export function createXaiSubscriptionTranscriptionProvider(input: {
|
|
|
86
87
|
...(signal ? { signal } : {}),
|
|
87
88
|
});
|
|
88
89
|
};
|
|
90
|
+
const tokenForRequest = async (refresh: boolean) => {
|
|
91
|
+
try {
|
|
92
|
+
return await (refresh ? auth.context.refresh() : auth.context.getToken());
|
|
93
|
+
} catch {
|
|
94
|
+
throw new TranscriptionServiceError({
|
|
95
|
+
code: "unavailable",
|
|
96
|
+
message: "Reconnect the SuperGrok account to use transcription.",
|
|
97
|
+
fallbackSafe: true,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
};
|
|
89
101
|
let response: Response;
|
|
90
102
|
try {
|
|
91
|
-
let token = await
|
|
103
|
+
let token = await tokenForRequest(false);
|
|
92
104
|
response = await request(token.accessToken);
|
|
93
|
-
if (response.status === 401) {
|
|
105
|
+
if (response.status === 401 || (await isXaiInvalidCredentialResponse(response))) {
|
|
94
106
|
await response.body?.cancel().catch(() => undefined);
|
|
95
|
-
token = await
|
|
107
|
+
token = await tokenForRequest(true);
|
|
96
108
|
response = await request(token.accessToken);
|
|
97
109
|
}
|
|
98
110
|
} catch (error) {
|
|
111
|
+
if (error instanceof TranscriptionServiceError) throw error;
|
|
99
112
|
throw fetchError(error);
|
|
100
113
|
}
|
|
101
114
|
if (!response.ok) throw responseError(response.status);
|
|
@@ -108,3 +121,36 @@ export function createXaiSubscriptionTranscriptionProvider(input: {
|
|
|
108
121
|
},
|
|
109
122
|
};
|
|
110
123
|
}
|
|
124
|
+
|
|
125
|
+
export async function isXaiInvalidCredentialResponse(response: Response): Promise<boolean> {
|
|
126
|
+
if (response.status !== 403) return false;
|
|
127
|
+
const reader = response.clone().body?.getReader();
|
|
128
|
+
if (!reader) return false;
|
|
129
|
+
const chunks: Uint8Array[] = [];
|
|
130
|
+
let size = 0;
|
|
131
|
+
try {
|
|
132
|
+
while (true) {
|
|
133
|
+
const chunk = await reader.read();
|
|
134
|
+
if (chunk.done) break;
|
|
135
|
+
size += chunk.value.byteLength;
|
|
136
|
+
if (size > 16_384) return false;
|
|
137
|
+
chunks.push(chunk.value);
|
|
138
|
+
}
|
|
139
|
+
const bytes = new Uint8Array(size);
|
|
140
|
+
let offset = 0;
|
|
141
|
+
for (const chunk of chunks) {
|
|
142
|
+
bytes.set(chunk, offset);
|
|
143
|
+
offset += chunk.byteLength;
|
|
144
|
+
}
|
|
145
|
+
const body = JSON.parse(new TextDecoder().decode(bytes));
|
|
146
|
+
return (
|
|
147
|
+
typeof body?.error === "string" &&
|
|
148
|
+
body.error.includes("[WKE=unauthenticated:bad-credentials]")
|
|
149
|
+
);
|
|
150
|
+
} catch {
|
|
151
|
+
return false;
|
|
152
|
+
} finally {
|
|
153
|
+
void reader.cancel().catch(() => undefined);
|
|
154
|
+
reader.releaseLock();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -220,8 +220,14 @@ function extensionForMimeType(mimeType: string): string {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
async function commandSucceeds(command: string, args: string[]): Promise<boolean> {
|
|
223
|
-
|
|
224
|
-
|
|
223
|
+
try {
|
|
224
|
+
const result = await runCommand(command, args);
|
|
225
|
+
return !result.spawnError && result.exitCode === 0;
|
|
226
|
+
} catch {
|
|
227
|
+
// Some runtimes throw during spawn instead of emitting an error event.
|
|
228
|
+
// An unavailable optional audio tool must not prevent client startup.
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
225
231
|
}
|
|
226
232
|
|
|
227
233
|
async function runCommand(
|
|
@@ -74,7 +74,7 @@ export function createTranscriptionService(input: {
|
|
|
74
74
|
);
|
|
75
75
|
},
|
|
76
76
|
async selectProvider(context) {
|
|
77
|
-
return (await firstAvailable(providers, context))?.id ?? null;
|
|
77
|
+
return (await firstAvailable(orderedProviders(providers, context), context))?.id ?? null;
|
|
78
78
|
},
|
|
79
79
|
async transcribe(request) {
|
|
80
80
|
const mimeType = normalizeMimeType(request.mimeType);
|
|
@@ -106,12 +106,10 @@ export function createTranscriptionService(input: {
|
|
|
106
106
|
workspaceId: request.workspaceId,
|
|
107
107
|
subjectId: request.subjectId,
|
|
108
108
|
})
|
|
109
|
-
: await firstAvailable(providers,
|
|
110
|
-
workspaceId: request.workspaceId,
|
|
111
|
-
subjectId: request.subjectId,
|
|
112
|
-
});
|
|
109
|
+
: await firstAvailable(orderedProviders(providers, request), request);
|
|
113
110
|
if (!provider) {
|
|
114
111
|
throw new TranscriptionServiceError({
|
|
112
|
+
fallbackSafe: true,
|
|
115
113
|
code: "unavailable",
|
|
116
114
|
message: "Transcription is unavailable.",
|
|
117
115
|
});
|
|
@@ -164,6 +162,23 @@ export function createTranscriptionService(input: {
|
|
|
164
162
|
retryable: true,
|
|
165
163
|
});
|
|
166
164
|
}
|
|
165
|
+
if (
|
|
166
|
+
error instanceof TranscriptionServiceError &&
|
|
167
|
+
error.fallbackSafe &&
|
|
168
|
+
!request.providerId &&
|
|
169
|
+
request.fallbackEnabled !== false &&
|
|
170
|
+
!request.signal?.aborted
|
|
171
|
+
) {
|
|
172
|
+
const excludedProviders = [...(request.excludedProviders ?? []), provider.id];
|
|
173
|
+
if (
|
|
174
|
+
await firstAvailable(
|
|
175
|
+
orderedProviders(providers, { ...request, excludedProviders }),
|
|
176
|
+
request,
|
|
177
|
+
)
|
|
178
|
+
) {
|
|
179
|
+
return await this.transcribe({ ...request, excludedProviders });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
167
182
|
throw error;
|
|
168
183
|
} finally {
|
|
169
184
|
deadline.dispose();
|
|
@@ -217,12 +232,34 @@ function createProviderRequestDeadline(
|
|
|
217
232
|
};
|
|
218
233
|
}
|
|
219
234
|
|
|
235
|
+
export function orderedProviders(
|
|
236
|
+
providers: readonly TranscriptionProvider[],
|
|
237
|
+
context: TranscriptionAvailabilityContext,
|
|
238
|
+
): TranscriptionProvider[] {
|
|
239
|
+
const preferred = providers.filter((provider) => provider.id === context.preferredProvider);
|
|
240
|
+
const ordered = context.preferredProvider
|
|
241
|
+
? context.fallbackEnabled === false
|
|
242
|
+
? preferred
|
|
243
|
+
: [...preferred, ...providers.filter((provider) => provider.id !== context.preferredProvider)]
|
|
244
|
+
: context.fallbackEnabled === false
|
|
245
|
+
? providers.slice(0, 1)
|
|
246
|
+
: [...providers];
|
|
247
|
+
const remaining = context.afterProvider
|
|
248
|
+
? ordered.slice(ordered.findIndex((provider) => provider.id === context.afterProvider) + 1)
|
|
249
|
+
: ordered;
|
|
250
|
+
return remaining.filter((provider) => !context.excludedProviders?.includes(provider.id));
|
|
251
|
+
}
|
|
252
|
+
|
|
220
253
|
async function firstAvailable(
|
|
221
254
|
providers: readonly TranscriptionProvider[],
|
|
222
255
|
context: TranscriptionAvailabilityContext,
|
|
223
256
|
) {
|
|
224
257
|
for (const provider of providers) {
|
|
225
|
-
|
|
258
|
+
try {
|
|
259
|
+
if (await provider.available(context)) return provider;
|
|
260
|
+
} catch {
|
|
261
|
+
/* No audio sent; another configured provider may be ready. */
|
|
262
|
+
}
|
|
226
263
|
}
|
|
227
264
|
return null;
|
|
228
265
|
}
|