@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,6 +1,8 @@
|
|
|
1
1
|
import { describe, test, expect } from "bun:test";
|
|
2
2
|
import {
|
|
3
3
|
generateMigrationSQL,
|
|
4
|
+
generateColumnMigrations,
|
|
5
|
+
runPluginMigrations,
|
|
4
6
|
applyMigrations,
|
|
5
7
|
ensureMigrationsTable,
|
|
6
8
|
getAppliedMigrations,
|
|
@@ -22,11 +24,14 @@ interface QueryLog {
|
|
|
22
24
|
function makeMockDB(opts?: {
|
|
23
25
|
existingMigrations?: Array<{ plugin_id: string; table_name: string; sql_hash: string }>;
|
|
24
26
|
existingTables?: string[];
|
|
27
|
+
/** Map of table name → existing column names (for information_schema.columns queries) */
|
|
28
|
+
existingColumns?: Record<string, string[]>;
|
|
25
29
|
failOnCreate?: boolean;
|
|
26
30
|
}): MigrateDB & { queries: QueryLog[] } {
|
|
27
31
|
const queries: QueryLog[] = [];
|
|
28
|
-
const existingMigrations = opts?.existingMigrations ?? [];
|
|
32
|
+
const existingMigrations = [...(opts?.existingMigrations ?? [])];
|
|
29
33
|
const existingTables = opts?.existingTables ?? [];
|
|
34
|
+
const existingColumns = opts?.existingColumns ?? {};
|
|
30
35
|
|
|
31
36
|
return {
|
|
32
37
|
queries,
|
|
@@ -39,9 +44,23 @@ function makeMockDB(opts?: {
|
|
|
39
44
|
if (sql.includes("FROM plugin_migrations")) {
|
|
40
45
|
return { rows: existingMigrations };
|
|
41
46
|
}
|
|
47
|
+
// Track migrations inserted via applyMigrations
|
|
48
|
+
if (sql.includes("INSERT INTO plugin_migrations") && params) {
|
|
49
|
+
existingMigrations.push({
|
|
50
|
+
plugin_id: String(params[0]),
|
|
51
|
+
table_name: String(params[1]),
|
|
52
|
+
sql_hash: String(params[2]),
|
|
53
|
+
});
|
|
54
|
+
return { rows: [] };
|
|
55
|
+
}
|
|
42
56
|
if (sql.includes("FROM pg_tables")) {
|
|
43
57
|
return { rows: existingTables.map((t) => ({ tablename: t })) };
|
|
44
58
|
}
|
|
59
|
+
if (sql.includes("information_schema.columns") && params?.[0]) {
|
|
60
|
+
const tableName = String(params[0]);
|
|
61
|
+
const cols = existingColumns[tableName] ?? [];
|
|
62
|
+
return { rows: cols.map((c) => ({ column_name: c })) };
|
|
63
|
+
}
|
|
45
64
|
return { rows: [] };
|
|
46
65
|
},
|
|
47
66
|
};
|
|
@@ -519,3 +538,338 @@ describe("diffSchema", () => {
|
|
|
519
538
|
expect(diff.existingTables).toHaveLength(0);
|
|
520
539
|
});
|
|
521
540
|
});
|
|
541
|
+
|
|
542
|
+
// ---------------------------------------------------------------------------
|
|
543
|
+
// generateColumnMigrations
|
|
544
|
+
// ---------------------------------------------------------------------------
|
|
545
|
+
|
|
546
|
+
describe("generateColumnMigrations", () => {
|
|
547
|
+
test("generates ALTER TABLE for missing columns", async () => {
|
|
548
|
+
const db = makeMockDB({
|
|
549
|
+
existingColumns: {
|
|
550
|
+
plugin_test_items: ["id", "name", "created_at", "updated_at"],
|
|
551
|
+
},
|
|
552
|
+
});
|
|
553
|
+
const plugins = [
|
|
554
|
+
makePlugin("test", {
|
|
555
|
+
items: {
|
|
556
|
+
fields: {
|
|
557
|
+
name: { type: "string", required: true },
|
|
558
|
+
priority: { type: "number" },
|
|
559
|
+
active: { type: "boolean" },
|
|
560
|
+
},
|
|
561
|
+
},
|
|
562
|
+
}),
|
|
563
|
+
];
|
|
564
|
+
|
|
565
|
+
const stmts = await generateColumnMigrations(
|
|
566
|
+
db,
|
|
567
|
+
plugins as Parameters<typeof generateColumnMigrations>[1],
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
// name already exists, priority and active are new
|
|
571
|
+
expect(stmts).toHaveLength(2);
|
|
572
|
+
expect(stmts[0].sql).toContain('ALTER TABLE "plugin_test_items"');
|
|
573
|
+
expect(stmts[0].sql).toContain('"priority" INTEGER');
|
|
574
|
+
expect(stmts[1].sql).toContain('"active" BOOLEAN');
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
test("skips tables that don't exist yet", async () => {
|
|
578
|
+
const db = makeMockDB({
|
|
579
|
+
existingColumns: {}, // no tables in DB
|
|
580
|
+
});
|
|
581
|
+
const plugins = [
|
|
582
|
+
makePlugin("test", {
|
|
583
|
+
items: { fields: { name: { type: "string" } } },
|
|
584
|
+
}),
|
|
585
|
+
];
|
|
586
|
+
|
|
587
|
+
const stmts = await generateColumnMigrations(
|
|
588
|
+
db,
|
|
589
|
+
plugins as Parameters<typeof generateColumnMigrations>[1],
|
|
590
|
+
);
|
|
591
|
+
expect(stmts).toHaveLength(0);
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
test("returns empty when all columns already exist", async () => {
|
|
595
|
+
const db = makeMockDB({
|
|
596
|
+
existingColumns: {
|
|
597
|
+
plugin_test_items: ["id", "name", "count", "created_at", "updated_at"],
|
|
598
|
+
},
|
|
599
|
+
});
|
|
600
|
+
const plugins = [
|
|
601
|
+
makePlugin("test", {
|
|
602
|
+
items: {
|
|
603
|
+
fields: {
|
|
604
|
+
name: { type: "string" },
|
|
605
|
+
count: { type: "number" },
|
|
606
|
+
},
|
|
607
|
+
},
|
|
608
|
+
}),
|
|
609
|
+
];
|
|
610
|
+
|
|
611
|
+
const stmts = await generateColumnMigrations(
|
|
612
|
+
db,
|
|
613
|
+
plugins as Parameters<typeof generateColumnMigrations>[1],
|
|
614
|
+
);
|
|
615
|
+
expect(stmts).toHaveLength(0);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
test("handles case-insensitive column matching", async () => {
|
|
619
|
+
const db = makeMockDB({
|
|
620
|
+
existingColumns: {
|
|
621
|
+
plugin_test_items: ["id", "MyColumn", "created_at", "updated_at"],
|
|
622
|
+
},
|
|
623
|
+
});
|
|
624
|
+
const plugins = [
|
|
625
|
+
makePlugin("test", {
|
|
626
|
+
items: {
|
|
627
|
+
fields: {
|
|
628
|
+
mycolumn: { type: "string" },
|
|
629
|
+
},
|
|
630
|
+
},
|
|
631
|
+
}),
|
|
632
|
+
];
|
|
633
|
+
|
|
634
|
+
const stmts = await generateColumnMigrations(
|
|
635
|
+
db,
|
|
636
|
+
plugins as Parameters<typeof generateColumnMigrations>[1],
|
|
637
|
+
);
|
|
638
|
+
// MyColumn matches mycolumn (case-insensitive)
|
|
639
|
+
expect(stmts).toHaveLength(0);
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
test("skips plugins without schema", async () => {
|
|
643
|
+
const db = makeMockDB();
|
|
644
|
+
const plugins = [{ id: "no-schema" }];
|
|
645
|
+
|
|
646
|
+
const stmts = await generateColumnMigrations(
|
|
647
|
+
db,
|
|
648
|
+
plugins as Parameters<typeof generateColumnMigrations>[1],
|
|
649
|
+
);
|
|
650
|
+
expect(stmts).toHaveLength(0);
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
test("generates columns with constraints", async () => {
|
|
654
|
+
const db = makeMockDB({
|
|
655
|
+
existingColumns: {
|
|
656
|
+
plugin_test_items: ["id", "created_at", "updated_at"],
|
|
657
|
+
},
|
|
658
|
+
});
|
|
659
|
+
const plugins = [
|
|
660
|
+
makePlugin("test", {
|
|
661
|
+
items: {
|
|
662
|
+
fields: {
|
|
663
|
+
email: { type: "string", required: true, unique: true },
|
|
664
|
+
priority: { type: "number", defaultValue: 0 },
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
}),
|
|
668
|
+
];
|
|
669
|
+
|
|
670
|
+
const stmts = await generateColumnMigrations(
|
|
671
|
+
db,
|
|
672
|
+
plugins as Parameters<typeof generateColumnMigrations>[1],
|
|
673
|
+
);
|
|
674
|
+
expect(stmts).toHaveLength(2);
|
|
675
|
+
expect(stmts[0].sql).toContain('"email" TEXT NOT NULL UNIQUE');
|
|
676
|
+
expect(stmts[1].sql).toContain('"priority" INTEGER DEFAULT 0');
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
test("generates deterministic hashes for ALTER statements", async () => {
|
|
680
|
+
const db = makeMockDB({
|
|
681
|
+
existingColumns: {
|
|
682
|
+
plugin_test_items: ["id", "created_at", "updated_at"],
|
|
683
|
+
},
|
|
684
|
+
});
|
|
685
|
+
const plugins = [
|
|
686
|
+
makePlugin("test", {
|
|
687
|
+
items: { fields: { name: { type: "string" } } },
|
|
688
|
+
}),
|
|
689
|
+
];
|
|
690
|
+
|
|
691
|
+
const stmts1 = await generateColumnMigrations(
|
|
692
|
+
db,
|
|
693
|
+
plugins as Parameters<typeof generateColumnMigrations>[1],
|
|
694
|
+
);
|
|
695
|
+
const stmts2 = await generateColumnMigrations(
|
|
696
|
+
db,
|
|
697
|
+
plugins as Parameters<typeof generateColumnMigrations>[1],
|
|
698
|
+
);
|
|
699
|
+
expect(stmts1[0].hash).toBe(stmts2[0].hash);
|
|
700
|
+
});
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// ---------------------------------------------------------------------------
|
|
704
|
+
// runPluginMigrations
|
|
705
|
+
// ---------------------------------------------------------------------------
|
|
706
|
+
|
|
707
|
+
describe("runPluginMigrations", () => {
|
|
708
|
+
test("runs CREATE TABLE and ALTER TABLE in sequence", async () => {
|
|
709
|
+
const db = makeMockDB({
|
|
710
|
+
// Simulate a table that was just created with only auto-columns —
|
|
711
|
+
// Phase 2 detects the missing user-declared column
|
|
712
|
+
existingColumns: {
|
|
713
|
+
plugin_test_items: ["id", "created_at", "updated_at"],
|
|
714
|
+
},
|
|
715
|
+
});
|
|
716
|
+
const plugins = [
|
|
717
|
+
makePlugin("test", {
|
|
718
|
+
items: {
|
|
719
|
+
fields: {
|
|
720
|
+
name: { type: "string" },
|
|
721
|
+
},
|
|
722
|
+
},
|
|
723
|
+
}),
|
|
724
|
+
];
|
|
725
|
+
|
|
726
|
+
const result = await runPluginMigrations(
|
|
727
|
+
db,
|
|
728
|
+
plugins as Parameters<typeof runPluginMigrations>[1],
|
|
729
|
+
);
|
|
730
|
+
|
|
731
|
+
// Phase 1: CREATE TABLE (1 table) + Phase 2: ALTER TABLE ADD COLUMN (1 column)
|
|
732
|
+
expect(result.applied).toEqual(["plugin_test_items", "plugin_test_items"]);
|
|
733
|
+
// Should have both CREATE TABLE and ALTER TABLE queries
|
|
734
|
+
const createQuery = db.queries.find((q) =>
|
|
735
|
+
q.sql.includes("CREATE TABLE") && q.sql.includes("plugin_test_items"),
|
|
736
|
+
);
|
|
737
|
+
expect(createQuery).toBeDefined();
|
|
738
|
+
const alterQuery = db.queries.find((q) =>
|
|
739
|
+
q.sql.includes("ALTER TABLE") && q.sql.includes('"name"'),
|
|
740
|
+
);
|
|
741
|
+
expect(alterQuery).toBeDefined();
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
test("merges results from both phases correctly", async () => {
|
|
745
|
+
const db = makeMockDB({
|
|
746
|
+
existingColumns: {
|
|
747
|
+
plugin_a_items: ["id", "x", "created_at", "updated_at"],
|
|
748
|
+
// plugin_b_things doesn't exist — no columns, Phase 2 skips it
|
|
749
|
+
},
|
|
750
|
+
});
|
|
751
|
+
const plugins = [
|
|
752
|
+
makePlugin("a", { items: { fields: { x: { type: "string" }, y: { type: "number" } } } }),
|
|
753
|
+
makePlugin("b", { things: { fields: { z: { type: "boolean" } } } }),
|
|
754
|
+
];
|
|
755
|
+
|
|
756
|
+
const result = await runPluginMigrations(
|
|
757
|
+
db,
|
|
758
|
+
plugins as Parameters<typeof runPluginMigrations>[1],
|
|
759
|
+
);
|
|
760
|
+
|
|
761
|
+
// Phase 1: 2 CREATE TABLE statements applied
|
|
762
|
+
// Phase 2: 1 ALTER TABLE for plugin_a_items.y (x already exists, plugin_b skipped)
|
|
763
|
+
expect(result.applied).toEqual([
|
|
764
|
+
"plugin_a_items", "plugin_b_things", "plugin_a_items",
|
|
765
|
+
]);
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
test("handles plugins with no schema", async () => {
|
|
769
|
+
const db = makeMockDB();
|
|
770
|
+
const plugins = [{ id: "no-schema" }];
|
|
771
|
+
|
|
772
|
+
const result = await runPluginMigrations(
|
|
773
|
+
db,
|
|
774
|
+
plugins as Parameters<typeof runPluginMigrations>[1],
|
|
775
|
+
);
|
|
776
|
+
expect(result.applied).toEqual([]);
|
|
777
|
+
expect(result.skipped).toEqual([]);
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
test("skips column migrations when no new columns needed", async () => {
|
|
781
|
+
const db = makeMockDB({
|
|
782
|
+
existingColumns: {
|
|
783
|
+
plugin_test_items: ["id", "name", "created_at", "updated_at"],
|
|
784
|
+
},
|
|
785
|
+
});
|
|
786
|
+
const plugins = [
|
|
787
|
+
makePlugin("test", {
|
|
788
|
+
items: {
|
|
789
|
+
fields: {
|
|
790
|
+
name: { type: "string" },
|
|
791
|
+
},
|
|
792
|
+
},
|
|
793
|
+
}),
|
|
794
|
+
];
|
|
795
|
+
|
|
796
|
+
await runPluginMigrations(
|
|
797
|
+
db,
|
|
798
|
+
plugins as Parameters<typeof runPluginMigrations>[1],
|
|
799
|
+
);
|
|
800
|
+
|
|
801
|
+
// ALTER TABLE should not appear (no new columns)
|
|
802
|
+
const alterQuery = db.queries.find((q) => q.sql.includes("ALTER TABLE"));
|
|
803
|
+
expect(alterQuery).toBeUndefined();
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
test("propagates Phase 1 errors and skips Phase 2", async () => {
|
|
807
|
+
const db = makeMockDB({ failOnCreate: true });
|
|
808
|
+
const plugins = [
|
|
809
|
+
makePlugin("test", {
|
|
810
|
+
items: { fields: { name: { type: "string" } } },
|
|
811
|
+
}),
|
|
812
|
+
];
|
|
813
|
+
|
|
814
|
+
await expect(
|
|
815
|
+
runPluginMigrations(db, plugins as Parameters<typeof runPluginMigrations>[1]),
|
|
816
|
+
).rejects.toThrow(/permission denied/);
|
|
817
|
+
|
|
818
|
+
// No ALTER TABLE queries should have been attempted
|
|
819
|
+
const alterQuery = db.queries.find((q) => q.sql.includes("ALTER TABLE"));
|
|
820
|
+
expect(alterQuery).toBeUndefined();
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
test("idempotent when run twice", async () => {
|
|
824
|
+
const db = makeMockDB({
|
|
825
|
+
existingColumns: {
|
|
826
|
+
plugin_test_items: ["id", "name", "created_at", "updated_at"],
|
|
827
|
+
},
|
|
828
|
+
});
|
|
829
|
+
const plugins = [
|
|
830
|
+
makePlugin("test", {
|
|
831
|
+
items: {
|
|
832
|
+
fields: { name: { type: "string" } },
|
|
833
|
+
},
|
|
834
|
+
}),
|
|
835
|
+
];
|
|
836
|
+
|
|
837
|
+
const result1 = await runPluginMigrations(
|
|
838
|
+
db,
|
|
839
|
+
plugins as Parameters<typeof runPluginMigrations>[1],
|
|
840
|
+
);
|
|
841
|
+
const result2 = await runPluginMigrations(
|
|
842
|
+
db,
|
|
843
|
+
plugins as Parameters<typeof runPluginMigrations>[1],
|
|
844
|
+
);
|
|
845
|
+
|
|
846
|
+
// First run applies CREATE TABLE
|
|
847
|
+
expect(result1.applied).toEqual(["plugin_test_items"]);
|
|
848
|
+
// Second run skips it (already tracked in plugin_migrations)
|
|
849
|
+
expect(result2.applied).toEqual([]);
|
|
850
|
+
expect(result2.skipped).toEqual(["plugin_test_items"]);
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
// ---------------------------------------------------------------------------
|
|
855
|
+
// generateColumnMigrations — error context
|
|
856
|
+
// ---------------------------------------------------------------------------
|
|
857
|
+
|
|
858
|
+
describe("generateColumnMigrations error context", () => {
|
|
859
|
+
test("wraps fieldToSQL errors with plugin and table context", async () => {
|
|
860
|
+
const db = makeMockDB({
|
|
861
|
+
existingColumns: {
|
|
862
|
+
plugin_test_items: ["id", "created_at", "updated_at"],
|
|
863
|
+
},
|
|
864
|
+
});
|
|
865
|
+
const plugins = [
|
|
866
|
+
makePlugin("test", {
|
|
867
|
+
items: { fields: { "bad name!": { type: "string" } } },
|
|
868
|
+
}),
|
|
869
|
+
];
|
|
870
|
+
|
|
871
|
+
await expect(
|
|
872
|
+
generateColumnMigrations(db, plugins as Parameters<typeof generateColumnMigrations>[1]),
|
|
873
|
+
).rejects.toThrow(/Plugin "test", table "plugin_test_items"/);
|
|
874
|
+
});
|
|
875
|
+
});
|
|
@@ -13,7 +13,7 @@ const minimalCtx: PluginContextLike = {
|
|
|
13
13
|
function makePlugin(overrides: Partial<PluginLike> = {}): PluginLike {
|
|
14
14
|
return {
|
|
15
15
|
id: "test-plugin",
|
|
16
|
-
|
|
16
|
+
types: ["datasource"],
|
|
17
17
|
version: "1.0.0",
|
|
18
18
|
...overrides,
|
|
19
19
|
};
|
|
@@ -282,12 +282,12 @@ describe("PluginRegistry", () => {
|
|
|
282
282
|
|
|
283
283
|
describe("getByType", () => {
|
|
284
284
|
test("filters by type and health status", async () => {
|
|
285
|
-
registry.register(makePlugin({ id: "ds1",
|
|
286
|
-
registry.register(makePlugin({ id: "ctx1",
|
|
285
|
+
registry.register(makePlugin({ id: "ds1", types: ["datasource"] }));
|
|
286
|
+
registry.register(makePlugin({ id: "ctx1", types: ["context"] }));
|
|
287
287
|
registry.register(
|
|
288
288
|
makePlugin({
|
|
289
289
|
id: "ds2",
|
|
290
|
-
|
|
290
|
+
types: ["datasource"],
|
|
291
291
|
initialize: async () => {
|
|
292
292
|
throw new Error("fail");
|
|
293
293
|
},
|
|
@@ -300,13 +300,40 @@ describe("PluginRegistry", () => {
|
|
|
300
300
|
});
|
|
301
301
|
|
|
302
302
|
test("returns empty array when no plugins of type", async () => {
|
|
303
|
-
registry.register(makePlugin({ id: "ds1",
|
|
303
|
+
registry.register(makePlugin({ id: "ds1", types: ["datasource"] }));
|
|
304
304
|
await registry.initializeAll(minimalCtx);
|
|
305
305
|
|
|
306
306
|
expect(registry.getByType("action")).toEqual([]);
|
|
307
307
|
});
|
|
308
308
|
});
|
|
309
309
|
|
|
310
|
+
// --- getAll ---
|
|
311
|
+
|
|
312
|
+
describe("getAll", () => {
|
|
313
|
+
test("returns all plugins regardless of status", async () => {
|
|
314
|
+
registry.register(makePlugin({ id: "healthy1", types: ["datasource"] }));
|
|
315
|
+
registry.register(makePlugin({
|
|
316
|
+
id: "unhealthy1",
|
|
317
|
+
types: ["context"],
|
|
318
|
+
initialize: async () => { throw new Error("fail"); },
|
|
319
|
+
}));
|
|
320
|
+
registry.register(makePlugin({ id: "healthy2", types: ["action"] }));
|
|
321
|
+
await registry.initializeAll(minimalCtx);
|
|
322
|
+
|
|
323
|
+
const all = registry.getAll();
|
|
324
|
+
expect(all.map((p) => p.id)).toEqual(["healthy1", "unhealthy1", "healthy2"]);
|
|
325
|
+
expect(all).toHaveLength(3);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test("returns plugins in registration order", () => {
|
|
329
|
+
registry.register(makePlugin({ id: "c" }));
|
|
330
|
+
registry.register(makePlugin({ id: "a" }));
|
|
331
|
+
registry.register(makePlugin({ id: "b" }));
|
|
332
|
+
|
|
333
|
+
expect(registry.getAll().map((p) => p.id)).toEqual(["c", "a", "b"]);
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
|
|
310
337
|
// --- getStatus ---
|
|
311
338
|
|
|
312
339
|
describe("getStatus", () => {
|