@useatlas/create 0.0.1 → 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 +11 -11
- package/templates/docker/bin/atlas.ts +120 -56
- 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 +4 -41
- 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 +38 -40
- 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 +104 -1
- package/templates/docker/src/lib/plugins/registry.ts +14 -8
- 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-sdk-compat.test.ts +1 -1
- 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 +11 -11
- package/templates/nextjs-standalone/bin/atlas.ts +120 -56
- 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 +4 -41
- 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 +38 -40
- 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 +104 -1
- package/templates/nextjs-standalone/src/lib/plugins/registry.ts +14 -8
- 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-sdk-compat.test.ts +1 -1
- 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,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for plugin-aware SQL validation (#15).
|
|
3
|
+
*
|
|
4
|
+
* Verifies:
|
|
5
|
+
* - ConnectionRegistry stores and returns plugin metadata
|
|
6
|
+
* - parserDatabase() consults plugin metadata before hardcoded switch
|
|
7
|
+
* - getExtraPatterns() (via validateSQL) consults plugin metadata before hardcoded switch
|
|
8
|
+
* - Custom validate() completely bypasses the standard pipeline
|
|
9
|
+
* - wireDatasourcePlugins passes parserDialect + forbiddenPatterns through
|
|
10
|
+
*/
|
|
11
|
+
import { describe, test, expect, beforeEach } from "bun:test";
|
|
12
|
+
import { ConnectionRegistry } from "@atlas/api/lib/db/connection";
|
|
13
|
+
import type { DBConnection, ConnectionPluginMeta } from "@atlas/api/lib/db/connection";
|
|
14
|
+
import { PluginRegistry } from "@atlas/api/lib/plugins/registry";
|
|
15
|
+
import type { PluginLike, PluginContextLike } from "@atlas/api/lib/plugins/registry";
|
|
16
|
+
import { wireDatasourcePlugins } from "@atlas/api/lib/plugins/wiring";
|
|
17
|
+
|
|
18
|
+
// --- Helpers ---
|
|
19
|
+
|
|
20
|
+
function mockConn(): DBConnection {
|
|
21
|
+
return {
|
|
22
|
+
async query() { return { columns: [], rows: [] }; },
|
|
23
|
+
async close() {},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const minimalCtx: PluginContextLike = {
|
|
28
|
+
db: null,
|
|
29
|
+
connections: { get: () => ({}), list: () => [] },
|
|
30
|
+
tools: { register: () => {} },
|
|
31
|
+
logger: {},
|
|
32
|
+
config: {},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// --- ConnectionRegistry plugin metadata ---
|
|
36
|
+
|
|
37
|
+
describe("ConnectionRegistry plugin metadata", () => {
|
|
38
|
+
let registry: ConnectionRegistry;
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
registry = new ConnectionRegistry();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("registerDirect stores and retrieves parserDialect", () => {
|
|
45
|
+
registry.registerDirect("bq", mockConn(), "postgres", "BigQuery", undefined, {
|
|
46
|
+
parserDialect: "BigQuery",
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
expect(registry.getParserDialect("bq")).toBe("BigQuery");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("registerDirect stores and retrieves forbiddenPatterns", () => {
|
|
53
|
+
const patterns = [/\bMERGE\b/i, /\bEXPORT\b/i];
|
|
54
|
+
registry.registerDirect("custom", mockConn(), "postgres", "Custom DB", undefined, {
|
|
55
|
+
forbiddenPatterns: patterns,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expect(registry.getForbiddenPatterns("custom")).toEqual(patterns);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("getParserDialect returns undefined when no meta", () => {
|
|
62
|
+
registry.registerDirect("plain", mockConn(), "postgres");
|
|
63
|
+
expect(registry.getParserDialect("plain")).toBeUndefined();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("getForbiddenPatterns returns empty array when no meta", () => {
|
|
67
|
+
registry.registerDirect("plain", mockConn(), "postgres");
|
|
68
|
+
expect(registry.getForbiddenPatterns("plain")).toEqual([]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("getParserDialect returns undefined for unregistered connection", () => {
|
|
72
|
+
expect(registry.getParserDialect("nonexistent")).toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("getForbiddenPatterns returns empty array for unregistered connection", () => {
|
|
76
|
+
expect(registry.getForbiddenPatterns("nonexistent")).toEqual([]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("registerDirect with both meta fields", () => {
|
|
80
|
+
const meta: ConnectionPluginMeta = {
|
|
81
|
+
parserDialect: "TransactSQL",
|
|
82
|
+
forbiddenPatterns: [/\bEXEC\b/i],
|
|
83
|
+
};
|
|
84
|
+
registry.registerDirect("mssql", mockConn(), "postgres", "SQL Server", undefined, meta);
|
|
85
|
+
|
|
86
|
+
expect(registry.getParserDialect("mssql")).toBe("TransactSQL");
|
|
87
|
+
expect(registry.getForbiddenPatterns("mssql")).toEqual([/\bEXEC\b/i]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("re-registration replaces meta", () => {
|
|
91
|
+
registry.registerDirect("ds", mockConn(), "postgres", undefined, undefined, {
|
|
92
|
+
parserDialect: "MySQL",
|
|
93
|
+
});
|
|
94
|
+
expect(registry.getParserDialect("ds")).toBe("MySQL");
|
|
95
|
+
|
|
96
|
+
registry.registerDirect("ds", mockConn(), "postgres", undefined, undefined, {
|
|
97
|
+
parserDialect: "BigQuery",
|
|
98
|
+
});
|
|
99
|
+
expect(registry.getParserDialect("ds")).toBe("BigQuery");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// --- parserDatabase with plugin metadata ---
|
|
104
|
+
|
|
105
|
+
describe("parserDatabase with plugin metadata", () => {
|
|
106
|
+
// We need to import parserDatabase which uses the global `connections` singleton.
|
|
107
|
+
// To test with our own registry, we'll use validateSQL indirectly via the
|
|
108
|
+
// parserDatabase export. But parserDatabase uses the global connections import.
|
|
109
|
+
// Instead, let's test through validateSQL which is the public API.
|
|
110
|
+
|
|
111
|
+
// Actually, parserDatabase is exported. We need to test that it consults
|
|
112
|
+
// the global connections registry. Let's use the global one.
|
|
113
|
+
|
|
114
|
+
beforeEach(async () => {
|
|
115
|
+
const { connections } = await import("@atlas/api/lib/db/connection");
|
|
116
|
+
connections._reset();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("parserDatabase uses plugin dialect over hardcoded", async () => {
|
|
120
|
+
const { connections } = await import("@atlas/api/lib/db/connection");
|
|
121
|
+
const { parserDatabase } = await import("@atlas/api/lib/tools/sql");
|
|
122
|
+
|
|
123
|
+
connections.registerDirect("bq-conn", mockConn(), "postgres", "BigQuery", undefined, {
|
|
124
|
+
parserDialect: "BigQuery",
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// With connectionId — should use plugin dialect
|
|
128
|
+
expect(parserDatabase("postgres", "bq-conn")).toBe("BigQuery");
|
|
129
|
+
|
|
130
|
+
// Without connectionId — should use hardcoded
|
|
131
|
+
expect(parserDatabase("postgres")).toBe("PostgresQL");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("parserDatabase falls back to hardcoded when no plugin dialect", async () => {
|
|
135
|
+
const { connections } = await import("@atlas/api/lib/db/connection");
|
|
136
|
+
const { parserDatabase } = await import("@atlas/api/lib/tools/sql");
|
|
137
|
+
|
|
138
|
+
connections.registerDirect("plain-pg", mockConn(), "postgres");
|
|
139
|
+
|
|
140
|
+
expect(parserDatabase("postgres", "plain-pg")).toBe("PostgresQL");
|
|
141
|
+
expect(parserDatabase("mysql", "plain-pg")).toBe("MySQL");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("parserDatabase defaults to PostgresQL for unknown dbType", async () => {
|
|
145
|
+
const { parserDatabase } = await import("@atlas/api/lib/tools/sql");
|
|
146
|
+
|
|
147
|
+
// Unknown dbType with no connectionId
|
|
148
|
+
expect(parserDatabase("custom-db" as never)).toBe("PostgresQL");
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// --- validateSQL with plugin-provided forbidden patterns ---
|
|
153
|
+
|
|
154
|
+
describe("validateSQL with plugin forbidden patterns", () => {
|
|
155
|
+
beforeEach(async () => {
|
|
156
|
+
const { connections } = await import("@atlas/api/lib/db/connection");
|
|
157
|
+
connections._reset();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("plugin-provided forbidden patterns block matching queries", async () => {
|
|
161
|
+
const { connections } = await import("@atlas/api/lib/db/connection");
|
|
162
|
+
const { validateSQL } = await import("@atlas/api/lib/tools/sql");
|
|
163
|
+
|
|
164
|
+
connections.registerDirect("strict-ds", mockConn(), "postgres", "Strict DB", undefined, {
|
|
165
|
+
forbiddenPatterns: [/\bUNION\b/i],
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// UNION is not forbidden for regular postgres, but our plugin says it is
|
|
169
|
+
const result = validateSQL("SELECT 1 UNION SELECT 2", "strict-ds");
|
|
170
|
+
expect(result.valid).toBe(false);
|
|
171
|
+
expect(result.error).toContain("UNION");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("plugin patterns do not affect connections without them", async () => {
|
|
175
|
+
const { connections } = await import("@atlas/api/lib/db/connection");
|
|
176
|
+
const { validateSQL } = await import("@atlas/api/lib/tools/sql");
|
|
177
|
+
|
|
178
|
+
// Register one with patterns, one without
|
|
179
|
+
connections.registerDirect("strict", mockConn(), "postgres", undefined, undefined, {
|
|
180
|
+
forbiddenPatterns: [/\bUNION\b/i],
|
|
181
|
+
});
|
|
182
|
+
connections.registerDirect("plain", mockConn(), "postgres");
|
|
183
|
+
|
|
184
|
+
// Blocked on strict
|
|
185
|
+
expect(validateSQL("SELECT 1 UNION SELECT 2", "strict").valid).toBe(false);
|
|
186
|
+
|
|
187
|
+
// Allowed on plain (postgres has no UNION restriction)
|
|
188
|
+
// Note: this requires the semantic layer whitelist to be off
|
|
189
|
+
process.env.ATLAS_TABLE_WHITELIST = "false";
|
|
190
|
+
expect(validateSQL("SELECT 1 UNION SELECT 2", "plain").valid).toBe(true);
|
|
191
|
+
delete process.env.ATLAS_TABLE_WHITELIST;
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// --- wireDatasourcePlugins passes metadata through ---
|
|
196
|
+
|
|
197
|
+
describe("wireDatasourcePlugins metadata passthrough", () => {
|
|
198
|
+
function makeMockConnectionRegistry() {
|
|
199
|
+
return {
|
|
200
|
+
registered: [] as { id: string; conn: unknown; dbType: string; description?: string; validate?: unknown; meta?: unknown }[],
|
|
201
|
+
async registerDirect(id: string, conn: unknown, dbType: string, description?: string, validate?: unknown, meta?: unknown) {
|
|
202
|
+
this.registered.push({ id, conn, dbType, description, validate, meta });
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
test("passes parserDialect and forbiddenPatterns from plugin", async () => {
|
|
208
|
+
const registry = new PluginRegistry();
|
|
209
|
+
const connRegistry = makeMockConnectionRegistry();
|
|
210
|
+
const patterns = [/\bCUSTOM_OP\b/i];
|
|
211
|
+
|
|
212
|
+
const plugin: PluginLike = {
|
|
213
|
+
id: "dialect-ds",
|
|
214
|
+
types: ["datasource"],
|
|
215
|
+
version: "1.0.0",
|
|
216
|
+
connection: {
|
|
217
|
+
create: () => ({ query: async () => ({ columns: [], rows: [] }), close: async () => {} }),
|
|
218
|
+
dbType: "postgres",
|
|
219
|
+
parserDialect: "BigQuery",
|
|
220
|
+
forbiddenPatterns: patterns,
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
registry.register(plugin);
|
|
224
|
+
await registry.initializeAll(minimalCtx);
|
|
225
|
+
|
|
226
|
+
await wireDatasourcePlugins(
|
|
227
|
+
registry,
|
|
228
|
+
connRegistry as unknown as import("@atlas/api/lib/db/connection").ConnectionRegistry,
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
expect(connRegistry.registered).toHaveLength(1);
|
|
232
|
+
expect(connRegistry.registered[0].meta).toEqual({
|
|
233
|
+
parserDialect: "BigQuery",
|
|
234
|
+
forbiddenPatterns: patterns,
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test("passes undefined meta when plugin has no dialect or patterns", async () => {
|
|
239
|
+
const registry = new PluginRegistry();
|
|
240
|
+
const connRegistry = makeMockConnectionRegistry();
|
|
241
|
+
|
|
242
|
+
const plugin: PluginLike = {
|
|
243
|
+
id: "plain-ds",
|
|
244
|
+
types: ["datasource"],
|
|
245
|
+
version: "1.0.0",
|
|
246
|
+
connection: {
|
|
247
|
+
create: () => ({ query: async () => ({ columns: [], rows: [] }), close: async () => {} }),
|
|
248
|
+
dbType: "postgres",
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
registry.register(plugin);
|
|
252
|
+
await registry.initializeAll(minimalCtx);
|
|
253
|
+
|
|
254
|
+
await wireDatasourcePlugins(
|
|
255
|
+
registry,
|
|
256
|
+
connRegistry as unknown as import("@atlas/api/lib/db/connection").ConnectionRegistry,
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
expect(connRegistry.registered).toHaveLength(1);
|
|
260
|
+
expect(connRegistry.registered[0].meta).toBeUndefined();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test("passes meta with only parserDialect", async () => {
|
|
264
|
+
const registry = new PluginRegistry();
|
|
265
|
+
const connRegistry = makeMockConnectionRegistry();
|
|
266
|
+
|
|
267
|
+
const plugin: PluginLike = {
|
|
268
|
+
id: "dialect-only",
|
|
269
|
+
types: ["datasource"],
|
|
270
|
+
version: "1.0.0",
|
|
271
|
+
connection: {
|
|
272
|
+
create: () => ({ query: async () => ({ columns: [], rows: [] }), close: async () => {} }),
|
|
273
|
+
dbType: "postgres",
|
|
274
|
+
parserDialect: "Redshift",
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
registry.register(plugin);
|
|
278
|
+
await registry.initializeAll(minimalCtx);
|
|
279
|
+
|
|
280
|
+
await wireDatasourcePlugins(
|
|
281
|
+
registry,
|
|
282
|
+
connRegistry as unknown as import("@atlas/api/lib/db/connection").ConnectionRegistry,
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
expect(connRegistry.registered).toHaveLength(1);
|
|
286
|
+
expect(connRegistry.registered[0].meta).toEqual({
|
|
287
|
+
parserDialect: "Redshift",
|
|
288
|
+
forbiddenPatterns: undefined,
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test("passes meta with only forbiddenPatterns", async () => {
|
|
293
|
+
const registry = new PluginRegistry();
|
|
294
|
+
const connRegistry = makeMockConnectionRegistry();
|
|
295
|
+
const patterns = [/\bDELETE\b/i];
|
|
296
|
+
|
|
297
|
+
const plugin: PluginLike = {
|
|
298
|
+
id: "patterns-only",
|
|
299
|
+
types: ["datasource"],
|
|
300
|
+
version: "1.0.0",
|
|
301
|
+
connection: {
|
|
302
|
+
create: () => ({ query: async () => ({ columns: [], rows: [] }), close: async () => {} }),
|
|
303
|
+
dbType: "postgres",
|
|
304
|
+
forbiddenPatterns: patterns,
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
registry.register(plugin);
|
|
308
|
+
await registry.initializeAll(minimalCtx);
|
|
309
|
+
|
|
310
|
+
await wireDatasourcePlugins(
|
|
311
|
+
registry,
|
|
312
|
+
connRegistry as unknown as import("@atlas/api/lib/db/connection").ConnectionRegistry,
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
expect(connRegistry.registered).toHaveLength(1);
|
|
316
|
+
expect(connRegistry.registered[0].meta).toEqual({
|
|
317
|
+
parserDialect: undefined,
|
|
318
|
+
forbiddenPatterns: patterns,
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
});
|
|
@@ -2,7 +2,7 @@ import { describe, expect, test, afterEach } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
// Import after mocks — getProviderType reads process.env at call time, so no
|
|
4
4
|
// module-level mocking is needed.
|
|
5
|
-
const { getProviderType } = await import("@atlas/api/lib/providers");
|
|
5
|
+
const { getProviderType, getDefaultProvider } = await import("@atlas/api/lib/providers");
|
|
6
6
|
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
8
8
|
// Env snapshot — capture/restore only the vars this test touches
|
|
@@ -10,6 +10,7 @@ const { getProviderType } = await import("@atlas/api/lib/providers");
|
|
|
10
10
|
|
|
11
11
|
const origProvider = process.env.ATLAS_PROVIDER;
|
|
12
12
|
const origModel = process.env.ATLAS_MODEL;
|
|
13
|
+
const origVercel = process.env.VERCEL;
|
|
13
14
|
|
|
14
15
|
afterEach(() => {
|
|
15
16
|
if (origProvider !== undefined) process.env.ATLAS_PROVIDER = origProvider;
|
|
@@ -17,6 +18,9 @@ afterEach(() => {
|
|
|
17
18
|
|
|
18
19
|
if (origModel !== undefined) process.env.ATLAS_MODEL = origModel;
|
|
19
20
|
else delete process.env.ATLAS_MODEL;
|
|
21
|
+
|
|
22
|
+
if (origVercel !== undefined) process.env.VERCEL = origVercel;
|
|
23
|
+
else delete process.env.VERCEL;
|
|
20
24
|
});
|
|
21
25
|
|
|
22
26
|
// ---------------------------------------------------------------------------
|
|
@@ -90,6 +94,21 @@ describe("getProviderType", () => {
|
|
|
90
94
|
expect(getProviderType()).toBe("bedrock");
|
|
91
95
|
});
|
|
92
96
|
|
|
97
|
+
// --- Vercel auto-detection ------------------------------------------------
|
|
98
|
+
|
|
99
|
+
test("defaults to 'gateway' when VERCEL env var is set and no ATLAS_PROVIDER", () => {
|
|
100
|
+
delete process.env.ATLAS_PROVIDER;
|
|
101
|
+
delete process.env.ATLAS_MODEL;
|
|
102
|
+
process.env.VERCEL = "1";
|
|
103
|
+
expect(getProviderType()).toBe("gateway");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("explicit ATLAS_PROVIDER overrides Vercel default", () => {
|
|
107
|
+
process.env.ATLAS_PROVIDER = "anthropic";
|
|
108
|
+
process.env.VERCEL = "1";
|
|
109
|
+
expect(getProviderType()).toBe("anthropic");
|
|
110
|
+
});
|
|
111
|
+
|
|
93
112
|
// --- Invalid provider ----------------------------------------------------
|
|
94
113
|
|
|
95
114
|
test("throws for an invalid provider string", () => {
|
|
@@ -97,3 +116,15 @@ describe("getProviderType", () => {
|
|
|
97
116
|
expect(() => getProviderType()).toThrow(Error);
|
|
98
117
|
});
|
|
99
118
|
});
|
|
119
|
+
|
|
120
|
+
describe("getDefaultProvider", () => {
|
|
121
|
+
test("returns 'anthropic' when VERCEL is not set", () => {
|
|
122
|
+
delete process.env.VERCEL;
|
|
123
|
+
expect(getDefaultProvider()).toBe("anthropic");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("returns 'gateway' when VERCEL is set", () => {
|
|
127
|
+
process.env.VERCEL = "1";
|
|
128
|
+
expect(getDefaultProvider()).toBe("gateway");
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -13,6 +13,11 @@ mock.module("fs", () => ({
|
|
|
13
13
|
|
|
14
14
|
mock.module("@atlas/api/lib/db/connection", () => ({
|
|
15
15
|
detectDBType: () => "postgres",
|
|
16
|
+
resolveDatasourceUrl: () => process.env.ATLAS_DATASOURCE_URL || null,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
mock.module("@atlas/api/lib/providers", () => ({
|
|
20
|
+
getDefaultProvider: () => "anthropic",
|
|
16
21
|
}));
|
|
17
22
|
|
|
18
23
|
mock.module("@atlas/api/lib/tools/explore-nsjail", () => ({
|
|
@@ -50,6 +55,10 @@ let mockConfig: Record<string, unknown> | null = null;
|
|
|
50
55
|
|
|
51
56
|
mock.module("@atlas/api/lib/config", () => ({
|
|
52
57
|
getConfig: () => mockConfig,
|
|
58
|
+
loadConfig: async () => {
|
|
59
|
+
mockConfig = { source: "env" };
|
|
60
|
+
return mockConfig;
|
|
61
|
+
},
|
|
53
62
|
}));
|
|
54
63
|
|
|
55
64
|
const { validateEnvironment, getStartupWarnings, resetStartupCache } =
|