@useatlas/create 0.0.2 → 0.0.4
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
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Salesforce SOQL query tool for the Atlas agent.
|
|
3
|
-
*
|
|
4
|
-
* Parallel to executeSQL but for Salesforce objects via SOQL.
|
|
5
|
-
* Uses the SalesforceDataSource instead of DBConnection.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { tool } from "ai";
|
|
9
|
-
import { z } from "zod";
|
|
10
|
-
import {
|
|
11
|
-
getSalesforceSource,
|
|
12
|
-
listSalesforceSources,
|
|
13
|
-
} from "@atlas/api/lib/db/salesforce";
|
|
14
|
-
import { validateSOQL, appendSOQLLimit } from "./soql-validation";
|
|
15
|
-
import { getWhitelistedTables } from "@atlas/api/lib/semantic";
|
|
16
|
-
import { logQueryAudit } from "@atlas/api/lib/auth/audit";
|
|
17
|
-
import { SENSITIVE_PATTERNS } from "@atlas/api/lib/security";
|
|
18
|
-
import { createLogger } from "@atlas/api/lib/logger";
|
|
19
|
-
|
|
20
|
-
const log = createLogger("salesforce-tool");
|
|
21
|
-
|
|
22
|
-
const ROW_LIMIT = parseInt(process.env.ATLAS_ROW_LIMIT ?? "1000", 10);
|
|
23
|
-
const QUERY_TIMEOUT = parseInt(
|
|
24
|
-
process.env.ATLAS_QUERY_TIMEOUT ?? "30000",
|
|
25
|
-
10,
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
export const querySalesforce = tool({
|
|
29
|
-
description: `Execute a read-only SOQL query against Salesforce. Only SELECT queries are allowed.
|
|
30
|
-
|
|
31
|
-
Rules:
|
|
32
|
-
- Always read the relevant entity schema from the semantic layer BEFORE writing SOQL
|
|
33
|
-
- Use exact field names from the schema — never guess
|
|
34
|
-
- SOQL does not support JOINs — use relationship queries instead (e.g. Account.Name)
|
|
35
|
-
- Include a LIMIT clause for large result sets
|
|
36
|
-
- If a query fails, fix the issue — do not retry the same SOQL`,
|
|
37
|
-
|
|
38
|
-
inputSchema: z.object({
|
|
39
|
-
soql: z.string().describe("The SELECT SOQL query to execute"),
|
|
40
|
-
explanation: z
|
|
41
|
-
.string()
|
|
42
|
-
.describe("Brief explanation of what this query does and why"),
|
|
43
|
-
connectionId: z
|
|
44
|
-
.string()
|
|
45
|
-
.optional()
|
|
46
|
-
.describe(
|
|
47
|
-
"Target Salesforce connection ID. Omit for the default Salesforce connection.",
|
|
48
|
-
),
|
|
49
|
-
}),
|
|
50
|
-
|
|
51
|
-
execute: async ({ soql, explanation, connectionId }) => {
|
|
52
|
-
// Resolve which Salesforce source to use
|
|
53
|
-
const sources = listSalesforceSources();
|
|
54
|
-
const connId = connectionId ?? (sources.length > 0 ? sources[0] : "default");
|
|
55
|
-
|
|
56
|
-
let source;
|
|
57
|
-
try {
|
|
58
|
-
source = getSalesforceSource(connId);
|
|
59
|
-
} catch {
|
|
60
|
-
return {
|
|
61
|
-
success: false,
|
|
62
|
-
error: `Salesforce source "${connId}" is not registered. Available: ${sources.join(", ") || "(none)"}`,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Get whitelist for this connection
|
|
67
|
-
const allowed = getWhitelistedTables(connId);
|
|
68
|
-
|
|
69
|
-
// Validate SOQL
|
|
70
|
-
const validation = validateSOQL(soql, allowed);
|
|
71
|
-
if (!validation.valid) {
|
|
72
|
-
logQueryAudit({
|
|
73
|
-
sql: soql.slice(0, 2000),
|
|
74
|
-
durationMs: 0,
|
|
75
|
-
rowCount: null,
|
|
76
|
-
success: false,
|
|
77
|
-
error: `Validation rejected: ${validation.error}`,
|
|
78
|
-
});
|
|
79
|
-
return { success: false, error: validation.error };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Auto-append LIMIT
|
|
83
|
-
const querySoql = appendSOQLLimit(soql.trim(), ROW_LIMIT);
|
|
84
|
-
|
|
85
|
-
const start = performance.now();
|
|
86
|
-
try {
|
|
87
|
-
const result = await source.query(querySoql, QUERY_TIMEOUT);
|
|
88
|
-
const durationMs = Math.round(performance.now() - start);
|
|
89
|
-
const truncated = result.rows.length >= ROW_LIMIT;
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
logQueryAudit({
|
|
93
|
-
sql: querySoql,
|
|
94
|
-
durationMs,
|
|
95
|
-
rowCount: result.rows.length,
|
|
96
|
-
success: true,
|
|
97
|
-
});
|
|
98
|
-
} catch (auditErr) {
|
|
99
|
-
log.warn({ err: auditErr }, "Failed to write query audit log");
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
success: true,
|
|
104
|
-
explanation,
|
|
105
|
-
row_count: result.rows.length,
|
|
106
|
-
columns: result.columns,
|
|
107
|
-
rows: result.rows,
|
|
108
|
-
truncated,
|
|
109
|
-
};
|
|
110
|
-
} catch (err) {
|
|
111
|
-
const durationMs = Math.round(performance.now() - start);
|
|
112
|
-
const message =
|
|
113
|
-
err instanceof Error ? err.message : "Unknown Salesforce error";
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
logQueryAudit({
|
|
117
|
-
sql: querySoql,
|
|
118
|
-
durationMs,
|
|
119
|
-
rowCount: null,
|
|
120
|
-
success: false,
|
|
121
|
-
error: message,
|
|
122
|
-
});
|
|
123
|
-
} catch (auditErr) {
|
|
124
|
-
log.warn({ err: auditErr }, "Failed to write query audit log");
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Block errors that might expose connection details or internal state
|
|
128
|
-
if (SENSITIVE_PATTERNS.test(message)) {
|
|
129
|
-
return {
|
|
130
|
-
success: false,
|
|
131
|
-
error: "Salesforce query failed — check server logs for details.",
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return { success: false, error: message };
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
});
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SOQL validation — regex + structural checks.
|
|
3
|
-
*
|
|
4
|
-
* SOQL is simpler than SQL, so no AST parser is needed. Validation layers:
|
|
5
|
-
* 0. Empty check
|
|
6
|
-
* 1. Regex mutation guard (INSERT, UPDATE, DELETE, UPSERT, MERGE, UNDELETE)
|
|
7
|
-
* 2. Must start with SELECT, no semicolons
|
|
8
|
-
* 3. Object whitelist — FROM object must be in the allowed set
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const SOQL_FORBIDDEN_PATTERNS = [
|
|
12
|
-
/\b(INSERT)\b/i,
|
|
13
|
-
/\b(UPDATE)\b/i,
|
|
14
|
-
/\b(DELETE)\b/i,
|
|
15
|
-
/\b(UPSERT)\b/i,
|
|
16
|
-
/\b(MERGE)\b/i,
|
|
17
|
-
/\b(UNDELETE)\b/i,
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Strip single-quoted string literals from SOQL so regex guards don't match
|
|
22
|
-
* keywords embedded in user values (e.g. `WHERE Name = 'delete this'`).
|
|
23
|
-
*/
|
|
24
|
-
function stripStringLiterals(soql: string): string {
|
|
25
|
-
return soql.replace(/'[^']*'/g, "''");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Extract top-level object names referenced in FROM clauses.
|
|
30
|
-
*
|
|
31
|
-
* Parent-to-child relationship subqueries — `(SELECT ... FROM Contacts)` inside
|
|
32
|
-
* the SELECT list — use relationship names (plural) that don't appear in the
|
|
33
|
-
* object whitelist. Salesforce enforces object-level security server-side for
|
|
34
|
-
* these, so we skip nested FROM inside parenthesized subqueries.
|
|
35
|
-
*
|
|
36
|
-
* Semi-join / anti-join subqueries in WHERE — `WHERE Id IN (SELECT ... FROM Contact)`
|
|
37
|
-
* — reference real object names and ARE checked.
|
|
38
|
-
*/
|
|
39
|
-
function extractFromObjects(soql: string): string[] {
|
|
40
|
-
const objects: string[] = [];
|
|
41
|
-
|
|
42
|
-
// Step 1: Remove parenthesized subqueries that appear in the SELECT clause
|
|
43
|
-
// (relationship subqueries). We do this by stripping content between the
|
|
44
|
-
// top-level SELECT and the top-level FROM, then extracting FROM objects from
|
|
45
|
-
// the remainder.
|
|
46
|
-
//
|
|
47
|
-
// Strategy: find the top-level FROM position (not inside parens), then only
|
|
48
|
-
// extract FROM objects from that point onward.
|
|
49
|
-
|
|
50
|
-
let depth = 0;
|
|
51
|
-
let topLevelFromIndex = -1;
|
|
52
|
-
|
|
53
|
-
// We need to find the top-level FROM keyword (not inside parentheses)
|
|
54
|
-
const upperSoql = soql.toUpperCase();
|
|
55
|
-
for (let i = 0; i < soql.length; i++) {
|
|
56
|
-
if (soql[i] === "(") {
|
|
57
|
-
depth++;
|
|
58
|
-
} else if (soql[i] === ")") {
|
|
59
|
-
depth--;
|
|
60
|
-
} else if (depth === 0) {
|
|
61
|
-
// Check if this position starts "FROM " at the top level
|
|
62
|
-
if (
|
|
63
|
-
upperSoql.startsWith("FROM", i) &&
|
|
64
|
-
(i === 0 || /\s/.test(soql[i - 1])) &&
|
|
65
|
-
i + 4 < soql.length &&
|
|
66
|
-
/\s/.test(soql[i + 4])
|
|
67
|
-
) {
|
|
68
|
-
topLevelFromIndex = i;
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (topLevelFromIndex === -1) {
|
|
75
|
-
return objects;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Extract the top-level FROM object
|
|
79
|
-
const afterFrom = soql.slice(topLevelFromIndex);
|
|
80
|
-
const topMatch = /\bFROM\s+(\w+)/i.exec(afterFrom);
|
|
81
|
-
if (topMatch) {
|
|
82
|
-
objects.push(topMatch[1]);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Now extract FROM objects in WHERE/HAVING subqueries (semi-joins/anti-joins).
|
|
86
|
-
// These are parenthesized SELECT...FROM blocks that appear AFTER the top-level FROM.
|
|
87
|
-
const whereClause = soql.slice(topLevelFromIndex + (topMatch ? topMatch[0].length : 4));
|
|
88
|
-
// Find FROM inside parenthesized subqueries in WHERE — these are real object references
|
|
89
|
-
const subqueryPattern = /\(\s*SELECT\b[^)]*\bFROM\s+(\w+)/gi;
|
|
90
|
-
let subMatch;
|
|
91
|
-
while ((subMatch = subqueryPattern.exec(whereClause)) !== null) {
|
|
92
|
-
objects.push(subMatch[1]);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return objects;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Validate a SOQL query for safety.
|
|
100
|
-
*
|
|
101
|
-
* @param soql - The SOQL query string.
|
|
102
|
-
* @param allowedObjects - Set of allowed Salesforce object names (case-insensitive).
|
|
103
|
-
* @returns Validation result.
|
|
104
|
-
*/
|
|
105
|
-
export function validateSOQL(
|
|
106
|
-
soql: string,
|
|
107
|
-
allowedObjects: Set<string>,
|
|
108
|
-
): { valid: boolean; error?: string } {
|
|
109
|
-
// 0. Empty check
|
|
110
|
-
const trimmed = soql.trim();
|
|
111
|
-
if (!trimmed) {
|
|
112
|
-
return { valid: false, error: "Empty query" };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Reject semicolons (no statement chaining)
|
|
116
|
-
if (trimmed.includes(";")) {
|
|
117
|
-
return { valid: false, error: "Semicolons are not allowed in SOQL queries" };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// 1. Regex mutation guard — strip string literals first so keywords inside
|
|
121
|
-
// values like `WHERE Name = 'delete this'` don't trigger false positives.
|
|
122
|
-
const stripped = stripStringLiterals(trimmed);
|
|
123
|
-
for (const pattern of SOQL_FORBIDDEN_PATTERNS) {
|
|
124
|
-
if (pattern.test(stripped)) {
|
|
125
|
-
return {
|
|
126
|
-
valid: false,
|
|
127
|
-
error: `Forbidden SOQL operation detected: ${pattern.source}`,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// 2. Must start with SELECT
|
|
133
|
-
if (!/^\s*SELECT\b/i.test(trimmed)) {
|
|
134
|
-
return {
|
|
135
|
-
valid: false,
|
|
136
|
-
error: "Only SELECT queries are allowed in SOQL",
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// 3. Object whitelist
|
|
141
|
-
const objects = extractFromObjects(trimmed);
|
|
142
|
-
if (objects.length === 0) {
|
|
143
|
-
return { valid: false, error: "No FROM clause found in query" };
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Build lowercase allowed set for case-insensitive comparison
|
|
147
|
-
const allowedLower = new Set(
|
|
148
|
-
Array.from(allowedObjects).map((o) => o.toLowerCase()),
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
for (const obj of objects) {
|
|
152
|
-
if (!allowedLower.has(obj.toLowerCase())) {
|
|
153
|
-
return {
|
|
154
|
-
valid: false,
|
|
155
|
-
error: `Object "${obj}" is not in the allowed list. Check catalog.yml for available objects.`,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return { valid: true };
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Append a LIMIT clause to a SOQL query if one is not already present.
|
|
165
|
-
*/
|
|
166
|
-
export function appendSOQLLimit(soql: string, limit: number): string {
|
|
167
|
-
const trimmed = soql.trim();
|
|
168
|
-
if (/\bLIMIT\b/i.test(trimmed)) {
|
|
169
|
-
return trimmed;
|
|
170
|
-
}
|
|
171
|
-
return `${trimmed} LIMIT ${limit}`;
|
|
172
|
-
}
|