@opengeni/api-router 0.30.1 → 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-office-import.d.ts +7 -4
- 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 +1129 -166
- 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 +25 -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 +113 -10
- 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 +71 -3
- 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/files.d.ts +4 -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 +1974 -256
- 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 +77 -9
- 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 +820 -222
- 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 +3170 -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 -38
- 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 +839 -131
- 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 +1040 -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 +337 -39
- 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-2PQMSRCB.js +0 -49759
- package/dist/chunk-2PQMSRCB.js.map +0 -1
- package/dist/routes/packs.d.ts +0 -3
- package/src/routes/packs.ts +0 -729
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { zValidator } from "@hono/zod-validator";
|
|
2
|
+
import {
|
|
3
|
+
CreateOrganizationServiceAccountRequest,
|
|
4
|
+
ListOrganizationServiceAccountsResponse,
|
|
5
|
+
OrganizationServiceAccount,
|
|
6
|
+
UpdateOrganizationServiceAccountRequest,
|
|
7
|
+
type AccessContext,
|
|
8
|
+
} from "@opengeni/contracts";
|
|
9
|
+
import { requireAccessContext, type ApiRouteDeps } from "@opengeni/core";
|
|
10
|
+
import {
|
|
11
|
+
createOrganizationServiceAccount,
|
|
12
|
+
deleteOrganizationServiceAccount,
|
|
13
|
+
getOrganizationServiceAccount,
|
|
14
|
+
listOrganizationServiceAccounts,
|
|
15
|
+
updateOrganizationServiceAccount,
|
|
16
|
+
} from "@opengeni/db";
|
|
17
|
+
import type { Context, Hono } from "hono";
|
|
18
|
+
import { HTTPException } from "hono/http-exception";
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
|
|
21
|
+
import { requireOrganizationApiKeyControlPermission, throwServiceAccountError } from "./api-keys";
|
|
22
|
+
|
|
23
|
+
/* ----------------------------------------------------------------------------
|
|
24
|
+
Service accounts: organization identities with no person behind them. They
|
|
25
|
+
hold organization API keys. Whoever may manage the organization's keys may
|
|
26
|
+
manage service accounts; only an organization administrator can make one an
|
|
27
|
+
admin. Deleting one revokes its keys at once.
|
|
28
|
+
-------------------------------------------------------------------------- */
|
|
29
|
+
|
|
30
|
+
const Id = z.string().uuid();
|
|
31
|
+
|
|
32
|
+
export function registerOrganizationServiceAccountRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
33
|
+
const path = "/v1/organizations/:organizationId/service-accounts";
|
|
34
|
+
|
|
35
|
+
app.get(path, async (c) => {
|
|
36
|
+
const { organizationId } = await requireControl(c, deps);
|
|
37
|
+
c.header("cache-control", "no-store");
|
|
38
|
+
return c.json(
|
|
39
|
+
ListOrganizationServiceAccountsResponse.parse({
|
|
40
|
+
serviceAccounts: await listOrganizationServiceAccounts(deps.db, organizationId),
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
app.post(path, zValidator("json", CreateOrganizationServiceAccountRequest), async (c) => {
|
|
46
|
+
const { organizationId, context } = await requireControl(c, deps);
|
|
47
|
+
const body = c.req.valid("json");
|
|
48
|
+
if (body.role === "admin") requireOrganizationAdmin(context, organizationId);
|
|
49
|
+
const created = await createOrganizationServiceAccount(deps.db, {
|
|
50
|
+
accountId: organizationId,
|
|
51
|
+
name: body.name,
|
|
52
|
+
description: body.description ?? null,
|
|
53
|
+
role: body.role,
|
|
54
|
+
createdBySubjectId: context.subjectId,
|
|
55
|
+
});
|
|
56
|
+
return c.json(OrganizationServiceAccount.parse(created), 201);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
app.get(`${path}/:serviceAccountId`, async (c) => {
|
|
60
|
+
const { organizationId } = await requireControl(c, deps);
|
|
61
|
+
const found = await getOrganizationServiceAccount(deps.db, organizationId, serviceAccountId(c));
|
|
62
|
+
if (!found) throw new HTTPException(404, { message: "Service account not found" });
|
|
63
|
+
return c.json(OrganizationServiceAccount.parse(found));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
app.patch(
|
|
67
|
+
`${path}/:serviceAccountId`,
|
|
68
|
+
zValidator("json", UpdateOrganizationServiceAccountRequest),
|
|
69
|
+
async (c) => {
|
|
70
|
+
const { organizationId, context } = await requireControl(c, deps);
|
|
71
|
+
const body = c.req.valid("json");
|
|
72
|
+
if (body.role === "admin") requireOrganizationAdmin(context, organizationId);
|
|
73
|
+
try {
|
|
74
|
+
return c.json(
|
|
75
|
+
OrganizationServiceAccount.parse(
|
|
76
|
+
await updateOrganizationServiceAccount(
|
|
77
|
+
deps.db,
|
|
78
|
+
organizationId,
|
|
79
|
+
serviceAccountId(c),
|
|
80
|
+
body,
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
throwServiceAccountError(error);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
app.delete(`${path}/:serviceAccountId`, async (c) => {
|
|
92
|
+
const { organizationId } = await requireControl(c, deps);
|
|
93
|
+
try {
|
|
94
|
+
await deleteOrganizationServiceAccount(deps.db, organizationId, serviceAccountId(c));
|
|
95
|
+
} catch (error) {
|
|
96
|
+
throwServiceAccountError(error);
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
return c.body(null, 204);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function requireControl(
|
|
104
|
+
c: Context,
|
|
105
|
+
deps: ApiRouteDeps,
|
|
106
|
+
): Promise<{ organizationId: string; context: AccessContext }> {
|
|
107
|
+
const parsed = Id.safeParse(c.req.param("organizationId"));
|
|
108
|
+
if (!parsed.success) throw new HTTPException(404, { message: "organization not found" });
|
|
109
|
+
const organizationId = parsed.data.toLowerCase();
|
|
110
|
+
const context = await requireAccessContext(c, deps);
|
|
111
|
+
requireOrganizationApiKeyControlPermission(context, organizationId);
|
|
112
|
+
return { organizationId, context };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function serviceAccountId(c: Context): string {
|
|
116
|
+
const parsed = Id.safeParse(c.req.param("serviceAccountId"));
|
|
117
|
+
if (!parsed.success) throw new HTTPException(404, { message: "Service account not found" });
|
|
118
|
+
return parsed.data.toLowerCase();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Only an organization administrator can make a service account an admin. */
|
|
122
|
+
function requireOrganizationAdmin(context: AccessContext, organizationId: string): void {
|
|
123
|
+
const grant = context.accountGrants.find((candidate) => candidate.accountId === organizationId);
|
|
124
|
+
if (!grant?.permissions.includes("account:admin"))
|
|
125
|
+
throw new HTTPException(403, {
|
|
126
|
+
message: "Only an organization administrator can make a service account an admin.",
|
|
127
|
+
});
|
|
128
|
+
}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ListOrganizationSessionsQuery,
|
|
3
|
+
type AccessContext,
|
|
4
|
+
type OrganizationSessionListResponse,
|
|
5
|
+
type Session,
|
|
6
|
+
type Workspace,
|
|
7
|
+
} from "@opengeni/contracts";
|
|
8
|
+
import {
|
|
9
|
+
accountScopedApiKeyWorkspaceAuthority,
|
|
10
|
+
organizationWorkspaceInScope,
|
|
11
|
+
hasPermission,
|
|
12
|
+
requireAccessContext,
|
|
13
|
+
requireAccessGrantAuthorization,
|
|
14
|
+
requireSessionAuthorizationListScope,
|
|
15
|
+
SessionAuthorizationDeniedError,
|
|
16
|
+
SessionAuthorizationUnavailableError,
|
|
17
|
+
type ApiRouteDeps,
|
|
18
|
+
isVerifiedDelegatedHumanAuthorization,
|
|
19
|
+
} from "@opengeni/core";
|
|
20
|
+
import {
|
|
21
|
+
decodeSessionListCursor,
|
|
22
|
+
listSessionsForSubject,
|
|
23
|
+
listSharedWorkspacesForAccount,
|
|
24
|
+
SessionListAccessError,
|
|
25
|
+
SessionListCursorError,
|
|
26
|
+
SessionListCursorExpiredError,
|
|
27
|
+
} from "@opengeni/db";
|
|
28
|
+
import type { Context, Hono } from "hono";
|
|
29
|
+
import { HTTPException } from "hono/http-exception";
|
|
30
|
+
import { z } from "zod";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Upper bound on the workspace page reads one request performs. The
|
|
34
|
+
* organization list fans out over every shared workspace in stable id order,
|
|
35
|
+
* one RLS-scoped transaction per workspace, so an organization with many empty
|
|
36
|
+
* tenant workspaces would otherwise turn a single request into an unbounded
|
|
37
|
+
* scan. When the budget runs out the page is returned short with `nextCursor`
|
|
38
|
+
* pointing at the next unread position.
|
|
39
|
+
*/
|
|
40
|
+
export const ORGANIZATION_SESSION_LIST_MAX_WORKSPACE_READS = 25;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Base64url JSON `{ workspaceId, cursor, pinnedOffset? }`; `cursor` is the
|
|
44
|
+
* workspace list cursor or null. A subject's pinned sessions precede the
|
|
45
|
+
* ordinary keyset page of a workspace; when a page boundary falls inside that
|
|
46
|
+
* pinned prefix, `pinnedOffset` records how many pinned rows were already
|
|
47
|
+
* returned so the next page resumes after them instead of repeating them.
|
|
48
|
+
*/
|
|
49
|
+
export type OrganizationSessionListCursor = {
|
|
50
|
+
workspaceId: string;
|
|
51
|
+
cursor: string | null;
|
|
52
|
+
pinnedOffset?: number | undefined;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const OrganizationId = z.string().uuid();
|
|
56
|
+
|
|
57
|
+
const OrganizationSessionListCursorEnvelope = z
|
|
58
|
+
.object({
|
|
59
|
+
workspaceId: z.string().uuid(),
|
|
60
|
+
cursor: z.string().min(1).nullable(),
|
|
61
|
+
pinnedOffset: z.number().int().nonnegative().max(10_000).optional(),
|
|
62
|
+
})
|
|
63
|
+
.strict();
|
|
64
|
+
|
|
65
|
+
export function encodeOrganizationSessionListCursor(cursor: OrganizationSessionListCursor): string {
|
|
66
|
+
return Buffer.from(JSON.stringify(cursor)).toString("base64url");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function decodeOrganizationSessionListCursor(
|
|
70
|
+
value: string,
|
|
71
|
+
): OrganizationSessionListCursor | null {
|
|
72
|
+
let parsed: unknown;
|
|
73
|
+
try {
|
|
74
|
+
parsed = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const envelope = OrganizationSessionListCursorEnvelope.safeParse(parsed);
|
|
79
|
+
if (!envelope.success) return null;
|
|
80
|
+
if (envelope.data.cursor !== null && !decodeSessionListCursor(envelope.data.cursor)) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return envelope.data;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type OrganizationSessionReadAuthority = "organization_api_key" | "account_admin";
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Who may read the organization-wide session list.
|
|
90
|
+
*
|
|
91
|
+
* An organization API key qualifies through its exact stamped workspace
|
|
92
|
+
* authority when that authority carries `sessions:read` (a `full` key holds the
|
|
93
|
+
* `workspace:admin` wildcard, a `read` key holds the literal). A human
|
|
94
|
+
* organization owner qualifies through an `account:admin` account grant, but
|
|
95
|
+
* that grant alone opens no workspace: every workspace is still authorized
|
|
96
|
+
* through the ordinary per-workspace grant resolution below, so an owner sees
|
|
97
|
+
* exactly the shared workspaces they are a member of.
|
|
98
|
+
*/
|
|
99
|
+
function requireOrganizationSessionReadAuthority(
|
|
100
|
+
context: AccessContext,
|
|
101
|
+
organizationId: string,
|
|
102
|
+
): OrganizationSessionReadAuthority {
|
|
103
|
+
const authority = accountScopedApiKeyWorkspaceAuthority(context);
|
|
104
|
+
if (authority) {
|
|
105
|
+
if (
|
|
106
|
+
authority.accountId === organizationId &&
|
|
107
|
+
hasPermission(authority.permissions, "sessions:read")
|
|
108
|
+
) {
|
|
109
|
+
return "organization_api_key";
|
|
110
|
+
}
|
|
111
|
+
throw new HTTPException(403, { message: "organization session read authority required" });
|
|
112
|
+
}
|
|
113
|
+
const accountGrant = context.accountGrants.find(
|
|
114
|
+
(candidate) => candidate.accountId === organizationId,
|
|
115
|
+
);
|
|
116
|
+
if (accountGrant?.permissions.includes("account:admin")) {
|
|
117
|
+
return "account_admin";
|
|
118
|
+
}
|
|
119
|
+
throw new HTTPException(403, { message: "organization session read authority required" });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Same projection as the workspace session list: denial reads as absence. */
|
|
123
|
+
function sessionAuthorizationHttpError(error: unknown): HTTPException {
|
|
124
|
+
if (error instanceof SessionAuthorizationDeniedError) {
|
|
125
|
+
return new HTTPException(404, { message: "session not found" });
|
|
126
|
+
}
|
|
127
|
+
if (error instanceof SessionAuthorizationUnavailableError) {
|
|
128
|
+
return new HTTPException(503, { message: "session authorization is unavailable" });
|
|
129
|
+
}
|
|
130
|
+
if (error instanceof HTTPException) return error;
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function compareWorkspaceIds(left: Workspace, right: Workspace): number {
|
|
135
|
+
return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function registerOrganizationSessionRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
139
|
+
app.get("/v1/organizations/:organizationId/sessions", async (c) => {
|
|
140
|
+
const organizationIdResult = OrganizationId.safeParse(c.req.param("organizationId"));
|
|
141
|
+
if (!organizationIdResult.success) {
|
|
142
|
+
throw new HTTPException(422, { message: "invalid organization id" });
|
|
143
|
+
}
|
|
144
|
+
const organizationId = organizationIdResult.data;
|
|
145
|
+
const context = await requireAccessContext(c, deps);
|
|
146
|
+
const readAuthority = requireOrganizationSessionReadAuthority(context, organizationId);
|
|
147
|
+
|
|
148
|
+
const queryResult = ListOrganizationSessionsQuery.safeParse(c.req.query());
|
|
149
|
+
if (!queryResult.success) {
|
|
150
|
+
const issue = queryResult.error.issues[0];
|
|
151
|
+
throw new HTTPException(400, {
|
|
152
|
+
message: issue
|
|
153
|
+
? `${issue.path.length > 0 ? `${issue.path.join(".")}: ` : ""}${issue.message}`
|
|
154
|
+
: "invalid organization session list query",
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
const query = queryResult.data;
|
|
158
|
+
const cursor = query.cursor ? decodeOrganizationSessionListCursor(query.cursor) : null;
|
|
159
|
+
if (query.cursor && !cursor) {
|
|
160
|
+
throw new HTTPException(400, { message: "cursor is invalid" });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Personal workspaces are excluded by the inventory itself; the stable id
|
|
164
|
+
// order is what makes the `{ workspaceId, cursor }` continuation resumable
|
|
165
|
+
// even when a workspace is created or deleted between pages.
|
|
166
|
+
const authority = accountScopedApiKeyWorkspaceAuthority(context);
|
|
167
|
+
const workspaces = (await listSharedWorkspacesForAccount(deps.db, organizationId))
|
|
168
|
+
.filter(
|
|
169
|
+
(workspace) =>
|
|
170
|
+
!authority || organizationWorkspaceInScope(authority.workspaceScope, workspace.id),
|
|
171
|
+
)
|
|
172
|
+
.sort(compareWorkspaceIds);
|
|
173
|
+
let index = 0;
|
|
174
|
+
let innerCursor: string | null = null;
|
|
175
|
+
let pinnedOffset = 0;
|
|
176
|
+
if (cursor) {
|
|
177
|
+
index = workspaces.findIndex((workspace) => workspace.id >= cursor.workspaceId);
|
|
178
|
+
if (index === -1) index = workspaces.length;
|
|
179
|
+
if (workspaces[index]?.id === cursor.workspaceId) {
|
|
180
|
+
innerCursor = cursor.cursor;
|
|
181
|
+
pinnedOffset = cursor.cursor === null ? (cursor.pinnedOffset ?? 0) : 0;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const sessions: Session[] = [];
|
|
186
|
+
let reads = 0;
|
|
187
|
+
while (
|
|
188
|
+
index < workspaces.length &&
|
|
189
|
+
sessions.length < query.limit &&
|
|
190
|
+
reads < ORGANIZATION_SESSION_LIST_MAX_WORKSPACE_READS
|
|
191
|
+
) {
|
|
192
|
+
const workspace = workspaces[index]!;
|
|
193
|
+
reads += 1;
|
|
194
|
+
const page = await listWorkspaceSessionPage(c, deps, {
|
|
195
|
+
workspace,
|
|
196
|
+
readAuthority,
|
|
197
|
+
innerCursor,
|
|
198
|
+
pinnedOffset,
|
|
199
|
+
limit: query.limit - sessions.length,
|
|
200
|
+
query,
|
|
201
|
+
});
|
|
202
|
+
if (page === null) {
|
|
203
|
+
// The caller holds no session read grant on this shared workspace
|
|
204
|
+
// (an organization owner who is not a member). Skip it entirely.
|
|
205
|
+
index += 1;
|
|
206
|
+
innerCursor = null;
|
|
207
|
+
pinnedOffset = 0;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
sessions.push(...page.sessions);
|
|
211
|
+
if (page.nextPinnedOffset !== null) {
|
|
212
|
+
// The page ended inside this workspace's pinned prefix.
|
|
213
|
+
innerCursor = null;
|
|
214
|
+
pinnedOffset = page.nextPinnedOffset;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
pinnedOffset = 0;
|
|
218
|
+
if (page.nextCursor) {
|
|
219
|
+
innerCursor = page.nextCursor;
|
|
220
|
+
} else {
|
|
221
|
+
index += 1;
|
|
222
|
+
innerCursor = null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const nextWorkspace = workspaces[index];
|
|
227
|
+
const response: OrganizationSessionListResponse = {
|
|
228
|
+
sessions,
|
|
229
|
+
nextCursor: nextWorkspace
|
|
230
|
+
? encodeOrganizationSessionListCursor({
|
|
231
|
+
workspaceId: nextWorkspace.id,
|
|
232
|
+
cursor: innerCursor,
|
|
233
|
+
...(innerCursor === null && pinnedOffset > 0 ? { pinnedOffset } : {}),
|
|
234
|
+
})
|
|
235
|
+
: null,
|
|
236
|
+
};
|
|
237
|
+
return c.json(response);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* One RLS-scoped workspace page, authorized exactly like
|
|
243
|
+
* `GET /v1/workspaces/:workspaceId/sessions`: the ordinary per-workspace grant
|
|
244
|
+
* (synthesized for an organization key, membership-backed for a human), the
|
|
245
|
+
* host list scope, and the subject-keyed row visibility. Private sessions the
|
|
246
|
+
* subject does not own never leave the database. Returns null only when an
|
|
247
|
+
* account administrator holds no session read grant on the workspace.
|
|
248
|
+
*/
|
|
249
|
+
async function listWorkspaceSessionPage(
|
|
250
|
+
c: Context,
|
|
251
|
+
deps: ApiRouteDeps,
|
|
252
|
+
input: {
|
|
253
|
+
workspace: Workspace;
|
|
254
|
+
readAuthority: OrganizationSessionReadAuthority;
|
|
255
|
+
innerCursor: string | null;
|
|
256
|
+
/** Pinned rows already returned from this workspace's first page. */
|
|
257
|
+
pinnedOffset: number;
|
|
258
|
+
limit: number;
|
|
259
|
+
query: ListOrganizationSessionsQuery;
|
|
260
|
+
},
|
|
261
|
+
): Promise<{
|
|
262
|
+
sessions: Session[];
|
|
263
|
+
nextCursor: string | null;
|
|
264
|
+
/** Set when the page boundary fell inside the pinned prefix; resume there with a null cursor. */
|
|
265
|
+
nextPinnedOffset: number | null;
|
|
266
|
+
} | null> {
|
|
267
|
+
let authorization: Awaited<ReturnType<typeof requireAccessGrantAuthorization>>;
|
|
268
|
+
try {
|
|
269
|
+
authorization = await requireAccessGrantAuthorization(
|
|
270
|
+
c,
|
|
271
|
+
deps,
|
|
272
|
+
input.workspace.id,
|
|
273
|
+
"sessions:read",
|
|
274
|
+
);
|
|
275
|
+
} catch (error) {
|
|
276
|
+
if (
|
|
277
|
+
input.readAuthority === "account_admin" &&
|
|
278
|
+
error instanceof HTTPException &&
|
|
279
|
+
error.status === 403
|
|
280
|
+
) {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
throw error;
|
|
284
|
+
}
|
|
285
|
+
const grant = authorization.grant;
|
|
286
|
+
let authorizationScope;
|
|
287
|
+
try {
|
|
288
|
+
authorizationScope = await requireSessionAuthorizationListScope(deps, grant, "http");
|
|
289
|
+
} catch (error) {
|
|
290
|
+
throw sessionAuthorizationHttpError(error);
|
|
291
|
+
}
|
|
292
|
+
const cursor = input.innerCursor ? decodeSessionListCursor(input.innerCursor) : null;
|
|
293
|
+
if (input.innerCursor && !cursor) {
|
|
294
|
+
throw new HTTPException(400, { message: "cursor is invalid" });
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
const list = async (limit: number) =>
|
|
298
|
+
await listSessionsForSubject(deps.db, input.workspace.id, {
|
|
299
|
+
subjectId: grant.subjectId,
|
|
300
|
+
limit,
|
|
301
|
+
materializeSnapshot: true,
|
|
302
|
+
...(cursor ? { cursor } : {}),
|
|
303
|
+
...(input.query.scopeSubjectId !== undefined
|
|
304
|
+
? { scopeSubjectId: input.query.scopeSubjectId }
|
|
305
|
+
: {}),
|
|
306
|
+
...(authorizationScope ? { authorizationScope } : {}),
|
|
307
|
+
personalWorkspaceOwnerException:
|
|
308
|
+
authorization.canonicalManagedHumanSession ||
|
|
309
|
+
isVerifiedDelegatedHumanAuthorization(authorization),
|
|
310
|
+
});
|
|
311
|
+
const withStatus = (rows: Session[]) =>
|
|
312
|
+
input.query.status ? rows.filter((session) => session.status === input.query.status) : rows;
|
|
313
|
+
let page = await list(input.limit);
|
|
314
|
+
let rows: Session[];
|
|
315
|
+
let nextPinnedOffset: number | null = null;
|
|
316
|
+
if (cursor) {
|
|
317
|
+
// A keyset continuation never carries pinned rows.
|
|
318
|
+
rows = page.sessions;
|
|
319
|
+
} else {
|
|
320
|
+
// The subject's pinned sessions are excluded from the ordinary keyset
|
|
321
|
+
// page and lead this workspace's first page. They count toward the
|
|
322
|
+
// requested limit like any other row: when the boundary falls inside
|
|
323
|
+
// the pinned prefix the caller resumes at `nextPinnedOffset`, and
|
|
324
|
+
// otherwise the ordinary page is re-read at exactly the remaining
|
|
325
|
+
// budget so its keyset cursor lands after the last returned row.
|
|
326
|
+
const pinned = page.pinned.slice(input.pinnedOffset);
|
|
327
|
+
if (pinned.length >= input.limit) {
|
|
328
|
+
rows = pinned.slice(0, input.limit);
|
|
329
|
+
nextPinnedOffset = input.pinnedOffset + input.limit;
|
|
330
|
+
return { sessions: withStatus(rows), nextCursor: null, nextPinnedOffset };
|
|
331
|
+
}
|
|
332
|
+
if (pinned.length > 0 && page.sessions.length > input.limit - pinned.length) {
|
|
333
|
+
page = await list(input.limit - pinned.length);
|
|
334
|
+
}
|
|
335
|
+
rows = [...pinned, ...page.sessions];
|
|
336
|
+
}
|
|
337
|
+
return { sessions: withStatus(rows), nextCursor: page.nextCursor, nextPinnedOffset };
|
|
338
|
+
} catch (error) {
|
|
339
|
+
if (error instanceof SessionListAccessError) {
|
|
340
|
+
throw new HTTPException(403, { message: error.message });
|
|
341
|
+
}
|
|
342
|
+
if (error instanceof SessionListCursorExpiredError) {
|
|
343
|
+
throw new HTTPException(410, { message: error.message });
|
|
344
|
+
}
|
|
345
|
+
if (error instanceof SessionListCursorError) {
|
|
346
|
+
throw new HTTPException(400, { message: error.message });
|
|
347
|
+
}
|
|
348
|
+
throw error;
|
|
349
|
+
}
|
|
350
|
+
}
|