@useatlas/create 0.0.6 → 0.0.7
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/LICENSE +21 -0
- package/README.md +1 -1
- package/index.ts +253 -36
- package/package.json +4 -4
- package/templates/docker/Dockerfile +1 -1
- package/templates/docker/Dockerfile.sidecar +1 -1
- package/templates/docker/bin/__tests__/duckdb-ingest.test.ts +17 -14
- package/templates/docker/bin/__tests__/failure-threshold.test.ts +148 -0
- package/templates/docker/bin/__tests__/fatal-error-propagation.test.ts +267 -0
- package/templates/docker/bin/__tests__/profiler-heuristics.test.ts +5 -5
- package/templates/docker/bin/__tests__/schema-drift.test.ts +39 -0
- package/templates/docker/bin/atlas.ts +981 -1819
- package/templates/docker/bin/benchmark.ts +14 -16
- package/templates/docker/bin/enrich.ts +7 -2
- package/templates/docker/brand.css +13 -0
- package/templates/docker/data/cybersec-semantic/catalog.yml +222 -0
- package/templates/docker/data/cybersec-semantic/entities/alerts.yml +195 -0
- package/templates/docker/data/cybersec-semantic/entities/assets.yml +191 -0
- package/templates/docker/data/cybersec-semantic/entities/compliance_assessments.yml +170 -0
- package/templates/docker/data/cybersec-semantic/entities/incidents.yml +219 -0
- package/templates/docker/data/cybersec-semantic/entities/organizations.yml +136 -0
- package/templates/docker/data/cybersec-semantic/entities/plans.yml +114 -0
- package/templates/docker/data/cybersec-semantic/entities/remediation_actions.yml +212 -0
- package/templates/docker/data/cybersec-semantic/entities/scan_results.yml +215 -0
- package/templates/docker/data/cybersec-semantic/entities/scans.yml +180 -0
- package/templates/docker/data/cybersec-semantic/entities/subscriptions.yml +184 -0
- package/templates/docker/data/cybersec-semantic/entities/users.yml +140 -0
- package/templates/docker/data/cybersec-semantic/entities/vulnerabilities.yml +154 -0
- package/templates/docker/data/cybersec-semantic/glossary.yml +207 -0
- package/templates/docker/data/cybersec-semantic/metrics/business.yml +148 -0
- package/templates/docker/data/cybersec-semantic/metrics/compliance.yml +138 -0
- package/templates/docker/data/cybersec-semantic/metrics/security.yml +181 -0
- package/templates/docker/data/cybersec.sql +8 -8
- package/templates/docker/data/demo.sql +3 -0
- package/templates/docker/data/ecommerce-semantic/catalog.yml +221 -0
- package/templates/docker/data/ecommerce-semantic/entities/categories.yml +91 -0
- package/templates/docker/data/ecommerce-semantic/entities/customers.yml +133 -0
- package/templates/docker/data/ecommerce-semantic/entities/email_campaigns.yml +119 -0
- package/templates/docker/data/ecommerce-semantic/entities/inventory_levels.yml +153 -0
- package/templates/docker/data/ecommerce-semantic/entities/order_items.yml +159 -0
- package/templates/docker/data/ecommerce-semantic/entities/orders.yml +199 -0
- package/templates/docker/data/ecommerce-semantic/entities/payments.yml +140 -0
- package/templates/docker/data/ecommerce-semantic/entities/product_reviews.yml +155 -0
- package/templates/docker/data/ecommerce-semantic/entities/products.yml +178 -0
- package/templates/docker/data/ecommerce-semantic/entities/promotions.yml +171 -0
- package/templates/docker/data/ecommerce-semantic/entities/returns.yml +144 -0
- package/templates/docker/data/ecommerce-semantic/entities/sellers.yml +124 -0
- package/templates/docker/data/ecommerce-semantic/entities/shipments.yml +159 -0
- package/templates/docker/data/ecommerce-semantic/glossary.yml +193 -0
- package/templates/docker/data/ecommerce-semantic/metrics/customers.yml +116 -0
- package/templates/docker/data/ecommerce-semantic/metrics/operations.yml +131 -0
- package/templates/docker/data/ecommerce-semantic/metrics/revenue.yml +120 -0
- package/templates/docker/docs/deploy.md +2 -1
- package/templates/docker/ee/src/__mocks__/internal.ts +170 -0
- package/templates/docker/ee/src/audit/purge-scheduler.ts +113 -0
- package/templates/docker/ee/src/audit/retention.ts +467 -0
- package/templates/docker/ee/src/auth/ip-allowlist.ts +367 -0
- package/templates/docker/ee/src/auth/roles.ts +562 -0
- package/templates/docker/ee/src/auth/scim.ts +343 -0
- package/templates/docker/ee/src/auth/sso.ts +538 -0
- package/templates/docker/ee/src/backups/engine.ts +355 -0
- package/templates/docker/ee/src/backups/index.ts +26 -0
- package/templates/docker/ee/src/backups/restore.ts +169 -0
- package/templates/docker/ee/src/backups/scheduler.ts +153 -0
- package/templates/docker/ee/src/backups/verify.ts +124 -0
- package/templates/docker/ee/src/branding/white-label.ts +228 -0
- package/templates/docker/ee/src/compliance/masking.ts +477 -0
- package/templates/docker/ee/src/compliance/patterns.ts +16 -0
- package/templates/docker/ee/src/compliance/pii-detection.ts +217 -0
- package/templates/docker/ee/src/compliance/reports.ts +402 -0
- package/templates/docker/ee/src/deploy-mode.ts +37 -0
- package/templates/docker/ee/src/governance/approval.ts +699 -0
- package/templates/docker/ee/src/index.ts +74 -0
- package/templates/docker/ee/src/platform/domains.ts +562 -0
- package/templates/docker/ee/src/platform/model-routing.ts +382 -0
- package/templates/docker/ee/src/platform/residency.ts +265 -0
- package/templates/docker/ee/src/sla/alerting.ts +382 -0
- package/templates/docker/ee/src/sla/index.ts +12 -0
- package/templates/docker/ee/src/sla/metrics.ts +275 -0
- package/templates/docker/ee/src/test-setup.ts +1 -0
- package/templates/docker/next.config.ts +4 -1
- package/templates/docker/package.json +49 -29
- package/templates/docker/sidecar/Dockerfile +1 -1
- package/templates/docker/src/api/index.ts +336 -24
- package/templates/docker/src/api/routes/actions.ts +443 -176
- package/templates/docker/src/api/routes/admin-abuse.ts +219 -0
- package/templates/docker/src/api/routes/admin-approval.ts +418 -0
- package/templates/docker/src/api/routes/admin-audit-retention.ts +405 -0
- package/templates/docker/src/api/routes/admin-auth.ts +122 -0
- package/templates/docker/src/api/routes/admin-branding.ts +252 -0
- package/templates/docker/src/api/routes/admin-compliance.ts +352 -0
- package/templates/docker/src/api/routes/admin-domains.ts +334 -0
- package/templates/docker/src/api/routes/admin-integrations.ts +2667 -0
- package/templates/docker/src/api/routes/admin-ip-allowlist.ts +261 -0
- package/templates/docker/src/api/routes/admin-learned-patterns.ts +525 -0
- package/templates/docker/src/api/routes/admin-model-config.ts +252 -0
- package/templates/docker/src/api/routes/admin-onboarding-emails.ts +145 -0
- package/templates/docker/src/api/routes/admin-orgs.ts +710 -0
- package/templates/docker/src/api/routes/admin-prompts.ts +694 -0
- package/templates/docker/src/api/routes/admin-residency.ts +570 -0
- package/templates/docker/src/api/routes/admin-roles.ts +296 -0
- package/templates/docker/src/api/routes/admin-router.ts +120 -0
- package/templates/docker/src/api/routes/admin-sandbox.ts +417 -0
- package/templates/docker/src/api/routes/admin-scim.ts +262 -0
- package/templates/docker/src/api/routes/admin-sso.ts +545 -0
- package/templates/docker/src/api/routes/admin-suggestions.ts +176 -0
- package/templates/docker/src/api/routes/admin-usage.ts +310 -0
- package/templates/docker/src/api/routes/admin.ts +4156 -898
- package/templates/docker/src/api/routes/auth-preamble.ts +105 -0
- package/templates/docker/src/api/routes/billing.ts +397 -0
- package/templates/docker/src/api/routes/chat.ts +597 -334
- package/templates/docker/src/api/routes/conversations.ts +987 -132
- package/templates/docker/src/api/routes/demo.ts +673 -0
- package/templates/docker/src/api/routes/discord.ts +274 -0
- package/templates/docker/src/api/routes/ee-error-handler.ts +32 -0
- package/templates/docker/src/api/routes/health.ts +129 -14
- package/templates/docker/src/api/routes/middleware.ts +244 -0
- package/templates/docker/src/api/routes/onboarding-emails.ts +134 -0
- package/templates/docker/src/api/routes/onboarding.ts +1109 -0
- package/templates/docker/src/api/routes/openapi.ts +184 -1597
- package/templates/docker/src/api/routes/platform-admin.ts +760 -0
- package/templates/docker/src/api/routes/platform-backups.ts +436 -0
- package/templates/docker/src/api/routes/platform-domains.ts +235 -0
- package/templates/docker/src/api/routes/platform-residency.ts +257 -0
- package/templates/docker/src/api/routes/platform-sla.ts +379 -0
- package/templates/docker/src/api/routes/prompts.ts +221 -0
- package/templates/docker/src/api/routes/public-branding.ts +106 -0
- package/templates/docker/src/api/routes/query.ts +330 -219
- package/templates/docker/src/api/routes/scheduled-tasks.ts +393 -297
- package/templates/docker/src/api/routes/semantic.ts +179 -0
- package/templates/docker/src/api/routes/sessions.ts +210 -0
- package/templates/docker/src/api/routes/shared-domains.ts +98 -0
- package/templates/docker/src/api/routes/shared-schemas.ts +139 -0
- package/templates/docker/src/api/routes/slack.ts +209 -52
- package/templates/docker/src/api/routes/suggestions.ts +233 -0
- package/templates/docker/src/api/routes/tables.ts +67 -0
- package/templates/docker/src/api/routes/teams.ts +222 -0
- package/templates/docker/src/api/routes/validate-sql.ts +188 -0
- package/templates/docker/src/api/routes/validation-hook.ts +62 -0
- package/templates/docker/src/api/routes/widget-loader.ts +356 -0
- package/templates/docker/src/api/routes/widget.ts +428 -0
- package/templates/docker/src/api/routes/wizard.ts +852 -0
- package/templates/docker/src/api/server.ts +187 -69
- package/templates/docker/src/app/error.tsx +5 -2
- package/templates/docker/src/app/globals.css +1 -1
- package/templates/docker/src/app/layout.tsx +7 -2
- package/templates/docker/src/app/page.tsx +39 -5
- package/templates/docker/src/components/data-table/data-table-column-header.tsx +99 -0
- package/templates/docker/src/components/data-table/data-table-date-filter.tsx +225 -0
- package/templates/docker/src/components/data-table/data-table-expandable.tsx +125 -0
- package/templates/docker/src/components/data-table/data-table-faceted-filter.tsx +189 -0
- package/templates/docker/src/components/data-table/data-table-pagination.tsx +112 -0
- package/templates/docker/src/components/data-table/data-table-range-filter.tsx +122 -0
- package/templates/docker/src/components/data-table/data-table-slider-filter.tsx +256 -0
- package/templates/docker/src/components/data-table/data-table-sort-list.tsx +407 -0
- package/templates/docker/src/components/data-table/data-table-toolbar.tsx +149 -0
- package/templates/docker/src/components/data-table/data-table-view-options.tsx +89 -0
- package/templates/docker/src/components/data-table/data-table.tsx +105 -0
- package/templates/docker/src/components/form-dialog.tsx +135 -0
- package/templates/docker/src/components/ui/accordion.tsx +66 -0
- package/templates/docker/src/components/ui/calendar.tsx +220 -0
- package/templates/docker/src/components/ui/checkbox.tsx +32 -0
- package/templates/docker/src/components/ui/faceted.tsx +283 -0
- package/templates/docker/src/components/ui/form.tsx +167 -0
- package/templates/docker/src/components/ui/label.tsx +24 -0
- package/templates/docker/src/components/ui/popover.tsx +89 -0
- package/templates/docker/src/components/ui/progress.tsx +31 -0
- package/templates/docker/src/components/ui/scroll-area.tsx +6 -2
- package/templates/docker/src/components/ui/slider.tsx +63 -0
- package/templates/docker/src/components/ui/sortable.tsx +581 -0
- package/templates/docker/src/components/ui/switch.tsx +35 -0
- package/templates/docker/src/components/ui/textarea.tsx +18 -0
- package/templates/docker/src/config/data-table.ts +82 -0
- package/templates/docker/src/env-check.ts +74 -0
- package/templates/docker/src/hooks/use-callback-ref.ts +27 -0
- package/templates/docker/src/hooks/use-data-table.ts +316 -0
- package/templates/docker/src/hooks/use-debounced-callback.ts +28 -0
- package/templates/docker/src/lib/action-types.ts +7 -41
- package/templates/docker/src/lib/agent-query.ts +4 -2
- package/templates/docker/src/lib/agent.ts +363 -31
- package/templates/docker/src/lib/auth/admin-permissions.ts +38 -0
- package/templates/docker/src/lib/auth/audit.ts +19 -4
- package/templates/docker/src/lib/auth/byot.ts +3 -3
- package/templates/docker/src/lib/auth/client.ts +33 -3
- package/templates/docker/src/lib/auth/detect.ts +29 -8
- package/templates/docker/src/lib/auth/managed.ts +104 -14
- package/templates/docker/src/lib/auth/middleware.ts +53 -6
- package/templates/docker/src/lib/auth/migrate.ts +140 -15
- package/templates/docker/src/lib/auth/oauth-state.ts +123 -0
- package/templates/docker/src/lib/auth/org-permissions.ts +55 -0
- package/templates/docker/src/lib/auth/permissions.ts +26 -19
- package/templates/docker/src/lib/auth/server.ts +355 -9
- package/templates/docker/src/lib/auth/simple-key.ts +3 -3
- package/templates/docker/src/lib/auth/types.ts +15 -21
- package/templates/docker/src/lib/billing/enforcement.ts +368 -0
- package/templates/docker/src/lib/billing/plans.ts +155 -0
- package/templates/docker/src/lib/cache/index.ts +92 -0
- package/templates/docker/src/lib/cache/keys.ts +30 -0
- package/templates/docker/src/lib/cache/lru.ts +79 -0
- package/templates/docker/src/lib/cache/types.ts +31 -0
- package/templates/docker/src/lib/compose-refs.ts +62 -0
- package/templates/docker/src/lib/config.ts +563 -11
- package/templates/docker/src/lib/connection-types.ts +9 -0
- package/templates/docker/src/lib/conversation-types.ts +1 -25
- package/templates/docker/src/lib/conversations.ts +345 -14
- package/templates/docker/src/lib/data-table.ts +61 -0
- package/templates/docker/src/lib/db/connection.ts +793 -39
- package/templates/docker/src/lib/db/internal.ts +985 -139
- package/templates/docker/src/lib/db/migrate.ts +295 -0
- package/templates/docker/src/lib/db/migrations/0000_baseline.sql +703 -0
- package/templates/docker/src/lib/db/migrations/0001_teams_installations.sql +14 -0
- package/templates/docker/src/lib/db/migrations/0002_discord_installations.sql +14 -0
- package/templates/docker/src/lib/db/migrations/0003_telegram_installations.sql +15 -0
- package/templates/docker/src/lib/db/migrations/0004_sandbox_credentials.sql +18 -0
- package/templates/docker/src/lib/db/migrations/0005_oauth_state.sql +16 -0
- package/templates/docker/src/lib/db/migrations/0006_byot_credentials.sql +14 -0
- package/templates/docker/src/lib/db/migrations/0007_gchat_installations.sql +15 -0
- package/templates/docker/src/lib/db/migrations/0008_github_installations.sql +14 -0
- package/templates/docker/src/lib/db/migrations/0009_linear_installations.sql +15 -0
- package/templates/docker/src/lib/db/migrations/0010_whatsapp_installations.sql +14 -0
- package/templates/docker/src/lib/db/migrations/0011_email_installations.sql +16 -0
- package/templates/docker/src/lib/db/migrations/0012_region_migrations.sql +25 -0
- package/templates/docker/src/lib/db/schema.ts +1120 -0
- package/templates/docker/src/lib/db/source-rate-limit.ts +89 -139
- package/templates/docker/src/lib/demo.ts +308 -0
- package/templates/docker/src/lib/discord/store.ts +225 -0
- package/templates/docker/src/lib/effect/ai.ts +243 -0
- package/templates/docker/src/lib/effect/errors.ts +234 -0
- package/templates/docker/src/lib/effect/hono.ts +454 -0
- package/templates/docker/src/lib/effect/index.ts +137 -0
- package/templates/docker/src/lib/effect/layers.ts +496 -0
- package/templates/docker/src/lib/effect/services.ts +776 -0
- package/templates/docker/src/lib/effect/sql.ts +178 -0
- package/templates/docker/src/lib/effect/toolkit.ts +123 -0
- package/templates/docker/src/lib/email/delivery.ts +232 -0
- package/templates/docker/src/lib/email/engine.ts +349 -0
- package/templates/docker/src/lib/email/hooks.ts +107 -0
- package/templates/docker/src/lib/email/index.ts +16 -0
- package/templates/docker/src/lib/email/scheduler.ts +72 -0
- package/templates/docker/src/lib/email/sequence.ts +73 -0
- package/templates/docker/src/lib/email/store.ts +163 -0
- package/templates/docker/src/lib/email/templates.ts +215 -0
- package/templates/docker/src/lib/format.ts +67 -0
- package/templates/docker/src/lib/gchat/store.ts +202 -0
- package/templates/docker/src/lib/github/store.ts +197 -0
- package/templates/docker/src/lib/id.ts +29 -0
- package/templates/docker/src/lib/integrations/types.ts +166 -0
- package/templates/docker/src/lib/learn/pattern-analyzer.ts +224 -0
- package/templates/docker/src/lib/learn/pattern-cache.ts +229 -0
- package/templates/docker/src/lib/learn/pattern-proposer.ts +87 -0
- package/templates/docker/src/lib/learn/suggestion-helpers.ts +34 -0
- package/templates/docker/src/lib/learn/suggestions.ts +139 -0
- package/templates/docker/src/lib/linear/store.ts +200 -0
- package/templates/docker/src/lib/logger.ts +35 -3
- package/templates/docker/src/lib/metering.ts +272 -0
- package/templates/docker/src/lib/parsers.ts +99 -0
- package/templates/docker/src/lib/plugins/hooks.ts +13 -11
- package/templates/docker/src/lib/plugins/index.ts +3 -1
- package/templates/docker/src/lib/plugins/registry.ts +58 -6
- package/templates/docker/src/lib/plugins/settings.ts +147 -0
- package/templates/docker/src/lib/plugins/wiring.ts +6 -9
- package/templates/docker/src/lib/profiler.ts +1665 -0
- package/templates/docker/src/lib/providers.ts +188 -13
- package/templates/docker/src/lib/rls.ts +172 -60
- package/templates/docker/src/lib/sandbox/credentials.ts +206 -0
- package/templates/docker/src/lib/sandbox/validate.ts +179 -0
- package/templates/docker/src/lib/scheduled-task-types.ts +26 -94
- package/templates/docker/src/lib/scheduled-tasks.ts +174 -34
- package/templates/docker/src/lib/scheduler/delivery.ts +248 -150
- package/templates/docker/src/lib/scheduler/engine.ts +190 -154
- package/templates/docker/src/lib/scheduler/executor.ts +74 -23
- package/templates/docker/src/lib/scheduler/preview.ts +72 -0
- package/templates/docker/src/lib/security/abuse.ts +463 -0
- package/templates/docker/src/lib/semantic/diff.ts +267 -0
- package/templates/docker/src/lib/semantic/entities.ts +167 -0
- package/templates/docker/src/lib/semantic/files.ts +283 -0
- package/templates/docker/src/lib/semantic/index.ts +27 -0
- package/templates/docker/src/lib/{semantic-index.ts → semantic/search.ts} +80 -9
- package/templates/docker/src/lib/semantic/sync.ts +581 -0
- package/templates/docker/src/lib/{semantic.ts → semantic/whitelist.ts} +189 -3
- package/templates/docker/src/lib/settings.ts +817 -0
- package/templates/docker/src/lib/sidecar-types.ts +13 -0
- package/templates/docker/src/lib/slack/store.ts +134 -25
- package/templates/docker/src/lib/startup.ts +528 -362
- package/templates/docker/src/lib/teams/store.ts +216 -0
- package/templates/docker/src/lib/telegram/store.ts +202 -0
- package/templates/docker/src/lib/telemetry.ts +40 -0
- package/templates/docker/src/lib/tools/actions/audit.ts +8 -5
- package/templates/docker/src/lib/tools/actions/email.ts +3 -1
- package/templates/docker/src/lib/tools/actions/handler.ts +276 -93
- package/templates/docker/src/lib/tools/actions/jira.ts +2 -2
- package/templates/docker/src/lib/tools/backends/detect.ts +16 -0
- package/templates/docker/src/lib/tools/backends/index.ts +11 -0
- package/templates/docker/src/lib/tools/backends/nsjail.ts +213 -0
- package/templates/docker/src/lib/tools/backends/shared.ts +103 -0
- package/templates/docker/src/lib/tools/backends/types.ts +26 -0
- package/templates/docker/src/lib/tools/explore-nsjail.ts +7 -228
- package/templates/docker/src/lib/tools/explore-sandbox.ts +4 -29
- package/templates/docker/src/lib/tools/explore-sidecar.ts +18 -2
- package/templates/docker/src/lib/tools/explore.ts +246 -54
- package/templates/docker/src/lib/tools/index.ts +17 -0
- package/templates/docker/src/lib/tools/python-nsjail.ts +11 -139
- package/templates/docker/src/lib/tools/python-sandbox.ts +9 -132
- package/templates/docker/src/lib/tools/python-sidecar.ts +184 -3
- package/templates/docker/src/lib/tools/python-stream.ts +33 -0
- package/templates/docker/src/lib/tools/python-wrapper.ts +129 -0
- package/templates/docker/src/lib/tools/python.ts +115 -15
- package/templates/docker/src/lib/tools/registry.ts +14 -2
- package/templates/docker/src/lib/tools/sql.ts +778 -362
- package/templates/docker/src/lib/tracing.ts +16 -0
- package/templates/docker/src/lib/whatsapp/store.ts +198 -0
- package/templates/docker/src/lib/workspace.ts +89 -0
- package/templates/docker/src/progress.ts +121 -0
- package/templates/docker/src/types/data-table.ts +48 -0
- package/templates/docker/src/ui/atlas-chat-reexport.ts +3 -0
- package/templates/docker/src/ui/components/actions/action-approval-card.tsx +26 -19
- package/templates/docker/src/ui/components/actions/action-status-badge.tsx +3 -3
- package/templates/docker/src/ui/components/admin/admin-layout.tsx +57 -39
- package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +213 -35
- package/templates/docker/src/ui/components/admin/delivery-status-badge.tsx +53 -0
- package/templates/docker/src/ui/components/admin/empty-state.tsx +27 -6
- package/templates/docker/src/ui/components/admin/entity-detail.tsx +3 -52
- package/templates/docker/src/ui/components/admin/error-banner.tsx +2 -2
- package/templates/docker/src/ui/components/admin/feature-disabled.tsx +28 -5
- package/templates/docker/src/ui/components/admin-content-wrapper.tsx +87 -0
- package/templates/docker/src/ui/components/atlas-chat.tsx +449 -166
- package/templates/docker/src/ui/components/branding-head.tsx +41 -0
- package/templates/docker/src/ui/components/chart/chart-detection.ts +62 -5
- package/templates/docker/src/ui/components/chart/result-chart.tsx +316 -125
- package/templates/docker/src/ui/components/chat/api-key-bar.tsx +4 -4
- package/templates/docker/src/ui/components/chat/data-table.tsx +45 -4
- package/templates/docker/src/ui/components/chat/error-banner.tsx +86 -5
- package/templates/docker/src/ui/components/chat/follow-up-chips.tsx +29 -0
- package/templates/docker/src/ui/components/chat/markdown.tsx +24 -0
- package/templates/docker/src/ui/components/chat/prompt-library.tsx +206 -0
- package/templates/docker/src/ui/components/chat/python-result-card.tsx +106 -78
- package/templates/docker/src/ui/components/chat/result-card-base.tsx +101 -0
- package/templates/docker/src/ui/components/chat/share-dialog.tsx +377 -0
- package/templates/docker/src/ui/components/chat/sql-result-card.tsx +94 -73
- package/templates/docker/src/ui/components/chat/suggestion-chips.tsx +46 -0
- package/templates/docker/src/ui/components/chat/tool-part.tsx +16 -4
- package/templates/docker/src/ui/components/conversations/conversation-item.tsx +48 -17
- package/templates/docker/src/ui/components/conversations/conversation-list.tsx +38 -24
- package/templates/docker/src/ui/components/conversations/conversation-sidebar.tsx +66 -7
- package/templates/docker/src/ui/components/conversations/delete-confirmation.tsx +9 -2
- package/templates/docker/src/ui/components/error-boundary.tsx +66 -0
- package/templates/docker/src/ui/components/notebook/delete-cell-dialog.tsx +48 -0
- package/templates/docker/src/ui/components/notebook/fork-branch-selector.tsx +68 -0
- package/templates/docker/src/ui/components/notebook/notebook-cell-input.tsx +76 -0
- package/templates/docker/src/ui/components/notebook/notebook-cell-output.tsx +58 -0
- package/templates/docker/src/ui/components/notebook/notebook-cell-toolbar.tsx +91 -0
- package/templates/docker/src/ui/components/notebook/notebook-cell.tsx +119 -0
- package/templates/docker/src/ui/components/notebook/notebook-empty-state.tsx +19 -0
- package/templates/docker/src/ui/components/notebook/notebook-export.ts +287 -0
- package/templates/docker/src/ui/components/notebook/notebook-input-bar.tsx +49 -0
- package/templates/docker/src/ui/components/notebook/notebook-shell.tsx +266 -0
- package/templates/docker/src/ui/components/notebook/notebook-text-cell.tsx +152 -0
- package/templates/docker/src/ui/components/notebook/types.ts +39 -0
- package/templates/docker/src/ui/components/notebook/use-keyboard-nav.ts +109 -0
- package/templates/docker/src/ui/components/notebook/use-notebook.ts +684 -0
- package/templates/docker/src/ui/components/org-switcher.tsx +111 -0
- package/templates/docker/src/ui/components/region-picker.tsx +103 -0
- package/templates/docker/src/ui/components/schema-explorer/schema-explorer.tsx +522 -0
- package/templates/docker/src/ui/components/social-icons.tsx +26 -0
- package/templates/docker/src/ui/components/tour/guided-tour.tsx +81 -0
- package/templates/docker/src/ui/components/tour/index.ts +5 -0
- package/templates/docker/src/ui/components/tour/nav-bar.tsx +100 -0
- package/templates/docker/src/ui/components/tour/tour-overlay.tsx +298 -0
- package/templates/docker/src/ui/components/tour/tour-steps.ts +43 -0
- package/templates/docker/src/ui/components/tour/types.ts +21 -0
- package/templates/docker/src/ui/components/tour/use-tour.ts +193 -0
- package/templates/docker/src/ui/context-reexport.ts +3 -0
- package/templates/docker/src/ui/hooks/theme-init-script.ts +17 -0
- package/templates/docker/src/ui/hooks/use-admin-fetch.ts +38 -30
- package/templates/docker/src/ui/hooks/use-admin-mutation.ts +188 -0
- package/templates/docker/src/ui/hooks/use-atlas-transport.ts +225 -0
- package/templates/docker/src/ui/hooks/use-branding.ts +68 -0
- package/templates/docker/src/ui/hooks/use-conversations.ts +106 -83
- package/templates/docker/src/ui/hooks/use-dark-mode.ts +134 -10
- package/templates/docker/src/ui/hooks/use-deploy-mode.ts +36 -0
- package/templates/docker/src/ui/hooks/use-platform-admin-guard.ts +49 -0
- package/templates/docker/src/ui/lib/action-types.ts +11 -63
- package/templates/docker/src/ui/lib/admin-schemas.ts +744 -0
- package/templates/docker/src/ui/lib/fetch-client.ts +84 -0
- package/templates/docker/src/ui/lib/fetch-error.ts +54 -0
- package/templates/docker/src/ui/lib/helpers.ts +94 -1
- package/templates/docker/src/ui/lib/types.ts +149 -140
- package/templates/docker/tsconfig.json +4 -2
- package/templates/nextjs-standalone/bin/__tests__/duckdb-ingest.test.ts +17 -14
- package/templates/nextjs-standalone/bin/__tests__/failure-threshold.test.ts +148 -0
- package/templates/nextjs-standalone/bin/__tests__/fatal-error-propagation.test.ts +267 -0
- package/templates/nextjs-standalone/bin/__tests__/profiler-heuristics.test.ts +5 -5
- package/templates/nextjs-standalone/bin/__tests__/schema-drift.test.ts +39 -0
- package/templates/nextjs-standalone/bin/atlas.ts +981 -1819
- package/templates/nextjs-standalone/bin/benchmark.ts +14 -16
- package/templates/nextjs-standalone/bin/enrich.ts +7 -2
- package/templates/nextjs-standalone/brand.css +13 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/catalog.yml +222 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/alerts.yml +195 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/assets.yml +191 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/compliance_assessments.yml +170 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/incidents.yml +219 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/organizations.yml +136 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/plans.yml +114 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/remediation_actions.yml +212 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/scan_results.yml +215 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/scans.yml +180 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/subscriptions.yml +184 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/users.yml +140 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/entities/vulnerabilities.yml +154 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/glossary.yml +207 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/metrics/business.yml +148 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/metrics/compliance.yml +138 -0
- package/templates/nextjs-standalone/data/cybersec-semantic/metrics/security.yml +181 -0
- package/templates/nextjs-standalone/data/cybersec.sql +8 -8
- package/templates/nextjs-standalone/data/demo.sql +3 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/catalog.yml +221 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/categories.yml +91 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/customers.yml +133 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/email_campaigns.yml +119 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/inventory_levels.yml +153 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/order_items.yml +159 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/orders.yml +199 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/payments.yml +140 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/product_reviews.yml +155 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/products.yml +178 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/promotions.yml +171 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/returns.yml +144 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/sellers.yml +124 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/entities/shipments.yml +159 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/glossary.yml +193 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/metrics/customers.yml +116 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/metrics/operations.yml +131 -0
- package/templates/nextjs-standalone/data/ecommerce-semantic/metrics/revenue.yml +120 -0
- package/templates/nextjs-standalone/docs/deploy.md +2 -1
- package/templates/nextjs-standalone/ee/src/__mocks__/internal.ts +170 -0
- package/templates/nextjs-standalone/ee/src/audit/purge-scheduler.ts +113 -0
- package/templates/nextjs-standalone/ee/src/audit/retention.ts +467 -0
- package/templates/nextjs-standalone/ee/src/auth/ip-allowlist.ts +367 -0
- package/templates/nextjs-standalone/ee/src/auth/roles.ts +562 -0
- package/templates/nextjs-standalone/ee/src/auth/scim.ts +343 -0
- package/templates/nextjs-standalone/ee/src/auth/sso.ts +538 -0
- package/templates/nextjs-standalone/ee/src/backups/engine.ts +355 -0
- package/templates/nextjs-standalone/ee/src/backups/index.ts +26 -0
- package/templates/nextjs-standalone/ee/src/backups/restore.ts +169 -0
- package/templates/nextjs-standalone/ee/src/backups/scheduler.ts +153 -0
- package/templates/nextjs-standalone/ee/src/backups/verify.ts +124 -0
- package/templates/nextjs-standalone/ee/src/branding/white-label.ts +228 -0
- package/templates/nextjs-standalone/ee/src/compliance/masking.ts +477 -0
- package/templates/nextjs-standalone/ee/src/compliance/patterns.ts +16 -0
- package/templates/nextjs-standalone/ee/src/compliance/pii-detection.ts +217 -0
- package/templates/nextjs-standalone/ee/src/compliance/reports.ts +402 -0
- package/templates/nextjs-standalone/ee/src/deploy-mode.ts +37 -0
- package/templates/nextjs-standalone/ee/src/governance/approval.ts +699 -0
- package/templates/nextjs-standalone/ee/src/index.ts +74 -0
- package/templates/nextjs-standalone/ee/src/platform/domains.ts +562 -0
- package/templates/nextjs-standalone/ee/src/platform/model-routing.ts +382 -0
- package/templates/nextjs-standalone/ee/src/platform/residency.ts +265 -0
- package/templates/nextjs-standalone/ee/src/sla/alerting.ts +382 -0
- package/templates/nextjs-standalone/ee/src/sla/index.ts +12 -0
- package/templates/nextjs-standalone/ee/src/sla/metrics.ts +275 -0
- package/templates/nextjs-standalone/ee/src/test-setup.ts +1 -0
- package/templates/nextjs-standalone/next.config.ts +1 -1
- package/templates/nextjs-standalone/package.json +50 -30
- package/templates/nextjs-standalone/src/api/index.ts +336 -24
- package/templates/nextjs-standalone/src/api/routes/actions.ts +443 -176
- package/templates/nextjs-standalone/src/api/routes/admin-abuse.ts +219 -0
- package/templates/nextjs-standalone/src/api/routes/admin-approval.ts +418 -0
- package/templates/nextjs-standalone/src/api/routes/admin-audit-retention.ts +405 -0
- package/templates/nextjs-standalone/src/api/routes/admin-auth.ts +122 -0
- package/templates/nextjs-standalone/src/api/routes/admin-branding.ts +252 -0
- package/templates/nextjs-standalone/src/api/routes/admin-compliance.ts +352 -0
- package/templates/nextjs-standalone/src/api/routes/admin-domains.ts +334 -0
- package/templates/nextjs-standalone/src/api/routes/admin-integrations.ts +2667 -0
- package/templates/nextjs-standalone/src/api/routes/admin-ip-allowlist.ts +261 -0
- package/templates/nextjs-standalone/src/api/routes/admin-learned-patterns.ts +525 -0
- package/templates/nextjs-standalone/src/api/routes/admin-model-config.ts +252 -0
- package/templates/nextjs-standalone/src/api/routes/admin-onboarding-emails.ts +145 -0
- package/templates/nextjs-standalone/src/api/routes/admin-orgs.ts +710 -0
- package/templates/nextjs-standalone/src/api/routes/admin-prompts.ts +694 -0
- package/templates/nextjs-standalone/src/api/routes/admin-residency.ts +570 -0
- package/templates/nextjs-standalone/src/api/routes/admin-roles.ts +296 -0
- package/templates/nextjs-standalone/src/api/routes/admin-router.ts +120 -0
- package/templates/nextjs-standalone/src/api/routes/admin-sandbox.ts +417 -0
- package/templates/nextjs-standalone/src/api/routes/admin-scim.ts +262 -0
- package/templates/nextjs-standalone/src/api/routes/admin-sso.ts +545 -0
- package/templates/nextjs-standalone/src/api/routes/admin-suggestions.ts +176 -0
- package/templates/nextjs-standalone/src/api/routes/admin-usage.ts +310 -0
- package/templates/nextjs-standalone/src/api/routes/admin.ts +4156 -898
- package/templates/nextjs-standalone/src/api/routes/auth-preamble.ts +105 -0
- package/templates/nextjs-standalone/src/api/routes/billing.ts +397 -0
- package/templates/nextjs-standalone/src/api/routes/chat.ts +597 -334
- package/templates/nextjs-standalone/src/api/routes/conversations.ts +987 -132
- package/templates/nextjs-standalone/src/api/routes/demo.ts +673 -0
- package/templates/nextjs-standalone/src/api/routes/discord.ts +274 -0
- package/templates/nextjs-standalone/src/api/routes/ee-error-handler.ts +32 -0
- package/templates/nextjs-standalone/src/api/routes/health.ts +129 -14
- package/templates/nextjs-standalone/src/api/routes/middleware.ts +244 -0
- package/templates/nextjs-standalone/src/api/routes/onboarding-emails.ts +134 -0
- package/templates/nextjs-standalone/src/api/routes/onboarding.ts +1109 -0
- package/templates/nextjs-standalone/src/api/routes/openapi.ts +184 -1597
- package/templates/nextjs-standalone/src/api/routes/platform-admin.ts +760 -0
- package/templates/nextjs-standalone/src/api/routes/platform-backups.ts +436 -0
- package/templates/nextjs-standalone/src/api/routes/platform-domains.ts +235 -0
- package/templates/nextjs-standalone/src/api/routes/platform-residency.ts +257 -0
- package/templates/nextjs-standalone/src/api/routes/platform-sla.ts +379 -0
- package/templates/nextjs-standalone/src/api/routes/prompts.ts +221 -0
- package/templates/nextjs-standalone/src/api/routes/public-branding.ts +106 -0
- package/templates/nextjs-standalone/src/api/routes/query.ts +330 -219
- package/templates/nextjs-standalone/src/api/routes/scheduled-tasks.ts +393 -297
- package/templates/nextjs-standalone/src/api/routes/semantic.ts +179 -0
- package/templates/nextjs-standalone/src/api/routes/sessions.ts +210 -0
- package/templates/nextjs-standalone/src/api/routes/shared-domains.ts +98 -0
- package/templates/nextjs-standalone/src/api/routes/shared-schemas.ts +139 -0
- package/templates/nextjs-standalone/src/api/routes/slack.ts +209 -52
- package/templates/nextjs-standalone/src/api/routes/suggestions.ts +233 -0
- package/templates/nextjs-standalone/src/api/routes/tables.ts +67 -0
- package/templates/nextjs-standalone/src/api/routes/teams.ts +222 -0
- package/templates/nextjs-standalone/src/api/routes/validate-sql.ts +188 -0
- package/templates/nextjs-standalone/src/api/routes/validation-hook.ts +62 -0
- package/templates/nextjs-standalone/src/api/routes/widget-loader.ts +356 -0
- package/templates/nextjs-standalone/src/api/routes/widget.ts +428 -0
- package/templates/nextjs-standalone/src/api/routes/wizard.ts +852 -0
- package/templates/nextjs-standalone/src/api/server.ts +187 -69
- package/templates/nextjs-standalone/src/app/error.tsx +5 -2
- package/templates/nextjs-standalone/src/app/globals.css +1 -1
- package/templates/nextjs-standalone/src/app/layout.tsx +7 -2
- package/templates/nextjs-standalone/src/app/page.tsx +39 -5
- package/templates/nextjs-standalone/src/components/data-table/data-table-column-header.tsx +99 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table-date-filter.tsx +225 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table-expandable.tsx +125 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table-faceted-filter.tsx +189 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table-pagination.tsx +112 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table-range-filter.tsx +122 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table-slider-filter.tsx +256 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table-sort-list.tsx +407 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table-toolbar.tsx +149 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table-view-options.tsx +89 -0
- package/templates/nextjs-standalone/src/components/data-table/data-table.tsx +105 -0
- package/templates/nextjs-standalone/src/components/form-dialog.tsx +135 -0
- package/templates/nextjs-standalone/src/components/ui/accordion.tsx +66 -0
- package/templates/nextjs-standalone/src/components/ui/calendar.tsx +220 -0
- package/templates/nextjs-standalone/src/components/ui/checkbox.tsx +32 -0
- package/templates/nextjs-standalone/src/components/ui/faceted.tsx +283 -0
- package/templates/nextjs-standalone/src/components/ui/form.tsx +167 -0
- package/templates/nextjs-standalone/src/components/ui/label.tsx +24 -0
- package/templates/nextjs-standalone/src/components/ui/popover.tsx +89 -0
- package/templates/nextjs-standalone/src/components/ui/progress.tsx +31 -0
- package/templates/nextjs-standalone/src/components/ui/scroll-area.tsx +6 -2
- package/templates/nextjs-standalone/src/components/ui/slider.tsx +63 -0
- package/templates/nextjs-standalone/src/components/ui/sortable.tsx +581 -0
- package/templates/nextjs-standalone/src/components/ui/switch.tsx +35 -0
- package/templates/nextjs-standalone/src/components/ui/textarea.tsx +18 -0
- package/templates/nextjs-standalone/src/config/data-table.ts +82 -0
- package/templates/nextjs-standalone/src/env-check.ts +74 -0
- package/templates/nextjs-standalone/src/hooks/use-callback-ref.ts +27 -0
- package/templates/nextjs-standalone/src/hooks/use-data-table.ts +316 -0
- package/templates/nextjs-standalone/src/hooks/use-debounced-callback.ts +28 -0
- package/templates/nextjs-standalone/src/lib/action-types.ts +7 -41
- package/templates/nextjs-standalone/src/lib/agent-query.ts +4 -2
- package/templates/nextjs-standalone/src/lib/agent.ts +363 -31
- package/templates/nextjs-standalone/src/lib/api-url.ts +2 -3
- package/templates/nextjs-standalone/src/lib/auth/admin-permissions.ts +38 -0
- package/templates/nextjs-standalone/src/lib/auth/audit.ts +19 -4
- package/templates/nextjs-standalone/src/lib/auth/byot.ts +3 -3
- package/templates/nextjs-standalone/src/lib/auth/detect.ts +29 -8
- package/templates/nextjs-standalone/src/lib/auth/managed.ts +104 -14
- package/templates/nextjs-standalone/src/lib/auth/middleware.ts +53 -6
- package/templates/nextjs-standalone/src/lib/auth/migrate.ts +140 -15
- package/templates/nextjs-standalone/src/lib/auth/oauth-state.ts +123 -0
- package/templates/nextjs-standalone/src/lib/auth/org-permissions.ts +55 -0
- package/templates/nextjs-standalone/src/lib/auth/permissions.ts +26 -19
- package/templates/nextjs-standalone/src/lib/auth/server.ts +355 -9
- package/templates/nextjs-standalone/src/lib/auth/simple-key.ts +3 -3
- package/templates/nextjs-standalone/src/lib/auth/types.ts +15 -21
- package/templates/nextjs-standalone/src/lib/billing/enforcement.ts +368 -0
- package/templates/nextjs-standalone/src/lib/billing/plans.ts +155 -0
- package/templates/nextjs-standalone/src/lib/cache/index.ts +92 -0
- package/templates/nextjs-standalone/src/lib/cache/keys.ts +30 -0
- package/templates/nextjs-standalone/src/lib/cache/lru.ts +79 -0
- package/templates/nextjs-standalone/src/lib/cache/types.ts +31 -0
- package/templates/nextjs-standalone/src/lib/compose-refs.ts +62 -0
- package/templates/nextjs-standalone/src/lib/config.ts +563 -11
- package/templates/nextjs-standalone/src/lib/connection-types.ts +9 -0
- package/templates/nextjs-standalone/src/lib/conversation-types.ts +1 -25
- package/templates/nextjs-standalone/src/lib/conversations.ts +345 -14
- package/templates/nextjs-standalone/src/lib/data-table.ts +61 -0
- package/templates/nextjs-standalone/src/lib/db/connection.ts +793 -39
- package/templates/nextjs-standalone/src/lib/db/internal.ts +985 -139
- package/templates/nextjs-standalone/src/lib/db/migrate.ts +295 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0000_baseline.sql +703 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0001_teams_installations.sql +14 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0002_discord_installations.sql +14 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0003_telegram_installations.sql +15 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0004_sandbox_credentials.sql +18 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0005_oauth_state.sql +16 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0006_byot_credentials.sql +14 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0007_gchat_installations.sql +15 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0008_github_installations.sql +14 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0009_linear_installations.sql +15 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0010_whatsapp_installations.sql +14 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0011_email_installations.sql +16 -0
- package/templates/nextjs-standalone/src/lib/db/migrations/0012_region_migrations.sql +25 -0
- package/templates/nextjs-standalone/src/lib/db/schema.ts +1120 -0
- package/templates/nextjs-standalone/src/lib/db/source-rate-limit.ts +89 -139
- package/templates/nextjs-standalone/src/lib/demo.ts +308 -0
- package/templates/nextjs-standalone/src/lib/discord/store.ts +225 -0
- package/templates/nextjs-standalone/src/lib/effect/ai.ts +243 -0
- package/templates/nextjs-standalone/src/lib/effect/errors.ts +234 -0
- package/templates/nextjs-standalone/src/lib/effect/hono.ts +454 -0
- package/templates/nextjs-standalone/src/lib/effect/index.ts +137 -0
- package/templates/nextjs-standalone/src/lib/effect/layers.ts +496 -0
- package/templates/nextjs-standalone/src/lib/effect/services.ts +776 -0
- package/templates/nextjs-standalone/src/lib/effect/sql.ts +178 -0
- package/templates/nextjs-standalone/src/lib/effect/toolkit.ts +123 -0
- package/templates/nextjs-standalone/src/lib/email/delivery.ts +232 -0
- package/templates/nextjs-standalone/src/lib/email/engine.ts +349 -0
- package/templates/nextjs-standalone/src/lib/email/hooks.ts +107 -0
- package/templates/nextjs-standalone/src/lib/email/index.ts +16 -0
- package/templates/nextjs-standalone/src/lib/email/scheduler.ts +72 -0
- package/templates/nextjs-standalone/src/lib/email/sequence.ts +73 -0
- package/templates/nextjs-standalone/src/lib/email/store.ts +163 -0
- package/templates/nextjs-standalone/src/lib/email/templates.ts +215 -0
- package/templates/nextjs-standalone/src/lib/format.test.ts +117 -0
- package/templates/nextjs-standalone/src/lib/format.ts +67 -0
- package/templates/nextjs-standalone/src/lib/gchat/store.ts +202 -0
- package/templates/nextjs-standalone/src/lib/github/store.ts +197 -0
- package/templates/nextjs-standalone/src/lib/id.ts +29 -0
- package/templates/nextjs-standalone/src/lib/integrations/types.ts +166 -0
- package/templates/nextjs-standalone/src/lib/learn/pattern-analyzer.ts +224 -0
- package/templates/nextjs-standalone/src/lib/learn/pattern-cache.ts +229 -0
- package/templates/nextjs-standalone/src/lib/learn/pattern-proposer.ts +87 -0
- package/templates/nextjs-standalone/src/lib/learn/suggestion-helpers.ts +34 -0
- package/templates/nextjs-standalone/src/lib/learn/suggestions.ts +139 -0
- package/templates/nextjs-standalone/src/lib/linear/store.ts +200 -0
- package/templates/nextjs-standalone/src/lib/logger.ts +35 -3
- package/templates/nextjs-standalone/src/lib/metering.ts +272 -0
- package/templates/nextjs-standalone/src/lib/parsers.ts +99 -0
- package/templates/nextjs-standalone/src/lib/plugins/hooks.ts +13 -11
- package/templates/nextjs-standalone/src/lib/plugins/index.ts +3 -1
- package/templates/nextjs-standalone/src/lib/plugins/registry.ts +58 -6
- package/templates/nextjs-standalone/src/lib/plugins/settings.ts +147 -0
- package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +6 -9
- package/templates/nextjs-standalone/src/lib/profiler.ts +1665 -0
- package/templates/nextjs-standalone/src/lib/providers.ts +188 -13
- package/templates/nextjs-standalone/src/lib/rls.ts +172 -60
- package/templates/nextjs-standalone/src/lib/sandbox/credentials.ts +206 -0
- package/templates/nextjs-standalone/src/lib/sandbox/validate.ts +179 -0
- package/templates/nextjs-standalone/src/lib/scheduled-task-types.ts +26 -94
- package/templates/nextjs-standalone/src/lib/scheduled-tasks.ts +174 -34
- package/templates/nextjs-standalone/src/lib/scheduler/delivery.ts +248 -150
- package/templates/nextjs-standalone/src/lib/scheduler/engine.ts +190 -154
- package/templates/nextjs-standalone/src/lib/scheduler/executor.ts +74 -23
- package/templates/nextjs-standalone/src/lib/scheduler/preview.ts +72 -0
- package/templates/nextjs-standalone/src/lib/security/abuse.ts +463 -0
- package/templates/nextjs-standalone/src/lib/semantic/diff.ts +267 -0
- package/templates/nextjs-standalone/src/lib/semantic/entities.ts +167 -0
- package/templates/nextjs-standalone/src/lib/semantic/files.ts +283 -0
- package/templates/nextjs-standalone/src/lib/semantic/index.ts +27 -0
- package/templates/nextjs-standalone/src/lib/{semantic-index.ts → semantic/search.ts} +80 -9
- package/templates/nextjs-standalone/src/lib/semantic/sync.ts +581 -0
- package/templates/nextjs-standalone/src/lib/{semantic.ts → semantic/whitelist.ts} +189 -3
- package/templates/nextjs-standalone/src/lib/settings.ts +817 -0
- package/templates/nextjs-standalone/src/lib/sidecar-types.ts +13 -0
- package/templates/nextjs-standalone/src/lib/slack/store.ts +134 -25
- package/templates/nextjs-standalone/src/lib/startup.ts +528 -362
- package/templates/nextjs-standalone/src/lib/teams/store.ts +216 -0
- package/templates/nextjs-standalone/src/lib/telegram/store.ts +202 -0
- package/templates/nextjs-standalone/src/lib/telemetry.ts +40 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/audit.ts +8 -5
- package/templates/nextjs-standalone/src/lib/tools/actions/email.ts +3 -1
- package/templates/nextjs-standalone/src/lib/tools/actions/handler.ts +276 -93
- package/templates/nextjs-standalone/src/lib/tools/actions/jira.ts +2 -2
- package/templates/nextjs-standalone/src/lib/tools/backends/detect.ts +16 -0
- package/templates/nextjs-standalone/src/lib/tools/backends/index.ts +11 -0
- package/templates/nextjs-standalone/src/lib/tools/backends/nsjail.ts +213 -0
- package/templates/nextjs-standalone/src/lib/tools/backends/shared.ts +103 -0
- package/templates/nextjs-standalone/src/lib/tools/backends/types.ts +26 -0
- package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +7 -228
- package/templates/nextjs-standalone/src/lib/tools/explore-sandbox.ts +4 -29
- package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +18 -2
- package/templates/nextjs-standalone/src/lib/tools/explore.ts +246 -54
- package/templates/nextjs-standalone/src/lib/tools/index.ts +17 -0
- package/templates/nextjs-standalone/src/lib/tools/python-nsjail.ts +11 -139
- package/templates/nextjs-standalone/src/lib/tools/python-sandbox.ts +9 -132
- package/templates/nextjs-standalone/src/lib/tools/python-sidecar.ts +184 -3
- package/templates/nextjs-standalone/src/lib/tools/python-stream.ts +33 -0
- package/templates/nextjs-standalone/src/lib/tools/python-wrapper.ts +129 -0
- package/templates/nextjs-standalone/src/lib/tools/python.ts +115 -15
- package/templates/nextjs-standalone/src/lib/tools/registry.ts +14 -2
- package/templates/nextjs-standalone/src/lib/tools/sql.ts +778 -362
- package/templates/nextjs-standalone/src/lib/tracing.ts +16 -0
- package/templates/nextjs-standalone/src/lib/whatsapp/store.ts +198 -0
- package/templates/nextjs-standalone/src/lib/workspace.ts +89 -0
- package/templates/nextjs-standalone/src/progress.ts +121 -0
- package/templates/nextjs-standalone/src/types/data-table.ts +48 -0
- package/templates/nextjs-standalone/src/ui/atlas-chat-reexport.ts +3 -0
- package/templates/nextjs-standalone/src/ui/components/actions/action-approval-card.tsx +26 -19
- package/templates/nextjs-standalone/src/ui/components/actions/action-status-badge.tsx +3 -3
- package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +57 -39
- package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +213 -35
- package/templates/nextjs-standalone/src/ui/components/admin/delivery-status-badge.tsx +53 -0
- package/templates/nextjs-standalone/src/ui/components/admin/empty-state.tsx +27 -6
- package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +3 -52
- package/templates/nextjs-standalone/src/ui/components/admin/error-banner.tsx +2 -2
- package/templates/nextjs-standalone/src/ui/components/admin/feature-disabled.tsx +28 -5
- package/templates/nextjs-standalone/src/ui/components/admin-content-wrapper.tsx +87 -0
- package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +449 -166
- package/templates/nextjs-standalone/src/ui/components/branding-head.tsx +41 -0
- package/templates/nextjs-standalone/src/ui/components/chart/chart-detection.ts +62 -5
- package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +316 -125
- package/templates/nextjs-standalone/src/ui/components/chat/api-key-bar.tsx +4 -4
- package/templates/nextjs-standalone/src/ui/components/chat/data-table.tsx +45 -4
- package/templates/nextjs-standalone/src/ui/components/chat/error-banner.tsx +86 -5
- package/templates/nextjs-standalone/src/ui/components/chat/follow-up-chips.tsx +29 -0
- package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +24 -0
- package/templates/nextjs-standalone/src/ui/components/chat/prompt-library.tsx +206 -0
- package/templates/nextjs-standalone/src/ui/components/chat/python-result-card.tsx +106 -78
- package/templates/nextjs-standalone/src/ui/components/chat/result-card-base.tsx +101 -0
- package/templates/nextjs-standalone/src/ui/components/chat/share-dialog.tsx +377 -0
- package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +94 -73
- package/templates/nextjs-standalone/src/ui/components/chat/suggestion-chips.tsx +46 -0
- package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +16 -4
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +48 -17
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-list.tsx +38 -24
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-sidebar.tsx +66 -7
- package/templates/nextjs-standalone/src/ui/components/conversations/delete-confirmation.tsx +9 -2
- package/templates/nextjs-standalone/src/ui/components/error-boundary.tsx +66 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/delete-cell-dialog.tsx +48 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/fork-branch-selector.tsx +68 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell-input.tsx +76 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell-output.tsx +58 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell-toolbar.tsx +91 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell.tsx +119 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/notebook-empty-state.tsx +19 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/notebook-export.ts +287 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/notebook-input-bar.tsx +49 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/notebook-shell.tsx +266 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/notebook-text-cell.tsx +152 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/types.ts +39 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/use-keyboard-nav.ts +109 -0
- package/templates/nextjs-standalone/src/ui/components/notebook/use-notebook.ts +684 -0
- package/templates/nextjs-standalone/src/ui/components/org-switcher.tsx +111 -0
- package/templates/nextjs-standalone/src/ui/components/region-picker.tsx +103 -0
- package/templates/nextjs-standalone/src/ui/components/schema-explorer/schema-explorer.tsx +522 -0
- package/templates/nextjs-standalone/src/ui/components/social-icons.tsx +26 -0
- package/templates/nextjs-standalone/src/ui/components/tour/guided-tour.tsx +81 -0
- package/templates/nextjs-standalone/src/ui/components/tour/index.ts +5 -0
- package/templates/nextjs-standalone/src/ui/components/tour/nav-bar.tsx +100 -0
- package/templates/nextjs-standalone/src/ui/components/tour/tour-overlay.tsx +298 -0
- package/templates/nextjs-standalone/src/ui/components/tour/tour-steps.ts +43 -0
- package/templates/nextjs-standalone/src/ui/components/tour/types.ts +21 -0
- package/templates/nextjs-standalone/src/ui/components/tour/use-tour.ts +193 -0
- package/templates/nextjs-standalone/src/ui/context-reexport.ts +3 -0
- package/templates/nextjs-standalone/src/ui/hooks/theme-init-script.ts +17 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-admin-fetch.ts +38 -30
- package/templates/nextjs-standalone/src/ui/hooks/use-admin-mutation.ts +188 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-atlas-transport.ts +225 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-branding.ts +68 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +106 -83
- package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +134 -10
- package/templates/nextjs-standalone/src/ui/hooks/use-deploy-mode.ts +36 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-platform-admin-guard.ts +49 -0
- package/templates/nextjs-standalone/src/ui/lib/action-types.ts +11 -63
- package/templates/nextjs-standalone/src/ui/lib/admin-schemas.ts +744 -0
- package/templates/nextjs-standalone/src/ui/lib/fetch-client.ts +84 -0
- package/templates/nextjs-standalone/src/ui/lib/fetch-error.ts +54 -0
- package/templates/nextjs-standalone/src/ui/lib/helpers.ts +94 -1
- package/templates/nextjs-standalone/src/ui/lib/types.ts +149 -140
- package/templates/nextjs-standalone/tsconfig.json +3 -2
- package/templates/docker/src/api/__tests__/actions.test.ts +0 -683
- package/templates/docker/src/api/__tests__/admin.test.ts +0 -820
- package/templates/docker/src/api/__tests__/auth.test.ts +0 -165
- package/templates/docker/src/api/__tests__/chat.test.ts +0 -376
- package/templates/docker/src/api/__tests__/conversations.test.ts +0 -555
- package/templates/docker/src/api/__tests__/cors.test.ts +0 -135
- package/templates/docker/src/api/__tests__/health-plugin.test.ts +0 -176
- package/templates/docker/src/api/__tests__/health.test.ts +0 -283
- package/templates/docker/src/api/__tests__/query.test.ts +0 -891
- package/templates/docker/src/api/__tests__/scheduled-tasks.test.ts +0 -601
- package/templates/docker/src/api/__tests__/slack.test.ts +0 -847
- package/templates/docker/src/lib/__tests__/agent-cache.test.ts +0 -439
- package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +0 -131
- package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +0 -166
- package/templates/docker/src/lib/__tests__/agent-integration.test.ts +0 -516
- package/templates/docker/src/lib/__tests__/config-actions.test.ts +0 -166
- package/templates/docker/src/lib/__tests__/config.test.ts +0 -1113
- package/templates/docker/src/lib/__tests__/conversations.test.ts +0 -589
- package/templates/docker/src/lib/__tests__/errors.test.ts +0 -256
- package/templates/docker/src/lib/__tests__/logger.test.ts +0 -200
- package/templates/docker/src/lib/__tests__/plugin-aware-validation.test.ts +0 -321
- package/templates/docker/src/lib/__tests__/providers.test.ts +0 -130
- package/templates/docker/src/lib/__tests__/rls.test.ts +0 -435
- package/templates/docker/src/lib/__tests__/scheduled-task-types.test.ts +0 -124
- package/templates/docker/src/lib/__tests__/scheduled-tasks.test.ts +0 -550
- package/templates/docker/src/lib/__tests__/semantic-index.test.ts +0 -547
- package/templates/docker/src/lib/__tests__/semantic-multisource.test.ts +0 -544
- package/templates/docker/src/lib/__tests__/semantic.test.ts +0 -363
- package/templates/docker/src/lib/__tests__/startup-actions.test.ts +0 -461
- package/templates/docker/src/lib/__tests__/startup-first-run.test.ts +0 -429
- package/templates/docker/src/lib/__tests__/startup.test.ts +0 -470
- package/templates/docker/src/lib/__tests__/tracing.test.ts +0 -28
- package/templates/docker/src/lib/auth/__tests__/audit.test.ts +0 -418
- package/templates/docker/src/lib/auth/__tests__/byot-integration.test.ts +0 -222
- package/templates/docker/src/lib/auth/__tests__/byot.test.ts +0 -366
- package/templates/docker/src/lib/auth/__tests__/detect.test.ts +0 -190
- package/templates/docker/src/lib/auth/__tests__/managed.test.ts +0 -173
- package/templates/docker/src/lib/auth/__tests__/middleware.test.ts +0 -456
- package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +0 -203
- package/templates/docker/src/lib/auth/__tests__/permissions.test.ts +0 -225
- package/templates/docker/src/lib/auth/__tests__/server.test.ts +0 -34
- package/templates/docker/src/lib/auth/__tests__/simple-key.test.ts +0 -176
- package/templates/docker/src/lib/auth/__tests__/types.test.ts +0 -44
- package/templates/docker/src/lib/db/__tests__/connection.test.ts +0 -144
- package/templates/docker/src/lib/db/__tests__/internal.test.ts +0 -387
- package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +0 -190
- package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -137
- package/templates/docker/src/lib/db/__tests__/registry.test.ts +0 -398
- package/templates/docker/src/lib/db/__tests__/source-rate-limit.test.ts +0 -130
- package/templates/docker/src/lib/errors.ts +0 -154
- package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +0 -204
- package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +0 -529
- package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +0 -875
- package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +0 -373
- package/templates/docker/src/lib/plugins/__tests__/tools.test.ts +0 -49
- package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +0 -799
- package/templates/docker/src/lib/scheduler/__tests__/delivery.test.ts +0 -192
- package/templates/docker/src/lib/scheduler/__tests__/engine.test.ts +0 -248
- package/templates/docker/src/lib/scheduler/__tests__/format-email.test.ts +0 -96
- package/templates/docker/src/lib/scheduler/__tests__/format-slack.test.ts +0 -78
- package/templates/docker/src/lib/scheduler/__tests__/format-webhook.test.ts +0 -78
- package/templates/docker/src/lib/scheduler/index.ts +0 -7
- package/templates/docker/src/lib/slack/__tests__/api.test.ts +0 -160
- package/templates/docker/src/lib/slack/__tests__/format.test.ts +0 -237
- package/templates/docker/src/lib/slack/__tests__/store.test.ts +0 -188
- package/templates/docker/src/lib/slack/__tests__/threads.test.ts +0 -112
- package/templates/docker/src/lib/slack/__tests__/verify.test.ts +0 -111
- package/templates/docker/src/lib/tools/__tests__/action-permissions.test.ts +0 -594
- package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +0 -240
- package/templates/docker/src/lib/tools/__tests__/explore-backend.test.ts +0 -267
- package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +0 -506
- package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +0 -374
- package/templates/docker/src/lib/tools/__tests__/explore-sdk-compat.test.ts +0 -82
- package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +0 -210
- package/templates/docker/src/lib/tools/__tests__/python-nsjail.test.ts +0 -515
- package/templates/docker/src/lib/tools/__tests__/python-sandbox.test.ts +0 -397
- package/templates/docker/src/lib/tools/__tests__/python-sidecar.test.ts +0 -365
- package/templates/docker/src/lib/tools/__tests__/python.test.ts +0 -331
- package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +0 -132
- package/templates/docker/src/lib/tools/__tests__/registry.test.ts +0 -242
- package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +0 -227
- package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +0 -100
- package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +0 -227
- package/templates/docker/src/lib/tools/__tests__/sql.test.ts +0 -709
- package/templates/docker/src/lib/tools/actions/__tests__/audit.test.ts +0 -211
- package/templates/docker/src/lib/tools/actions/__tests__/email.test.ts +0 -378
- package/templates/docker/src/lib/tools/actions/__tests__/handler.test.ts +0 -681
- package/templates/docker/src/lib/tools/actions/__tests__/jira.test.ts +0 -427
- package/templates/docker/src/test-setup.ts +0 -38
- package/templates/docker/src/types/vercel-sandbox.d.ts +0 -61
- package/templates/docker/src/ui/components/chat/managed-auth-card.tsx +0 -116
- package/templates/nextjs-standalone/src/api/__tests__/actions.test.ts +0 -683
- package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +0 -820
- package/templates/nextjs-standalone/src/api/__tests__/auth.test.ts +0 -165
- package/templates/nextjs-standalone/src/api/__tests__/chat.test.ts +0 -376
- package/templates/nextjs-standalone/src/api/__tests__/conversations.test.ts +0 -555
- package/templates/nextjs-standalone/src/api/__tests__/cors.test.ts +0 -135
- package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +0 -176
- package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +0 -283
- package/templates/nextjs-standalone/src/api/__tests__/query.test.ts +0 -891
- package/templates/nextjs-standalone/src/api/__tests__/scheduled-tasks.test.ts +0 -601
- package/templates/nextjs-standalone/src/api/__tests__/slack.test.ts +0 -847
- package/templates/nextjs-standalone/src/app/global-error.tsx +0 -68
- package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +0 -439
- package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +0 -131
- package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +0 -166
- package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +0 -516
- package/templates/nextjs-standalone/src/lib/__tests__/config-actions.test.ts +0 -166
- package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +0 -1113
- package/templates/nextjs-standalone/src/lib/__tests__/conversations.test.ts +0 -589
- package/templates/nextjs-standalone/src/lib/__tests__/errors.test.ts +0 -256
- package/templates/nextjs-standalone/src/lib/__tests__/logger.test.ts +0 -200
- package/templates/nextjs-standalone/src/lib/__tests__/plugin-aware-validation.test.ts +0 -321
- package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +0 -130
- package/templates/nextjs-standalone/src/lib/__tests__/rls.test.ts +0 -435
- package/templates/nextjs-standalone/src/lib/__tests__/scheduled-task-types.test.ts +0 -124
- package/templates/nextjs-standalone/src/lib/__tests__/scheduled-tasks.test.ts +0 -550
- package/templates/nextjs-standalone/src/lib/__tests__/semantic-index.test.ts +0 -547
- package/templates/nextjs-standalone/src/lib/__tests__/semantic-multisource.test.ts +0 -544
- package/templates/nextjs-standalone/src/lib/__tests__/semantic.test.ts +0 -363
- package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +0 -461
- package/templates/nextjs-standalone/src/lib/__tests__/startup-first-run.test.ts +0 -429
- package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +0 -470
- package/templates/nextjs-standalone/src/lib/__tests__/tracing.test.ts +0 -28
- package/templates/nextjs-standalone/src/lib/auth/__tests__/audit.test.ts +0 -418
- package/templates/nextjs-standalone/src/lib/auth/__tests__/byot-integration.test.ts +0 -222
- package/templates/nextjs-standalone/src/lib/auth/__tests__/byot.test.ts +0 -366
- package/templates/nextjs-standalone/src/lib/auth/__tests__/detect.test.ts +0 -190
- package/templates/nextjs-standalone/src/lib/auth/__tests__/managed.test.ts +0 -173
- package/templates/nextjs-standalone/src/lib/auth/__tests__/middleware.test.ts +0 -456
- package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +0 -203
- package/templates/nextjs-standalone/src/lib/auth/__tests__/permissions.test.ts +0 -225
- package/templates/nextjs-standalone/src/lib/auth/__tests__/server.test.ts +0 -34
- package/templates/nextjs-standalone/src/lib/auth/__tests__/simple-key.test.ts +0 -176
- package/templates/nextjs-standalone/src/lib/auth/__tests__/types.test.ts +0 -44
- package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +0 -144
- package/templates/nextjs-standalone/src/lib/db/__tests__/internal.test.ts +0 -387
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +0 -190
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -137
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +0 -398
- package/templates/nextjs-standalone/src/lib/db/__tests__/source-rate-limit.test.ts +0 -130
- package/templates/nextjs-standalone/src/lib/errors.ts +0 -154
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +0 -204
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +0 -529
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +0 -875
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +0 -373
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/tools.test.ts +0 -49
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +0 -799
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/delivery.test.ts +0 -192
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/engine.test.ts +0 -248
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-email.test.ts +0 -96
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-slack.test.ts +0 -78
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-webhook.test.ts +0 -78
- package/templates/nextjs-standalone/src/lib/scheduler/index.ts +0 -7
- package/templates/nextjs-standalone/src/lib/slack/__tests__/api.test.ts +0 -160
- package/templates/nextjs-standalone/src/lib/slack/__tests__/format.test.ts +0 -237
- package/templates/nextjs-standalone/src/lib/slack/__tests__/store.test.ts +0 -188
- package/templates/nextjs-standalone/src/lib/slack/__tests__/threads.test.ts +0 -112
- package/templates/nextjs-standalone/src/lib/slack/__tests__/verify.test.ts +0 -111
- package/templates/nextjs-standalone/src/lib/tools/__tests__/action-permissions.test.ts +0 -594
- package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +0 -240
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-backend.test.ts +0 -267
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +0 -506
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +0 -374
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sdk-compat.test.ts +0 -82
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +0 -210
- package/templates/nextjs-standalone/src/lib/tools/__tests__/python-nsjail.test.ts +0 -515
- package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sandbox.test.ts +0 -397
- package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sidecar.test.ts +0 -365
- package/templates/nextjs-standalone/src/lib/tools/__tests__/python.test.ts +0 -331
- package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +0 -132
- package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +0 -242
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +0 -227
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +0 -100
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +0 -227
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +0 -709
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/audit.test.ts +0 -211
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/email.test.ts +0 -378
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/handler.test.ts +0 -681
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/jira.test.ts +0 -427
- package/templates/nextjs-standalone/src/test-setup.ts +0 -38
- package/templates/nextjs-standalone/src/ui/components/chat/managed-auth-card.tsx +0 -116
|
@@ -15,22 +15,89 @@
|
|
|
15
15
|
|
|
16
16
|
import { tool } from "ai";
|
|
17
17
|
import { z } from "zod";
|
|
18
|
+
import { Effect } from "effect";
|
|
18
19
|
import { Parser } from "node-sql-parser";
|
|
19
|
-
import { connections, detectDBType } from "@atlas/api/lib/db/connection";
|
|
20
|
+
import { connections, detectDBType, ConnectionNotRegisteredError, NoDatasourceConfiguredError, PoolCapacityExceededError } from "@atlas/api/lib/db/connection";
|
|
20
21
|
import type { DBConnection, DBType } from "@atlas/api/lib/db/connection";
|
|
21
|
-
import { getWhitelistedTables } from "@atlas/api/lib/semantic";
|
|
22
|
+
import { getWhitelistedTables, getOrgWhitelistedTables } from "@atlas/api/lib/semantic";
|
|
22
23
|
import { logQueryAudit } from "@atlas/api/lib/auth/audit";
|
|
23
24
|
import { SENSITIVE_PATTERNS } from "@atlas/api/lib/security";
|
|
24
25
|
import { withSpan } from "@atlas/api/lib/tracing";
|
|
25
26
|
import { createLogger, getRequestContext } from "@atlas/api/lib/logger";
|
|
26
|
-
import {
|
|
27
|
+
import { withSourceSlot } from "@atlas/api/lib/db/source-rate-limit";
|
|
27
28
|
import { getConfig } from "@atlas/api/lib/config";
|
|
28
|
-
import { resolveRLSFilters, injectRLSConditions } from "@atlas/api/lib/rls";
|
|
29
|
+
import { resolveRLSFilters, injectRLSConditions, type RLSFilterGroup } from "@atlas/api/lib/rls";
|
|
30
|
+
import { getSetting, getSettingAuto } from "@atlas/api/lib/settings";
|
|
31
|
+
import { getCache, buildCacheKey, cacheEnabled, getDefaultTtl } from "@atlas/api/lib/cache/index";
|
|
32
|
+
import { proposePatternIfNovel } from "@atlas/api/lib/learn/pattern-proposer";
|
|
33
|
+
import {
|
|
34
|
+
ConnectionNotFoundError, PoolExhaustedError, NoDatasourceError,
|
|
35
|
+
QueryExecutionError, RateLimitExceededError, ConcurrencyLimitError,
|
|
36
|
+
RLSError, PluginRejectedError,
|
|
37
|
+
} from "@atlas/api/lib/effect/errors";
|
|
29
38
|
|
|
30
39
|
const log = createLogger("sql");
|
|
31
40
|
|
|
32
41
|
const parser = new Parser();
|
|
33
42
|
|
|
43
|
+
// ── Classification ──────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
interface SQLClassification {
|
|
46
|
+
readonly tablesAccessed: string[];
|
|
47
|
+
readonly columnsAccessed: string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type SQLValidationResult =
|
|
51
|
+
| { valid: true; error?: undefined; classification: SQLClassification }
|
|
52
|
+
| { valid: false; error: string; classification?: undefined };
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Extract table and column references from validated SQL.
|
|
56
|
+
*
|
|
57
|
+
* Uses node-sql-parser's tableList/columnList helpers.
|
|
58
|
+
* CTE names are excluded from tablesAccessed.
|
|
59
|
+
* SELECT * is stored as ["*"] in columnsAccessed.
|
|
60
|
+
* Best-effort: returns empty arrays on extraction failure.
|
|
61
|
+
*/
|
|
62
|
+
export function extractClassification(
|
|
63
|
+
sql: string,
|
|
64
|
+
dialect: string,
|
|
65
|
+
cteNames: Set<string>,
|
|
66
|
+
): SQLClassification {
|
|
67
|
+
try {
|
|
68
|
+
const tableRefs = parser.tableList(sql, { database: dialect });
|
|
69
|
+
const tablesAccessed = [...new Set(
|
|
70
|
+
tableRefs
|
|
71
|
+
.map((ref) => {
|
|
72
|
+
const parts = ref.split("::");
|
|
73
|
+
return parts.pop()?.toLowerCase() ?? "";
|
|
74
|
+
})
|
|
75
|
+
.filter((t) => t && !cteNames.has(t)),
|
|
76
|
+
)];
|
|
77
|
+
|
|
78
|
+
const columnRefs = parser.columnList(sql, { database: dialect });
|
|
79
|
+
const columnsAccessed = [...new Set(
|
|
80
|
+
columnRefs
|
|
81
|
+
.map((ref) => {
|
|
82
|
+
const parts = ref.split("::");
|
|
83
|
+
const col = parts.pop() ?? "";
|
|
84
|
+
// node-sql-parser uses "(.*)" for SELECT *
|
|
85
|
+
if (col === "(.*)") return "*";
|
|
86
|
+
return col.toLowerCase();
|
|
87
|
+
})
|
|
88
|
+
.filter(Boolean),
|
|
89
|
+
)];
|
|
90
|
+
|
|
91
|
+
return { tablesAccessed, columnsAccessed };
|
|
92
|
+
} catch (err) {
|
|
93
|
+
log.warn(
|
|
94
|
+
{ err: err instanceof Error ? err : new Error(String(err)), sql: sql.slice(0, 200), dialect },
|
|
95
|
+
"Classification extraction failed — storing empty arrays",
|
|
96
|
+
);
|
|
97
|
+
return { tablesAccessed: [], columnsAccessed: [] };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
34
101
|
/**
|
|
35
102
|
* Strip SQL comments for regex guard testing.
|
|
36
103
|
*
|
|
@@ -130,7 +197,7 @@ function getExtraPatterns(dbType: DBType | string, connectionId?: string): RegEx
|
|
|
130
197
|
}
|
|
131
198
|
}
|
|
132
199
|
|
|
133
|
-
export function validateSQL(sql: string, connectionId?: string):
|
|
200
|
+
export function validateSQL(sql: string, connectionId?: string): SQLValidationResult {
|
|
134
201
|
// Resolve DB type for this connection.
|
|
135
202
|
// When an explicit connectionId is given but not found, return a validation
|
|
136
203
|
// error instead of silently falling back — wrong parser mode is a security risk.
|
|
@@ -139,14 +206,14 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
|
|
|
139
206
|
try {
|
|
140
207
|
dbType = connections.getDBType(connectionId);
|
|
141
208
|
} catch (err) {
|
|
142
|
-
log.
|
|
209
|
+
log.warn({ err, connectionId }, "getDBType failed for connectionId");
|
|
143
210
|
return { valid: false, error: `Connection "${connectionId}" is not registered.` };
|
|
144
211
|
}
|
|
145
212
|
} else {
|
|
146
213
|
try {
|
|
147
214
|
dbType = detectDBType();
|
|
148
215
|
} catch (err) {
|
|
149
|
-
log.
|
|
216
|
+
log.warn({ err }, "detectDBType failed — no valid datasource configured");
|
|
150
217
|
return { valid: false, error: "No valid datasource configured. Set ATLAS_DATASOURCE_URL to a PostgreSQL or MySQL connection string, or register a datasource plugin." };
|
|
151
218
|
}
|
|
152
219
|
}
|
|
@@ -196,12 +263,9 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
|
|
|
196
263
|
error: `Only SELECT statements are allowed, got: ${stmt.type}`,
|
|
197
264
|
};
|
|
198
265
|
}
|
|
199
|
-
// CTE
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (Array.isArray((stmt as any).with)) {
|
|
203
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
204
|
-
for (const cte of (stmt as any).with) {
|
|
266
|
+
// Extract CTE names so they can be excluded from the table whitelist check
|
|
267
|
+
if (Array.isArray(stmt.with)) {
|
|
268
|
+
for (const cte of stmt.with) {
|
|
205
269
|
const name = cte?.name?.value ?? cte?.name;
|
|
206
270
|
if (typeof name === "string") cteNames.add(name.toLowerCase());
|
|
207
271
|
}
|
|
@@ -215,11 +279,15 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
|
|
|
215
279
|
};
|
|
216
280
|
}
|
|
217
281
|
|
|
218
|
-
// 3. Table whitelist check
|
|
219
|
-
|
|
282
|
+
// 3. Table whitelist check — use getSettingAuto for SaaS hot-reload
|
|
283
|
+
const whitelistSetting = getSettingAuto("ATLAS_TABLE_WHITELIST") ?? process.env.ATLAS_TABLE_WHITELIST;
|
|
284
|
+
if (whitelistSetting !== "false") {
|
|
220
285
|
try {
|
|
221
286
|
const tables = parser.tableList(trimmed, { database: parserDatabase(dbType, connectionId) });
|
|
222
|
-
const
|
|
287
|
+
const orgId = getRequestContext()?.user?.activeOrganizationId;
|
|
288
|
+
const allowed = orgId
|
|
289
|
+
? getOrgWhitelistedTables(orgId, connectionId)
|
|
290
|
+
: getWhitelistedTables(connectionId);
|
|
223
291
|
|
|
224
292
|
for (const ref of tables) {
|
|
225
293
|
// tableList returns "select::schema::table" format
|
|
@@ -249,9 +317,10 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
|
|
|
249
317
|
}
|
|
250
318
|
}
|
|
251
319
|
}
|
|
252
|
-
} catch {
|
|
320
|
+
} catch (err) {
|
|
253
321
|
// Table extraction uses the same parser that just succeeded in step 2.
|
|
254
322
|
// If it fails here, reject to avoid bypassing the whitelist.
|
|
323
|
+
log.warn({ err, sql: trimmed.slice(0, 200) }, "Table extraction failed after successful AST parse");
|
|
255
324
|
return {
|
|
256
325
|
valid: false,
|
|
257
326
|
error: "Could not verify table permissions. Rewrite using standard SQL syntax.",
|
|
@@ -259,265 +328,207 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
|
|
|
259
328
|
}
|
|
260
329
|
}
|
|
261
330
|
|
|
262
|
-
|
|
331
|
+
// 4. Extract classification data (best-effort, never blocks validation)
|
|
332
|
+
const classification = extractClassification(
|
|
333
|
+
trimmed,
|
|
334
|
+
parserDatabase(dbType, connectionId),
|
|
335
|
+
cteNames,
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
return { valid: true, classification };
|
|
263
339
|
}
|
|
264
340
|
|
|
265
|
-
|
|
266
|
-
const QUERY_TIMEOUT = parseInt(
|
|
267
|
-
process.env.ATLAS_QUERY_TIMEOUT ?? "30000",
|
|
268
|
-
10
|
|
269
|
-
);
|
|
341
|
+
let lastWarnedRowLimit: string | undefined;
|
|
270
342
|
|
|
271
|
-
|
|
272
|
-
|
|
343
|
+
/** Read row limit from settings cache (DB override > env var > default). Called per-query so admin changes take effect without restart. */
|
|
344
|
+
function getRowLimit(): number {
|
|
345
|
+
const raw = getSetting("ATLAS_ROW_LIMIT") ?? "1000";
|
|
346
|
+
const n = parseInt(raw, 10);
|
|
347
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
348
|
+
if (raw !== lastWarnedRowLimit) {
|
|
349
|
+
log.warn({ value: raw }, "Invalid ATLAS_ROW_LIMIT value; using default 1000");
|
|
350
|
+
lastWarnedRowLimit = raw;
|
|
351
|
+
}
|
|
352
|
+
return 1000;
|
|
353
|
+
}
|
|
354
|
+
return n;
|
|
355
|
+
}
|
|
273
356
|
|
|
274
|
-
|
|
275
|
-
- Always read the relevant entity schema from the semantic layer BEFORE writing SQL
|
|
276
|
-
- Use exact column names from the schema — never guess
|
|
277
|
-
- Use canonical metric SQL from metrics/*.yml when available
|
|
278
|
-
- Include a LIMIT clause for large result sets
|
|
279
|
-
- If a query fails, fix the issue — do not retry the same SQL`,
|
|
357
|
+
let lastWarnedQueryTimeout: string | undefined;
|
|
280
358
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
.
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
359
|
+
/** Read query timeout from settings cache (DB override > env var > default). Called per-query so admin changes take effect without restart. */
|
|
360
|
+
function getQueryTimeout(): number {
|
|
361
|
+
const raw = getSetting("ATLAS_QUERY_TIMEOUT") ?? "30000";
|
|
362
|
+
const n = parseInt(raw, 10);
|
|
363
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
364
|
+
if (raw !== lastWarnedQueryTimeout) {
|
|
365
|
+
log.warn({ value: raw }, "Invalid ATLAS_QUERY_TIMEOUT value; using default 30000ms");
|
|
366
|
+
lastWarnedQueryTimeout = raw;
|
|
367
|
+
}
|
|
368
|
+
return 30000;
|
|
369
|
+
}
|
|
370
|
+
return n;
|
|
371
|
+
}
|
|
293
372
|
|
|
294
|
-
|
|
295
|
-
const connId = connectionId ?? "default";
|
|
373
|
+
// ── Effect Pipeline ──────────────────────────────────────────────────
|
|
296
374
|
|
|
297
|
-
|
|
298
|
-
// Use getDefault() for "default" to trigger lazy initialization from
|
|
299
|
-
// ATLAS_DATASOURCE_URL — plain get("default") throws on fresh startup.
|
|
300
|
-
let db: DBConnection;
|
|
301
|
-
let dbType: DBType;
|
|
302
|
-
try {
|
|
303
|
-
if (connId === "default") {
|
|
304
|
-
db = connections.getDefault();
|
|
305
|
-
dbType = connections.getDBType(connId);
|
|
306
|
-
} else {
|
|
307
|
-
db = connections.get(connId);
|
|
308
|
-
dbType = connections.getDBType(connId);
|
|
309
|
-
}
|
|
310
|
-
} catch {
|
|
311
|
-
return {
|
|
312
|
-
success: false,
|
|
313
|
-
error: `Connection "${connId}" is not registered. Available: ${connections.list().join(", ") || "(none)"}`,
|
|
314
|
-
};
|
|
315
|
-
}
|
|
375
|
+
type CustomValidator = (sql: string) => { valid: boolean; reason?: string } | Promise<{ valid: boolean; reason?: string }>;
|
|
316
376
|
|
|
317
|
-
|
|
377
|
+
/** Union of all errors the pipeline can produce in the error channel. */
|
|
378
|
+
type PipelineError =
|
|
379
|
+
| ConnectionNotFoundError
|
|
380
|
+
| PoolExhaustedError
|
|
381
|
+
| NoDatasourceError
|
|
382
|
+
| RateLimitExceededError
|
|
383
|
+
| ConcurrencyLimitError
|
|
384
|
+
| RLSError
|
|
385
|
+
| PluginRejectedError
|
|
386
|
+
| QueryExecutionError;
|
|
318
387
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if (typeof result?.valid !== "boolean") {
|
|
343
|
-
log.error({ connectionId: connId, returnValue: result }, "Custom validator returned invalid shape");
|
|
344
|
-
logQueryAudit({
|
|
345
|
-
sql: normalizedSql.slice(0, 2000),
|
|
346
|
-
durationMs: 0,
|
|
347
|
-
rowCount: null,
|
|
348
|
-
success: false,
|
|
349
|
-
error: "Custom validator returned invalid result",
|
|
350
|
-
sourceId: connId,
|
|
351
|
-
sourceType: dbType,
|
|
388
|
+
/** Resolve the database connection. Fails with tagged connection errors. */
|
|
389
|
+
function resolveConnectionEffect(
|
|
390
|
+
connId: string,
|
|
391
|
+
orgId: string | undefined,
|
|
392
|
+
): Effect.Effect<
|
|
393
|
+
{ db: DBConnection; dbType: DBType },
|
|
394
|
+
ConnectionNotFoundError | PoolExhaustedError | NoDatasourceError
|
|
395
|
+
> {
|
|
396
|
+
return Effect.try({
|
|
397
|
+
try: () => {
|
|
398
|
+
let db: DBConnection;
|
|
399
|
+
if (orgId) db = connections.getForOrg(orgId, connId);
|
|
400
|
+
else if (connId === "default") db = connections.getDefault();
|
|
401
|
+
else db = connections.get(connId);
|
|
402
|
+
const dbType = connections.getDBType(connId);
|
|
403
|
+
return { db, dbType };
|
|
404
|
+
},
|
|
405
|
+
catch: (err) => {
|
|
406
|
+
if (err instanceof ConnectionNotRegisteredError) {
|
|
407
|
+
return new ConnectionNotFoundError({
|
|
408
|
+
message: `Connection "${connId}" is not registered. Available: ${connections.list().join(", ") || "(none)"}`,
|
|
409
|
+
connectionId: connId,
|
|
410
|
+
available: connections.list(),
|
|
352
411
|
});
|
|
353
|
-
return { success: false, error: `Query validation misconfigured for connection "${connId}"` };
|
|
354
412
|
}
|
|
355
|
-
if (
|
|
356
|
-
|
|
357
|
-
sql: normalizedSql.slice(0, 2000),
|
|
358
|
-
durationMs: 0,
|
|
359
|
-
rowCount: null,
|
|
360
|
-
success: false,
|
|
361
|
-
error: `Validation rejected: ${result.reason ?? "Query rejected by custom validator"}`,
|
|
362
|
-
sourceId: connId,
|
|
363
|
-
sourceType: dbType,
|
|
364
|
-
});
|
|
365
|
-
return { success: false, error: result.reason ?? "Query rejected by custom validator" };
|
|
413
|
+
if (err instanceof NoDatasourceConfiguredError) {
|
|
414
|
+
return new NoDatasourceError({ message: (err as Error).message });
|
|
366
415
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
rowCount: null,
|
|
374
|
-
success: false,
|
|
375
|
-
error: `Validation rejected: ${validation.error}`,
|
|
376
|
-
sourceId: connId,
|
|
377
|
-
sourceType: dbType,
|
|
416
|
+
if (err instanceof PoolCapacityExceededError) {
|
|
417
|
+
log.warn({ connectionId: connId, orgId }, "Org pool capacity exceeded");
|
|
418
|
+
return new PoolExhaustedError({
|
|
419
|
+
message: "Connection pool capacity reached — the system is handling many concurrent tenants. Try again shortly.",
|
|
420
|
+
current: err.currentSlots,
|
|
421
|
+
max: err.maxTotalConnections,
|
|
378
422
|
});
|
|
379
|
-
return { success: false, error: validation.error };
|
|
380
423
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
sql: sql.slice(0, 2000),
|
|
388
|
-
durationMs: 0,
|
|
389
|
-
rowCount: null,
|
|
390
|
-
success: false,
|
|
391
|
-
error: `Rate limited: ${slot.reason}`,
|
|
392
|
-
sourceId: connId,
|
|
393
|
-
sourceType: dbType,
|
|
394
|
-
targetHost,
|
|
424
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
425
|
+
log.error({ err, connectionId: connId }, "Unexpected error during connection lookup");
|
|
426
|
+
return new ConnectionNotFoundError({
|
|
427
|
+
message: `Connection "${connId}" failed to initialize: ${message}`,
|
|
428
|
+
connectionId: connId,
|
|
429
|
+
available: connections.list(),
|
|
395
430
|
});
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
431
|
+
},
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Run query validation (custom validator or standard SQL).
|
|
437
|
+
* Returns a result object — validation rejection is a normal outcome, not an error channel event.
|
|
438
|
+
* `auditError` preserves specific error detail for audit logs.
|
|
439
|
+
*/
|
|
440
|
+
function runQueryValidationEffect(
|
|
441
|
+
sql: string,
|
|
442
|
+
connId: string,
|
|
443
|
+
dbType: DBType | string,
|
|
444
|
+
customValidator: CustomValidator | undefined,
|
|
445
|
+
): Effect.Effect<{ ok: true; classification?: SQLClassification } | { ok: false; error: string; auditError: string }> {
|
|
446
|
+
if (!customValidator) {
|
|
447
|
+
const validation = validateSQL(sql, connId);
|
|
448
|
+
if (!validation.valid) {
|
|
449
|
+
return Effect.succeed({ ok: false as const, error: validation.error, auditError: `Validation rejected: ${validation.error}` });
|
|
401
450
|
}
|
|
451
|
+
return Effect.succeed({ ok: true as const, classification: validation.classification });
|
|
452
|
+
}
|
|
402
453
|
|
|
403
|
-
|
|
404
|
-
|
|
454
|
+
// Custom validator (async) — errors are caught and returned as result values, not thrown
|
|
455
|
+
return Effect.promise(async () => {
|
|
456
|
+
let result: { valid: boolean; reason?: string };
|
|
405
457
|
try {
|
|
406
|
-
|
|
407
|
-
mutatedSql = await dispatchMutableHook(
|
|
408
|
-
"beforeQuery",
|
|
409
|
-
hookCtx,
|
|
410
|
-
"sql",
|
|
411
|
-
);
|
|
458
|
+
result = await customValidator(sql);
|
|
412
459
|
} catch (err) {
|
|
413
460
|
const message = err instanceof Error ? err.message : String(err);
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
});
|
|
425
|
-
return { success: false, error: `Query rejected by plugin: ${message}` };
|
|
461
|
+
log.error({ err, connectionId: connId, sql: sql.slice(0, 200) }, "Custom validator threw an exception");
|
|
462
|
+
return { ok: false as const, error: `Query validation failed for connection "${connId}": internal validator error`, auditError: `Custom validator error: ${message}` };
|
|
463
|
+
}
|
|
464
|
+
if (typeof result?.valid !== "boolean") {
|
|
465
|
+
log.error({ connectionId: connId, returnValue: result }, "Custom validator returned invalid shape");
|
|
466
|
+
return { ok: false as const, error: `Query validation misconfigured for connection "${connId}"`, auditError: "Custom validator returned invalid result" };
|
|
467
|
+
}
|
|
468
|
+
if (!result.valid) {
|
|
469
|
+
const reason = result.reason ?? "Query rejected by custom validator";
|
|
470
|
+
return { ok: false as const, error: reason, auditError: `Validation rejected: ${reason}` };
|
|
426
471
|
}
|
|
472
|
+
return { ok: true as const, classification: undefined as SQLClassification | undefined };
|
|
473
|
+
});
|
|
474
|
+
}
|
|
427
475
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
});
|
|
450
|
-
return { success: false, error: `Re-validation failed for connection "${connId}": internal validator error` };
|
|
451
|
-
}
|
|
452
|
-
if (typeof reresult?.valid !== "boolean") {
|
|
453
|
-
decrementSourceConcurrency(connId);
|
|
454
|
-
log.error({ connectionId: connId, returnValue: reresult }, "Custom validator returned invalid shape during re-validation");
|
|
455
|
-
logQueryAudit({
|
|
456
|
-
sql: normalizedMutated.slice(0, 2000),
|
|
457
|
-
durationMs: 0,
|
|
458
|
-
rowCount: null,
|
|
459
|
-
success: false,
|
|
460
|
-
error: "Custom validator returned invalid result during re-validation",
|
|
461
|
-
sourceId: connId,
|
|
462
|
-
sourceType: dbType,
|
|
463
|
-
targetHost,
|
|
464
|
-
});
|
|
465
|
-
return { success: false, error: `Query validation misconfigured for connection "${connId}"` };
|
|
466
|
-
}
|
|
467
|
-
if (!reresult.valid) {
|
|
468
|
-
decrementSourceConcurrency(connId);
|
|
469
|
-
logQueryAudit({
|
|
470
|
-
sql: normalizedMutated.slice(0, 2000),
|
|
471
|
-
durationMs: 0,
|
|
472
|
-
rowCount: null,
|
|
473
|
-
success: false,
|
|
474
|
-
error: `Plugin-rewritten SQL failed validation: ${reresult.reason ?? "Query rejected by custom validator"}`,
|
|
475
|
-
sourceId: connId,
|
|
476
|
-
sourceType: dbType,
|
|
477
|
-
targetHost,
|
|
478
|
-
});
|
|
479
|
-
return { success: false, error: `Plugin-rewritten SQL failed validation: ${reresult.reason ?? "Query rejected by custom validator"}` };
|
|
476
|
+
/** Apply RLS conditions. Returns the (possibly modified) SQL. Fails with RLSError. */
|
|
477
|
+
function applyRLSEffect(
|
|
478
|
+
sql: string,
|
|
479
|
+
connId: string,
|
|
480
|
+
dbType: DBType | string,
|
|
481
|
+
targetHost: string | undefined,
|
|
482
|
+
): Effect.Effect<string, RLSError> {
|
|
483
|
+
return Effect.gen(function* () {
|
|
484
|
+
const config = getConfig();
|
|
485
|
+
let rlsConfig = config?.rls;
|
|
486
|
+
|
|
487
|
+
// In SaaS mode only, overlay settings-based RLS config for hot-reload.
|
|
488
|
+
// Only activates when there is a DB override for ATLAS_RLS_ENABLED — env
|
|
489
|
+
// vars and defaults are handled by the boot-time config and don't trigger
|
|
490
|
+
// the overlay, preserving multi-policy configs from atlas.config.ts.
|
|
491
|
+
if (config?.deployMode === "saas") {
|
|
492
|
+
const rlsEnabledSetting = getSettingAuto("ATLAS_RLS_ENABLED");
|
|
493
|
+
if (rlsEnabledSetting !== undefined) {
|
|
494
|
+
if (rlsEnabledSetting !== "true") {
|
|
495
|
+
// Explicitly disabled via settings — skip RLS
|
|
496
|
+
return sql;
|
|
480
497
|
}
|
|
481
|
-
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
498
|
+
// Setting says enabled — build/overlay config from settings
|
|
499
|
+
const column = getSettingAuto("ATLAS_RLS_COLUMN");
|
|
500
|
+
const claim = getSettingAuto("ATLAS_RLS_CLAIM");
|
|
501
|
+
if (column && claim) {
|
|
502
|
+
rlsConfig = {
|
|
503
|
+
enabled: true,
|
|
504
|
+
policies: [{ tables: ["*"], column, claim }],
|
|
505
|
+
combineWith: rlsConfig?.combineWith ?? "and",
|
|
506
|
+
};
|
|
507
|
+
} else {
|
|
508
|
+
// RLS enabled but missing required config — fail closed
|
|
509
|
+
log.error(
|
|
510
|
+
{ column: !!column, claim: !!claim },
|
|
511
|
+
"RLS enabled via settings but ATLAS_RLS_COLUMN or ATLAS_RLS_CLAIM is missing — blocking query",
|
|
512
|
+
);
|
|
513
|
+
return yield* new RLSError({
|
|
514
|
+
message: "Row-level security is enabled but not fully configured. Contact your administrator.",
|
|
515
|
+
phase: "filter",
|
|
494
516
|
});
|
|
495
|
-
return { success: false, error: `Plugin-rewritten SQL failed validation: ${revalidation.error}` };
|
|
496
517
|
}
|
|
497
518
|
}
|
|
498
519
|
}
|
|
499
520
|
|
|
500
|
-
|
|
501
|
-
// Applied after validation + plugin hooks so plugins cannot strip RLS.
|
|
502
|
-
// Skipped for custom validators (non-SQL languages like SOQL).
|
|
503
|
-
const config = getConfig();
|
|
504
|
-
const rlsConfig = config?.rls;
|
|
505
|
-
if (rlsConfig?.enabled && !customValidator) {
|
|
506
|
-
if (!config) {
|
|
507
|
-
// Config not loaded — fail-closed rather than risk missing RLS.
|
|
508
|
-
decrementSourceConcurrency(connId);
|
|
509
|
-
log.error("getConfig() returned null during RLS-enabled SQL execution — config not loaded");
|
|
510
|
-
return { success: false, error: "Server configuration not initialized. Please retry." };
|
|
511
|
-
}
|
|
512
|
-
const ctx = getRequestContext();
|
|
513
|
-
const user = ctx?.user;
|
|
521
|
+
if (!rlsConfig?.enabled) return sql;
|
|
514
522
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
523
|
+
const ctx = getRequestContext();
|
|
524
|
+
const user = ctx?.user;
|
|
525
|
+
|
|
526
|
+
// Extract tables
|
|
527
|
+
const queriedTables = yield* Effect.try({
|
|
528
|
+
try: () => {
|
|
518
529
|
const dialect = parserDatabase(dbType, connId);
|
|
519
|
-
const tableRefs = parser.tableList(
|
|
520
|
-
|
|
530
|
+
const tableRefs = parser.tableList(sql, { database: dialect });
|
|
531
|
+
return new Set(
|
|
521
532
|
tableRefs
|
|
522
533
|
.map((ref) => {
|
|
523
534
|
const parts = ref.split("::");
|
|
@@ -525,156 +536,561 @@ Rules:
|
|
|
525
536
|
})
|
|
526
537
|
.filter(Boolean),
|
|
527
538
|
);
|
|
528
|
-
}
|
|
529
|
-
|
|
539
|
+
},
|
|
540
|
+
catch: (tableErr) => {
|
|
530
541
|
const tableErrMsg = tableErr instanceof Error ? tableErr.message : String(tableErr);
|
|
531
|
-
log.error({ err: tableErr, sql:
|
|
542
|
+
log.error({ err: tableErr, sql: sql.slice(0, 200) }, "RLS: failed to extract table list from query");
|
|
532
543
|
logQueryAudit({
|
|
533
|
-
sql:
|
|
534
|
-
durationMs: 0,
|
|
535
|
-
rowCount: null,
|
|
536
|
-
success: false,
|
|
544
|
+
sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
|
|
537
545
|
error: `RLS: could not extract tables from query: ${tableErrMsg}`,
|
|
538
|
-
sourceId: connId,
|
|
539
|
-
sourceType: dbType,
|
|
540
|
-
targetHost,
|
|
546
|
+
sourceId: connId, sourceType: dbType, targetHost,
|
|
541
547
|
});
|
|
542
|
-
return {
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
const filterResult = resolveRLSFilters(user, queriedTables, rlsConfig);
|
|
546
|
-
if ("error" in filterResult) {
|
|
547
|
-
decrementSourceConcurrency(connId);
|
|
548
|
-
log.warn({ error: filterResult.error, userId: user?.id }, "RLS filter resolution failed — query blocked");
|
|
549
|
-
logQueryAudit({
|
|
550
|
-
sql: normalizedMutated.slice(0, 2000),
|
|
551
|
-
durationMs: 0,
|
|
552
|
-
rowCount: null,
|
|
553
|
-
success: false,
|
|
554
|
-
error: `RLS blocked: ${filterResult.error}`,
|
|
555
|
-
sourceId: connId,
|
|
556
|
-
sourceType: dbType,
|
|
557
|
-
targetHost,
|
|
548
|
+
return new RLSError({
|
|
549
|
+
message: "Query could not be analyzed for row-level security. Rewrite using standard SQL.",
|
|
550
|
+
phase: "extraction",
|
|
558
551
|
});
|
|
559
|
-
|
|
560
|
-
|
|
552
|
+
},
|
|
553
|
+
});
|
|
561
554
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
555
|
+
// Resolve filters
|
|
556
|
+
const filterResult = resolveRLSFilters(user, queriedTables, rlsConfig);
|
|
557
|
+
if ("error" in filterResult) {
|
|
558
|
+
log.warn({ error: filterResult.error, userId: user?.id }, "RLS filter resolution failed — query blocked");
|
|
559
|
+
logQueryAudit({
|
|
560
|
+
sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
|
|
561
|
+
error: `RLS blocked: ${filterResult.error}`,
|
|
562
|
+
sourceId: connId, sourceType: dbType, targetHost,
|
|
563
|
+
});
|
|
564
|
+
return yield* new RLSError({ message: filterResult.error, phase: "filter" });
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Inject conditions
|
|
568
|
+
const hasFilters = filterResult.groups.some((g: RLSFilterGroup) => g.filters.length > 0);
|
|
569
|
+
if (hasFilters) {
|
|
570
|
+
const injected = yield* Effect.try({
|
|
571
|
+
try: () => injectRLSConditions(sql, filterResult.groups, filterResult.combineWith, dbType),
|
|
572
|
+
catch: (err) => {
|
|
571
573
|
const msg = err instanceof Error ? err.message : String(err);
|
|
572
574
|
log.error({ err, userId: user?.id }, "RLS injection failed — query blocked");
|
|
573
575
|
logQueryAudit({
|
|
574
|
-
sql:
|
|
575
|
-
durationMs: 0,
|
|
576
|
-
rowCount: null,
|
|
577
|
-
success: false,
|
|
576
|
+
sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
|
|
578
577
|
error: `RLS injection failed: ${msg}`,
|
|
579
|
-
sourceId: connId,
|
|
580
|
-
sourceType: dbType,
|
|
581
|
-
targetHost,
|
|
578
|
+
sourceId: connId, sourceType: dbType, targetHost,
|
|
582
579
|
});
|
|
583
|
-
return {
|
|
584
|
-
}
|
|
585
|
-
}
|
|
580
|
+
return new RLSError({ message: "Query could not be processed for row-level security.", phase: "injection" });
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
log.debug(
|
|
584
|
+
{ groups: filterResult.groups.length, combineWith: filterResult.combineWith, userId: user?.id },
|
|
585
|
+
"RLS conditions injected",
|
|
586
|
+
);
|
|
587
|
+
return injected;
|
|
586
588
|
}
|
|
587
589
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
let querySql = normalizedMutated;
|
|
592
|
-
if (!customValidator && !/\bLIMIT\b/i.test(querySql)) {
|
|
593
|
-
querySql += ` LIMIT ${ROW_LIMIT}`;
|
|
594
|
-
}
|
|
590
|
+
return sql;
|
|
591
|
+
});
|
|
592
|
+
}
|
|
595
593
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
594
|
+
/**
|
|
595
|
+
* Execute a validated query with tracing, cache write, audit logging, plugin hooks,
|
|
596
|
+
* and error filtering. Called inside withSourceSlot — concurrency release is automatic.
|
|
597
|
+
*/
|
|
598
|
+
function executeAndAuditEffect(opts: {
|
|
599
|
+
db: DBConnection;
|
|
600
|
+
dbType: DBType;
|
|
601
|
+
connId: string;
|
|
602
|
+
orgId: string | undefined;
|
|
603
|
+
targetHost: string | undefined;
|
|
604
|
+
querySql: string;
|
|
605
|
+
queryTimeout: number;
|
|
606
|
+
rowLimit: number;
|
|
607
|
+
explanation: string;
|
|
608
|
+
classification: SQLClassification | undefined;
|
|
609
|
+
cacheKey: string | null;
|
|
610
|
+
hookMetadata: Record<string, unknown>;
|
|
611
|
+
dispatchHook: (event: "afterQuery", ctx: Record<string, unknown>) => Promise<void>;
|
|
612
|
+
}): Effect.Effect<Record<string, unknown>, QueryExecutionError> {
|
|
613
|
+
const {
|
|
614
|
+
db, dbType, connId, orgId, targetHost, querySql, queryTimeout,
|
|
615
|
+
rowLimit, explanation, classification, cacheKey, hookMetadata, dispatchHook,
|
|
616
|
+
} = opts;
|
|
617
|
+
|
|
618
|
+
const start = performance.now();
|
|
619
|
+
|
|
620
|
+
return Effect.tryPromise({
|
|
621
|
+
try: () =>
|
|
622
|
+
withSpan(
|
|
601
623
|
"atlas.sql.execute",
|
|
602
|
-
{
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
);
|
|
624
|
+
{ "db.system": dbType, "atlas.connection_id": connId },
|
|
625
|
+
() => db.query(querySql, queryTimeout),
|
|
626
|
+
(r) => ({ "atlas.row_count": r.rows.length, "atlas.column_count": r.columns.length }),
|
|
627
|
+
),
|
|
628
|
+
catch: (err) => {
|
|
608
629
|
const durationMs = Math.round(performance.now() - start);
|
|
609
|
-
const
|
|
630
|
+
const message = err instanceof Error ? err.message : "Unknown database error";
|
|
631
|
+
|
|
632
|
+
connections.recordQuery(connId, durationMs, orgId);
|
|
633
|
+
connections.recordError(connId, orgId);
|
|
634
|
+
|
|
635
|
+
// SLA metric (fire-and-forget, enterprise feature)
|
|
636
|
+
if (orgId) {
|
|
637
|
+
import("@atlas/ee/sla/index")
|
|
638
|
+
.then(({ recordQueryMetric }) => recordQueryMetric(orgId, durationMs, true))
|
|
639
|
+
.catch((slaErr) => {
|
|
640
|
+
// Dynamic import failure = ee not installed (expected in non-enterprise).
|
|
641
|
+
// Runtime error from recordQueryMetric = log warning for diagnostics.
|
|
642
|
+
if (slaErr instanceof Error && !slaErr.message.includes("Cannot find module")) {
|
|
643
|
+
log.warn({ err: slaErr.message, connectionId: connId }, "SLA metric recording failed");
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
}
|
|
610
647
|
|
|
611
648
|
try {
|
|
612
649
|
logQueryAudit({
|
|
613
|
-
sql: querySql,
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
sourceId: connId,
|
|
618
|
-
sourceType: dbType,
|
|
619
|
-
targetHost,
|
|
650
|
+
sql: querySql, durationMs, rowCount: null, success: false, error: message,
|
|
651
|
+
sourceId: connId, sourceType: dbType, targetHost,
|
|
652
|
+
tablesAccessed: classification?.tablesAccessed,
|
|
653
|
+
columnsAccessed: classification?.columnsAccessed,
|
|
620
654
|
});
|
|
621
655
|
} catch (auditErr) {
|
|
622
656
|
log.warn({ err: auditErr }, "Failed to write query audit log");
|
|
623
657
|
}
|
|
624
658
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
659
|
+
// Filter sensitive errors before returning to the agent
|
|
660
|
+
if (SENSITIVE_PATTERNS.test(message)) {
|
|
661
|
+
return new QueryExecutionError({ message: "Database query failed — check server logs for details." });
|
|
662
|
+
}
|
|
663
|
+
const dbErr = err as { hint?: string; position?: string };
|
|
664
|
+
let detail = message;
|
|
665
|
+
if (dbErr.hint) detail += ` — Hint: ${dbErr.hint}`;
|
|
666
|
+
if (dbErr.position) detail += ` (at character ${dbErr.position})`;
|
|
667
|
+
return new QueryExecutionError({ message: detail, hint: dbErr.hint, position: dbErr.position });
|
|
668
|
+
},
|
|
669
|
+
}).pipe(
|
|
670
|
+
// Success path: metrics, cache, audit, hooks, masking
|
|
671
|
+
Effect.flatMap((result) =>
|
|
672
|
+
Effect.tryPromise({
|
|
673
|
+
try: async () => {
|
|
674
|
+
const durationMs = Math.round(performance.now() - start);
|
|
675
|
+
const truncated = result.rows.length >= rowLimit;
|
|
676
|
+
|
|
677
|
+
connections.recordQuery(connId, durationMs, orgId);
|
|
678
|
+
connections.recordSuccess(connId, orgId);
|
|
679
|
+
|
|
680
|
+
// SLA metric (fire-and-forget, enterprise feature)
|
|
681
|
+
if (orgId) {
|
|
682
|
+
try {
|
|
683
|
+
const { recordQueryMetric } = await import("@atlas/ee/sla/index");
|
|
684
|
+
recordQueryMetric(orgId, durationMs, false);
|
|
685
|
+
} catch (err) {
|
|
686
|
+
// Dynamic import failure = ee not installed (expected in non-enterprise).
|
|
687
|
+
// Runtime error from recordQueryMetric = log warning for diagnostics.
|
|
688
|
+
if (err instanceof Error && !err.message.includes("Cannot find module")) {
|
|
689
|
+
log.warn({ err: err.message, connectionId: connId }, "SLA metric recording failed");
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// Cache write (fail open)
|
|
695
|
+
if (cacheKey) {
|
|
696
|
+
try {
|
|
697
|
+
getCache().set(cacheKey, {
|
|
698
|
+
columns: result.columns, rows: result.rows,
|
|
699
|
+
cachedAt: Date.now(), ttl: getDefaultTtl(),
|
|
700
|
+
});
|
|
701
|
+
} catch (cacheErr) {
|
|
702
|
+
log.error({ err: cacheErr, connectionId: connId }, "Cache write failed — result not cached");
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
try {
|
|
707
|
+
logQueryAudit({
|
|
708
|
+
sql: querySql, durationMs, rowCount: result.rows.length, success: true,
|
|
709
|
+
sourceId: connId, sourceType: dbType, targetHost,
|
|
710
|
+
tablesAccessed: classification?.tablesAccessed,
|
|
711
|
+
columnsAccessed: classification?.columnsAccessed,
|
|
712
|
+
});
|
|
713
|
+
} catch (auditErr) {
|
|
714
|
+
log.warn({ err: auditErr }, "Failed to write query audit log");
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
try {
|
|
718
|
+
await dispatchHook("afterQuery", {
|
|
719
|
+
sql: querySql, connectionId: connId,
|
|
720
|
+
result: { columns: result.columns, rows: result.rows },
|
|
721
|
+
durationMs,
|
|
722
|
+
});
|
|
723
|
+
} catch (hookErr) {
|
|
724
|
+
log.warn(
|
|
725
|
+
{ err: hookErr instanceof Error ? hookErr.message : String(hookErr), connectionId: connId },
|
|
726
|
+
"afterQuery hook failed — query result unaffected",
|
|
727
|
+
);
|
|
728
|
+
}
|
|
631
729
|
|
|
730
|
+
// Pattern learning (fire-and-forget)
|
|
731
|
+
proposePatternIfNovel({
|
|
732
|
+
sql: querySql, dialect: parserDatabase(dbType, connId), connectionId: connId,
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
// PII masking (fails open)
|
|
736
|
+
let maskedRows = result.rows;
|
|
737
|
+
let maskingApplied = false;
|
|
738
|
+
if (classification?.tablesAccessed.length && orgId) {
|
|
739
|
+
try {
|
|
740
|
+
const { applyMasking } = await import("@atlas/ee/compliance/masking");
|
|
741
|
+
const maskCtx = getRequestContext();
|
|
742
|
+
maskedRows = await applyMasking({
|
|
743
|
+
columns: result.columns, rows: result.rows,
|
|
744
|
+
tablesAccessed: classification.tablesAccessed,
|
|
745
|
+
orgId, userRole: maskCtx?.user?.role,
|
|
746
|
+
});
|
|
747
|
+
maskingApplied = maskedRows !== result.rows;
|
|
748
|
+
} catch (err) {
|
|
749
|
+
log.warn(
|
|
750
|
+
{ err: err instanceof Error ? err.message : String(err), connectionId: connId },
|
|
751
|
+
"PII masking failed — returning unmasked results",
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const hasHookMeta = Object.keys(hookMetadata).length > 0;
|
|
757
|
+
return {
|
|
758
|
+
success: true,
|
|
759
|
+
explanation,
|
|
760
|
+
row_count: maskedRows.length,
|
|
761
|
+
columns: result.columns,
|
|
762
|
+
rows: maskedRows,
|
|
763
|
+
truncated,
|
|
764
|
+
cached: false,
|
|
765
|
+
maskingApplied,
|
|
766
|
+
...(hasHookMeta && { metadata: hookMetadata }),
|
|
767
|
+
} as Record<string, unknown>;
|
|
768
|
+
},
|
|
769
|
+
catch: (err) => {
|
|
770
|
+
// Query succeeded but post-processing failed — return the error
|
|
771
|
+
// rather than losing the completed query result as an unrecoverable defect.
|
|
772
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
773
|
+
log.error({ err, connectionId: connId }, "Post-query processing failed after successful execution");
|
|
774
|
+
return new QueryExecutionError({ message: `Query succeeded but post-processing failed: ${message}` });
|
|
775
|
+
},
|
|
776
|
+
}),
|
|
777
|
+
),
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/** Map a pipeline error to the tool's {success: false} response format. Exhaustive over PipelineError. */
|
|
782
|
+
function pipelineErrorToResponse(error: PipelineError): Record<string, unknown> {
|
|
783
|
+
switch (error._tag) {
|
|
784
|
+
case "RateLimitExceededError":
|
|
632
785
|
return {
|
|
633
|
-
success:
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
columns: result.columns,
|
|
637
|
-
rows: result.rows,
|
|
638
|
-
truncated,
|
|
786
|
+
success: false,
|
|
787
|
+
error: error.message,
|
|
788
|
+
...(error.retryAfterMs != null && { retryAfterMs: error.retryAfterMs }),
|
|
639
789
|
};
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
790
|
+
case "ConcurrencyLimitError":
|
|
791
|
+
case "ConnectionNotFoundError":
|
|
792
|
+
case "PoolExhaustedError":
|
|
793
|
+
case "NoDatasourceError":
|
|
794
|
+
case "RLSError":
|
|
795
|
+
case "PluginRejectedError":
|
|
796
|
+
case "QueryExecutionError":
|
|
797
|
+
return { success: false, error: error.message };
|
|
798
|
+
default: {
|
|
799
|
+
const _exhaustive: never = error;
|
|
800
|
+
return { success: false, error: `Unknown pipeline error: ${(_exhaustive as { message: string }).message}` };
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
644
804
|
|
|
645
|
-
|
|
805
|
+
export const executeSQL = tool({
|
|
806
|
+
description: `Execute a read-only SQL query against the database. Only SELECT statements are allowed.
|
|
807
|
+
|
|
808
|
+
Rules:
|
|
809
|
+
- Always read the relevant entity schema from the semantic layer BEFORE writing SQL
|
|
810
|
+
- Use exact column names from the schema — never guess
|
|
811
|
+
- Use canonical metric SQL from metrics/*.yml when available
|
|
812
|
+
- Include a LIMIT clause for large result sets
|
|
813
|
+
- If a query fails, fix the issue — do not retry the same SQL`,
|
|
814
|
+
|
|
815
|
+
inputSchema: z.object({
|
|
816
|
+
sql: z.string().describe("The SELECT query to execute"),
|
|
817
|
+
explanation: z
|
|
818
|
+
.string()
|
|
819
|
+
.describe("Brief explanation of what this query does and why"),
|
|
820
|
+
connectionId: z
|
|
821
|
+
.string()
|
|
822
|
+
.optional()
|
|
823
|
+
.describe(
|
|
824
|
+
"Target connection ID. Check the entity YAML's `connection` field to determine which source a table belongs to. Omit for the default connection.",
|
|
825
|
+
),
|
|
826
|
+
}),
|
|
827
|
+
|
|
828
|
+
execute: async ({ sql, explanation, connectionId }) => {
|
|
829
|
+
const connId = connectionId ?? "default";
|
|
830
|
+
|
|
831
|
+
// The full pipeline runs as an Effect.gen program. Tagged errors flow through
|
|
832
|
+
// the error channel; expected rejections (validation, approval, cache) return
|
|
833
|
+
// as {success: false} values. At the boundary, catchAll maps errors to responses.
|
|
834
|
+
const pipeline = Effect.gen(function* () {
|
|
835
|
+
// Resolve org context for tenant-scoped pool isolation
|
|
836
|
+
const reqCtx = getRequestContext();
|
|
837
|
+
const orgId = connections.isOrgPoolingEnabled()
|
|
838
|
+
? reqCtx?.user?.activeOrganizationId
|
|
839
|
+
: undefined;
|
|
840
|
+
|
|
841
|
+
// Step 1: Resolve connection (tagged errors)
|
|
842
|
+
const { db, dbType } = yield* resolveConnectionEffect(connId, orgId);
|
|
843
|
+
|
|
844
|
+
const targetHost = connections.getTargetHost(connId);
|
|
845
|
+
const customValidator = connections.getValidator(connId);
|
|
846
|
+
const normalizedSql = sql.trim().replace(/;\s*$/, "").trimEnd();
|
|
847
|
+
|
|
848
|
+
// Step 2: Validate (custom validator or standard SQL validation)
|
|
849
|
+
const initial = yield* runQueryValidationEffect(normalizedSql, connId, dbType, customValidator);
|
|
850
|
+
if (!initial.ok) {
|
|
646
851
|
logQueryAudit({
|
|
647
|
-
sql:
|
|
648
|
-
|
|
649
|
-
rowCount: null,
|
|
650
|
-
success: false,
|
|
651
|
-
error: message,
|
|
652
|
-
sourceId: connId,
|
|
653
|
-
sourceType: dbType,
|
|
654
|
-
targetHost,
|
|
852
|
+
sql: normalizedSql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
|
|
853
|
+
error: initial.auditError, sourceId: connId, sourceType: dbType,
|
|
655
854
|
});
|
|
656
|
-
|
|
657
|
-
log.warn({ err: auditErr }, "Failed to write query audit log");
|
|
855
|
+
return { success: false, error: initial.error };
|
|
658
856
|
}
|
|
857
|
+
// Classification is only populated for standard SQL (validateSQL path).
|
|
858
|
+
// Custom validators (SOQL, GraphQL) bypass node-sql-parser so classification
|
|
859
|
+
// stays undefined — their audit entries store NULL for tables/columns_accessed.
|
|
860
|
+
const classification = initial.classification;
|
|
659
861
|
|
|
660
|
-
//
|
|
661
|
-
if (
|
|
662
|
-
|
|
663
|
-
|
|
862
|
+
// Step 3: Enterprise approval check (fail-open for availability, hard-fail for request creation)
|
|
863
|
+
if (classification) {
|
|
864
|
+
const approvalResult = yield* Effect.tryPromise({
|
|
865
|
+
try: async () => {
|
|
866
|
+
// Phase 1: check availability (fail open)
|
|
867
|
+
let approvalMatch: { required: boolean; matchedRules: { id: string; name: string }[] } | null = null;
|
|
868
|
+
try {
|
|
869
|
+
const { checkApprovalRequired } = await import("@atlas/ee/governance/approval");
|
|
870
|
+
const checkReqCtx = getRequestContext();
|
|
871
|
+
const checkOrgId = checkReqCtx?.user?.activeOrganizationId;
|
|
872
|
+
approvalMatch = await checkApprovalRequired(
|
|
873
|
+
checkOrgId, classification.tablesAccessed, classification.columnsAccessed,
|
|
874
|
+
);
|
|
875
|
+
} catch (err) {
|
|
876
|
+
log.warn(
|
|
877
|
+
{ err: err instanceof Error ? err.message : String(err), connectionId: connId },
|
|
878
|
+
"Approval check failed — proceeding without approval gate",
|
|
879
|
+
);
|
|
880
|
+
}
|
|
664
881
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
882
|
+
// Phase 2: create request (hard fail — governance bypass is worse than a failed query)
|
|
883
|
+
if (approvalMatch?.required) {
|
|
884
|
+
const { createApprovalRequest, hasApprovedRequest } = await import("@atlas/ee/governance/approval");
|
|
885
|
+
const reqCtxForApproval = getRequestContext();
|
|
886
|
+
const approvalOrgId = reqCtxForApproval?.user?.activeOrganizationId;
|
|
887
|
+
const userId = reqCtxForApproval?.user?.id;
|
|
888
|
+
const userEmail = reqCtxForApproval?.user?.label ?? null;
|
|
889
|
+
|
|
890
|
+
if (!userId || !approvalOrgId) {
|
|
891
|
+
log.warn(
|
|
892
|
+
{ connectionId: connId, orgId: approvalOrgId },
|
|
893
|
+
"Approval required but user identity unavailable — blocking query",
|
|
894
|
+
);
|
|
895
|
+
return {
|
|
896
|
+
success: false,
|
|
897
|
+
error: "This query requires approval but the requester identity could not be determined. Please sign in and try again.",
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
const alreadyApproved = await hasApprovedRequest(approvalOrgId, userId, normalizedSql);
|
|
902
|
+
if (!alreadyApproved) {
|
|
903
|
+
const firstRule = approvalMatch.matchedRules[0];
|
|
904
|
+
const approvalReq = await createApprovalRequest({
|
|
905
|
+
orgId: approvalOrgId,
|
|
906
|
+
ruleId: firstRule.id,
|
|
907
|
+
ruleName: firstRule.name,
|
|
908
|
+
requesterId: userId,
|
|
909
|
+
requesterEmail: userEmail,
|
|
910
|
+
querySql: normalizedSql,
|
|
911
|
+
explanation,
|
|
912
|
+
connectionId: connId,
|
|
913
|
+
tablesAccessed: classification.tablesAccessed,
|
|
914
|
+
columnsAccessed: classification.columnsAccessed,
|
|
915
|
+
});
|
|
916
|
+
logQueryAudit({
|
|
917
|
+
sql: normalizedSql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
|
|
918
|
+
error: `Approval required: ${firstRule.name}`,
|
|
919
|
+
sourceId: connId, sourceType: dbType, targetHost,
|
|
920
|
+
});
|
|
921
|
+
return {
|
|
922
|
+
success: false,
|
|
923
|
+
approval_required: true,
|
|
924
|
+
approval_request_id: approvalReq.id,
|
|
925
|
+
matched_rules: approvalMatch.matchedRules.map((r: { name: string }) => r.name),
|
|
926
|
+
message: `This query requires approval before execution. Rule: "${firstRule.name}". ` +
|
|
927
|
+
`An approval request has been submitted (ID: ${approvalReq.id}). ` +
|
|
928
|
+
`An admin must approve it before the query can run.`,
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
return null; // proceed to execution
|
|
933
|
+
},
|
|
934
|
+
catch: (err) => {
|
|
935
|
+
// Phase 2 failure — governance bypass is worse than a failed query.
|
|
936
|
+
// Surface as a typed error so it reaches the agent as {success: false}.
|
|
937
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
938
|
+
log.error({ err, connectionId: connId }, "Approval request creation failed — blocking query");
|
|
939
|
+
return new QueryExecutionError({ message: `Approval workflow failed: ${message}` });
|
|
940
|
+
},
|
|
941
|
+
});
|
|
942
|
+
if (approvalResult !== null) return approvalResult;
|
|
671
943
|
}
|
|
672
|
-
|
|
673
|
-
|
|
944
|
+
|
|
945
|
+
// Step 4: Cache check (short-circuit on hit)
|
|
946
|
+
let cacheKey: string | null = null;
|
|
947
|
+
if (cacheEnabled()) {
|
|
948
|
+
try {
|
|
949
|
+
const ctx = getRequestContext();
|
|
950
|
+
const cacheOrgId = ctx?.user?.activeOrganizationId;
|
|
951
|
+
const claims = ctx?.user?.claims;
|
|
952
|
+
cacheKey = buildCacheKey(normalizedSql, connId, cacheOrgId, claims);
|
|
953
|
+
const cached = getCache().get(cacheKey);
|
|
954
|
+
if (cached) {
|
|
955
|
+
logQueryAudit({
|
|
956
|
+
sql: normalizedSql.slice(0, 2000), durationMs: 0, rowCount: cached.rows.length,
|
|
957
|
+
success: true, sourceId: connId, sourceType: dbType, targetHost,
|
|
958
|
+
});
|
|
959
|
+
// Apply PII masking to cached results (same as live query path)
|
|
960
|
+
const cacheResponse = yield* Effect.tryPromise({
|
|
961
|
+
try: async () => {
|
|
962
|
+
let cachedRows = cached.rows;
|
|
963
|
+
let cachedMaskingApplied = false;
|
|
964
|
+
if (classification?.tablesAccessed.length && orgId) {
|
|
965
|
+
try {
|
|
966
|
+
const { applyMasking } = await import("@atlas/ee/compliance/masking");
|
|
967
|
+
cachedRows = await applyMasking({
|
|
968
|
+
columns: cached.columns, rows: cached.rows,
|
|
969
|
+
tablesAccessed: classification.tablesAccessed,
|
|
970
|
+
orgId, userRole: ctx?.user?.role,
|
|
971
|
+
});
|
|
972
|
+
cachedMaskingApplied = cachedRows !== cached.rows;
|
|
973
|
+
} catch (err) {
|
|
974
|
+
log.warn(
|
|
975
|
+
{ err: err instanceof Error ? err.message : String(err), connectionId: connId },
|
|
976
|
+
"PII masking failed on cached results — returning unmasked results",
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
return {
|
|
981
|
+
success: true, explanation, row_count: cachedRows.length,
|
|
982
|
+
columns: cached.columns, rows: cachedRows,
|
|
983
|
+
truncated: cachedRows.length >= getRowLimit(), cached: true,
|
|
984
|
+
maskingApplied: cachedMaskingApplied,
|
|
985
|
+
};
|
|
986
|
+
},
|
|
987
|
+
catch: (err) => {
|
|
988
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
989
|
+
log.error({ err, connectionId: connId }, "Cache response processing failed");
|
|
990
|
+
return new QueryExecutionError({ message: `Cache response processing failed: ${message}` });
|
|
991
|
+
},
|
|
992
|
+
});
|
|
993
|
+
return cacheResponse;
|
|
994
|
+
}
|
|
995
|
+
} catch (cacheErr) {
|
|
996
|
+
log.error({ err: cacheErr, connectionId: connId }, "Cache read failed — executing query against database");
|
|
997
|
+
cacheKey = null;
|
|
998
|
+
}
|
|
674
999
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
1000
|
+
|
|
1001
|
+
// Step 5: Execute inside a rate-limit slot (concurrency release is automatic)
|
|
1002
|
+
return yield* withSourceSlot(connId,
|
|
1003
|
+
Effect.gen(function* () {
|
|
1004
|
+
// Plugin beforeQuery hook (may rewrite SQL)
|
|
1005
|
+
const { dispatchHook, dispatchMutableHook } = yield* Effect.tryPromise({
|
|
1006
|
+
try: () => import("@atlas/api/lib/plugins/hooks"),
|
|
1007
|
+
catch: (err) => {
|
|
1008
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1009
|
+
log.error({ err, connectionId: connId }, "Failed to load plugin hooks module");
|
|
1010
|
+
return new PluginRejectedError({ message: `Plugin system unavailable: ${message}`, connectionId: connId });
|
|
1011
|
+
},
|
|
1012
|
+
});
|
|
1013
|
+
const hookMetadata: Record<string, unknown> = {};
|
|
1014
|
+
const hookCtx = { sql, connectionId: connId, metadata: hookMetadata };
|
|
1015
|
+
const mutatedSql = yield* Effect.tryPromise({
|
|
1016
|
+
try: () => dispatchMutableHook("beforeQuery", hookCtx, "sql"),
|
|
1017
|
+
catch: (err) => {
|
|
1018
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1019
|
+
return new PluginRejectedError({
|
|
1020
|
+
message: `Query rejected by plugin: ${message}`,
|
|
1021
|
+
connectionId: connId,
|
|
1022
|
+
});
|
|
1023
|
+
},
|
|
1024
|
+
}).pipe(
|
|
1025
|
+
Effect.tapError((error) =>
|
|
1026
|
+
Effect.sync(() =>
|
|
1027
|
+
logQueryAudit({
|
|
1028
|
+
sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
|
|
1029
|
+
error: `Plugin rejected: ${error.message}`,
|
|
1030
|
+
sourceId: connId, sourceType: dbType, targetHost,
|
|
1031
|
+
}),
|
|
1032
|
+
),
|
|
1033
|
+
),
|
|
1034
|
+
);
|
|
1035
|
+
|
|
1036
|
+
// Re-validate if plugin rewrote the SQL
|
|
1037
|
+
let normalizedMutated = mutatedSql.trim().replace(/;\s*$/, "").trimEnd();
|
|
1038
|
+
if (normalizedMutated !== normalizedSql) {
|
|
1039
|
+
const revalidation = yield* runQueryValidationEffect(normalizedMutated, connId, dbType, customValidator);
|
|
1040
|
+
if (!revalidation.ok) {
|
|
1041
|
+
logQueryAudit({
|
|
1042
|
+
sql: normalizedMutated.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
|
|
1043
|
+
error: `Plugin-rewritten SQL failed validation: ${revalidation.auditError}`,
|
|
1044
|
+
sourceId: connId, sourceType: dbType, targetHost,
|
|
1045
|
+
});
|
|
1046
|
+
return { success: false, error: `Plugin-rewritten SQL failed validation: ${revalidation.error}` };
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// RLS: inject WHERE conditions (skipped for custom validators / non-SQL languages)
|
|
1051
|
+
if (!customValidator) {
|
|
1052
|
+
normalizedMutated = yield* applyRLSEffect(normalizedMutated, connId, dbType, targetHost);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// Auto-append LIMIT if not present
|
|
1056
|
+
const rowLimit = getRowLimit();
|
|
1057
|
+
const queryTimeout = getQueryTimeout();
|
|
1058
|
+
let querySql = normalizedMutated;
|
|
1059
|
+
if (!customValidator && !/\bLIMIT\b/i.test(querySql)) {
|
|
1060
|
+
querySql += ` LIMIT ${rowLimit}`;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// Execute the query
|
|
1064
|
+
return yield* executeAndAuditEffect({
|
|
1065
|
+
db, dbType, connId, orgId, targetHost, querySql, queryTimeout,
|
|
1066
|
+
rowLimit, explanation, classification, cacheKey: cacheKey ?? null,
|
|
1067
|
+
hookMetadata, dispatchHook,
|
|
1068
|
+
});
|
|
1069
|
+
}),
|
|
1070
|
+
).pipe(
|
|
1071
|
+
// Audit log rate-limit rejections (inner errors have their own audit handling)
|
|
1072
|
+
Effect.tapError((error) => {
|
|
1073
|
+
if (error._tag === "RateLimitExceededError" || error._tag === "ConcurrencyLimitError") {
|
|
1074
|
+
return Effect.sync(() =>
|
|
1075
|
+
logQueryAudit({
|
|
1076
|
+
sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
|
|
1077
|
+
error: `Rate limited: ${error.message}`,
|
|
1078
|
+
sourceId: connId, sourceType: dbType, targetHost,
|
|
1079
|
+
}),
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
return Effect.void;
|
|
1083
|
+
}),
|
|
1084
|
+
);
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
// Run the pipeline, mapping tagged errors to {success: false} tool responses
|
|
1088
|
+
return Effect.runPromise(
|
|
1089
|
+
pipeline.pipe(
|
|
1090
|
+
Effect.catchAll((error: PipelineError) =>
|
|
1091
|
+
Effect.succeed(pipelineErrorToResponse(error)),
|
|
1092
|
+
),
|
|
1093
|
+
),
|
|
1094
|
+
);
|
|
679
1095
|
},
|
|
680
1096
|
});
|