@useatlas/create 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +231 -0
- package/index.ts +829 -0
- package/package.json +38 -0
- package/templates/docker/.env.example +67 -0
- package/templates/docker/Dockerfile +52 -0
- package/templates/docker/bin/__tests__/benchmark.test.ts +598 -0
- package/templates/docker/bin/__tests__/duckdb-ingest.test.ts +171 -0
- package/templates/docker/bin/__tests__/eval.test.ts +434 -0
- package/templates/docker/bin/__tests__/matview-partition.test.ts +615 -0
- package/templates/docker/bin/__tests__/multi-source.test.ts +113 -0
- package/templates/docker/bin/__tests__/plugin-cli.test.ts +322 -0
- package/templates/docker/bin/__tests__/profiler-heuristics.test.ts +608 -0
- package/templates/docker/bin/__tests__/query.test.ts +240 -0
- package/templates/docker/bin/__tests__/schema-drift.test.ts +542 -0
- package/templates/docker/bin/__tests__/view-yaml-generation.test.ts +146 -0
- package/templates/docker/bin/atlas.ts +5044 -0
- package/templates/docker/bin/benchmark.ts +695 -0
- package/templates/docker/bin/enrich.ts +559 -0
- package/templates/docker/bin/eval.ts +770 -0
- package/templates/docker/bin/smoke.ts +438 -0
- package/templates/docker/data/.gitkeep +0 -0
- package/templates/docker/data/cybersec.sql +1961 -0
- package/templates/docker/data/demo-semantic/catalog.yml +40 -0
- package/templates/docker/data/demo-semantic/entities/accounts.yml +170 -0
- package/templates/docker/data/demo-semantic/entities/companies.yml +207 -0
- package/templates/docker/data/demo-semantic/entities/people.yml +145 -0
- package/templates/docker/data/demo-semantic/glossary.yml +22 -0
- package/templates/docker/data/demo-semantic/metrics/accounts.yml +38 -0
- package/templates/docker/data/demo-semantic/metrics/companies.yml +89 -0
- package/templates/docker/data/demo.sql +373 -0
- package/templates/docker/data/ecommerce.sql +1690 -0
- package/templates/docker/data/init-demo-db.sql +8 -0
- package/templates/docker/docker-compose.yml +34 -0
- package/templates/docker/docs/deploy.md +390 -0
- package/templates/docker/eslint.config.mjs +18 -0
- package/templates/docker/gitignore +5 -0
- package/templates/docker/next.config.ts +9 -0
- package/templates/docker/package.json +59 -0
- package/templates/docker/postcss.config.mjs +8 -0
- package/templates/docker/public/.gitkeep +0 -0
- package/templates/docker/public/favicon.svg +4 -0
- package/templates/docker/railway.json +13 -0
- package/templates/docker/render.yaml +34 -0
- package/templates/docker/semantic/catalog.yml +5 -0
- package/templates/docker/semantic/entities/.gitkeep +0 -0
- package/templates/docker/semantic/glossary.yml +6 -0
- package/templates/docker/semantic/metrics/.gitkeep +0 -0
- package/templates/docker/sidecar/Dockerfile +28 -0
- package/templates/docker/sidecar/railway.json +14 -0
- package/templates/docker/sidecar/server.ts +188 -0
- package/templates/docker/src/api/__tests__/actions.test.ts +683 -0
- package/templates/docker/src/api/__tests__/admin.test.ts +820 -0
- package/templates/docker/src/api/__tests__/auth.test.ts +165 -0
- package/templates/docker/src/api/__tests__/chat.test.ts +376 -0
- package/templates/docker/src/api/__tests__/conversations.test.ts +555 -0
- package/templates/docker/src/api/__tests__/cors.test.ts +135 -0
- package/templates/docker/src/api/__tests__/health-plugin.test.ts +169 -0
- package/templates/docker/src/api/__tests__/health.test.ts +261 -0
- package/templates/docker/src/api/__tests__/query.test.ts +891 -0
- package/templates/docker/src/api/__tests__/scheduled-tasks.test.ts +601 -0
- package/templates/docker/src/api/__tests__/slack.test.ts +847 -0
- package/templates/docker/src/api/index.ts +117 -0
- package/templates/docker/src/api/routes/actions.ts +274 -0
- package/templates/docker/src/api/routes/admin.ts +757 -0
- package/templates/docker/src/api/routes/auth.ts +48 -0
- package/templates/docker/src/api/routes/chat.ts +465 -0
- package/templates/docker/src/api/routes/conversations.ts +266 -0
- package/templates/docker/src/api/routes/health.ts +287 -0
- package/templates/docker/src/api/routes/openapi.ts +390 -0
- package/templates/docker/src/api/routes/query.ts +318 -0
- package/templates/docker/src/api/routes/scheduled-tasks.ts +467 -0
- package/templates/docker/src/api/routes/slack.ts +611 -0
- package/templates/docker/src/api/server.ts +226 -0
- package/templates/docker/src/app/api/[...route]/route.ts +33 -0
- package/templates/docker/src/app/error.tsx +24 -0
- package/templates/docker/src/app/globals.css +126 -0
- package/templates/docker/src/app/layout.tsx +19 -0
- package/templates/docker/src/app/page.tsx +14 -0
- package/templates/docker/src/global.d.ts +1 -0
- package/templates/docker/src/lib/__tests__/agent-cache.test.ts +437 -0
- package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +114 -0
- package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +164 -0
- package/templates/docker/src/lib/__tests__/agent-integration.test.ts +514 -0
- package/templates/docker/src/lib/__tests__/config-actions.test.ts +166 -0
- package/templates/docker/src/lib/__tests__/config.test.ts +1063 -0
- package/templates/docker/src/lib/__tests__/conversations.test.ts +589 -0
- package/templates/docker/src/lib/__tests__/errors.test.ts +256 -0
- package/templates/docker/src/lib/__tests__/logger.test.ts +200 -0
- package/templates/docker/src/lib/__tests__/providers.test.ts +99 -0
- package/templates/docker/src/lib/__tests__/rls.test.ts +435 -0
- package/templates/docker/src/lib/__tests__/scheduled-task-types.test.ts +124 -0
- package/templates/docker/src/lib/__tests__/scheduled-tasks.test.ts +550 -0
- package/templates/docker/src/lib/__tests__/semantic-index.test.ts +547 -0
- package/templates/docker/src/lib/__tests__/semantic-multisource.test.ts +544 -0
- package/templates/docker/src/lib/__tests__/semantic.test.ts +363 -0
- package/templates/docker/src/lib/__tests__/startup-actions.test.ts +452 -0
- package/templates/docker/src/lib/__tests__/startup.test.ts +465 -0
- package/templates/docker/src/lib/__tests__/tracing.test.ts +28 -0
- package/templates/docker/src/lib/action-types.ts +95 -0
- package/templates/docker/src/lib/agent-query.ts +178 -0
- package/templates/docker/src/lib/agent.ts +505 -0
- package/templates/docker/src/lib/api-url.ts +2 -0
- package/templates/docker/src/lib/auth/__tests__/audit.test.ts +418 -0
- package/templates/docker/src/lib/auth/__tests__/byot-integration.test.ts +222 -0
- package/templates/docker/src/lib/auth/__tests__/byot.test.ts +366 -0
- package/templates/docker/src/lib/auth/__tests__/detect.test.ts +190 -0
- package/templates/docker/src/lib/auth/__tests__/managed.test.ts +173 -0
- package/templates/docker/src/lib/auth/__tests__/middleware.test.ts +456 -0
- package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +201 -0
- package/templates/docker/src/lib/auth/__tests__/permissions.test.ts +225 -0
- package/templates/docker/src/lib/auth/__tests__/server.test.ts +34 -0
- package/templates/docker/src/lib/auth/__tests__/simple-key.test.ts +176 -0
- package/templates/docker/src/lib/auth/__tests__/types.test.ts +44 -0
- package/templates/docker/src/lib/auth/audit.ts +89 -0
- package/templates/docker/src/lib/auth/byot.ts +158 -0
- package/templates/docker/src/lib/auth/client.ts +35 -0
- package/templates/docker/src/lib/auth/detect.ts +83 -0
- package/templates/docker/src/lib/auth/managed.ts +73 -0
- package/templates/docker/src/lib/auth/middleware.ts +208 -0
- package/templates/docker/src/lib/auth/migrate.ts +111 -0
- package/templates/docker/src/lib/auth/permissions.ts +156 -0
- package/templates/docker/src/lib/auth/server.ts +142 -0
- package/templates/docker/src/lib/auth/simple-key.ts +92 -0
- package/templates/docker/src/lib/auth/types.ts +49 -0
- package/templates/docker/src/lib/config.ts +704 -0
- package/templates/docker/src/lib/conversation-types.ts +29 -0
- package/templates/docker/src/lib/conversations.ts +270 -0
- package/templates/docker/src/lib/db/__tests__/connection.test.ts +69 -0
- package/templates/docker/src/lib/db/__tests__/duckdb.test.ts +141 -0
- package/templates/docker/src/lib/db/__tests__/internal.test.ts +387 -0
- package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +207 -0
- package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +156 -0
- package/templates/docker/src/lib/db/__tests__/registry.test.ts +595 -0
- package/templates/docker/src/lib/db/__tests__/salesforce.test.ts +339 -0
- package/templates/docker/src/lib/db/__tests__/snowflake.test.ts +217 -0
- package/templates/docker/src/lib/db/__tests__/source-rate-limit.test.ts +130 -0
- package/templates/docker/src/lib/db/connection.ts +753 -0
- package/templates/docker/src/lib/db/duckdb.ts +122 -0
- package/templates/docker/src/lib/db/internal.ts +273 -0
- package/templates/docker/src/lib/db/salesforce.ts +342 -0
- package/templates/docker/src/lib/db/source-rate-limit.ts +191 -0
- package/templates/docker/src/lib/errors.ts +154 -0
- package/templates/docker/src/lib/logger.ts +98 -0
- package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +202 -0
- package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +529 -0
- package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +521 -0
- package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +346 -0
- package/templates/docker/src/lib/plugins/__tests__/tools.test.ts +49 -0
- package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +585 -0
- package/templates/docker/src/lib/plugins/hooks.ts +162 -0
- package/templates/docker/src/lib/plugins/index.ts +9 -0
- package/templates/docker/src/lib/plugins/migrate.ts +309 -0
- package/templates/docker/src/lib/plugins/registry.ts +231 -0
- package/templates/docker/src/lib/plugins/tools.ts +39 -0
- package/templates/docker/src/lib/plugins/wiring.ts +291 -0
- package/templates/docker/src/lib/providers.ts +102 -0
- package/templates/docker/src/lib/rls.ts +321 -0
- package/templates/docker/src/lib/scheduled-task-types.ts +132 -0
- package/templates/docker/src/lib/scheduled-tasks.ts +475 -0
- package/templates/docker/src/lib/scheduler/__tests__/delivery.test.ts +192 -0
- package/templates/docker/src/lib/scheduler/__tests__/engine.test.ts +248 -0
- package/templates/docker/src/lib/scheduler/__tests__/format-email.test.ts +96 -0
- package/templates/docker/src/lib/scheduler/__tests__/format-slack.test.ts +78 -0
- package/templates/docker/src/lib/scheduler/__tests__/format-webhook.test.ts +78 -0
- package/templates/docker/src/lib/scheduler/delivery.ts +248 -0
- package/templates/docker/src/lib/scheduler/engine.ts +317 -0
- package/templates/docker/src/lib/scheduler/executor.ts +73 -0
- package/templates/docker/src/lib/scheduler/format-email.ts +109 -0
- package/templates/docker/src/lib/scheduler/format-slack.ts +35 -0
- package/templates/docker/src/lib/scheduler/format-webhook.ts +37 -0
- package/templates/docker/src/lib/scheduler/index.ts +7 -0
- package/templates/docker/src/lib/security.ts +11 -0
- package/templates/docker/src/lib/semantic-index.ts +503 -0
- package/templates/docker/src/lib/semantic.ts +387 -0
- package/templates/docker/src/lib/sidecar-types.ts +16 -0
- package/templates/docker/src/lib/slack/__tests__/api.test.ts +160 -0
- package/templates/docker/src/lib/slack/__tests__/format.test.ts +237 -0
- package/templates/docker/src/lib/slack/__tests__/store.test.ts +188 -0
- package/templates/docker/src/lib/slack/__tests__/threads.test.ts +112 -0
- package/templates/docker/src/lib/slack/__tests__/verify.test.ts +111 -0
- package/templates/docker/src/lib/slack/api.ts +102 -0
- package/templates/docker/src/lib/slack/format.ts +209 -0
- package/templates/docker/src/lib/slack/store.ts +107 -0
- package/templates/docker/src/lib/slack/threads.ts +64 -0
- package/templates/docker/src/lib/slack/verify.ts +71 -0
- package/templates/docker/src/lib/startup.ts +730 -0
- package/templates/docker/src/lib/tools/__tests__/action-permissions.test.ts +594 -0
- package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +238 -0
- package/templates/docker/src/lib/tools/__tests__/explore-backend.test.ts +267 -0
- package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +492 -0
- package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +374 -0
- package/templates/docker/src/lib/tools/__tests__/explore-sdk-compat.test.ts +82 -0
- package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +208 -0
- package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +144 -0
- package/templates/docker/src/lib/tools/__tests__/registry.test.ts +235 -0
- package/templates/docker/src/lib/tools/__tests__/salesforce-tool.test.ts +154 -0
- package/templates/docker/src/lib/tools/__tests__/soql-validation.test.ts +303 -0
- package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +225 -0
- package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +98 -0
- package/templates/docker/src/lib/tools/__tests__/sql-duckdb.test.ts +233 -0
- package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +225 -0
- package/templates/docker/src/lib/tools/__tests__/sql.test.ts +1012 -0
- package/templates/docker/src/lib/tools/actions/__tests__/audit.test.ts +211 -0
- package/templates/docker/src/lib/tools/actions/__tests__/email.test.ts +378 -0
- package/templates/docker/src/lib/tools/actions/__tests__/handler.test.ts +681 -0
- package/templates/docker/src/lib/tools/actions/__tests__/jira.test.ts +427 -0
- package/templates/docker/src/lib/tools/actions/audit.ts +47 -0
- package/templates/docker/src/lib/tools/actions/email.ts +191 -0
- package/templates/docker/src/lib/tools/actions/handler.ts +591 -0
- package/templates/docker/src/lib/tools/actions/index.ts +23 -0
- package/templates/docker/src/lib/tools/actions/jira.ts +220 -0
- package/templates/docker/src/lib/tools/explore-nsjail.ts +343 -0
- package/templates/docker/src/lib/tools/explore-sandbox.ts +264 -0
- package/templates/docker/src/lib/tools/explore-sidecar.ts +163 -0
- package/templates/docker/src/lib/tools/explore.ts +379 -0
- package/templates/docker/src/lib/tools/registry.ts +221 -0
- package/templates/docker/src/lib/tools/salesforce.ts +138 -0
- package/templates/docker/src/lib/tools/soql-validation.ts +172 -0
- package/templates/docker/src/lib/tools/sql.ts +680 -0
- package/templates/docker/src/lib/tracing.ts +40 -0
- package/templates/docker/src/lib/utils.ts +6 -0
- package/templates/docker/src/test-setup.ts +38 -0
- package/templates/docker/src/types/vercel-sandbox.d.ts +54 -0
- package/templates/docker/src/ui/components/actions/action-approval-card.tsx +295 -0
- package/templates/docker/src/ui/components/actions/action-status-badge.tsx +50 -0
- package/templates/docker/src/ui/components/admin/admin-layout.tsx +26 -0
- package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +96 -0
- package/templates/docker/src/ui/components/admin/empty-state.tsx +24 -0
- package/templates/docker/src/ui/components/admin/entity-detail.tsx +233 -0
- package/templates/docker/src/ui/components/admin/entity-list.tsx +96 -0
- package/templates/docker/src/ui/components/admin/error-banner.tsx +22 -0
- package/templates/docker/src/ui/components/admin/feature-disabled.tsx +44 -0
- package/templates/docker/src/ui/components/admin/health-badge.tsx +30 -0
- package/templates/docker/src/ui/components/admin/loading-state.tsx +14 -0
- package/templates/docker/src/ui/components/admin/stat-card.tsx +32 -0
- package/templates/docker/src/ui/components/atlas-chat.tsx +370 -0
- package/templates/docker/src/ui/components/chart/chart-detection.ts +261 -0
- package/templates/docker/src/ui/components/chart/result-chart.tsx +375 -0
- package/templates/docker/src/ui/components/chat/api-key-bar.tsx +66 -0
- package/templates/docker/src/ui/components/chat/copy-button.tsx +25 -0
- package/templates/docker/src/ui/components/chat/data-table.tsx +102 -0
- package/templates/docker/src/ui/components/chat/error-banner.tsx +32 -0
- package/templates/docker/src/ui/components/chat/explore-card.tsx +41 -0
- package/templates/docker/src/ui/components/chat/loading-card.tsx +10 -0
- package/templates/docker/src/ui/components/chat/managed-auth-card.tsx +116 -0
- package/templates/docker/src/ui/components/chat/markdown.tsx +72 -0
- package/templates/docker/src/ui/components/chat/sql-block.tsx +30 -0
- package/templates/docker/src/ui/components/chat/sql-result-card.tsx +144 -0
- package/templates/docker/src/ui/components/chat/starter-prompts.ts +6 -0
- package/templates/docker/src/ui/components/chat/tool-part.tsx +40 -0
- package/templates/docker/src/ui/components/chat/typing-indicator.tsx +19 -0
- package/templates/docker/src/ui/components/conversations/conversation-item.tsx +120 -0
- package/templates/docker/src/ui/components/conversations/conversation-list.tsx +66 -0
- package/templates/docker/src/ui/components/conversations/conversation-sidebar.tsx +78 -0
- package/templates/docker/src/ui/components/conversations/delete-confirmation.tsx +27 -0
- package/templates/docker/src/ui/context.tsx +78 -0
- package/templates/docker/src/ui/hooks/use-admin-fetch.ts +104 -0
- package/templates/docker/src/ui/hooks/use-conversations.ts +184 -0
- package/templates/docker/src/ui/hooks/use-dark-mode.ts +17 -0
- package/templates/docker/src/ui/lib/action-types.ts +63 -0
- package/templates/docker/src/ui/lib/helpers.ts +104 -0
- package/templates/docker/src/ui/lib/types.ts +145 -0
- package/templates/docker/tsconfig.json +41 -0
- package/templates/docker/vercel.json +3 -0
- package/templates/nextjs-standalone/.env.example +68 -0
- package/templates/nextjs-standalone/bin/__tests__/benchmark.test.ts +598 -0
- package/templates/nextjs-standalone/bin/__tests__/duckdb-ingest.test.ts +171 -0
- package/templates/nextjs-standalone/bin/__tests__/eval.test.ts +434 -0
- package/templates/nextjs-standalone/bin/__tests__/matview-partition.test.ts +615 -0
- package/templates/nextjs-standalone/bin/__tests__/multi-source.test.ts +113 -0
- package/templates/nextjs-standalone/bin/__tests__/plugin-cli.test.ts +322 -0
- package/templates/nextjs-standalone/bin/__tests__/profiler-heuristics.test.ts +608 -0
- package/templates/nextjs-standalone/bin/__tests__/query.test.ts +240 -0
- package/templates/nextjs-standalone/bin/__tests__/schema-drift.test.ts +542 -0
- package/templates/nextjs-standalone/bin/__tests__/view-yaml-generation.test.ts +146 -0
- package/templates/nextjs-standalone/bin/atlas.ts +5044 -0
- package/templates/nextjs-standalone/bin/benchmark.ts +695 -0
- package/templates/nextjs-standalone/bin/enrich.ts +559 -0
- package/templates/nextjs-standalone/bin/eval.ts +770 -0
- package/templates/nextjs-standalone/bin/smoke.ts +438 -0
- package/templates/nextjs-standalone/data/.gitkeep +0 -0
- package/templates/nextjs-standalone/data/cybersec.sql +1961 -0
- package/templates/nextjs-standalone/data/demo-semantic/catalog.yml +40 -0
- package/templates/nextjs-standalone/data/demo-semantic/entities/accounts.yml +170 -0
- package/templates/nextjs-standalone/data/demo-semantic/entities/companies.yml +207 -0
- package/templates/nextjs-standalone/data/demo-semantic/entities/people.yml +145 -0
- package/templates/nextjs-standalone/data/demo-semantic/glossary.yml +22 -0
- package/templates/nextjs-standalone/data/demo-semantic/metrics/accounts.yml +38 -0
- package/templates/nextjs-standalone/data/demo-semantic/metrics/companies.yml +89 -0
- package/templates/nextjs-standalone/data/demo.sql +373 -0
- package/templates/nextjs-standalone/data/ecommerce.sql +1690 -0
- package/templates/nextjs-standalone/data/init-demo-db.sql +8 -0
- package/templates/nextjs-standalone/docs/deploy.md +390 -0
- package/templates/nextjs-standalone/eslint.config.mjs +18 -0
- package/templates/nextjs-standalone/gitignore +5 -0
- package/templates/nextjs-standalone/next.config.ts +10 -0
- package/templates/nextjs-standalone/package.json +63 -0
- package/templates/nextjs-standalone/postcss.config.mjs +8 -0
- package/templates/nextjs-standalone/semantic/catalog.yml +5 -0
- package/templates/nextjs-standalone/semantic/entities/.gitkeep +0 -0
- package/templates/nextjs-standalone/semantic/glossary.yml +6 -0
- package/templates/nextjs-standalone/semantic/metrics/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/api/__tests__/actions.test.ts +683 -0
- package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +820 -0
- package/templates/nextjs-standalone/src/api/__tests__/auth.test.ts +165 -0
- package/templates/nextjs-standalone/src/api/__tests__/chat.test.ts +376 -0
- package/templates/nextjs-standalone/src/api/__tests__/conversations.test.ts +555 -0
- package/templates/nextjs-standalone/src/api/__tests__/cors.test.ts +135 -0
- package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +169 -0
- package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +261 -0
- package/templates/nextjs-standalone/src/api/__tests__/query.test.ts +891 -0
- package/templates/nextjs-standalone/src/api/__tests__/scheduled-tasks.test.ts +601 -0
- package/templates/nextjs-standalone/src/api/__tests__/slack.test.ts +847 -0
- package/templates/nextjs-standalone/src/api/index.ts +117 -0
- package/templates/nextjs-standalone/src/api/routes/actions.ts +274 -0
- package/templates/nextjs-standalone/src/api/routes/admin.ts +757 -0
- package/templates/nextjs-standalone/src/api/routes/auth.ts +48 -0
- package/templates/nextjs-standalone/src/api/routes/chat.ts +465 -0
- package/templates/nextjs-standalone/src/api/routes/conversations.ts +266 -0
- package/templates/nextjs-standalone/src/api/routes/health.ts +287 -0
- package/templates/nextjs-standalone/src/api/routes/openapi.ts +390 -0
- package/templates/nextjs-standalone/src/api/routes/query.ts +318 -0
- package/templates/nextjs-standalone/src/api/routes/scheduled-tasks.ts +467 -0
- package/templates/nextjs-standalone/src/api/routes/slack.ts +611 -0
- package/templates/nextjs-standalone/src/api/server.ts +226 -0
- package/templates/nextjs-standalone/src/app/api/[...route]/route.ts +33 -0
- package/templates/nextjs-standalone/src/app/error.tsx +24 -0
- package/templates/nextjs-standalone/src/app/global-error.tsx +68 -0
- package/templates/nextjs-standalone/src/app/globals.css +126 -0
- package/templates/nextjs-standalone/src/app/layout.tsx +19 -0
- package/templates/nextjs-standalone/src/app/page.tsx +14 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +437 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +114 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +164 -0
- package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +514 -0
- package/templates/nextjs-standalone/src/lib/__tests__/config-actions.test.ts +166 -0
- package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +1063 -0
- package/templates/nextjs-standalone/src/lib/__tests__/conversations.test.ts +589 -0
- package/templates/nextjs-standalone/src/lib/__tests__/errors.test.ts +256 -0
- package/templates/nextjs-standalone/src/lib/__tests__/logger.test.ts +200 -0
- package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +99 -0
- package/templates/nextjs-standalone/src/lib/__tests__/rls.test.ts +435 -0
- package/templates/nextjs-standalone/src/lib/__tests__/scheduled-task-types.test.ts +124 -0
- package/templates/nextjs-standalone/src/lib/__tests__/scheduled-tasks.test.ts +550 -0
- package/templates/nextjs-standalone/src/lib/__tests__/semantic-index.test.ts +547 -0
- package/templates/nextjs-standalone/src/lib/__tests__/semantic-multisource.test.ts +544 -0
- package/templates/nextjs-standalone/src/lib/__tests__/semantic.test.ts +363 -0
- package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +452 -0
- package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +465 -0
- package/templates/nextjs-standalone/src/lib/__tests__/tracing.test.ts +28 -0
- package/templates/nextjs-standalone/src/lib/action-types.ts +95 -0
- package/templates/nextjs-standalone/src/lib/agent-query.ts +178 -0
- package/templates/nextjs-standalone/src/lib/agent.ts +505 -0
- package/templates/nextjs-standalone/src/lib/api-url.ts +3 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/audit.test.ts +418 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/byot-integration.test.ts +222 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/byot.test.ts +366 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/detect.test.ts +190 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/managed.test.ts +173 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/middleware.test.ts +456 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +201 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/permissions.test.ts +225 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/server.test.ts +34 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/simple-key.test.ts +176 -0
- package/templates/nextjs-standalone/src/lib/auth/__tests__/types.test.ts +44 -0
- package/templates/nextjs-standalone/src/lib/auth/audit.ts +89 -0
- package/templates/nextjs-standalone/src/lib/auth/byot.ts +158 -0
- package/templates/nextjs-standalone/src/lib/auth/client.ts +23 -0
- package/templates/nextjs-standalone/src/lib/auth/detect.ts +83 -0
- package/templates/nextjs-standalone/src/lib/auth/managed.ts +73 -0
- package/templates/nextjs-standalone/src/lib/auth/middleware.ts +208 -0
- package/templates/nextjs-standalone/src/lib/auth/migrate.ts +111 -0
- package/templates/nextjs-standalone/src/lib/auth/permissions.ts +156 -0
- package/templates/nextjs-standalone/src/lib/auth/server.ts +142 -0
- package/templates/nextjs-standalone/src/lib/auth/simple-key.ts +92 -0
- package/templates/nextjs-standalone/src/lib/auth/types.ts +49 -0
- package/templates/nextjs-standalone/src/lib/config.ts +704 -0
- package/templates/nextjs-standalone/src/lib/conversation-types.ts +29 -0
- package/templates/nextjs-standalone/src/lib/conversations.ts +270 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +69 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/duckdb.test.ts +141 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/internal.test.ts +387 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +207 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +156 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +595 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/salesforce.test.ts +339 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/snowflake.test.ts +217 -0
- package/templates/nextjs-standalone/src/lib/db/__tests__/source-rate-limit.test.ts +130 -0
- package/templates/nextjs-standalone/src/lib/db/connection.ts +753 -0
- package/templates/nextjs-standalone/src/lib/db/duckdb.ts +122 -0
- package/templates/nextjs-standalone/src/lib/db/internal.ts +273 -0
- package/templates/nextjs-standalone/src/lib/db/salesforce.ts +342 -0
- package/templates/nextjs-standalone/src/lib/db/source-rate-limit.ts +191 -0
- package/templates/nextjs-standalone/src/lib/errors.ts +154 -0
- package/templates/nextjs-standalone/src/lib/logger.ts +98 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +202 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +529 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +521 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +346 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/tools.test.ts +49 -0
- package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +585 -0
- package/templates/nextjs-standalone/src/lib/plugins/hooks.ts +162 -0
- package/templates/nextjs-standalone/src/lib/plugins/index.ts +9 -0
- package/templates/nextjs-standalone/src/lib/plugins/migrate.ts +309 -0
- package/templates/nextjs-standalone/src/lib/plugins/registry.ts +231 -0
- package/templates/nextjs-standalone/src/lib/plugins/tools.ts +39 -0
- package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +291 -0
- package/templates/nextjs-standalone/src/lib/providers.ts +102 -0
- package/templates/nextjs-standalone/src/lib/rls.ts +321 -0
- package/templates/nextjs-standalone/src/lib/scheduled-task-types.ts +132 -0
- package/templates/nextjs-standalone/src/lib/scheduled-tasks.ts +475 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/delivery.test.ts +192 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/engine.test.ts +248 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-email.test.ts +96 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-slack.test.ts +78 -0
- package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-webhook.test.ts +78 -0
- package/templates/nextjs-standalone/src/lib/scheduler/delivery.ts +248 -0
- package/templates/nextjs-standalone/src/lib/scheduler/engine.ts +317 -0
- package/templates/nextjs-standalone/src/lib/scheduler/executor.ts +73 -0
- package/templates/nextjs-standalone/src/lib/scheduler/format-email.ts +109 -0
- package/templates/nextjs-standalone/src/lib/scheduler/format-slack.ts +35 -0
- package/templates/nextjs-standalone/src/lib/scheduler/format-webhook.ts +37 -0
- package/templates/nextjs-standalone/src/lib/scheduler/index.ts +7 -0
- package/templates/nextjs-standalone/src/lib/security.ts +11 -0
- package/templates/nextjs-standalone/src/lib/semantic-index.ts +503 -0
- package/templates/nextjs-standalone/src/lib/semantic.ts +387 -0
- package/templates/nextjs-standalone/src/lib/sidecar-types.ts +16 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/api.test.ts +160 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/format.test.ts +237 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/store.test.ts +188 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/threads.test.ts +112 -0
- package/templates/nextjs-standalone/src/lib/slack/__tests__/verify.test.ts +111 -0
- package/templates/nextjs-standalone/src/lib/slack/api.ts +102 -0
- package/templates/nextjs-standalone/src/lib/slack/format.ts +209 -0
- package/templates/nextjs-standalone/src/lib/slack/store.ts +107 -0
- package/templates/nextjs-standalone/src/lib/slack/threads.ts +64 -0
- package/templates/nextjs-standalone/src/lib/slack/verify.ts +71 -0
- package/templates/nextjs-standalone/src/lib/startup.ts +730 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/action-permissions.test.ts +594 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +238 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-backend.test.ts +267 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +492 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +374 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sdk-compat.test.ts +82 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +208 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +144 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +235 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/salesforce-tool.test.ts +154 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/soql-validation.test.ts +303 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +225 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +98 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-duckdb.test.ts +233 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +225 -0
- package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +1012 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/audit.test.ts +211 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/email.test.ts +378 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/handler.test.ts +681 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/jira.test.ts +427 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/audit.ts +47 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/email.ts +191 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/handler.ts +591 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/index.ts +23 -0
- package/templates/nextjs-standalone/src/lib/tools/actions/jira.ts +220 -0
- package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +343 -0
- package/templates/nextjs-standalone/src/lib/tools/explore-sandbox.ts +264 -0
- package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +163 -0
- package/templates/nextjs-standalone/src/lib/tools/explore.ts +379 -0
- package/templates/nextjs-standalone/src/lib/tools/registry.ts +221 -0
- package/templates/nextjs-standalone/src/lib/tools/salesforce.ts +138 -0
- package/templates/nextjs-standalone/src/lib/tools/soql-validation.ts +172 -0
- package/templates/nextjs-standalone/src/lib/tools/sql.ts +680 -0
- package/templates/nextjs-standalone/src/lib/tracing.ts +40 -0
- package/templates/nextjs-standalone/src/lib/utils.ts +6 -0
- package/templates/nextjs-standalone/src/test-setup.ts +38 -0
- package/templates/nextjs-standalone/src/ui/components/actions/action-approval-card.tsx +295 -0
- package/templates/nextjs-standalone/src/ui/components/actions/action-status-badge.tsx +50 -0
- package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +26 -0
- package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +96 -0
- package/templates/nextjs-standalone/src/ui/components/admin/empty-state.tsx +24 -0
- package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +233 -0
- package/templates/nextjs-standalone/src/ui/components/admin/entity-list.tsx +96 -0
- package/templates/nextjs-standalone/src/ui/components/admin/error-banner.tsx +22 -0
- package/templates/nextjs-standalone/src/ui/components/admin/feature-disabled.tsx +44 -0
- package/templates/nextjs-standalone/src/ui/components/admin/health-badge.tsx +30 -0
- package/templates/nextjs-standalone/src/ui/components/admin/loading-state.tsx +14 -0
- package/templates/nextjs-standalone/src/ui/components/admin/stat-card.tsx +32 -0
- package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +370 -0
- package/templates/nextjs-standalone/src/ui/components/chart/chart-detection.ts +261 -0
- package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +375 -0
- package/templates/nextjs-standalone/src/ui/components/chat/api-key-bar.tsx +66 -0
- package/templates/nextjs-standalone/src/ui/components/chat/copy-button.tsx +25 -0
- package/templates/nextjs-standalone/src/ui/components/chat/data-table.tsx +102 -0
- package/templates/nextjs-standalone/src/ui/components/chat/error-banner.tsx +32 -0
- package/templates/nextjs-standalone/src/ui/components/chat/explore-card.tsx +41 -0
- package/templates/nextjs-standalone/src/ui/components/chat/loading-card.tsx +10 -0
- package/templates/nextjs-standalone/src/ui/components/chat/managed-auth-card.tsx +116 -0
- package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +72 -0
- package/templates/nextjs-standalone/src/ui/components/chat/sql-block.tsx +30 -0
- package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +144 -0
- package/templates/nextjs-standalone/src/ui/components/chat/starter-prompts.ts +6 -0
- package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +40 -0
- package/templates/nextjs-standalone/src/ui/components/chat/typing-indicator.tsx +19 -0
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +120 -0
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-list.tsx +66 -0
- package/templates/nextjs-standalone/src/ui/components/conversations/conversation-sidebar.tsx +78 -0
- package/templates/nextjs-standalone/src/ui/components/conversations/delete-confirmation.tsx +27 -0
- package/templates/nextjs-standalone/src/ui/context.tsx +78 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-admin-fetch.ts +104 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +184 -0
- package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +17 -0
- package/templates/nextjs-standalone/src/ui/lib/action-types.ts +63 -0
- package/templates/nextjs-standalone/src/ui/lib/helpers.ts +104 -0
- package/templates/nextjs-standalone/src/ui/lib/types.ts +145 -0
- package/templates/nextjs-standalone/tsconfig.json +32 -0
- package/templates/nextjs-standalone/vercel.json +4 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin hook dispatch runtime.
|
|
3
|
+
*
|
|
4
|
+
* Dispatches lifecycle hooks (beforeQuery, afterQuery, beforeExplore,
|
|
5
|
+
* afterExplore, onRequest, onResponse) to all healthy plugins that
|
|
6
|
+
* define matching hook entries. Zero overhead when no plugins are registered.
|
|
7
|
+
*
|
|
8
|
+
* Mutable hooks (beforeQuery, beforeExplore) can return a mutation object
|
|
9
|
+
* to rewrite the SQL/command, or throw to reject the operation. All other
|
|
10
|
+
* hooks are observation-only (void return — handler return values are
|
|
11
|
+
* discarded). Mutations chain in registration order across healthy plugins
|
|
12
|
+
* — unhealthy plugins are silently skipped.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { plugins } from "./registry";
|
|
16
|
+
import type { PluginRegistry } from "./registry";
|
|
17
|
+
import { createLogger } from "@atlas/api/lib/logger";
|
|
18
|
+
|
|
19
|
+
const log = createLogger("plugins:hooks");
|
|
20
|
+
|
|
21
|
+
interface HookEntry<T> {
|
|
22
|
+
matcher?: (ctx: T) => boolean;
|
|
23
|
+
handler: (ctx: T) => Promise<unknown> | unknown;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type HookName = "beforeQuery" | "afterQuery" | "beforeExplore" | "afterExplore" | "onRequest" | "onResponse";
|
|
27
|
+
|
|
28
|
+
/** Hook names that support mutation via dispatchMutableHook. */
|
|
29
|
+
type MutableHookName = "beforeQuery" | "beforeExplore";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Dispatch a named hook to all healthy plugins (observation-only —
|
|
33
|
+
* handler return values are discarded).
|
|
34
|
+
*
|
|
35
|
+
* - Skips entirely when no plugins are registered (zero overhead).
|
|
36
|
+
* - Respects `matcher` filters on individual hook entries.
|
|
37
|
+
* - Catches and logs errors from hook handlers — never crashes the caller.
|
|
38
|
+
*
|
|
39
|
+
* @param registry - Optional plugin registry override (default: global singleton). For testing.
|
|
40
|
+
*/
|
|
41
|
+
export async function dispatchHook<T>(
|
|
42
|
+
hookName: HookName,
|
|
43
|
+
context: T,
|
|
44
|
+
registry?: PluginRegistry,
|
|
45
|
+
): Promise<void> {
|
|
46
|
+
const reg = registry ?? plugins;
|
|
47
|
+
if (reg.size === 0) return;
|
|
48
|
+
|
|
49
|
+
const healthyPlugins = reg.getAllHealthy();
|
|
50
|
+
if (healthyPlugins.length === 0) return;
|
|
51
|
+
|
|
52
|
+
for (const plugin of healthyPlugins) {
|
|
53
|
+
const hooks = (plugin as Record<string, unknown>).hooks as Record<string, HookEntry<T>[]> | undefined;
|
|
54
|
+
if (!hooks?.[hookName]) continue;
|
|
55
|
+
|
|
56
|
+
for (const entry of hooks[hookName]) {
|
|
57
|
+
try {
|
|
58
|
+
if (entry.matcher && !entry.matcher(context)) continue;
|
|
59
|
+
await entry.handler(context);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
log.warn(
|
|
62
|
+
{ pluginId: plugin.id, hookName, err: err instanceof Error ? err : new Error(String(err)) },
|
|
63
|
+
"Plugin hook failed",
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Dispatch a mutable hook and return the final mutated value.
|
|
72
|
+
*
|
|
73
|
+
* - Chains mutations in plugin registration order across healthy plugins.
|
|
74
|
+
* - Each hook handler receives a context with the latest mutated value applied.
|
|
75
|
+
* - Handlers that return `void`/`undefined` pass through without mutation.
|
|
76
|
+
* - Handlers that return a mutation object (e.g. `{ sql }`) update the value
|
|
77
|
+
* for subsequent hooks.
|
|
78
|
+
* - If any handler **throws**, the error propagates immediately — the caller
|
|
79
|
+
* should treat this as a rejection (e.g. deny the query).
|
|
80
|
+
* - Matcher errors are caught and logged (skipping the entry), NOT treated
|
|
81
|
+
* as rejections.
|
|
82
|
+
*
|
|
83
|
+
* @param hookName - "beforeQuery" or "beforeExplore"
|
|
84
|
+
* @param context - The initial hook context
|
|
85
|
+
* @param mutateKey - The context key to mutate (e.g. "sql" or "command")
|
|
86
|
+
* @param registry - Optional plugin registry override. For testing.
|
|
87
|
+
* @returns The final mutated value (or the original if no hooks mutated it).
|
|
88
|
+
*/
|
|
89
|
+
export async function dispatchMutableHook<
|
|
90
|
+
T extends Record<string, unknown>,
|
|
91
|
+
K extends string & keyof T,
|
|
92
|
+
>(
|
|
93
|
+
hookName: MutableHookName,
|
|
94
|
+
context: T,
|
|
95
|
+
mutateKey: K,
|
|
96
|
+
registry?: PluginRegistry,
|
|
97
|
+
): Promise<T[K]> {
|
|
98
|
+
const reg = registry ?? plugins;
|
|
99
|
+
let currentValue = context[mutateKey];
|
|
100
|
+
|
|
101
|
+
if (reg.size === 0) return currentValue;
|
|
102
|
+
|
|
103
|
+
const healthyPlugins = reg.getAllHealthy();
|
|
104
|
+
if (healthyPlugins.length === 0) return currentValue;
|
|
105
|
+
|
|
106
|
+
// Build a mutable copy of the context so each hook sees the latest value
|
|
107
|
+
const mutableCtx = { ...context };
|
|
108
|
+
|
|
109
|
+
for (const plugin of healthyPlugins) {
|
|
110
|
+
const hooks = (plugin as Record<string, unknown>).hooks as Record<string, HookEntry<T>[]> | undefined;
|
|
111
|
+
if (!hooks?.[hookName]) continue;
|
|
112
|
+
|
|
113
|
+
for (const entry of hooks[hookName]) {
|
|
114
|
+
// Matcher errors are bugs, not rejections — catch and skip
|
|
115
|
+
if (entry.matcher) {
|
|
116
|
+
let matched: boolean;
|
|
117
|
+
try {
|
|
118
|
+
matched = entry.matcher(mutableCtx);
|
|
119
|
+
} catch (matcherErr) {
|
|
120
|
+
log.error(
|
|
121
|
+
{ pluginId: plugin.id, hookName, err: matcherErr instanceof Error ? matcherErr : new Error(String(matcherErr)) },
|
|
122
|
+
"Plugin hook matcher threw — skipping entry",
|
|
123
|
+
);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (!matched) continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Handler throws propagate — intentional for "deny" use cases
|
|
130
|
+
let result: unknown;
|
|
131
|
+
try {
|
|
132
|
+
result = await entry.handler(mutableCtx);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
log.warn(
|
|
135
|
+
{ pluginId: plugin.id, hookName, err: err instanceof Error ? err : new Error(String(err)) },
|
|
136
|
+
"Plugin hook rejected operation",
|
|
137
|
+
);
|
|
138
|
+
throw err;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Apply mutation if the handler returned one
|
|
142
|
+
if (result != null && typeof result === "object" && mutateKey in (result as Record<string, unknown>)) {
|
|
143
|
+
const newValue = (result as Record<string, unknown>)[mutateKey];
|
|
144
|
+
if (typeof newValue !== typeof currentValue) {
|
|
145
|
+
log.error(
|
|
146
|
+
{ pluginId: plugin.id, hookName, mutateKey, expectedType: typeof currentValue, gotType: typeof newValue },
|
|
147
|
+
"Plugin returned wrong type for mutated value — ignoring mutation",
|
|
148
|
+
);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
currentValue = newValue as T[K];
|
|
152
|
+
(mutableCtx as Record<string, unknown>)[mutateKey] = currentValue;
|
|
153
|
+
log.debug(
|
|
154
|
+
{ pluginId: plugin.id, hookName, mutateKey },
|
|
155
|
+
"Plugin mutated hook value",
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return currentValue;
|
|
162
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin system — public API from @atlas/api.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { plugins, PluginRegistry } from "./registry";
|
|
6
|
+
export type { PluginLike, PluginContextLike, PluginHealthResult, PluginType, PluginStatus, PluginDescription } from "./registry";
|
|
7
|
+
export { wireDatasourcePlugins, wireActionPlugins, wireInteractionPlugins, wireContextPlugins } from "./wiring";
|
|
8
|
+
export { dispatchHook } from "./hooks";
|
|
9
|
+
export { getPluginTools, setPluginTools, getContextFragments, setContextFragments } from "./tools";
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-driven plugin migrations.
|
|
3
|
+
*
|
|
4
|
+
* Reads `schema` declarations from plugin objects, generates CREATE TABLE
|
|
5
|
+
* SQL for the internal database, and tracks applied migrations in a
|
|
6
|
+
* `plugin_migrations` table for idempotency.
|
|
7
|
+
*
|
|
8
|
+
* Table names are prefixed with `plugin_` to avoid collisions with Atlas
|
|
9
|
+
* internal tables.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { createLogger } from "@atlas/api/lib/logger";
|
|
13
|
+
|
|
14
|
+
const log = createLogger("plugins:migrate");
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Types (structural — no import from @atlas/plugin-sdk)
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
interface FieldDef {
|
|
21
|
+
type: "string" | "number" | "boolean" | "date";
|
|
22
|
+
required?: boolean;
|
|
23
|
+
references?: { model: string; field: string };
|
|
24
|
+
unique?: boolean;
|
|
25
|
+
defaultValue?: unknown;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface TableDef {
|
|
29
|
+
fields: Record<string, FieldDef>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface PluginWithSchema {
|
|
33
|
+
id: string;
|
|
34
|
+
schema?: Record<string, TableDef>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// SQL type mapping
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
const TYPE_MAP: Record<string, string> = {
|
|
42
|
+
string: "TEXT",
|
|
43
|
+
number: "INTEGER",
|
|
44
|
+
boolean: "BOOLEAN",
|
|
45
|
+
date: "TIMESTAMPTZ",
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const SAFE_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
49
|
+
|
|
50
|
+
function validateIdentifier(name: string, context: string): void {
|
|
51
|
+
if (!SAFE_IDENTIFIER.test(name)) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Invalid identifier "${name}" in ${context}. ` +
|
|
54
|
+
`Must contain only letters, digits, and underscores, and start with a letter or underscore.`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function fieldToSQL(name: string, field: FieldDef): string {
|
|
60
|
+
validateIdentifier(name, "column name");
|
|
61
|
+
|
|
62
|
+
const sqlType = TYPE_MAP[field.type];
|
|
63
|
+
if (!sqlType) {
|
|
64
|
+
throw new Error(`Unknown field type "${field.type}" on column "${name}"`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const parts = [`"${name}" ${sqlType}`];
|
|
68
|
+
|
|
69
|
+
if (field.required) parts.push("NOT NULL");
|
|
70
|
+
if (field.unique) parts.push("UNIQUE");
|
|
71
|
+
|
|
72
|
+
if (field.defaultValue !== undefined) {
|
|
73
|
+
if (typeof field.defaultValue === "string") {
|
|
74
|
+
// Escape single quotes in default values
|
|
75
|
+
parts.push(`DEFAULT '${field.defaultValue.replace(/'/g, "''")}'`);
|
|
76
|
+
} else if (typeof field.defaultValue === "boolean") {
|
|
77
|
+
parts.push(`DEFAULT ${field.defaultValue}`);
|
|
78
|
+
} else if (typeof field.defaultValue === "number") {
|
|
79
|
+
if (!Number.isFinite(field.defaultValue)) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Invalid numeric defaultValue "${field.defaultValue}" on column "${name}". ` +
|
|
82
|
+
`Default values must be finite numbers.`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
parts.push(`DEFAULT ${field.defaultValue}`);
|
|
86
|
+
} else {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Unsupported defaultValue type "${typeof field.defaultValue}" on column "${name}". ` +
|
|
89
|
+
`Only string, boolean, and number default values are supported.`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return parts.join(" ");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// Table name prefixing
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Build a safe prefixed table name: `plugin_{pluginId}_{tableName}`.
|
|
103
|
+
* Replaces non-alphanumeric/underscore chars with underscores for safety.
|
|
104
|
+
*/
|
|
105
|
+
export function prefixTableName(pluginId: string, tableName: string): string {
|
|
106
|
+
const safePlugin = pluginId.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
107
|
+
const safeTable = tableName.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
108
|
+
return `plugin_${safePlugin}_${safeTable}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// SQL generation
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
export interface MigrationStatement {
|
|
116
|
+
pluginId: string;
|
|
117
|
+
tableName: string;
|
|
118
|
+
prefixedName: string;
|
|
119
|
+
sql: string;
|
|
120
|
+
hash: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Hash a SQL string for change detection. Uses a simple string hash
|
|
125
|
+
* (not crypto — just for detecting drift, not security).
|
|
126
|
+
*/
|
|
127
|
+
function hashSQL(sql: string): string {
|
|
128
|
+
let h = 0;
|
|
129
|
+
for (let i = 0; i < sql.length; i++) {
|
|
130
|
+
h = ((h << 5) - h + sql.charCodeAt(i)) | 0;
|
|
131
|
+
}
|
|
132
|
+
return (h >>> 0).toString(16).padStart(8, "0");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Generate CREATE TABLE IF NOT EXISTS statements from plugin schema
|
|
137
|
+
* declarations. Each table gets an auto-generated `id` primary key
|
|
138
|
+
* and `created_at`/`updated_at` timestamps.
|
|
139
|
+
*/
|
|
140
|
+
export function generateMigrationSQL(plugins: PluginWithSchema[]): MigrationStatement[] {
|
|
141
|
+
const statements: MigrationStatement[] = [];
|
|
142
|
+
|
|
143
|
+
for (const plugin of plugins) {
|
|
144
|
+
if (!plugin.schema) continue;
|
|
145
|
+
|
|
146
|
+
for (const [tableName, tableDef] of Object.entries(plugin.schema)) {
|
|
147
|
+
const prefixed = prefixTableName(plugin.id, tableName);
|
|
148
|
+
const columns: string[] = [
|
|
149
|
+
'"id" UUID PRIMARY KEY DEFAULT gen_random_uuid()',
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
for (const [fieldName, fieldDef] of Object.entries(tableDef.fields)) {
|
|
153
|
+
columns.push(fieldToSQL(fieldName, fieldDef));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Add foreign key constraints after columns
|
|
157
|
+
for (const [fieldName, fieldDef] of Object.entries(tableDef.fields)) {
|
|
158
|
+
if (fieldDef.references) {
|
|
159
|
+
validateIdentifier(fieldDef.references.field, `references.field on column "${fieldName}"`);
|
|
160
|
+
const refTable = prefixTableName(plugin.id, fieldDef.references.model);
|
|
161
|
+
columns.push(
|
|
162
|
+
`FOREIGN KEY ("${fieldName}") REFERENCES "${refTable}"("${fieldDef.references.field}")`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
columns.push('"created_at" TIMESTAMPTZ DEFAULT now()');
|
|
168
|
+
columns.push('"updated_at" TIMESTAMPTZ DEFAULT now()');
|
|
169
|
+
|
|
170
|
+
const sql = `CREATE TABLE IF NOT EXISTS "${prefixed}" (\n ${columns.join(",\n ")}\n);`;
|
|
171
|
+
|
|
172
|
+
statements.push({
|
|
173
|
+
pluginId: plugin.id,
|
|
174
|
+
tableName,
|
|
175
|
+
prefixedName: prefixed,
|
|
176
|
+
sql,
|
|
177
|
+
hash: hashSQL(sql),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return statements;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
// Migration tracking table
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
const MIGRATIONS_TABLE_SQL = `
|
|
190
|
+
CREATE TABLE IF NOT EXISTS plugin_migrations (
|
|
191
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
192
|
+
plugin_id TEXT NOT NULL,
|
|
193
|
+
table_name TEXT NOT NULL,
|
|
194
|
+
sql_hash TEXT NOT NULL,
|
|
195
|
+
applied_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
196
|
+
UNIQUE(plugin_id, table_name, sql_hash)
|
|
197
|
+
);
|
|
198
|
+
`;
|
|
199
|
+
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// Apply migrations
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
/** Internal DB interface — matches the shape from internal.ts */
|
|
205
|
+
export interface MigrateDB {
|
|
206
|
+
query(sql: string, params?: unknown[]): Promise<{ rows: Record<string, unknown>[] }>;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Ensure the plugin_migrations tracking table exists.
|
|
211
|
+
*/
|
|
212
|
+
export async function ensureMigrationsTable(db: MigrateDB): Promise<void> {
|
|
213
|
+
await db.query(MIGRATIONS_TABLE_SQL);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Check which migrations have already been applied.
|
|
218
|
+
* Returns a Set of "pluginId:tableName:hash" keys.
|
|
219
|
+
*/
|
|
220
|
+
export async function getAppliedMigrations(db: MigrateDB): Promise<Set<string>> {
|
|
221
|
+
const result = await db.query(
|
|
222
|
+
"SELECT plugin_id, table_name, sql_hash FROM plugin_migrations"
|
|
223
|
+
);
|
|
224
|
+
const applied = new Set<string>();
|
|
225
|
+
for (const row of result.rows) {
|
|
226
|
+
applied.add(`${row.plugin_id}:${row.table_name}:${row.sql_hash}`);
|
|
227
|
+
}
|
|
228
|
+
return applied;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Apply pending migrations to the internal database.
|
|
233
|
+
* Skips already-applied migrations (idempotent).
|
|
234
|
+
*
|
|
235
|
+
* @returns Summary of applied and skipped migrations.
|
|
236
|
+
*/
|
|
237
|
+
export async function applyMigrations(
|
|
238
|
+
db: MigrateDB,
|
|
239
|
+
statements: MigrationStatement[],
|
|
240
|
+
): Promise<{ applied: string[]; skipped: string[] }> {
|
|
241
|
+
await ensureMigrationsTable(db);
|
|
242
|
+
const existing = await getAppliedMigrations(db);
|
|
243
|
+
const applied: string[] = [];
|
|
244
|
+
const skipped: string[] = [];
|
|
245
|
+
|
|
246
|
+
for (const stmt of statements) {
|
|
247
|
+
const key = `${stmt.pluginId}:${stmt.tableName}:${stmt.hash}`;
|
|
248
|
+
if (existing.has(key)) {
|
|
249
|
+
skipped.push(stmt.prefixedName);
|
|
250
|
+
log.debug({ table: stmt.prefixedName }, "Migration already applied — skipping");
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
await db.query(stmt.sql);
|
|
256
|
+
await db.query(
|
|
257
|
+
"INSERT INTO plugin_migrations (plugin_id, table_name, sql_hash) VALUES ($1, $2, $3)",
|
|
258
|
+
[stmt.pluginId, stmt.tableName, stmt.hash],
|
|
259
|
+
);
|
|
260
|
+
} catch (err) {
|
|
261
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
262
|
+
throw new Error(
|
|
263
|
+
`Migration failed for "${stmt.prefixedName}": ${detail}. ` +
|
|
264
|
+
`Applied so far: [${applied.join(", ") || "none"}]. ` +
|
|
265
|
+
`Remaining migrations were not attempted.`,
|
|
266
|
+
{ cause: err },
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
applied.push(stmt.prefixedName);
|
|
270
|
+
log.info({ table: stmt.prefixedName, pluginId: stmt.pluginId }, "Migration applied");
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return { applied, skipped };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
// Diff: compare declared schema vs actual tables
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
|
|
280
|
+
export interface SchemaDiff {
|
|
281
|
+
newTables: string[];
|
|
282
|
+
existingTables: string[];
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Compare declared plugin schemas against actual tables in the database.
|
|
287
|
+
*/
|
|
288
|
+
export async function diffSchema(
|
|
289
|
+
db: MigrateDB,
|
|
290
|
+
statements: MigrationStatement[],
|
|
291
|
+
): Promise<SchemaDiff> {
|
|
292
|
+
const result = await db.query(
|
|
293
|
+
"SELECT tablename FROM pg_tables WHERE schemaname = 'public'"
|
|
294
|
+
);
|
|
295
|
+
const existing = new Set(result.rows.map((r) => String(r.tablename)));
|
|
296
|
+
|
|
297
|
+
const newTables: string[] = [];
|
|
298
|
+
const existingTables: string[] = [];
|
|
299
|
+
|
|
300
|
+
for (const stmt of statements) {
|
|
301
|
+
if (existing.has(stmt.prefixedName)) {
|
|
302
|
+
existingTables.push(stmt.prefixedName);
|
|
303
|
+
} else {
|
|
304
|
+
newTables.push(stmt.prefixedName);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return { newTables, existingTables };
|
|
309
|
+
}
|