@useatlas/create 0.0.1
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/README.md +231 -0
- package/index.ts +829 -0
- package/package.json +38 -0
- package/templates/docker/.env.example +67 -0
- package/templates/docker/Dockerfile +52 -0
- package/templates/docker/bin/__tests__/benchmark.test.ts +598 -0
- package/templates/docker/bin/__tests__/duckdb-ingest.test.ts +171 -0
- package/templates/docker/bin/__tests__/eval.test.ts +434 -0
- package/templates/docker/bin/__tests__/matview-partition.test.ts +615 -0
- package/templates/docker/bin/__tests__/multi-source.test.ts +113 -0
- package/templates/docker/bin/__tests__/plugin-cli.test.ts +322 -0
- package/templates/docker/bin/__tests__/profiler-heuristics.test.ts +608 -0
- package/templates/docker/bin/__tests__/query.test.ts +240 -0
- package/templates/docker/bin/__tests__/schema-drift.test.ts +542 -0
- package/templates/docker/bin/__tests__/view-yaml-generation.test.ts +146 -0
- package/templates/docker/bin/atlas.ts +5044 -0
- package/templates/docker/bin/benchmark.ts +695 -0
- package/templates/docker/bin/enrich.ts +559 -0
- package/templates/docker/bin/eval.ts +770 -0
- package/templates/docker/bin/smoke.ts +438 -0
- package/templates/docker/data/.gitkeep +0 -0
- package/templates/docker/data/cybersec.sql +1961 -0
- package/templates/docker/data/demo-semantic/catalog.yml +40 -0
- package/templates/docker/data/demo-semantic/entities/accounts.yml +170 -0
- package/templates/docker/data/demo-semantic/entities/companies.yml +207 -0
- package/templates/docker/data/demo-semantic/entities/people.yml +145 -0
- package/templates/docker/data/demo-semantic/glossary.yml +22 -0
- package/templates/docker/data/demo-semantic/metrics/accounts.yml +38 -0
- package/templates/docker/data/demo-semantic/metrics/companies.yml +89 -0
- package/templates/docker/data/demo.sql +373 -0
- package/templates/docker/data/ecommerce.sql +1690 -0
- package/templates/docker/data/init-demo-db.sql +8 -0
- package/templates/docker/docker-compose.yml +34 -0
- package/templates/docker/docs/deploy.md +390 -0
- package/templates/docker/eslint.config.mjs +18 -0
- package/templates/docker/gitignore +5 -0
- package/templates/docker/next.config.ts +9 -0
- package/templates/docker/package.json +59 -0
- package/templates/docker/postcss.config.mjs +8 -0
- package/templates/docker/public/.gitkeep +0 -0
- package/templates/docker/public/favicon.svg +4 -0
- package/templates/docker/railway.json +13 -0
- package/templates/docker/render.yaml +34 -0
- package/templates/docker/semantic/catalog.yml +5 -0
- package/templates/docker/semantic/entities/.gitkeep +0 -0
- package/templates/docker/semantic/glossary.yml +6 -0
- package/templates/docker/semantic/metrics/.gitkeep +0 -0
- package/templates/docker/sidecar/Dockerfile +28 -0
- package/templates/docker/sidecar/railway.json +14 -0
- package/templates/docker/sidecar/server.ts +188 -0
- package/templates/docker/src/api/__tests__/actions.test.ts +683 -0
- package/templates/docker/src/api/__tests__/admin.test.ts +820 -0
- package/templates/docker/src/api/__tests__/auth.test.ts +165 -0
- package/templates/docker/src/api/__tests__/chat.test.ts +376 -0
- package/templates/docker/src/api/__tests__/conversations.test.ts +555 -0
- package/templates/docker/src/api/__tests__/cors.test.ts +135 -0
- package/templates/docker/src/api/__tests__/health-plugin.test.ts +169 -0
- package/templates/docker/src/api/__tests__/health.test.ts +261 -0
- package/templates/docker/src/api/__tests__/query.test.ts +891 -0
- package/templates/docker/src/api/__tests__/scheduled-tasks.test.ts +601 -0
- package/templates/docker/src/api/__tests__/slack.test.ts +847 -0
- package/templates/docker/src/api/index.ts +117 -0
- package/templates/docker/src/api/routes/actions.ts +274 -0
- package/templates/docker/src/api/routes/admin.ts +757 -0
- package/templates/docker/src/api/routes/auth.ts +48 -0
- package/templates/docker/src/api/routes/chat.ts +465 -0
- package/templates/docker/src/api/routes/conversations.ts +266 -0
- package/templates/docker/src/api/routes/health.ts +287 -0
- package/templates/docker/src/api/routes/openapi.ts +390 -0
- package/templates/docker/src/api/routes/query.ts +318 -0
- package/templates/docker/src/api/routes/scheduled-tasks.ts +467 -0
- package/templates/docker/src/api/routes/slack.ts +611 -0
- package/templates/docker/src/api/server.ts +226 -0
- package/templates/docker/src/app/api/[...route]/route.ts +33 -0
- package/templates/docker/src/app/error.tsx +24 -0
- package/templates/docker/src/app/globals.css +126 -0
- package/templates/docker/src/app/layout.tsx +19 -0
- package/templates/docker/src/app/page.tsx +14 -0
- package/templates/docker/src/global.d.ts +1 -0
- package/templates/docker/src/lib/__tests__/agent-cache.test.ts +437 -0
- package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +114 -0
- package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +164 -0
- package/templates/docker/src/lib/__tests__/agent-integration.test.ts +514 -0
- package/templates/docker/src/lib/__tests__/config-actions.test.ts +166 -0
- package/templates/docker/src/lib/__tests__/config.test.ts +1063 -0
- package/templates/docker/src/lib/__tests__/conversations.test.ts +589 -0
- package/templates/docker/src/lib/__tests__/errors.test.ts +256 -0
- package/templates/docker/src/lib/__tests__/logger.test.ts +200 -0
- package/templates/docker/src/lib/__tests__/providers.test.ts +99 -0
- package/templates/docker/src/lib/__tests__/rls.test.ts +435 -0
- package/templates/docker/src/lib/__tests__/scheduled-task-types.test.ts +124 -0
- package/templates/docker/src/lib/__tests__/scheduled-tasks.test.ts +550 -0
- package/templates/docker/src/lib/__tests__/semantic-index.test.ts +547 -0
- package/templates/docker/src/lib/__tests__/semantic-multisource.test.ts +544 -0
- package/templates/docker/src/lib/__tests__/semantic.test.ts +363 -0
- package/templates/docker/src/lib/__tests__/startup-actions.test.ts +452 -0
- package/templates/docker/src/lib/__tests__/startup.test.ts +465 -0
- package/templates/docker/src/lib/__tests__/tracing.test.ts +28 -0
- package/templates/docker/src/lib/action-types.ts +95 -0
- package/templates/docker/src/lib/agent-query.ts +178 -0
- package/templates/docker/src/lib/agent.ts +505 -0
- package/templates/docker/src/lib/api-url.ts +2 -0
- package/templates/docker/src/lib/auth/__tests__/audit.test.ts +418 -0
- package/templates/docker/src/lib/auth/__tests__/byot-integration.test.ts +222 -0
- package/templates/docker/src/lib/auth/__tests__/byot.test.ts +366 -0
- package/templates/docker/src/lib/auth/__tests__/detect.test.ts +190 -0
- package/templates/docker/src/lib/auth/__tests__/managed.test.ts +173 -0
- package/templates/docker/src/lib/auth/__tests__/middleware.test.ts +456 -0
- package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +201 -0
- package/templates/docker/src/lib/auth/__tests__/permissions.test.ts +225 -0
- package/templates/docker/src/lib/auth/__tests__/server.test.ts +34 -0
- package/templates/docker/src/lib/auth/__tests__/simple-key.test.ts +176 -0
- package/templates/docker/src/lib/auth/__tests__/types.test.ts +44 -0
- package/templates/docker/src/lib/auth/audit.ts +89 -0
- package/templates/docker/src/lib/auth/byot.ts +158 -0
- package/templates/docker/src/lib/auth/client.ts +35 -0
- package/templates/docker/src/lib/auth/detect.ts +83 -0
- package/templates/docker/src/lib/auth/managed.ts +73 -0
- package/templates/docker/src/lib/auth/middleware.ts +208 -0
- package/templates/docker/src/lib/auth/migrate.ts +111 -0
- package/templates/docker/src/lib/auth/permissions.ts +156 -0
- package/templates/docker/src/lib/auth/server.ts +142 -0
- package/templates/docker/src/lib/auth/simple-key.ts +92 -0
- package/templates/docker/src/lib/auth/types.ts +49 -0
- package/templates/docker/src/lib/config.ts +704 -0
- package/templates/docker/src/lib/conversation-types.ts +29 -0
- package/templates/docker/src/lib/conversations.ts +270 -0
- package/templates/docker/src/lib/db/__tests__/connection.test.ts +69 -0
- package/templates/docker/src/lib/db/__tests__/duckdb.test.ts +141 -0
- package/templates/docker/src/lib/db/__tests__/internal.test.ts +387 -0
- package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +207 -0
- package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +156 -0
- package/templates/docker/src/lib/db/__tests__/registry.test.ts +595 -0
- package/templates/docker/src/lib/db/__tests__/salesforce.test.ts +339 -0
- package/templates/docker/src/lib/db/__tests__/snowflake.test.ts +217 -0
- package/templates/docker/src/lib/db/__tests__/source-rate-limit.test.ts +130 -0
- package/templates/docker/src/lib/db/connection.ts +753 -0
- package/templates/docker/src/lib/db/duckdb.ts +122 -0
- package/templates/docker/src/lib/db/internal.ts +273 -0
- package/templates/docker/src/lib/db/salesforce.ts +342 -0
- package/templates/docker/src/lib/db/source-rate-limit.ts +191 -0
- package/templates/docker/src/lib/errors.ts +154 -0
- package/templates/docker/src/lib/logger.ts +98 -0
- package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +202 -0
- package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +529 -0
- package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +521 -0
- package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +346 -0
- package/templates/docker/src/lib/plugins/__tests__/tools.test.ts +49 -0
- package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +585 -0
- package/templates/docker/src/lib/plugins/hooks.ts +162 -0
- package/templates/docker/src/lib/plugins/index.ts +9 -0
- package/templates/docker/src/lib/plugins/migrate.ts +309 -0
- package/templates/docker/src/lib/plugins/registry.ts +231 -0
- package/templates/docker/src/lib/plugins/tools.ts +39 -0
- package/templates/docker/src/lib/plugins/wiring.ts +291 -0
- package/templates/docker/src/lib/providers.ts +102 -0
- package/templates/docker/src/lib/rls.ts +321 -0
- package/templates/docker/src/lib/scheduled-task-types.ts +132 -0
- package/templates/docker/src/lib/scheduled-tasks.ts +475 -0
- package/templates/docker/src/lib/scheduler/__tests__/delivery.test.ts +192 -0
- package/templates/docker/src/lib/scheduler/__tests__/engine.test.ts +248 -0
- package/templates/docker/src/lib/scheduler/__tests__/format-email.test.ts +96 -0
- package/templates/docker/src/lib/scheduler/__tests__/format-slack.test.ts +78 -0
- package/templates/docker/src/lib/scheduler/__tests__/format-webhook.test.ts +78 -0
- package/templates/docker/src/lib/scheduler/delivery.ts +248 -0
- package/templates/docker/src/lib/scheduler/engine.ts +317 -0
- package/templates/docker/src/lib/scheduler/executor.ts +73 -0
- package/templates/docker/src/lib/scheduler/format-email.ts +109 -0
- package/templates/docker/src/lib/scheduler/format-slack.ts +35 -0
- package/templates/docker/src/lib/scheduler/format-webhook.ts +37 -0
- package/templates/docker/src/lib/scheduler/index.ts +7 -0
- package/templates/docker/src/lib/security.ts +11 -0
- package/templates/docker/src/lib/semantic-index.ts +503 -0
- package/templates/docker/src/lib/semantic.ts +387 -0
- package/templates/docker/src/lib/sidecar-types.ts +16 -0
- package/templates/docker/src/lib/slack/__tests__/api.test.ts +160 -0
- package/templates/docker/src/lib/slack/__tests__/format.test.ts +237 -0
- package/templates/docker/src/lib/slack/__tests__/store.test.ts +188 -0
- package/templates/docker/src/lib/slack/__tests__/threads.test.ts +112 -0
- package/templates/docker/src/lib/slack/__tests__/verify.test.ts +111 -0
- package/templates/docker/src/lib/slack/api.ts +102 -0
- package/templates/docker/src/lib/slack/format.ts +209 -0
- package/templates/docker/src/lib/slack/store.ts +107 -0
- package/templates/docker/src/lib/slack/threads.ts +64 -0
- package/templates/docker/src/lib/slack/verify.ts +71 -0
- package/templates/docker/src/lib/startup.ts +730 -0
- package/templates/docker/src/lib/tools/__tests__/action-permissions.test.ts +594 -0
- package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +238 -0
- package/templates/docker/src/lib/tools/__tests__/explore-backend.test.ts +267 -0
- package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +492 -0
- package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +374 -0
- package/templates/docker/src/lib/tools/__tests__/explore-sdk-compat.test.ts +82 -0
- package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +208 -0
- package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +144 -0
- package/templates/docker/src/lib/tools/__tests__/registry.test.ts +235 -0
- package/templates/docker/src/lib/tools/__tests__/salesforce-tool.test.ts +154 -0
- package/templates/docker/src/lib/tools/__tests__/soql-validation.test.ts +303 -0
- package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +225 -0
- package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +98 -0
- package/templates/docker/src/lib/tools/__tests__/sql-duckdb.test.ts +233 -0
- package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +225 -0
- package/templates/docker/src/lib/tools/__tests__/sql.test.ts +1012 -0
- package/templates/docker/src/lib/tools/actions/__tests__/audit.test.ts +211 -0
- package/templates/docker/src/lib/tools/actions/__tests__/email.test.ts +378 -0
- package/templates/docker/src/lib/tools/actions/__tests__/handler.test.ts +681 -0
- package/templates/docker/src/lib/tools/actions/__tests__/jira.test.ts +427 -0
- package/templates/docker/src/lib/tools/actions/audit.ts +47 -0
- package/templates/docker/src/lib/tools/actions/email.ts +191 -0
- package/templates/docker/src/lib/tools/actions/handler.ts +591 -0
- package/templates/docker/src/lib/tools/actions/index.ts +23 -0
- package/templates/docker/src/lib/tools/actions/jira.ts +220 -0
- package/templates/docker/src/lib/tools/explore-nsjail.ts +343 -0
- package/templates/docker/src/lib/tools/explore-sandbox.ts +264 -0
- package/templates/docker/src/lib/tools/explore-sidecar.ts +163 -0
- package/templates/docker/src/lib/tools/explore.ts +379 -0
- package/templates/docker/src/lib/tools/registry.ts +221 -0
- package/templates/docker/src/lib/tools/salesforce.ts +138 -0
- package/templates/docker/src/lib/tools/soql-validation.ts +172 -0
- package/templates/docker/src/lib/tools/sql.ts +680 -0
- package/templates/docker/src/lib/tracing.ts +40 -0
- package/templates/docker/src/lib/utils.ts +6 -0
- package/templates/docker/src/test-setup.ts +38 -0
- package/templates/docker/src/types/vercel-sandbox.d.ts +54 -0
- package/templates/docker/src/ui/components/actions/action-approval-card.tsx +295 -0
- package/templates/docker/src/ui/components/actions/action-status-badge.tsx +50 -0
- package/templates/docker/src/ui/components/admin/admin-layout.tsx +26 -0
- package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +96 -0
- package/templates/docker/src/ui/components/admin/empty-state.tsx +24 -0
- package/templates/docker/src/ui/components/admin/entity-detail.tsx +233 -0
- package/templates/docker/src/ui/components/admin/entity-list.tsx +96 -0
- package/templates/docker/src/ui/components/admin/error-banner.tsx +22 -0
- package/templates/docker/src/ui/components/admin/feature-disabled.tsx +44 -0
- package/templates/docker/src/ui/components/admin/health-badge.tsx +30 -0
- package/templates/docker/src/ui/components/admin/loading-state.tsx +14 -0
- package/templates/docker/src/ui/components/admin/stat-card.tsx +32 -0
- package/templates/docker/src/ui/components/atlas-chat.tsx +370 -0
- package/templates/docker/src/ui/components/chart/chart-detection.ts +261 -0
- package/templates/docker/src/ui/components/chart/result-chart.tsx +375 -0
- package/templates/docker/src/ui/components/chat/api-key-bar.tsx +66 -0
- package/templates/docker/src/ui/components/chat/copy-button.tsx +25 -0
- package/templates/docker/src/ui/components/chat/data-table.tsx +102 -0
- package/templates/docker/src/ui/components/chat/error-banner.tsx +32 -0
- package/templates/docker/src/ui/components/chat/explore-card.tsx +41 -0
- package/templates/docker/src/ui/components/chat/loading-card.tsx +10 -0
- package/templates/docker/src/ui/components/chat/managed-auth-card.tsx +116 -0
- package/templates/docker/src/ui/components/chat/markdown.tsx +72 -0
- package/templates/docker/src/ui/components/chat/sql-block.tsx +30 -0
- package/templates/docker/src/ui/components/chat/sql-result-card.tsx +144 -0
- package/templates/docker/src/ui/components/chat/starter-prompts.ts +6 -0
- package/templates/docker/src/ui/components/chat/tool-part.tsx +40 -0
- package/templates/docker/src/ui/components/chat/typing-indicator.tsx +19 -0
- package/templates/docker/src/ui/components/conversations/conversation-item.tsx +120 -0
- package/templates/docker/src/ui/components/conversations/conversation-list.tsx +66 -0
- package/templates/docker/src/ui/components/conversations/conversation-sidebar.tsx +78 -0
- package/templates/docker/src/ui/components/conversations/delete-confirmation.tsx +27 -0
- package/templates/docker/src/ui/context.tsx +78 -0
- package/templates/docker/src/ui/hooks/use-admin-fetch.ts +104 -0
- package/templates/docker/src/ui/hooks/use-conversations.ts +184 -0
- package/templates/docker/src/ui/hooks/use-dark-mode.ts +17 -0
- package/templates/docker/src/ui/lib/action-types.ts +63 -0
- package/templates/docker/src/ui/lib/helpers.ts +104 -0
- package/templates/docker/src/ui/lib/types.ts +145 -0
- package/templates/docker/tsconfig.json +41 -0
- package/templates/docker/vercel.json +3 -0
- package/templates/nextjs-standalone/.env.example +68 -0
- package/templates/nextjs-standalone/bin/__tests__/benchmark.test.ts +598 -0
- package/templates/nextjs-standalone/bin/__tests__/duckdb-ingest.test.ts +171 -0
- package/templates/nextjs-standalone/bin/__tests__/eval.test.ts +434 -0
- package/templates/nextjs-standalone/bin/__tests__/matview-partition.test.ts +615 -0
- package/templates/nextjs-standalone/bin/__tests__/multi-source.test.ts +113 -0
- package/templates/nextjs-standalone/bin/__tests__/plugin-cli.test.ts +322 -0
- package/templates/nextjs-standalone/bin/__tests__/profiler-heuristics.test.ts +608 -0
- package/templates/nextjs-standalone/bin/__tests__/query.test.ts +240 -0
- package/templates/nextjs-standalone/bin/__tests__/schema-drift.test.ts +542 -0
- package/templates/nextjs-standalone/bin/__tests__/view-yaml-generation.test.ts +146 -0
- package/templates/nextjs-standalone/bin/atlas.ts +5044 -0
- package/templates/nextjs-standalone/bin/benchmark.ts +695 -0
- package/templates/nextjs-standalone/bin/enrich.ts +559 -0
- package/templates/nextjs-standalone/bin/eval.ts +770 -0
- package/templates/nextjs-standalone/bin/smoke.ts +438 -0
- package/templates/nextjs-standalone/data/.gitkeep +0 -0
- package/templates/nextjs-standalone/data/cybersec.sql +1961 -0
- package/templates/nextjs-standalone/data/demo-semantic/catalog.yml +40 -0
- package/templates/nextjs-standalone/data/demo-semantic/entities/accounts.yml +170 -0
- package/templates/nextjs-standalone/data/demo-semantic/entities/companies.yml +207 -0
- package/templates/nextjs-standalone/data/demo-semantic/entities/people.yml +145 -0
- package/templates/nextjs-standalone/data/demo-semantic/glossary.yml +22 -0
- package/templates/nextjs-standalone/data/demo-semantic/metrics/accounts.yml +38 -0
- package/templates/nextjs-standalone/data/demo-semantic/metrics/companies.yml +89 -0
- package/templates/nextjs-standalone/data/demo.sql +373 -0
- package/templates/nextjs-standalone/data/ecommerce.sql +1690 -0
- package/templates/nextjs-standalone/data/init-demo-db.sql +8 -0
- package/templates/nextjs-standalone/docs/deploy.md +390 -0
- package/templates/nextjs-standalone/eslint.config.mjs +18 -0
- package/templates/nextjs-standalone/gitignore +5 -0
- package/templates/nextjs-standalone/next.config.ts +10 -0
- package/templates/nextjs-standalone/package.json +63 -0
- package/templates/nextjs-standalone/postcss.config.mjs +8 -0
- package/templates/nextjs-standalone/semantic/catalog.yml +5 -0
- package/templates/nextjs-standalone/semantic/entities/.gitkeep +0 -0
- package/templates/nextjs-standalone/semantic/glossary.yml +6 -0
- package/templates/nextjs-standalone/semantic/metrics/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/api/__tests__/actions.test.ts +683 -0
- package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +820 -0
- package/templates/nextjs-standalone/src/api/__tests__/auth.test.ts +165 -0
- package/templates/nextjs-standalone/src/api/__tests__/chat.test.ts +376 -0
- package/templates/nextjs-standalone/src/api/__tests__/conversations.test.ts +555 -0
- package/templates/nextjs-standalone/src/api/__tests__/cors.test.ts +135 -0
- package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +169 -0
- package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +261 -0
- package/templates/nextjs-standalone/src/api/__tests__/query.test.ts +891 -0
- package/templates/nextjs-standalone/src/api/__tests__/scheduled-tasks.test.ts +601 -0
- package/templates/nextjs-standalone/src/api/__tests__/slack.test.ts +847 -0
- package/templates/nextjs-standalone/src/api/index.ts +117 -0
- package/templates/nextjs-standalone/src/api/routes/actions.ts +274 -0
- package/templates/nextjs-standalone/src/api/routes/admin.ts +757 -0
- package/templates/nextjs-standalone/src/api/routes/auth.ts +48 -0
- package/templates/nextjs-standalone/src/api/routes/chat.ts +465 -0
- package/templates/nextjs-standalone/src/api/routes/conversations.ts +266 -0
- package/templates/nextjs-standalone/src/api/routes/health.ts +287 -0
- package/templates/nextjs-standalone/src/api/routes/openapi.ts +390 -0
- package/templates/nextjs-standalone/src/api/routes/query.ts +318 -0
- package/templates/nextjs-standalone/src/api/routes/scheduled-tasks.ts +467 -0
- package/templates/nextjs-standalone/src/api/routes/slack.ts +611 -0
- package/templates/nextjs-standalone/src/api/server.ts +226 -0
- package/templates/nextjs-standalone/src/app/api/[...route]/route.ts +33 -0
- package/templates/nextjs-standalone/src/app/error.tsx +24 -0
- package/templates/nextjs-standalone/src/app/global-error.tsx +68 -0
- package/templates/nextjs-standalone/src/app/globals.css +126 -0
- package/templates/nextjs-standalone/src/app/layout.tsx +19 -0
- package/templates/nextjs-standalone/src/app/page.tsx +14 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +437 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +114 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +164 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +514 -0
- package/templates/nextjs-standalone/src/lib/__tests__/config-actions.test.ts +166 -0
- package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +1063 -0
- package/templates/nextjs-standalone/src/lib/__tests__/conversations.test.ts +589 -0
- package/templates/nextjs-standalone/src/lib/__tests__/errors.test.ts +256 -0
- package/templates/nextjs-standalone/src/lib/__tests__/logger.test.ts +200 -0
- package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +99 -0
- package/templates/nextjs-standalone/src/lib/__tests__/rls.test.ts +435 -0
- package/templates/nextjs-standalone/src/lib/__tests__/scheduled-task-types.test.ts +124 -0
- package/templates/nextjs-standalone/src/lib/__tests__/scheduled-tasks.test.ts +550 -0
- package/templates/nextjs-standalone/src/lib/__tests__/semantic-index.test.ts +547 -0
- package/templates/nextjs-standalone/src/lib/__tests__/semantic-multisource.test.ts +544 -0
- package/templates/nextjs-standalone/src/lib/__tests__/semantic.test.ts +363 -0
- package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +452 -0
- package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +465 -0
- package/templates/nextjs-standalone/src/lib/__tests__/tracing.test.ts +28 -0
- package/templates/nextjs-standalone/src/lib/action-types.ts +95 -0
- package/templates/nextjs-standalone/src/lib/agent-query.ts +178 -0
- package/templates/nextjs-standalone/src/lib/agent.ts +505 -0
- package/templates/nextjs-standalone/src/lib/api-url.ts +3 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/audit.test.ts +418 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/byot-integration.test.ts +222 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/byot.test.ts +366 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/detect.test.ts +190 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/managed.test.ts +173 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/middleware.test.ts +456 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +201 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/permissions.test.ts +225 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/server.test.ts +34 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/simple-key.test.ts +176 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/types.test.ts +44 -0
- package/templates/nextjs-standalone/src/lib/auth/audit.ts +89 -0
- package/templates/nextjs-standalone/src/lib/auth/byot.ts +158 -0
- package/templates/nextjs-standalone/src/lib/auth/client.ts +23 -0
- package/templates/nextjs-standalone/src/lib/auth/detect.ts +83 -0
- package/templates/nextjs-standalone/src/lib/auth/managed.ts +73 -0
- package/templates/nextjs-standalone/src/lib/auth/middleware.ts +208 -0
- package/templates/nextjs-standalone/src/lib/auth/migrate.ts +111 -0
- package/templates/nextjs-standalone/src/lib/auth/permissions.ts +156 -0
- package/templates/nextjs-standalone/src/lib/auth/server.ts +142 -0
- package/templates/nextjs-standalone/src/lib/auth/simple-key.ts +92 -0
- package/templates/nextjs-standalone/src/lib/auth/types.ts +49 -0
- package/templates/nextjs-standalone/src/lib/config.ts +704 -0
- package/templates/nextjs-standalone/src/lib/conversation-types.ts +29 -0
- package/templates/nextjs-standalone/src/lib/conversations.ts +270 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +69 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/duckdb.test.ts +141 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/internal.test.ts +387 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +207 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +156 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +595 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/salesforce.test.ts +339 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/snowflake.test.ts +217 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/source-rate-limit.test.ts +130 -0
- package/templates/nextjs-standalone/src/lib/db/connection.ts +753 -0
- package/templates/nextjs-standalone/src/lib/db/duckdb.ts +122 -0
- package/templates/nextjs-standalone/src/lib/db/internal.ts +273 -0
- package/templates/nextjs-standalone/src/lib/db/salesforce.ts +342 -0
- package/templates/nextjs-standalone/src/lib/db/source-rate-limit.ts +191 -0
- package/templates/nextjs-standalone/src/lib/errors.ts +154 -0
- package/templates/nextjs-standalone/src/lib/logger.ts +98 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +202 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +529 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +521 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +346 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/tools.test.ts +49 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +585 -0
- package/templates/nextjs-standalone/src/lib/plugins/hooks.ts +162 -0
- package/templates/nextjs-standalone/src/lib/plugins/index.ts +9 -0
- package/templates/nextjs-standalone/src/lib/plugins/migrate.ts +309 -0
- package/templates/nextjs-standalone/src/lib/plugins/registry.ts +231 -0
- package/templates/nextjs-standalone/src/lib/plugins/tools.ts +39 -0
- package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +291 -0
- package/templates/nextjs-standalone/src/lib/providers.ts +102 -0
- package/templates/nextjs-standalone/src/lib/rls.ts +321 -0
- package/templates/nextjs-standalone/src/lib/scheduled-task-types.ts +132 -0
- package/templates/nextjs-standalone/src/lib/scheduled-tasks.ts +475 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/delivery.test.ts +192 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/engine.test.ts +248 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-email.test.ts +96 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-slack.test.ts +78 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-webhook.test.ts +78 -0
- package/templates/nextjs-standalone/src/lib/scheduler/delivery.ts +248 -0
- package/templates/nextjs-standalone/src/lib/scheduler/engine.ts +317 -0
- package/templates/nextjs-standalone/src/lib/scheduler/executor.ts +73 -0
- package/templates/nextjs-standalone/src/lib/scheduler/format-email.ts +109 -0
- package/templates/nextjs-standalone/src/lib/scheduler/format-slack.ts +35 -0
- package/templates/nextjs-standalone/src/lib/scheduler/format-webhook.ts +37 -0
- package/templates/nextjs-standalone/src/lib/scheduler/index.ts +7 -0
- package/templates/nextjs-standalone/src/lib/security.ts +11 -0
- package/templates/nextjs-standalone/src/lib/semantic-index.ts +503 -0
- package/templates/nextjs-standalone/src/lib/semantic.ts +387 -0
- package/templates/nextjs-standalone/src/lib/sidecar-types.ts +16 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/api.test.ts +160 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/format.test.ts +237 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/store.test.ts +188 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/threads.test.ts +112 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/verify.test.ts +111 -0
- package/templates/nextjs-standalone/src/lib/slack/api.ts +102 -0
- package/templates/nextjs-standalone/src/lib/slack/format.ts +209 -0
- package/templates/nextjs-standalone/src/lib/slack/store.ts +107 -0
- package/templates/nextjs-standalone/src/lib/slack/threads.ts +64 -0
- package/templates/nextjs-standalone/src/lib/slack/verify.ts +71 -0
- package/templates/nextjs-standalone/src/lib/startup.ts +730 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/action-permissions.test.ts +594 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +238 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-backend.test.ts +267 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +492 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +374 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sdk-compat.test.ts +82 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +208 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +144 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +235 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/salesforce-tool.test.ts +154 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/soql-validation.test.ts +303 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +225 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +98 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-duckdb.test.ts +233 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +225 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +1012 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/audit.test.ts +211 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/email.test.ts +378 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/handler.test.ts +681 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/jira.test.ts +427 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/audit.ts +47 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/email.ts +191 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/handler.ts +591 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/index.ts +23 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/jira.ts +220 -0
- package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +343 -0
- package/templates/nextjs-standalone/src/lib/tools/explore-sandbox.ts +264 -0
- package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +163 -0
- package/templates/nextjs-standalone/src/lib/tools/explore.ts +379 -0
- package/templates/nextjs-standalone/src/lib/tools/registry.ts +221 -0
- package/templates/nextjs-standalone/src/lib/tools/salesforce.ts +138 -0
- package/templates/nextjs-standalone/src/lib/tools/soql-validation.ts +172 -0
- package/templates/nextjs-standalone/src/lib/tools/sql.ts +680 -0
- package/templates/nextjs-standalone/src/lib/tracing.ts +40 -0
- package/templates/nextjs-standalone/src/lib/utils.ts +6 -0
- package/templates/nextjs-standalone/src/test-setup.ts +38 -0
- package/templates/nextjs-standalone/src/ui/components/actions/action-approval-card.tsx +295 -0
- package/templates/nextjs-standalone/src/ui/components/actions/action-status-badge.tsx +50 -0
- package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +26 -0
- package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +96 -0
- package/templates/nextjs-standalone/src/ui/components/admin/empty-state.tsx +24 -0
- package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +233 -0
- package/templates/nextjs-standalone/src/ui/components/admin/entity-list.tsx +96 -0
- package/templates/nextjs-standalone/src/ui/components/admin/error-banner.tsx +22 -0
- package/templates/nextjs-standalone/src/ui/components/admin/feature-disabled.tsx +44 -0
- package/templates/nextjs-standalone/src/ui/components/admin/health-badge.tsx +30 -0
- package/templates/nextjs-standalone/src/ui/components/admin/loading-state.tsx +14 -0
- package/templates/nextjs-standalone/src/ui/components/admin/stat-card.tsx +32 -0
- package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +370 -0
- package/templates/nextjs-standalone/src/ui/components/chart/chart-detection.ts +261 -0
- package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +375 -0
- package/templates/nextjs-standalone/src/ui/components/chat/api-key-bar.tsx +66 -0
- package/templates/nextjs-standalone/src/ui/components/chat/copy-button.tsx +25 -0
- package/templates/nextjs-standalone/src/ui/components/chat/data-table.tsx +102 -0
- package/templates/nextjs-standalone/src/ui/components/chat/error-banner.tsx +32 -0
- package/templates/nextjs-standalone/src/ui/components/chat/explore-card.tsx +41 -0
- package/templates/nextjs-standalone/src/ui/components/chat/loading-card.tsx +10 -0
- package/templates/nextjs-standalone/src/ui/components/chat/managed-auth-card.tsx +116 -0
- package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +72 -0
- package/templates/nextjs-standalone/src/ui/components/chat/sql-block.tsx +30 -0
- package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +144 -0
- package/templates/nextjs-standalone/src/ui/components/chat/starter-prompts.ts +6 -0
- package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +40 -0
- package/templates/nextjs-standalone/src/ui/components/chat/typing-indicator.tsx +19 -0
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +120 -0
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-list.tsx +66 -0
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-sidebar.tsx +78 -0
- package/templates/nextjs-standalone/src/ui/components/conversations/delete-confirmation.tsx +27 -0
- package/templates/nextjs-standalone/src/ui/context.tsx +78 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-admin-fetch.ts +104 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +184 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +17 -0
- package/templates/nextjs-standalone/src/ui/lib/action-types.ts +63 -0
- package/templates/nextjs-standalone/src/ui/lib/helpers.ts +104 -0
- package/templates/nextjs-standalone/src/ui/lib/types.ts +145 -0
- package/templates/nextjs-standalone/tsconfig.json +32 -0
- package/templates/nextjs-standalone/vercel.json +4 -0
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative configuration for Atlas.
|
|
3
|
+
*
|
|
4
|
+
* Loads configuration from `atlas.config.ts` in the project root (if present),
|
|
5
|
+
* falling back to environment variables for backward compatibility. The config
|
|
6
|
+
* file is optional and additive — existing env-var-only deploys work without
|
|
7
|
+
* changes.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* // atlas.config.ts
|
|
12
|
+
* import { defineConfig } from "@atlas/api/lib/config";
|
|
13
|
+
*
|
|
14
|
+
* export default defineConfig({
|
|
15
|
+
* datasources: {
|
|
16
|
+
* default: { url: process.env.ATLAS_DATASOURCE_URL! },
|
|
17
|
+
* warehouse: { url: "postgresql://...", schema: "analytics", description: "Data warehouse" },
|
|
18
|
+
* },
|
|
19
|
+
* tools: ["explore", "executeSQL"],
|
|
20
|
+
* auth: "auto",
|
|
21
|
+
* semanticLayer: "./semantic",
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { z } from "zod";
|
|
27
|
+
import * as fs from "fs";
|
|
28
|
+
import * as path from "path";
|
|
29
|
+
import { createLogger } from "./logger";
|
|
30
|
+
import type { ConnectionRegistry } from "./db/connection";
|
|
31
|
+
import type { ToolRegistry } from "./tools/registry";
|
|
32
|
+
import { ACTION_APPROVAL_MODES, type ActionApprovalMode } from "@atlas/api/lib/action-types";
|
|
33
|
+
import { ATLAS_ROLES } from "@atlas/api/lib/auth/types";
|
|
34
|
+
|
|
35
|
+
const log = createLogger("config");
|
|
36
|
+
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Zod schema
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
const RateLimitConfigSchema = z.object({
|
|
42
|
+
/** Max queries per minute for this datasource. */
|
|
43
|
+
queriesPerMinute: z.number().int().positive().default(60),
|
|
44
|
+
/** Max concurrent queries for this datasource. */
|
|
45
|
+
concurrency: z.number().int().positive().default(5),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export type RateLimitConfig = z.infer<typeof RateLimitConfigSchema>;
|
|
49
|
+
|
|
50
|
+
const DatasourceConfigSchema = z.object({
|
|
51
|
+
/** Database connection string (postgresql://, mysql://, clickhouse://, snowflake://, duckdb://, or salesforce://). */
|
|
52
|
+
url: z.string().min(1, "Datasource URL must not be empty"),
|
|
53
|
+
/** PostgreSQL schema name (sets search_path). Ignored for MySQL, ClickHouse, Snowflake, DuckDB, and Salesforce. */
|
|
54
|
+
schema: z.string().optional(),
|
|
55
|
+
/** Human-readable description shown in the agent system prompt. */
|
|
56
|
+
description: z.string().optional(),
|
|
57
|
+
/** Max connections in the pool for this datasource. */
|
|
58
|
+
maxConnections: z.number().int().positive().optional(),
|
|
59
|
+
/** Idle timeout in milliseconds before a connection is closed. */
|
|
60
|
+
idleTimeoutMs: z.number().int().positive().optional(),
|
|
61
|
+
/** Per-source rate limiting configuration. */
|
|
62
|
+
rateLimit: RateLimitConfigSchema.optional(),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export type DatasourceConfig = z.infer<typeof DatasourceConfigSchema>;
|
|
66
|
+
|
|
67
|
+
const AuthConfigSchema = z.union([
|
|
68
|
+
z.literal("auto"),
|
|
69
|
+
z.literal("none"),
|
|
70
|
+
z.literal("api-key"),
|
|
71
|
+
z.literal("managed"),
|
|
72
|
+
z.literal("byot"),
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
export type AuthConfig = z.infer<typeof AuthConfigSchema>;
|
|
76
|
+
|
|
77
|
+
const ActionApprovalSchema = z.enum(ACTION_APPROVAL_MODES);
|
|
78
|
+
|
|
79
|
+
const ActionDefaultsSchema = z.object({
|
|
80
|
+
approval: ActionApprovalSchema.optional(),
|
|
81
|
+
timeout: z.number().int().positive().optional(),
|
|
82
|
+
maxPerConversation: z.number().int().positive().optional(),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export type ActionDefaults = z.infer<typeof ActionDefaultsSchema>;
|
|
86
|
+
|
|
87
|
+
const AtlasRoleSchema = z.enum(ATLAS_ROLES);
|
|
88
|
+
|
|
89
|
+
const PerActionConfigSchema = z.object({
|
|
90
|
+
enabled: z.boolean().optional(),
|
|
91
|
+
approval: ActionApprovalSchema.optional(),
|
|
92
|
+
/** Minimum role required to approve this action. Overrides the approval mode's default role mapping. */
|
|
93
|
+
requiredRole: AtlasRoleSchema.optional(),
|
|
94
|
+
credentials: z.record(z.string(), z.object({ env: z.string() })).optional(),
|
|
95
|
+
rateLimit: z.number().int().positive().optional(),
|
|
96
|
+
}).passthrough();
|
|
97
|
+
|
|
98
|
+
export type PerActionConfig = z.infer<typeof PerActionConfigSchema>;
|
|
99
|
+
|
|
100
|
+
const ActionsConfigSchema = z.object({
|
|
101
|
+
defaults: ActionDefaultsSchema.optional(),
|
|
102
|
+
}).catchall(PerActionConfigSchema);
|
|
103
|
+
|
|
104
|
+
export type ActionsConfig = z.infer<typeof ActionsConfigSchema>;
|
|
105
|
+
|
|
106
|
+
const RLSPolicySchema = z.object({
|
|
107
|
+
/** Tables this policy applies to. Use ["*"] for all tables. */
|
|
108
|
+
tables: z.array(z.string().min(1)).min(1),
|
|
109
|
+
/** Column name to filter on in the matched tables. Must be a valid SQL identifier. */
|
|
110
|
+
column: z.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, "Must be a valid column name"),
|
|
111
|
+
/** Claim path to extract the filter value from the user's claims. Supports dot-delimited paths. */
|
|
112
|
+
claim: z.string().min(1),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
export type RLSPolicy = z.infer<typeof RLSPolicySchema>;
|
|
116
|
+
|
|
117
|
+
const RLSConfigSchema = z.object({
|
|
118
|
+
/** Whether RLS is active. When true, policies are enforced on every query. */
|
|
119
|
+
enabled: z.boolean().default(false),
|
|
120
|
+
/** RLS policies. Each policy maps a claim to a column on one or more tables. */
|
|
121
|
+
policies: z.array(RLSPolicySchema).default([]),
|
|
122
|
+
}).refine(
|
|
123
|
+
(cfg) => !cfg.enabled || cfg.policies.length > 0,
|
|
124
|
+
{ message: "RLS is enabled but no policies are defined", path: ["policies"] },
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
export type RLSConfig = z.infer<typeof RLSConfigSchema>;
|
|
128
|
+
|
|
129
|
+
const AtlasConfigSchema = z.object({
|
|
130
|
+
/**
|
|
131
|
+
* Named datasource connections. The "default" key is used when no
|
|
132
|
+
* connectionId is specified. At least one datasource should be defined.
|
|
133
|
+
*/
|
|
134
|
+
datasources: z.record(z.string(), DatasourceConfigSchema).optional(),
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Tool names to enable. When omitted, defaults to the two core tools
|
|
138
|
+
* (explore, executeSQL).
|
|
139
|
+
*/
|
|
140
|
+
tools: z.array(z.string()).optional(),
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Auth mode. "auto" (default) auto-detects from env vars — same as the
|
|
144
|
+
* current behavior. Other values pin the mode explicitly.
|
|
145
|
+
*/
|
|
146
|
+
auth: AuthConfigSchema.optional().default("auto"),
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Path to the semantic layer directory, relative to the project root.
|
|
150
|
+
* Defaults to "./semantic".
|
|
151
|
+
*/
|
|
152
|
+
semanticLayer: z.string().optional().default("./semantic"),
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Action framework configuration. Per-action overrides use the action
|
|
156
|
+
* type as the key (e.g. `"slack:send"`). The special `defaults` key
|
|
157
|
+
* sets fallback values for all actions.
|
|
158
|
+
*/
|
|
159
|
+
actions: ActionsConfigSchema.optional(),
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Maximum total pool slots across all datasource pools.
|
|
163
|
+
* When a new datasource registration would exceed this limit,
|
|
164
|
+
* the least-recently-used datasource is evicted.
|
|
165
|
+
*/
|
|
166
|
+
maxTotalConnections: z.number().int().positive().default(100),
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Plugin instances to register at boot. Each element should satisfy
|
|
170
|
+
* the `AtlasPlugin` interface from `@atlas/plugin-sdk`.
|
|
171
|
+
*
|
|
172
|
+
* Zod validates structural shape (id, type, version) at config load
|
|
173
|
+
* time. Plugin-level configSchema validation happens at factory call
|
|
174
|
+
* time via `createPlugin()`.
|
|
175
|
+
*/
|
|
176
|
+
plugins: z.array(z.unknown()).optional(),
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Scheduler configuration for recurring scheduled tasks.
|
|
180
|
+
* Requires ATLAS_SCHEDULER_ENABLED=true to activate.
|
|
181
|
+
*/
|
|
182
|
+
scheduler: z.object({
|
|
183
|
+
/** Execution backend: "bun" runs an in-process tick loop, "webhook" relies on external cron hitting POST /:id/run, "vercel" uses Vercel Cron hitting POST /tick. */
|
|
184
|
+
backend: z.enum(["bun", "webhook", "vercel"]).default("bun"),
|
|
185
|
+
/** Maximum concurrent task executions per tick. */
|
|
186
|
+
maxConcurrentTasks: z.number().int().positive().default(5),
|
|
187
|
+
/** Per-task execution timeout in milliseconds. */
|
|
188
|
+
taskTimeout: z.number().int().positive().default(60_000),
|
|
189
|
+
/** Tick interval in seconds (how often the scheduler checks for due tasks). */
|
|
190
|
+
tickIntervalSeconds: z.number().int().positive().default(60),
|
|
191
|
+
}).optional(),
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Row-Level Security configuration. When enabled, every SQL query gets
|
|
195
|
+
* automatic WHERE clause injection based on the authenticated user's claims.
|
|
196
|
+
*/
|
|
197
|
+
rls: RLSConfigSchema.optional(),
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
/** The output type after Zod parsing (defaults applied, all fields present). */
|
|
201
|
+
export type AtlasConfig = z.infer<typeof AtlasConfigSchema>;
|
|
202
|
+
|
|
203
|
+
/** The input type for user-authored config (optional fields allowed). */
|
|
204
|
+
export type AtlasConfigInput = z.input<typeof AtlasConfigSchema>;
|
|
205
|
+
|
|
206
|
+
/** Expose schemas for external validation (e.g. tests). */
|
|
207
|
+
export { AtlasConfigSchema, RateLimitConfigSchema, RLSPolicySchema, RLSConfigSchema };
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* The resolved config after merging the config file with env var defaults.
|
|
211
|
+
* Guaranteed to have all fields populated.
|
|
212
|
+
*/
|
|
213
|
+
export interface ResolvedConfig {
|
|
214
|
+
datasources: Record<string, DatasourceConfig>;
|
|
215
|
+
tools: string[];
|
|
216
|
+
auth: AuthConfig;
|
|
217
|
+
semanticLayer: string;
|
|
218
|
+
/** Action framework configuration (optional, only when actions are enabled). */
|
|
219
|
+
actions?: ActionsConfig;
|
|
220
|
+
/** Maximum total pool slots across all datasource pools. */
|
|
221
|
+
maxTotalConnections: number;
|
|
222
|
+
/** Plugin instances to register at boot. */
|
|
223
|
+
plugins?: unknown[];
|
|
224
|
+
/** Scheduler configuration (only when ATLAS_SCHEDULER_ENABLED=true). */
|
|
225
|
+
scheduler?: {
|
|
226
|
+
backend: "bun" | "webhook" | "vercel";
|
|
227
|
+
maxConcurrentTasks: number;
|
|
228
|
+
taskTimeout: number;
|
|
229
|
+
tickIntervalSeconds: number;
|
|
230
|
+
};
|
|
231
|
+
/** Row-Level Security configuration. */
|
|
232
|
+
rls?: RLSConfig;
|
|
233
|
+
/** Whether the config was loaded from a file or synthesized from env vars. */
|
|
234
|
+
source: "file" | "env";
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
// defineConfig() — type-safe authoring helper
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Type-safe helper for authoring `atlas.config.ts`. Validates the config
|
|
243
|
+
* at build time via TypeScript and at runtime via Zod.
|
|
244
|
+
*
|
|
245
|
+
* Accepts the input shape (optional fields allowed). Zod applies defaults
|
|
246
|
+
* during `loadConfig()`.
|
|
247
|
+
*/
|
|
248
|
+
export function defineConfig(config: AtlasConfigInput): AtlasConfigInput {
|
|
249
|
+
return config;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
// Config loading
|
|
254
|
+
// ---------------------------------------------------------------------------
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Resolved config singleton — populated by {@link loadConfig}.
|
|
258
|
+
* Starts as null; after `loadConfig()` runs, this is always set.
|
|
259
|
+
*/
|
|
260
|
+
let _resolved: ResolvedConfig | null = null;
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Return the current resolved config, or null if {@link loadConfig} has
|
|
264
|
+
* not been called yet.
|
|
265
|
+
*/
|
|
266
|
+
export function getConfig(): ResolvedConfig | null {
|
|
267
|
+
return _resolved;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Build a ResolvedConfig from environment variables alone.
|
|
272
|
+
* This is the fallback path when no `atlas.config.ts` exists.
|
|
273
|
+
*/
|
|
274
|
+
export function configFromEnv(): ResolvedConfig {
|
|
275
|
+
const datasources: Record<string, DatasourceConfig> = {};
|
|
276
|
+
|
|
277
|
+
if (process.env.ATLAS_DATASOURCE_URL) {
|
|
278
|
+
datasources.default = {
|
|
279
|
+
url: process.env.ATLAS_DATASOURCE_URL,
|
|
280
|
+
...(process.env.ATLAS_SCHEMA ? { schema: process.env.ATLAS_SCHEMA } : {}),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Action framework config from env vars
|
|
285
|
+
let actions: ActionsConfig | undefined;
|
|
286
|
+
if (process.env.ATLAS_ACTIONS_ENABLED === "true") {
|
|
287
|
+
const defaults: ActionDefaults = {};
|
|
288
|
+
const approval = process.env.ATLAS_ACTION_APPROVAL;
|
|
289
|
+
if (approval) {
|
|
290
|
+
if ((ACTION_APPROVAL_MODES as readonly string[]).includes(approval)) {
|
|
291
|
+
defaults.approval = approval as ActionApprovalMode;
|
|
292
|
+
} else {
|
|
293
|
+
log.warn({ value: approval, valid: ACTION_APPROVAL_MODES }, "Invalid ATLAS_ACTION_APPROVAL — using default 'manual'");
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const timeout = parseInt(process.env.ATLAS_ACTION_TIMEOUT ?? "", 10);
|
|
297
|
+
if (Number.isFinite(timeout) && timeout > 0) {
|
|
298
|
+
defaults.timeout = timeout;
|
|
299
|
+
}
|
|
300
|
+
const maxPerConv = parseInt(process.env.ATLAS_ACTION_MAX_PER_CONVERSATION ?? "", 10);
|
|
301
|
+
if (Number.isFinite(maxPerConv) && maxPerConv > 0) {
|
|
302
|
+
defaults.maxPerConversation = maxPerConv;
|
|
303
|
+
}
|
|
304
|
+
actions = { defaults };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Scheduler config from env vars
|
|
308
|
+
let scheduler: ResolvedConfig["scheduler"];
|
|
309
|
+
if (process.env.ATLAS_SCHEDULER_ENABLED === "true") {
|
|
310
|
+
const rawBackend = process.env.ATLAS_SCHEDULER_BACKEND;
|
|
311
|
+
const backend = rawBackend === "webhook" ? "webhook" as const : rawBackend === "vercel" ? "vercel" as const : "bun" as const;
|
|
312
|
+
const maxConcurrent = parseInt(process.env.ATLAS_SCHEDULER_MAX_CONCURRENT ?? "", 10);
|
|
313
|
+
const timeout = parseInt(process.env.ATLAS_SCHEDULER_TIMEOUT ?? "", 10);
|
|
314
|
+
const tick = parseInt(process.env.ATLAS_SCHEDULER_TICK_INTERVAL ?? "", 10);
|
|
315
|
+
scheduler = {
|
|
316
|
+
backend,
|
|
317
|
+
maxConcurrentTasks: Number.isFinite(maxConcurrent) && maxConcurrent > 0 ? maxConcurrent : 5,
|
|
318
|
+
taskTimeout: Number.isFinite(timeout) && timeout > 0 ? timeout : 60_000,
|
|
319
|
+
tickIntervalSeconds: Number.isFinite(tick) && tick > 0 ? tick : 60,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// RLS config from env vars (single-policy shorthand)
|
|
324
|
+
let rls: RLSConfig | undefined;
|
|
325
|
+
if (process.env.ATLAS_RLS_ENABLED === "true") {
|
|
326
|
+
const column = process.env.ATLAS_RLS_COLUMN;
|
|
327
|
+
const claim = process.env.ATLAS_RLS_CLAIM;
|
|
328
|
+
if (!column || !claim) {
|
|
329
|
+
throw new Error(
|
|
330
|
+
`ATLAS_RLS_ENABLED=true requires both ATLAS_RLS_COLUMN and ATLAS_RLS_CLAIM to be set. ` +
|
|
331
|
+
`Got: ATLAS_RLS_COLUMN=${column ?? "(unset)"}, ATLAS_RLS_CLAIM=${claim ?? "(unset)"}`,
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
rls = { enabled: true, policies: [{ tables: ["*"], column, claim }] };
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
datasources,
|
|
339
|
+
tools: ["explore", "executeSQL"],
|
|
340
|
+
auth: "auto",
|
|
341
|
+
semanticLayer: "./semantic",
|
|
342
|
+
...(actions ? { actions } : {}),
|
|
343
|
+
maxTotalConnections: 100,
|
|
344
|
+
...(scheduler ? { scheduler } : {}),
|
|
345
|
+
...(rls ? { rls } : {}),
|
|
346
|
+
source: "env",
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Attempt to find and dynamically import `atlas.config.ts` (or `.js`, `.mjs`)
|
|
352
|
+
* from the project root. Returns null when no config file is found.
|
|
353
|
+
*
|
|
354
|
+
* Uses a cache-busting query parameter on the import path so that the file
|
|
355
|
+
* is always re-evaluated (important when the server restarts with a changed
|
|
356
|
+
* config).
|
|
357
|
+
*/
|
|
358
|
+
async function tryLoadConfigFile(
|
|
359
|
+
projectRoot: string,
|
|
360
|
+
): Promise<AtlasConfig | null> {
|
|
361
|
+
const candidates = [
|
|
362
|
+
"atlas.config.ts",
|
|
363
|
+
"atlas.config.js",
|
|
364
|
+
"atlas.config.mjs",
|
|
365
|
+
];
|
|
366
|
+
|
|
367
|
+
for (const filename of candidates) {
|
|
368
|
+
const filePath = path.resolve(projectRoot, filename);
|
|
369
|
+
if (!fs.existsSync(filePath)) continue;
|
|
370
|
+
|
|
371
|
+
try {
|
|
372
|
+
log.info({ file: filePath }, "Loading config file");
|
|
373
|
+
// Cache-bust: append timestamp so Bun re-evaluates the module
|
|
374
|
+
const mod = await import(`${filePath}?t=${Date.now()}`);
|
|
375
|
+
if (mod.default === undefined || mod.default === null) {
|
|
376
|
+
throw new Error(
|
|
377
|
+
`Config file "${filename}" does not have a default export. ` +
|
|
378
|
+
`Use \`export default defineConfig({ ... })\` or \`module.exports = { ... }\`.`,
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
const raw = mod.default;
|
|
382
|
+
return raw;
|
|
383
|
+
} catch (err) {
|
|
384
|
+
// If the file exists but fails to parse/import, that is a hard error
|
|
385
|
+
// that the user needs to fix — do not silently fall back to env vars.
|
|
386
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
387
|
+
throw new Error(
|
|
388
|
+
`Failed to load config file "${filename}": ${detail}`,
|
|
389
|
+
{ cause: err },
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// ---------------------------------------------------------------------------
|
|
398
|
+
// Plugin shape validation
|
|
399
|
+
// ---------------------------------------------------------------------------
|
|
400
|
+
|
|
401
|
+
const VALID_PLUGIN_TYPES = new Set(["datasource", "context", "interaction", "action"]);
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Validate plugin array entries have the required structural shape:
|
|
405
|
+
* `id` (non-empty string), `type` (valid PluginType), `version` (non-empty string).
|
|
406
|
+
*
|
|
407
|
+
* Also detects duplicate plugin IDs.
|
|
408
|
+
*
|
|
409
|
+
* This is the sole structural validation point for plugins in the config
|
|
410
|
+
* pipeline — it must not be removed. Plugin-level configSchema validation
|
|
411
|
+
* is handled by `createPlugin()` at factory call time (typically before
|
|
412
|
+
* this runs, during config file evaluation).
|
|
413
|
+
*
|
|
414
|
+
* @throws {Error} When any plugin entry fails validation.
|
|
415
|
+
*/
|
|
416
|
+
function validatePlugins(plugins: unknown[]): void {
|
|
417
|
+
const errors: string[] = [];
|
|
418
|
+
const seenIds = new Map<string, number>();
|
|
419
|
+
|
|
420
|
+
for (let i = 0; i < plugins.length; i++) {
|
|
421
|
+
const p = plugins[i];
|
|
422
|
+
|
|
423
|
+
if (p === null || p === undefined || typeof p !== "object") {
|
|
424
|
+
errors.push(`plugin at index ${i}: expected a plugin object, got ${p === null ? "null" : typeof p}`);
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const obj = p as Record<string, unknown>;
|
|
429
|
+
|
|
430
|
+
// Build label upfront: use plugin id if available, otherwise index
|
|
431
|
+
const hasId = "id" in obj && typeof obj.id === "string" && obj.id.trim();
|
|
432
|
+
const label = hasId ? `plugin "${obj.id}" (index ${i})` : `plugin at index ${i}`;
|
|
433
|
+
|
|
434
|
+
// id
|
|
435
|
+
if (!("id" in obj) || typeof obj.id !== "string") {
|
|
436
|
+
errors.push(`${label} is missing "id" (string)`);
|
|
437
|
+
} else if (!obj.id.trim()) {
|
|
438
|
+
errors.push(`${label} has an empty "id"`);
|
|
439
|
+
} else {
|
|
440
|
+
// Duplicate id check
|
|
441
|
+
const prevIndex = seenIds.get(obj.id);
|
|
442
|
+
if (prevIndex !== undefined) {
|
|
443
|
+
errors.push(`${label} has duplicate id "${obj.id}" (first seen at index ${prevIndex})`);
|
|
444
|
+
} else {
|
|
445
|
+
seenIds.set(obj.id, i);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// type
|
|
450
|
+
if (!("type" in obj) || typeof obj.type !== "string") {
|
|
451
|
+
errors.push(`${label} is missing "type" (string)`);
|
|
452
|
+
} else if (!VALID_PLUGIN_TYPES.has(obj.type)) {
|
|
453
|
+
errors.push(`${label} has invalid type "${obj.type}" — must be one of: datasource, context, interaction, action`);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// version
|
|
457
|
+
if (!("version" in obj) || typeof obj.version !== "string") {
|
|
458
|
+
errors.push(`${label} is missing "version" (string)`);
|
|
459
|
+
} else if (!obj.version.trim()) {
|
|
460
|
+
errors.push(`${label} has an empty "version"`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (errors.length > 0) {
|
|
465
|
+
throw new Error(
|
|
466
|
+
`Invalid plugin configuration:\n${errors.map((e) => ` - ${e}`).join("\n")}`,
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Validate a raw config object against the Zod schema and return a
|
|
473
|
+
* ResolvedConfig. Throws on validation failure with human-readable errors.
|
|
474
|
+
*/
|
|
475
|
+
export function validateAndResolve(raw: unknown): ResolvedConfig {
|
|
476
|
+
if (raw !== null && (typeof raw !== "object" || Array.isArray(raw))) {
|
|
477
|
+
throw new Error(
|
|
478
|
+
`atlas.config.ts must export a plain object. Got ${Array.isArray(raw) ? "array" : typeof raw}.`,
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const parseResult = AtlasConfigSchema.safeParse(raw);
|
|
483
|
+
if (!parseResult.success) {
|
|
484
|
+
const formatted = parseResult.error.issues
|
|
485
|
+
.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`)
|
|
486
|
+
.join("\n");
|
|
487
|
+
throw new Error(`Invalid atlas.config.ts:\n${formatted}`);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const config = parseResult.data;
|
|
491
|
+
|
|
492
|
+
// Structural validation of plugin entries (id, type, version)
|
|
493
|
+
if (config.plugins?.length) {
|
|
494
|
+
validatePlugins(config.plugins);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return {
|
|
498
|
+
datasources: config.datasources ?? {},
|
|
499
|
+
tools: config.tools ?? ["explore", "executeSQL"],
|
|
500
|
+
auth: config.auth ?? "auto",
|
|
501
|
+
semanticLayer: config.semanticLayer ?? "./semantic",
|
|
502
|
+
...(config.actions ? { actions: config.actions } : {}),
|
|
503
|
+
maxTotalConnections: config.maxTotalConnections ?? 100,
|
|
504
|
+
...(config.plugins?.length ? { plugins: config.plugins } : {}),
|
|
505
|
+
...(config.scheduler ? { scheduler: config.scheduler } : {}),
|
|
506
|
+
...(config.rls ? { rls: config.rls } : {}),
|
|
507
|
+
source: "file",
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Load and validate Atlas configuration.
|
|
513
|
+
*
|
|
514
|
+
* Resolution order:
|
|
515
|
+
* 1. Look for `atlas.config.ts` (or .js/.mjs) in the project root.
|
|
516
|
+
* 2. If found, parse and validate with Zod.
|
|
517
|
+
* 3. If not found, build a config from environment variables.
|
|
518
|
+
*
|
|
519
|
+
* The resolved config is cached as a module-level singleton accessible
|
|
520
|
+
* via {@link getConfig}.
|
|
521
|
+
*
|
|
522
|
+
* @param projectRoot - The directory to search for config files. Defaults
|
|
523
|
+
* to `process.cwd()`.
|
|
524
|
+
* @throws {Error} When the config file exists but is invalid (Zod errors
|
|
525
|
+
* are formatted into a human-readable message).
|
|
526
|
+
*/
|
|
527
|
+
export async function loadConfig(
|
|
528
|
+
projectRoot: string = process.cwd(),
|
|
529
|
+
): Promise<ResolvedConfig> {
|
|
530
|
+
const raw = await tryLoadConfigFile(projectRoot);
|
|
531
|
+
|
|
532
|
+
if (raw === null) {
|
|
533
|
+
log.info("No atlas.config.ts found — using environment variables");
|
|
534
|
+
const resolved = configFromEnv();
|
|
535
|
+
_resolved = resolved;
|
|
536
|
+
return resolved;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const resolved = validateAndResolve(raw);
|
|
540
|
+
|
|
541
|
+
log.info(
|
|
542
|
+
{
|
|
543
|
+
datasources: Object.keys(resolved.datasources),
|
|
544
|
+
tools: resolved.tools,
|
|
545
|
+
auth: resolved.auth,
|
|
546
|
+
semanticLayer: resolved.semanticLayer,
|
|
547
|
+
},
|
|
548
|
+
"Config loaded from file",
|
|
549
|
+
);
|
|
550
|
+
|
|
551
|
+
_resolved = resolved;
|
|
552
|
+
return resolved;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// ---------------------------------------------------------------------------
|
|
556
|
+
// Wiring helpers — apply config to ConnectionRegistry and ToolRegistry
|
|
557
|
+
// ---------------------------------------------------------------------------
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Register datasources from the resolved config into the ConnectionRegistry.
|
|
561
|
+
* Skips if no datasources are defined (the registry will lazy-init from
|
|
562
|
+
* ATLAS_DATASOURCE_URL on first access, preserving backward compat).
|
|
563
|
+
*
|
|
564
|
+
* @param config - The resolved configuration.
|
|
565
|
+
* @param registry - The ConnectionRegistry to register into. When omitted,
|
|
566
|
+
* uses the global singleton from `./db/connection`.
|
|
567
|
+
*/
|
|
568
|
+
export async function applyDatasources(
|
|
569
|
+
config: ResolvedConfig,
|
|
570
|
+
registry?: ConnectionRegistry,
|
|
571
|
+
): Promise<void> {
|
|
572
|
+
if (Object.keys(config.datasources).length === 0) {
|
|
573
|
+
log.debug("No datasources in config — ConnectionRegistry will use env var fallback");
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const connRegistry = registry ?? (await import("./db/connection")).connections;
|
|
578
|
+
const { detectDBType } = await import("./db/connection");
|
|
579
|
+
|
|
580
|
+
connRegistry.setMaxTotalConnections(config.maxTotalConnections);
|
|
581
|
+
|
|
582
|
+
for (const [id, ds] of Object.entries(config.datasources)) {
|
|
583
|
+
try {
|
|
584
|
+
const dbType = detectDBType(ds.url);
|
|
585
|
+
if (dbType === "salesforce") {
|
|
586
|
+
log.info({ connectionId: id }, "Registering Salesforce datasource from config");
|
|
587
|
+
const { parseSalesforceURL, registerSalesforceSource } = await import("./db/salesforce");
|
|
588
|
+
const sfConfig = parseSalesforceURL(ds.url);
|
|
589
|
+
registerSalesforceSource(id, sfConfig);
|
|
590
|
+
} else {
|
|
591
|
+
log.info({ connectionId: id }, "Registering datasource from config");
|
|
592
|
+
connRegistry.register(id, {
|
|
593
|
+
url: ds.url,
|
|
594
|
+
schema: ds.schema,
|
|
595
|
+
description: ds.description,
|
|
596
|
+
maxConnections: ds.maxConnections,
|
|
597
|
+
idleTimeoutMs: ds.idleTimeoutMs,
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
// Fire initial health check — logs on failure but does not block startup.
|
|
601
|
+
// A degraded connection is still usable (the DB may recover).
|
|
602
|
+
connRegistry.healthCheck(id).then((result) => {
|
|
603
|
+
if (result.status !== "healthy") {
|
|
604
|
+
log.warn(
|
|
605
|
+
{ connectionId: id, status: result.status, message: result.message },
|
|
606
|
+
"Datasource registered but initial health check failed — connection may be misconfigured",
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
}).catch((healthErr) => {
|
|
610
|
+
log.warn(
|
|
611
|
+
{ err: healthErr instanceof Error ? healthErr.message : String(healthErr), connectionId: id },
|
|
612
|
+
"Initial health check failed after registration",
|
|
613
|
+
);
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
if (ds.rateLimit) {
|
|
618
|
+
const { registerSourceRateLimit } = await import("./db/source-rate-limit");
|
|
619
|
+
registerSourceRateLimit(id, {
|
|
620
|
+
queriesPerMinute: ds.rateLimit.queriesPerMinute,
|
|
621
|
+
concurrency: ds.rateLimit.concurrency,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
} catch (err) {
|
|
625
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
626
|
+
throw new Error(
|
|
627
|
+
`Failed to register datasource "${id}": ${detail}`,
|
|
628
|
+
{ cause: err },
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Validate that the tool names in the config match registered tools in the
|
|
636
|
+
* default registry. Throws if any tool names are unrecognized.
|
|
637
|
+
*
|
|
638
|
+
* @param config - The resolved configuration.
|
|
639
|
+
* @param registry - The ToolRegistry to validate against. When omitted,
|
|
640
|
+
* uses the default registry from `./tools/registry`.
|
|
641
|
+
* @throws {Error} When config references tool names not in the registry.
|
|
642
|
+
*/
|
|
643
|
+
export async function validateToolConfig(
|
|
644
|
+
config: ResolvedConfig,
|
|
645
|
+
registry?: ToolRegistry,
|
|
646
|
+
): Promise<void> {
|
|
647
|
+
const toolRegistry = registry ?? (await import("./tools/registry")).defaultRegistry;
|
|
648
|
+
|
|
649
|
+
const unknownTools: string[] = [];
|
|
650
|
+
for (const toolName of config.tools) {
|
|
651
|
+
if (!toolRegistry.get(toolName)) {
|
|
652
|
+
unknownTools.push(toolName);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
if (unknownTools.length > 0) {
|
|
656
|
+
const available = Object.keys(toolRegistry.getAll());
|
|
657
|
+
throw new Error(
|
|
658
|
+
`Unknown tool(s) in config: ${unknownTools.join(", ")}. ` +
|
|
659
|
+
`Available: ${available.join(", ")}.`,
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// ---------------------------------------------------------------------------
|
|
665
|
+
// Startup integration — single entry point for server boot
|
|
666
|
+
// ---------------------------------------------------------------------------
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Load config, wire datasources, and validate tool names.
|
|
670
|
+
* Call this once during server startup (e.g. in server.ts).
|
|
671
|
+
*
|
|
672
|
+
* @param projectRoot - Directory to search for config files.
|
|
673
|
+
* @param opts - Optional dependency injection for registries (used in tests).
|
|
674
|
+
* @throws {Error} When the config file is present but invalid.
|
|
675
|
+
*/
|
|
676
|
+
export async function initializeConfig(
|
|
677
|
+
projectRoot?: string,
|
|
678
|
+
opts?: {
|
|
679
|
+
connectionRegistry?: ConnectionRegistry;
|
|
680
|
+
toolRegistry?: ToolRegistry;
|
|
681
|
+
},
|
|
682
|
+
): Promise<ResolvedConfig> {
|
|
683
|
+
const config = await loadConfig(projectRoot);
|
|
684
|
+
const connRegistry = opts?.connectionRegistry;
|
|
685
|
+
await applyDatasources(config, connRegistry);
|
|
686
|
+
await validateToolConfig(config, opts?.toolRegistry);
|
|
687
|
+
|
|
688
|
+
// Start periodic health checks when datasources are registered
|
|
689
|
+
const registry = connRegistry ?? (await import("./db/connection")).connections;
|
|
690
|
+
if (registry.list().length > 0) {
|
|
691
|
+
registry.startHealthChecks();
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return config;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// ---------------------------------------------------------------------------
|
|
698
|
+
// Test helper
|
|
699
|
+
// ---------------------------------------------------------------------------
|
|
700
|
+
|
|
701
|
+
/** Reset the cached config. For testing only. */
|
|
702
|
+
export function _resetConfig(): void {
|
|
703
|
+
_resolved = null;
|
|
704
|
+
}
|