@useatlas/create 0.0.2 → 0.0.3
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 +4 -18
- package/index.ts +191 -31
- package/package.json +1 -1
- package/templates/docker/.env.example +3 -3
- package/templates/docker/Dockerfile.sidecar +28 -0
- package/templates/docker/bin/__tests__/plugin-cli.test.ts +9 -9
- package/templates/docker/bin/atlas.ts +108 -44
- package/templates/docker/data/demo-semantic/catalog.yml +51 -27
- package/templates/docker/data/demo-semantic/entities/accounts.yml +95 -103
- package/templates/docker/data/demo-semantic/entities/companies.yml +88 -152
- package/templates/docker/data/demo-semantic/entities/people.yml +82 -95
- package/templates/docker/data/demo-semantic/glossary.yml +104 -8
- package/templates/docker/data/demo-semantic/metrics/accounts.yml +62 -23
- package/templates/docker/data/demo-semantic/metrics/companies.yml +52 -78
- package/templates/docker/docker-compose.yml +1 -1
- package/templates/docker/docs/deploy.md +2 -39
- package/templates/docker/package.json +17 -1
- package/templates/docker/semantic/catalog.yml +62 -3
- package/templates/docker/semantic/entities/accounts.yml +162 -0
- package/templates/docker/semantic/entities/companies.yml +143 -0
- package/templates/docker/semantic/entities/people.yml +132 -0
- package/templates/docker/semantic/glossary.yml +116 -4
- package/templates/docker/semantic/metrics/accounts.yml +77 -0
- package/templates/docker/semantic/metrics/companies.yml +63 -0
- package/templates/docker/sidecar/Dockerfile +5 -6
- package/templates/docker/sidecar/railway.json +1 -2
- package/templates/docker/src/api/__tests__/admin.test.ts +7 -7
- package/templates/docker/src/api/__tests__/health-plugin.test.ts +7 -0
- package/templates/docker/src/api/__tests__/health.test.ts +30 -8
- package/templates/docker/src/api/routes/admin.ts +549 -8
- package/templates/docker/src/api/routes/chat.ts +5 -20
- package/templates/docker/src/api/routes/health.ts +39 -27
- package/templates/docker/src/api/routes/openapi.ts +1329 -74
- package/templates/docker/src/api/routes/query.ts +2 -1
- package/templates/docker/src/api/server.ts +27 -0
- package/templates/docker/src/app/api/[...route]/route.ts +2 -2
- package/templates/docker/src/app/globals.css +13 -12
- package/templates/docker/src/app/layout.tsx +9 -2
- package/templates/docker/src/components/ui/alert-dialog.tsx +196 -0
- package/templates/docker/src/components/ui/badge.tsx +48 -0
- package/templates/docker/src/components/ui/button.tsx +64 -0
- package/templates/docker/src/components/ui/card.tsx +92 -0
- package/templates/docker/src/components/ui/collapsible.tsx +33 -0
- package/templates/docker/src/components/ui/command.tsx +184 -0
- package/templates/docker/src/components/ui/dialog.tsx +158 -0
- package/templates/docker/src/components/ui/dropdown-menu.tsx +257 -0
- package/templates/docker/src/components/ui/input.tsx +21 -0
- package/templates/docker/src/components/ui/scroll-area.tsx +58 -0
- package/templates/docker/src/components/ui/select.tsx +190 -0
- package/templates/docker/src/components/ui/separator.tsx +28 -0
- package/templates/docker/src/components/ui/sheet.tsx +143 -0
- package/templates/docker/src/components/ui/sidebar.tsx +726 -0
- package/templates/docker/src/components/ui/skeleton.tsx +13 -0
- package/templates/docker/src/components/ui/table.tsx +116 -0
- package/templates/docker/src/components/ui/tabs.tsx +91 -0
- package/templates/docker/src/components/ui/toggle-group.tsx +83 -0
- package/templates/docker/src/components/ui/toggle.tsx +47 -0
- package/templates/docker/src/components/ui/tooltip.tsx +57 -0
- package/templates/docker/src/hooks/use-mobile.ts +19 -0
- package/templates/docker/src/lib/__tests__/agent-cache.test.ts +2 -0
- package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +17 -0
- package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +2 -0
- package/templates/docker/src/lib/__tests__/agent-integration.test.ts +2 -0
- package/templates/docker/src/lib/__tests__/config.test.ts +69 -19
- package/templates/docker/src/lib/__tests__/plugin-aware-validation.test.ts +321 -0
- package/templates/docker/src/lib/__tests__/providers.test.ts +32 -1
- package/templates/docker/src/lib/__tests__/startup-actions.test.ts +9 -0
- package/templates/docker/src/lib/__tests__/startup-first-run.test.ts +429 -0
- package/templates/docker/src/lib/__tests__/startup.test.ts +5 -0
- package/templates/docker/src/lib/agent-query.ts +5 -23
- package/templates/docker/src/lib/agent.ts +32 -112
- package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +5 -3
- package/templates/docker/src/lib/auth/middleware.ts +30 -4
- package/templates/docker/src/lib/auth/migrate.ts +97 -0
- package/templates/docker/src/lib/auth/server.ts +12 -1
- package/templates/docker/src/lib/config.ts +37 -39
- package/templates/docker/src/lib/db/__tests__/connection.test.ts +89 -14
- package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +1 -18
- package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -19
- package/templates/docker/src/lib/db/__tests__/registry.test.ts +11 -208
- package/templates/docker/src/lib/db/connection.ts +87 -265
- package/templates/docker/src/lib/db/internal.ts +6 -1
- package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +3 -1
- package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +2 -2
- package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +355 -1
- package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +32 -5
- package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +228 -14
- package/templates/docker/src/lib/plugins/index.ts +4 -1
- package/templates/docker/src/lib/plugins/migrate.ts +103 -0
- package/templates/docker/src/lib/plugins/registry.ts +12 -6
- package/templates/docker/src/lib/plugins/wiring.ts +113 -4
- package/templates/docker/src/lib/providers.ts +6 -1
- package/templates/docker/src/lib/security.ts +24 -0
- package/templates/docker/src/lib/semantic.ts +2 -0
- package/templates/docker/src/lib/sidecar-types.ts +12 -1
- package/templates/docker/src/lib/startup.ts +71 -101
- package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +2 -0
- package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +32 -18
- package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +14 -14
- package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
- package/templates/docker/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
- package/templates/docker/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
- package/templates/docker/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
- package/templates/docker/src/lib/tools/__tests__/python.test.ts +331 -0
- package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
- package/templates/docker/src/lib/tools/__tests__/registry.test.ts +38 -31
- package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
- package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
- package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
- package/templates/docker/src/lib/tools/__tests__/sql.test.ts +5 -308
- package/templates/docker/src/lib/tools/explore-nsjail.ts +17 -12
- package/templates/docker/src/lib/tools/explore-sidecar.ts +25 -0
- package/templates/docker/src/lib/tools/explore.ts +28 -32
- package/templates/docker/src/lib/tools/python-nsjail.ts +396 -0
- package/templates/docker/src/lib/tools/python-sandbox.ts +476 -0
- package/templates/docker/src/lib/tools/python-sidecar.ts +150 -0
- package/templates/docker/src/lib/tools/python.ts +367 -0
- package/templates/docker/src/lib/tools/registry.ts +49 -22
- package/templates/docker/src/lib/tools/sql.ts +88 -88
- package/templates/docker/src/types/vercel-sandbox.d.ts +7 -0
- package/templates/docker/src/ui/components/admin/admin-layout.tsx +77 -8
- package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +25 -17
- package/templates/docker/src/ui/components/admin/change-password-dialog.tsx +128 -0
- package/templates/docker/src/ui/components/admin/entity-detail.tsx +3 -3
- package/templates/docker/src/ui/components/admin/semantic-file-tree.tsx +159 -0
- package/templates/docker/src/ui/components/atlas-chat.tsx +64 -12
- package/templates/docker/src/ui/components/chart/result-chart.tsx +25 -15
- package/templates/docker/src/ui/components/chat/markdown.tsx +88 -42
- package/templates/docker/src/ui/components/chat/python-result-card.tsx +244 -0
- package/templates/docker/src/ui/components/chat/sql-block.tsx +39 -15
- package/templates/docker/src/ui/components/chat/sql-result-card.tsx +6 -1
- package/templates/docker/src/ui/components/chat/tool-part.tsx +12 -3
- package/templates/docker/src/ui/components/chat/typing-indicator.tsx +5 -2
- package/templates/docker/src/ui/components/conversations/conversation-item.tsx +25 -20
- package/templates/docker/src/ui/context.tsx +1 -1
- package/templates/docker/src/ui/hooks/use-conversations.ts +3 -3
- package/templates/docker/src/ui/hooks/use-dark-mode.ts +17 -10
- package/templates/docker/tsconfig.json +2 -2
- package/templates/nextjs-standalone/.env.example +1 -1
- package/templates/nextjs-standalone/bin/__tests__/plugin-cli.test.ts +9 -9
- package/templates/nextjs-standalone/bin/atlas.ts +108 -44
- package/templates/nextjs-standalone/data/demo-semantic/catalog.yml +51 -27
- package/templates/nextjs-standalone/data/demo-semantic/entities/accounts.yml +95 -103
- package/templates/nextjs-standalone/data/demo-semantic/entities/companies.yml +88 -152
- package/templates/nextjs-standalone/data/demo-semantic/entities/people.yml +82 -95
- package/templates/nextjs-standalone/data/demo-semantic/glossary.yml +104 -8
- package/templates/nextjs-standalone/data/demo-semantic/metrics/accounts.yml +62 -23
- package/templates/nextjs-standalone/data/demo-semantic/metrics/companies.yml +52 -78
- package/templates/nextjs-standalone/docs/deploy.md +2 -39
- package/templates/nextjs-standalone/package.json +11 -2
- package/templates/nextjs-standalone/scripts/migrate-auth.ts +25 -0
- package/templates/nextjs-standalone/scripts/seed-demo.ts +94 -0
- package/templates/nextjs-standalone/semantic/catalog.yml +62 -3
- package/templates/nextjs-standalone/semantic/entities/accounts.yml +162 -0
- package/templates/nextjs-standalone/semantic/entities/companies.yml +143 -0
- package/templates/nextjs-standalone/semantic/entities/people.yml +132 -0
- package/templates/nextjs-standalone/semantic/glossary.yml +116 -4
- package/templates/nextjs-standalone/semantic/metrics/accounts.yml +77 -0
- package/templates/nextjs-standalone/semantic/metrics/companies.yml +63 -0
- package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +7 -7
- package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +7 -0
- package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +30 -8
- package/templates/nextjs-standalone/src/api/routes/admin.ts +549 -8
- package/templates/nextjs-standalone/src/api/routes/chat.ts +5 -20
- package/templates/nextjs-standalone/src/api/routes/health.ts +39 -27
- package/templates/nextjs-standalone/src/api/routes/openapi.ts +1329 -74
- package/templates/nextjs-standalone/src/api/routes/query.ts +2 -1
- package/templates/nextjs-standalone/src/api/server.ts +27 -0
- package/templates/nextjs-standalone/src/app/api/[...route]/route.ts +2 -2
- package/templates/nextjs-standalone/src/app/globals.css +13 -12
- package/templates/nextjs-standalone/src/app/layout.tsx +9 -2
- package/templates/nextjs-standalone/src/components/ui/alert-dialog.tsx +196 -0
- package/templates/nextjs-standalone/src/components/ui/badge.tsx +48 -0
- package/templates/nextjs-standalone/src/components/ui/button.tsx +64 -0
- package/templates/nextjs-standalone/src/components/ui/card.tsx +92 -0
- package/templates/nextjs-standalone/src/components/ui/collapsible.tsx +33 -0
- package/templates/nextjs-standalone/src/components/ui/command.tsx +184 -0
- package/templates/nextjs-standalone/src/components/ui/dialog.tsx +158 -0
- package/templates/nextjs-standalone/src/components/ui/dropdown-menu.tsx +257 -0
- package/templates/nextjs-standalone/src/components/ui/input.tsx +21 -0
- package/templates/nextjs-standalone/src/components/ui/scroll-area.tsx +58 -0
- package/templates/nextjs-standalone/src/components/ui/select.tsx +190 -0
- package/templates/nextjs-standalone/src/components/ui/separator.tsx +28 -0
- package/templates/nextjs-standalone/src/components/ui/sheet.tsx +143 -0
- package/templates/nextjs-standalone/src/components/ui/sidebar.tsx +726 -0
- package/templates/nextjs-standalone/src/components/ui/skeleton.tsx +13 -0
- package/templates/nextjs-standalone/src/components/ui/table.tsx +116 -0
- package/templates/nextjs-standalone/src/components/ui/tabs.tsx +91 -0
- package/templates/nextjs-standalone/src/components/ui/toggle-group.tsx +83 -0
- package/templates/nextjs-standalone/src/components/ui/toggle.tsx +47 -0
- package/templates/nextjs-standalone/src/components/ui/tooltip.tsx +57 -0
- package/templates/nextjs-standalone/src/hooks/use-mobile.ts +19 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +2 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +17 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +2 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +2 -0
- package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +69 -19
- package/templates/nextjs-standalone/src/lib/__tests__/plugin-aware-validation.test.ts +321 -0
- package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +32 -1
- package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +9 -0
- package/templates/nextjs-standalone/src/lib/__tests__/startup-first-run.test.ts +429 -0
- package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +5 -0
- package/templates/nextjs-standalone/src/lib/agent-query.ts +5 -23
- package/templates/nextjs-standalone/src/lib/agent.ts +32 -112
- package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +5 -3
- package/templates/nextjs-standalone/src/lib/auth/middleware.ts +30 -4
- package/templates/nextjs-standalone/src/lib/auth/migrate.ts +97 -0
- package/templates/nextjs-standalone/src/lib/auth/server.ts +12 -1
- package/templates/nextjs-standalone/src/lib/config.ts +37 -39
- package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +89 -14
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +1 -18
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -19
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +11 -208
- package/templates/nextjs-standalone/src/lib/db/connection.ts +87 -265
- package/templates/nextjs-standalone/src/lib/db/internal.ts +6 -1
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +3 -1
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +2 -2
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +355 -1
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +32 -5
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +228 -14
- package/templates/nextjs-standalone/src/lib/plugins/index.ts +4 -1
- package/templates/nextjs-standalone/src/lib/plugins/migrate.ts +103 -0
- package/templates/nextjs-standalone/src/lib/plugins/registry.ts +12 -6
- package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +113 -4
- package/templates/nextjs-standalone/src/lib/providers.ts +6 -1
- package/templates/nextjs-standalone/src/lib/security.ts +24 -0
- package/templates/nextjs-standalone/src/lib/semantic.ts +2 -0
- package/templates/nextjs-standalone/src/lib/sidecar-types.ts +12 -1
- package/templates/nextjs-standalone/src/lib/startup.ts +71 -101
- package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +2 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +32 -18
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +14 -14
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
- package/templates/nextjs-standalone/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/python.test.ts +331 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
- package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +38 -31
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +5 -308
- package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +17 -12
- package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +25 -0
- package/templates/nextjs-standalone/src/lib/tools/explore.ts +28 -32
- package/templates/nextjs-standalone/src/lib/tools/python-nsjail.ts +396 -0
- package/templates/nextjs-standalone/src/lib/tools/python-sandbox.ts +476 -0
- package/templates/nextjs-standalone/src/lib/tools/python-sidecar.ts +150 -0
- package/templates/nextjs-standalone/src/lib/tools/python.ts +367 -0
- package/templates/nextjs-standalone/src/lib/tools/registry.ts +49 -22
- package/templates/nextjs-standalone/src/lib/tools/sql.ts +88 -88
- package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +77 -8
- package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +25 -17
- package/templates/nextjs-standalone/src/ui/components/admin/change-password-dialog.tsx +128 -0
- package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +3 -3
- package/templates/nextjs-standalone/src/ui/components/admin/semantic-file-tree.tsx +159 -0
- package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +64 -12
- package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +25 -15
- package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +88 -42
- package/templates/nextjs-standalone/src/ui/components/chat/python-result-card.tsx +244 -0
- package/templates/nextjs-standalone/src/ui/components/chat/sql-block.tsx +39 -15
- package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +6 -1
- package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +12 -3
- package/templates/nextjs-standalone/src/ui/components/chat/typing-indicator.tsx +5 -2
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +25 -20
- package/templates/nextjs-standalone/src/ui/context.tsx +1 -1
- package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +3 -3
- package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +17 -10
- package/templates/nextjs-standalone/tsconfig.json +0 -1
- package/templates/nextjs-standalone/vercel.json +4 -1
- package/templates/docker/render.yaml +0 -34
- package/templates/docker/semantic/entities/.gitkeep +0 -0
- package/templates/docker/semantic/metrics/.gitkeep +0 -0
- package/templates/docker/src/lib/db/__tests__/duckdb.test.ts +0 -141
- package/templates/docker/src/lib/db/__tests__/salesforce.test.ts +0 -339
- package/templates/docker/src/lib/db/__tests__/snowflake.test.ts +0 -217
- package/templates/docker/src/lib/db/duckdb.ts +0 -122
- package/templates/docker/src/lib/db/salesforce.ts +0 -342
- package/templates/docker/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
- package/templates/docker/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
- package/templates/docker/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
- package/templates/docker/src/lib/tools/salesforce.ts +0 -138
- package/templates/docker/src/lib/tools/soql-validation.ts +0 -172
- package/templates/nextjs-standalone/semantic/entities/.gitkeep +0 -0
- package/templates/nextjs-standalone/semantic/metrics/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/duckdb.test.ts +0 -141
- package/templates/nextjs-standalone/src/lib/db/__tests__/salesforce.test.ts +0 -339
- package/templates/nextjs-standalone/src/lib/db/__tests__/snowflake.test.ts +0 -217
- package/templates/nextjs-standalone/src/lib/db/duckdb.ts +0 -122
- package/templates/nextjs-standalone/src/lib/db/salesforce.ts +0 -342
- package/templates/nextjs-standalone/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
- package/templates/nextjs-standalone/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
- package/templates/nextjs-standalone/src/lib/tools/salesforce.ts +0 -138
- package/templates/nextjs-standalone/src/lib/tools/soql-validation.ts +0 -172
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, mock } from "bun:test";
|
|
2
|
+
import { resetAuthModeCache } from "@atlas/api/lib/auth/detect";
|
|
3
|
+
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Control variables for mocks — mutated per-test in beforeEach
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
let mockDatasourceUrl: string | null = null;
|
|
9
|
+
let mockSemanticFiles: string[] | Error = ["orders.yml"];
|
|
10
|
+
let mockPgConnectError: Error | null = null;
|
|
11
|
+
let mockMysqlConnectError: Error | null = null;
|
|
12
|
+
let mockConfigResult: Record<string, unknown> | null = { source: "env" };
|
|
13
|
+
let mockConfigLoadError: Error | null = null;
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Mocks — must be set up before importing the module under test
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
mock.module("fs", () => ({
|
|
20
|
+
existsSync: () => false,
|
|
21
|
+
readdirSync: () => {
|
|
22
|
+
if (mockSemanticFiles instanceof Error) throw mockSemanticFiles;
|
|
23
|
+
return mockSemanticFiles;
|
|
24
|
+
},
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
mock.module("@atlas/api/lib/db/connection", () => ({
|
|
28
|
+
detectDBType: (url: string) => {
|
|
29
|
+
if (url.startsWith("mysql")) return "mysql";
|
|
30
|
+
return "postgres";
|
|
31
|
+
},
|
|
32
|
+
resolveDatasourceUrl: () => mockDatasourceUrl,
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
mock.module("@atlas/api/lib/providers", () => ({
|
|
36
|
+
getDefaultProvider: () => "anthropic",
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
mock.module("pg", () => ({
|
|
40
|
+
Pool: class MockPool {
|
|
41
|
+
async connect() {
|
|
42
|
+
if (mockPgConnectError) throw mockPgConnectError;
|
|
43
|
+
return {
|
|
44
|
+
release: () => {},
|
|
45
|
+
query: async () => ({ rows: [{ "?column?": 1 }] }),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async end() {}
|
|
49
|
+
},
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
mock.module("mysql2/promise", () => ({
|
|
53
|
+
createPool: () => ({
|
|
54
|
+
getConnection: async () => {
|
|
55
|
+
if (mockMysqlConnectError) throw mockMysqlConnectError;
|
|
56
|
+
return { release: () => {} };
|
|
57
|
+
},
|
|
58
|
+
end: async () => {},
|
|
59
|
+
}),
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
mock.module("@atlas/api/lib/config", () => ({
|
|
63
|
+
getConfig: () => mockConfigResult,
|
|
64
|
+
loadConfig: async () => {
|
|
65
|
+
if (mockConfigLoadError) throw mockConfigLoadError;
|
|
66
|
+
mockConfigResult = { source: "env" };
|
|
67
|
+
return mockConfigResult;
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
mock.module("@atlas/api/lib/tools/explore-nsjail", () => ({
|
|
72
|
+
findNsjailBinary: () => null,
|
|
73
|
+
testNsjailCapabilities: async () => ({ ok: true }),
|
|
74
|
+
isNsjailAvailable: () => false,
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
mock.module("@atlas/api/lib/tools/explore", () => ({
|
|
78
|
+
markNsjailFailed: () => {},
|
|
79
|
+
markSidecarFailed: () => {},
|
|
80
|
+
getExploreBackendType: () => "just-bash",
|
|
81
|
+
getActiveSandboxPluginId: () => null,
|
|
82
|
+
invalidateExploreBackend: () => {},
|
|
83
|
+
}));
|
|
84
|
+
|
|
85
|
+
mock.module("@atlas/api/lib/auth/migrate", () => ({
|
|
86
|
+
getMigrationError: () => null,
|
|
87
|
+
}));
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Import under test (AFTER mocks)
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
const { validateEnvironment, getStartupWarnings, resetStartupCache } =
|
|
94
|
+
await import("@atlas/api/lib/startup");
|
|
95
|
+
|
|
96
|
+
const { maskConnectionUrl } = await import("@atlas/api/lib/security");
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Env snapshot — capture/restore only the vars this test touches
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
const MANAGED_VARS = [
|
|
103
|
+
"ATLAS_DATASOURCE_URL", "DATABASE_URL", "ATLAS_API_KEY", "ATLAS_PROVIDER",
|
|
104
|
+
"ATLAS_AUTH_MODE", "BETTER_AUTH_SECRET", "BETTER_AUTH_URL",
|
|
105
|
+
"BETTER_AUTH_TRUSTED_ORIGINS", "ATLAS_AUTH_JWKS_URL", "ATLAS_AUTH_ISSUER",
|
|
106
|
+
"ATLAS_AUTH_AUDIENCE", "ATLAS_SANDBOX", "ATLAS_SANDBOX_URL",
|
|
107
|
+
"ATLAS_RUNTIME", "VERCEL", "ANTHROPIC_API_KEY", "OPENAI_API_KEY",
|
|
108
|
+
"AWS_ACCESS_KEY_ID", "AI_GATEWAY_API_KEY", "ATLAS_DEMO_DATA",
|
|
109
|
+
] as const;
|
|
110
|
+
|
|
111
|
+
const saved: Record<string, string | undefined> = {};
|
|
112
|
+
|
|
113
|
+
beforeEach(() => {
|
|
114
|
+
for (const key of MANAGED_VARS) saved[key] = process.env[key];
|
|
115
|
+
resetStartupCache();
|
|
116
|
+
resetAuthModeCache();
|
|
117
|
+
|
|
118
|
+
// Clean all managed vars
|
|
119
|
+
for (const key of MANAGED_VARS) delete process.env[key];
|
|
120
|
+
|
|
121
|
+
// Default: ollama (no key needed), no datasource, semantic layer present, config loaded
|
|
122
|
+
process.env.ATLAS_PROVIDER = "ollama";
|
|
123
|
+
mockDatasourceUrl = null;
|
|
124
|
+
mockSemanticFiles = ["orders.yml"];
|
|
125
|
+
mockPgConnectError = null;
|
|
126
|
+
mockMysqlConnectError = null;
|
|
127
|
+
mockConfigResult = { source: "env" };
|
|
128
|
+
mockConfigLoadError = null;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
afterEach(() => {
|
|
132
|
+
for (const key of MANAGED_VARS) {
|
|
133
|
+
if (saved[key] !== undefined) process.env[key] = saved[key];
|
|
134
|
+
else delete process.env[key];
|
|
135
|
+
}
|
|
136
|
+
resetStartupCache();
|
|
137
|
+
resetAuthModeCache();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
// 1. Missing LLM provider API key
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
describe("first-run: missing LLM provider API key", () => {
|
|
145
|
+
it("includes env var name and signup URL for anthropic", async () => {
|
|
146
|
+
process.env.ATLAS_PROVIDER = "anthropic";
|
|
147
|
+
delete process.env.ANTHROPIC_API_KEY;
|
|
148
|
+
|
|
149
|
+
const errors = await validateEnvironment();
|
|
150
|
+
const err = errors.find((e) => e.code === "MISSING_API_KEY");
|
|
151
|
+
expect(err).toBeDefined();
|
|
152
|
+
expect(err!.message).toContain("ANTHROPIC_API_KEY");
|
|
153
|
+
expect(err!.message).toContain(".env");
|
|
154
|
+
expect(err!.message).toContain("console.anthropic.com");
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("includes env var name and signup URL for openai", async () => {
|
|
158
|
+
process.env.ATLAS_PROVIDER = "openai";
|
|
159
|
+
delete process.env.OPENAI_API_KEY;
|
|
160
|
+
|
|
161
|
+
const errors = await validateEnvironment();
|
|
162
|
+
const err = errors.find((e) => e.code === "MISSING_API_KEY");
|
|
163
|
+
expect(err).toBeDefined();
|
|
164
|
+
expect(err!.message).toContain("OPENAI_API_KEY");
|
|
165
|
+
expect(err!.message).toContain("platform.openai.com");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("includes env var name and signup URL for gateway", async () => {
|
|
169
|
+
process.env.ATLAS_PROVIDER = "gateway";
|
|
170
|
+
delete process.env.AI_GATEWAY_API_KEY;
|
|
171
|
+
|
|
172
|
+
const errors = await validateEnvironment();
|
|
173
|
+
const err = errors.find((e) => e.code === "MISSING_API_KEY");
|
|
174
|
+
expect(err).toBeDefined();
|
|
175
|
+
expect(err!.message).toContain("AI_GATEWAY_API_KEY");
|
|
176
|
+
expect(err!.message).toContain("vercel.com");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("includes env var name without signup URL for bedrock", async () => {
|
|
180
|
+
process.env.ATLAS_PROVIDER = "bedrock";
|
|
181
|
+
delete process.env.AWS_ACCESS_KEY_ID;
|
|
182
|
+
|
|
183
|
+
const errors = await validateEnvironment();
|
|
184
|
+
const err = errors.find((e) => e.code === "MISSING_API_KEY");
|
|
185
|
+
expect(err).toBeDefined();
|
|
186
|
+
expect(err!.message).toContain("AWS_ACCESS_KEY_ID");
|
|
187
|
+
expect(err!.message).toContain(".env");
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("no error when using ollama (no key required)", async () => {
|
|
191
|
+
process.env.ATLAS_PROVIDER = "ollama";
|
|
192
|
+
|
|
193
|
+
const errors = await validateEnvironment();
|
|
194
|
+
expect(errors.find((e) => e.code === "MISSING_API_KEY")).toBeUndefined();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("no error when API key is set", async () => {
|
|
198
|
+
process.env.ATLAS_PROVIDER = "anthropic";
|
|
199
|
+
process.env.ANTHROPIC_API_KEY = "sk-ant-test-key";
|
|
200
|
+
|
|
201
|
+
const errors = await validateEnvironment();
|
|
202
|
+
expect(errors.find((e) => e.code === "MISSING_API_KEY")).toBeUndefined();
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
// 2. Missing datasource URL
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
describe("first-run: missing datasource URL", () => {
|
|
211
|
+
it("warns with format examples when ATLAS_DATASOURCE_URL not set", async () => {
|
|
212
|
+
mockDatasourceUrl = null;
|
|
213
|
+
|
|
214
|
+
await validateEnvironment();
|
|
215
|
+
const warnings = getStartupWarnings();
|
|
216
|
+
expect(
|
|
217
|
+
warnings.some((w) =>
|
|
218
|
+
w.includes("ATLAS_DATASOURCE_URL") && w.includes("postgresql://"),
|
|
219
|
+
),
|
|
220
|
+
).toBe(true);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("errors when DATABASE_URL is set but ATLAS_DATASOURCE_URL is not", async () => {
|
|
224
|
+
mockDatasourceUrl = null;
|
|
225
|
+
process.env.DATABASE_URL = "postgresql://atlas:atlas@localhost:5432/atlas";
|
|
226
|
+
|
|
227
|
+
const errors = await validateEnvironment();
|
|
228
|
+
const err = errors.find((e) => e.code === "MISSING_DATASOURCE_URL");
|
|
229
|
+
expect(err).toBeDefined();
|
|
230
|
+
expect(err!.message).toContain("ATLAS_DATASOURCE_URL");
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
// 3. Empty semantic layer
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
|
|
238
|
+
describe("first-run: empty semantic layer", () => {
|
|
239
|
+
it("suggests running atlas init when no entities found", async () => {
|
|
240
|
+
mockSemanticFiles = [];
|
|
241
|
+
|
|
242
|
+
const errors = await validateEnvironment();
|
|
243
|
+
const err = errors.find((e) => e.code === "MISSING_SEMANTIC_LAYER");
|
|
244
|
+
expect(err).toBeDefined();
|
|
245
|
+
expect(err!.message).toContain("atlas");
|
|
246
|
+
expect(err!.message).toContain("init");
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("suggests --demo option for demo data", async () => {
|
|
250
|
+
mockSemanticFiles = [];
|
|
251
|
+
|
|
252
|
+
const errors = await validateEnvironment();
|
|
253
|
+
const err = errors.find((e) => e.code === "MISSING_SEMANTIC_LAYER");
|
|
254
|
+
expect(err).toBeDefined();
|
|
255
|
+
expect(err!.message).toContain("--demo");
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
// 4. Database unreachable — masked URLs
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
|
|
263
|
+
describe("first-run: database unreachable", () => {
|
|
264
|
+
// Note: mock.module("pg") does not intercept require("pg") (native binding).
|
|
265
|
+
// MySQL tests verify the masked URL integration; maskConnectionUrl is unit-tested below.
|
|
266
|
+
|
|
267
|
+
it("shows masked URL in mysql connection error", async () => {
|
|
268
|
+
mockDatasourceUrl = "mysql://admin:p4ssw0rd@mysql.example.com:3306/appdb";
|
|
269
|
+
mockMysqlConnectError = new Error("connect ECONNREFUSED");
|
|
270
|
+
|
|
271
|
+
const errors = await validateEnvironment();
|
|
272
|
+
const err = errors.find((e) => e.code === "DB_UNREACHABLE");
|
|
273
|
+
expect(err).toBeDefined();
|
|
274
|
+
expect(err!.message).toContain("***@mysql.example.com:3306");
|
|
275
|
+
expect(err!.message).not.toContain("p4ssw0rd");
|
|
276
|
+
expect(err!.message).not.toContain("admin:p4ssw0rd");
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("does not leak connection credentials in mysql error messages", async () => {
|
|
280
|
+
mockDatasourceUrl = "mysql://user:MyS3cretPass@host:3306/db";
|
|
281
|
+
mockMysqlConnectError = new Error("timeout expired");
|
|
282
|
+
|
|
283
|
+
const errors = await validateEnvironment();
|
|
284
|
+
const err = errors.find((e) => e.code === "DB_UNREACHABLE");
|
|
285
|
+
expect(err).toBeDefined();
|
|
286
|
+
expect(err!.message).not.toContain("MyS3cretPass");
|
|
287
|
+
expect(err!.message).not.toContain("user:MyS3cretPass");
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("includes ECONNREFUSED hint for mysql", async () => {
|
|
291
|
+
mockDatasourceUrl = "mysql://user:pass@host:3306/db";
|
|
292
|
+
mockMysqlConnectError = new Error("connect ECONNREFUSED 127.0.0.1:3306");
|
|
293
|
+
|
|
294
|
+
const errors = await validateEnvironment();
|
|
295
|
+
const err = errors.find((e) => e.code === "DB_UNREACHABLE");
|
|
296
|
+
expect(err).toBeDefined();
|
|
297
|
+
expect(err!.message).toContain("connection was refused");
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it("reports malformed postgres URL without leaking credentials", async () => {
|
|
301
|
+
mockDatasourceUrl = "not-a-valid-url";
|
|
302
|
+
|
|
303
|
+
const errors = await validateEnvironment();
|
|
304
|
+
const err = errors.find((e) => e.code === "DB_UNREACHABLE");
|
|
305
|
+
expect(err).toBeDefined();
|
|
306
|
+
expect(err!.message).toContain("malformed");
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// ---------------------------------------------------------------------------
|
|
311
|
+
// 4b. maskConnectionUrl — unit tests
|
|
312
|
+
// ---------------------------------------------------------------------------
|
|
313
|
+
|
|
314
|
+
describe("maskConnectionUrl", () => {
|
|
315
|
+
it("masks username and password in postgresql URL", () => {
|
|
316
|
+
expect(maskConnectionUrl("postgresql://user:s3cret@host:5432/db")).toBe(
|
|
317
|
+
"postgresql://***@host:5432/db",
|
|
318
|
+
);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("masks username and password in mysql URL", () => {
|
|
322
|
+
expect(maskConnectionUrl("mysql://admin:p4ss@host:3306/db")).toBe(
|
|
323
|
+
"mysql://***@host:3306/db",
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it("preserves URL without credentials", () => {
|
|
328
|
+
expect(maskConnectionUrl("postgresql://host:5432/db")).toBe(
|
|
329
|
+
"postgresql://host:5432/db",
|
|
330
|
+
);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("masks username-only URLs", () => {
|
|
334
|
+
const result = maskConnectionUrl("postgresql://user@host:5432/db");
|
|
335
|
+
expect(result).toContain("***@host:5432");
|
|
336
|
+
expect(result).not.toContain("user@");
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("returns <invalid-url> for unparseable URLs", () => {
|
|
340
|
+
expect(maskConnectionUrl("not-a-url")).toBe("<invalid-url>");
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it("preserves non-sensitive query parameters", () => {
|
|
344
|
+
const result = maskConnectionUrl("postgresql://user:pass@host:5432/db?sslmode=require");
|
|
345
|
+
expect(result).toContain("sslmode=require");
|
|
346
|
+
expect(result).not.toContain("pass");
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("masks sensitive query parameters", () => {
|
|
350
|
+
const result = maskConnectionUrl("postgresql://user:pass@host:5432/db?password=secret&sslmode=require");
|
|
351
|
+
expect(result).not.toContain("secret");
|
|
352
|
+
expect(result).toContain("password=***");
|
|
353
|
+
expect(result).toContain("sslmode=require");
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// ---------------------------------------------------------------------------
|
|
358
|
+
// 5. Invalid atlas.config.ts
|
|
359
|
+
// ---------------------------------------------------------------------------
|
|
360
|
+
|
|
361
|
+
describe("first-run: invalid atlas.config.ts", () => {
|
|
362
|
+
it("shows Zod validation error with field path", async () => {
|
|
363
|
+
mockConfigResult = null;
|
|
364
|
+
mockConfigLoadError = new Error(
|
|
365
|
+
"Invalid atlas.config.ts:\n - datasources.default.url: Datasource URL must not be empty",
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
const errors = await validateEnvironment();
|
|
369
|
+
const err = errors.find((e) => e.code === "INVALID_CONFIG");
|
|
370
|
+
expect(err).toBeDefined();
|
|
371
|
+
expect(err!.message).toContain("datasources.default.url");
|
|
372
|
+
expect(err!.message).toContain("Datasource URL must not be empty");
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it("no error when config is already loaded", async () => {
|
|
376
|
+
mockConfigResult = { source: "file" };
|
|
377
|
+
mockConfigLoadError = null;
|
|
378
|
+
|
|
379
|
+
const errors = await validateEnvironment();
|
|
380
|
+
expect(errors.find((e) => e.code === "INVALID_CONFIG")).toBeUndefined();
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it("no error when no config file exists (env var fallback)", async () => {
|
|
384
|
+
mockConfigResult = null;
|
|
385
|
+
mockConfigLoadError = null;
|
|
386
|
+
|
|
387
|
+
const errors = await validateEnvironment();
|
|
388
|
+
expect(errors.find((e) => e.code === "INVALID_CONFIG")).toBeUndefined();
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// ---------------------------------------------------------------------------
|
|
393
|
+
// 6. Auth misconfiguration
|
|
394
|
+
// ---------------------------------------------------------------------------
|
|
395
|
+
|
|
396
|
+
describe("first-run: auth misconfiguration", () => {
|
|
397
|
+
it("shows current length and generation hint for weak BETTER_AUTH_SECRET", async () => {
|
|
398
|
+
process.env.BETTER_AUTH_SECRET = "too-short";
|
|
399
|
+
|
|
400
|
+
const errors = await validateEnvironment();
|
|
401
|
+
const err = errors.find((e) => e.code === "WEAK_AUTH_SECRET");
|
|
402
|
+
expect(err).toBeDefined();
|
|
403
|
+
expect(err!.message).toContain("currently 9");
|
|
404
|
+
expect(err!.message).toContain("openssl rand");
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it("shows specific guidance for BYOT mode missing ATLAS_AUTH_ISSUER", async () => {
|
|
408
|
+
process.env.ATLAS_AUTH_JWKS_URL =
|
|
409
|
+
"https://idp.example.com/.well-known/jwks.json";
|
|
410
|
+
delete process.env.ATLAS_AUTH_ISSUER;
|
|
411
|
+
|
|
412
|
+
const errors = await validateEnvironment();
|
|
413
|
+
const err = errors.find((e) => e.code === "MISSING_AUTH_ISSUER");
|
|
414
|
+
expect(err).toBeDefined();
|
|
415
|
+
expect(err!.message).toContain("ATLAS_AUTH_ISSUER");
|
|
416
|
+
expect(err!.message).toContain("issuer URL");
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it("shows guidance when ATLAS_AUTH_MODE is explicit but prereq is missing", async () => {
|
|
420
|
+
process.env.ATLAS_AUTH_MODE = "managed";
|
|
421
|
+
delete process.env.BETTER_AUTH_SECRET;
|
|
422
|
+
|
|
423
|
+
const errors = await validateEnvironment();
|
|
424
|
+
const err = errors.find((e) => e.code === "MISSING_AUTH_PREREQ");
|
|
425
|
+
expect(err).toBeDefined();
|
|
426
|
+
expect(err!.message).toContain("BETTER_AUTH_SECRET");
|
|
427
|
+
expect(err!.message).toContain("32 characters");
|
|
428
|
+
});
|
|
429
|
+
});
|
|
@@ -15,6 +15,11 @@ mock.module("fs", () => ({
|
|
|
15
15
|
// Mock db/connection — avoid real DB imports
|
|
16
16
|
mock.module("@atlas/api/lib/db/connection", () => ({
|
|
17
17
|
detectDBType: () => "postgres",
|
|
18
|
+
resolveDatasourceUrl: () => process.env.ATLAS_DATASOURCE_URL || null,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
mock.module("@atlas/api/lib/providers", () => ({
|
|
22
|
+
getDefaultProvider: () => "anthropic",
|
|
18
23
|
}));
|
|
19
24
|
|
|
20
25
|
// Mock explore-nsjail — controllable sandbox capability check
|
|
@@ -30,9 +30,8 @@ export interface AgentQueryResult {
|
|
|
30
30
|
/**
|
|
31
31
|
* Run the Atlas agent on a single question and return structured results.
|
|
32
32
|
*
|
|
33
|
-
* Creates a UIMessage from the question,
|
|
34
|
-
*
|
|
35
|
-
* answer from tool results.
|
|
33
|
+
* Creates a UIMessage from the question, invokes the agent loop, and
|
|
34
|
+
* extracts SQL queries, data, and the final answer from tool results.
|
|
36
35
|
*/
|
|
37
36
|
export async function executeAgentQuery(
|
|
38
37
|
question: string,
|
|
@@ -57,32 +56,15 @@ export async function executeAgentQuery(
|
|
|
57
56
|
},
|
|
58
57
|
];
|
|
59
58
|
|
|
60
|
-
// Optionally include
|
|
59
|
+
// Optionally include action tools
|
|
61
60
|
let toolRegistry;
|
|
62
61
|
const includeActions = process.env.ATLAS_ACTIONS_ENABLED === "true";
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
const { listSalesforceSources } = await import(
|
|
66
|
-
"@atlas/api/lib/db/salesforce"
|
|
67
|
-
);
|
|
68
|
-
includeSalesforce = listSalesforceSources().length > 0;
|
|
69
|
-
} catch (err: unknown) {
|
|
70
|
-
const code = (err as { code?: string })?.code;
|
|
71
|
-
const isModuleNotFound =
|
|
72
|
-
code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND";
|
|
73
|
-
if (!isModuleNotFound) {
|
|
74
|
-
log.error(
|
|
75
|
-
{ err: err instanceof Error ? err : new Error(String(err)) },
|
|
76
|
-
"Failed to initialize Salesforce tool registry — falling back to default tools",
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (includeSalesforce || includeActions) {
|
|
62
|
+
if (includeActions) {
|
|
81
63
|
try {
|
|
82
64
|
const { buildRegistry } = await import(
|
|
83
65
|
"@atlas/api/lib/tools/registry"
|
|
84
66
|
);
|
|
85
|
-
toolRegistry = await buildRegistry({
|
|
67
|
+
toolRegistry = await buildRegistry({ includeActions });
|
|
86
68
|
} catch (err) {
|
|
87
69
|
log.error(
|
|
88
70
|
{ err: err instanceof Error ? err : new Error(String(err)) },
|