@useatlas/create 0.0.5 → 0.0.7

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.
Files changed (952) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/index.ts +253 -36
  4. package/package.json +4 -4
  5. package/templates/docker/Dockerfile +1 -1
  6. package/templates/docker/Dockerfile.sidecar +1 -1
  7. package/templates/docker/bin/__tests__/duckdb-ingest.test.ts +17 -14
  8. package/templates/docker/bin/__tests__/failure-threshold.test.ts +148 -0
  9. package/templates/docker/bin/__tests__/fatal-error-propagation.test.ts +267 -0
  10. package/templates/docker/bin/__tests__/profiler-heuristics.test.ts +5 -5
  11. package/templates/docker/bin/__tests__/schema-drift.test.ts +39 -0
  12. package/templates/docker/bin/atlas.ts +981 -1819
  13. package/templates/docker/bin/benchmark.ts +14 -16
  14. package/templates/docker/bin/enrich.ts +7 -2
  15. package/templates/docker/brand.css +13 -0
  16. package/templates/docker/data/cybersec-semantic/catalog.yml +222 -0
  17. package/templates/docker/data/cybersec-semantic/entities/alerts.yml +195 -0
  18. package/templates/docker/data/cybersec-semantic/entities/assets.yml +191 -0
  19. package/templates/docker/data/cybersec-semantic/entities/compliance_assessments.yml +170 -0
  20. package/templates/docker/data/cybersec-semantic/entities/incidents.yml +219 -0
  21. package/templates/docker/data/cybersec-semantic/entities/organizations.yml +136 -0
  22. package/templates/docker/data/cybersec-semantic/entities/plans.yml +114 -0
  23. package/templates/docker/data/cybersec-semantic/entities/remediation_actions.yml +212 -0
  24. package/templates/docker/data/cybersec-semantic/entities/scan_results.yml +215 -0
  25. package/templates/docker/data/cybersec-semantic/entities/scans.yml +180 -0
  26. package/templates/docker/data/cybersec-semantic/entities/subscriptions.yml +184 -0
  27. package/templates/docker/data/cybersec-semantic/entities/users.yml +140 -0
  28. package/templates/docker/data/cybersec-semantic/entities/vulnerabilities.yml +154 -0
  29. package/templates/docker/data/cybersec-semantic/glossary.yml +207 -0
  30. package/templates/docker/data/cybersec-semantic/metrics/business.yml +148 -0
  31. package/templates/docker/data/cybersec-semantic/metrics/compliance.yml +138 -0
  32. package/templates/docker/data/cybersec-semantic/metrics/security.yml +181 -0
  33. package/templates/docker/data/cybersec.sql +8 -8
  34. package/templates/docker/data/demo.sql +3 -0
  35. package/templates/docker/data/ecommerce-semantic/catalog.yml +221 -0
  36. package/templates/docker/data/ecommerce-semantic/entities/categories.yml +91 -0
  37. package/templates/docker/data/ecommerce-semantic/entities/customers.yml +133 -0
  38. package/templates/docker/data/ecommerce-semantic/entities/email_campaigns.yml +119 -0
  39. package/templates/docker/data/ecommerce-semantic/entities/inventory_levels.yml +153 -0
  40. package/templates/docker/data/ecommerce-semantic/entities/order_items.yml +159 -0
  41. package/templates/docker/data/ecommerce-semantic/entities/orders.yml +199 -0
  42. package/templates/docker/data/ecommerce-semantic/entities/payments.yml +140 -0
  43. package/templates/docker/data/ecommerce-semantic/entities/product_reviews.yml +155 -0
  44. package/templates/docker/data/ecommerce-semantic/entities/products.yml +178 -0
  45. package/templates/docker/data/ecommerce-semantic/entities/promotions.yml +171 -0
  46. package/templates/docker/data/ecommerce-semantic/entities/returns.yml +144 -0
  47. package/templates/docker/data/ecommerce-semantic/entities/sellers.yml +124 -0
  48. package/templates/docker/data/ecommerce-semantic/entities/shipments.yml +159 -0
  49. package/templates/docker/data/ecommerce-semantic/glossary.yml +193 -0
  50. package/templates/docker/data/ecommerce-semantic/metrics/customers.yml +116 -0
  51. package/templates/docker/data/ecommerce-semantic/metrics/operations.yml +131 -0
  52. package/templates/docker/data/ecommerce-semantic/metrics/revenue.yml +120 -0
  53. package/templates/docker/docs/deploy.md +2 -1
  54. package/templates/docker/ee/src/__mocks__/internal.ts +170 -0
  55. package/templates/docker/ee/src/audit/purge-scheduler.ts +113 -0
  56. package/templates/docker/ee/src/audit/retention.ts +467 -0
  57. package/templates/docker/ee/src/auth/ip-allowlist.ts +367 -0
  58. package/templates/docker/ee/src/auth/roles.ts +562 -0
  59. package/templates/docker/ee/src/auth/scim.ts +343 -0
  60. package/templates/docker/ee/src/auth/sso.ts +538 -0
  61. package/templates/docker/ee/src/backups/engine.ts +355 -0
  62. package/templates/docker/ee/src/backups/index.ts +26 -0
  63. package/templates/docker/ee/src/backups/restore.ts +169 -0
  64. package/templates/docker/ee/src/backups/scheduler.ts +153 -0
  65. package/templates/docker/ee/src/backups/verify.ts +124 -0
  66. package/templates/docker/ee/src/branding/white-label.ts +228 -0
  67. package/templates/docker/ee/src/compliance/masking.ts +477 -0
  68. package/templates/docker/ee/src/compliance/patterns.ts +16 -0
  69. package/templates/docker/ee/src/compliance/pii-detection.ts +217 -0
  70. package/templates/docker/ee/src/compliance/reports.ts +402 -0
  71. package/templates/docker/ee/src/deploy-mode.ts +37 -0
  72. package/templates/docker/ee/src/governance/approval.ts +699 -0
  73. package/templates/docker/ee/src/index.ts +74 -0
  74. package/templates/docker/ee/src/platform/domains.ts +562 -0
  75. package/templates/docker/ee/src/platform/model-routing.ts +382 -0
  76. package/templates/docker/ee/src/platform/residency.ts +265 -0
  77. package/templates/docker/ee/src/sla/alerting.ts +382 -0
  78. package/templates/docker/ee/src/sla/index.ts +12 -0
  79. package/templates/docker/ee/src/sla/metrics.ts +275 -0
  80. package/templates/docker/ee/src/test-setup.ts +1 -0
  81. package/templates/docker/next.config.ts +4 -1
  82. package/templates/docker/package.json +49 -29
  83. package/templates/docker/sidecar/Dockerfile +1 -1
  84. package/templates/docker/src/api/index.ts +336 -24
  85. package/templates/docker/src/api/routes/actions.ts +443 -176
  86. package/templates/docker/src/api/routes/admin-abuse.ts +219 -0
  87. package/templates/docker/src/api/routes/admin-approval.ts +418 -0
  88. package/templates/docker/src/api/routes/admin-audit-retention.ts +405 -0
  89. package/templates/docker/src/api/routes/admin-auth.ts +122 -0
  90. package/templates/docker/src/api/routes/admin-branding.ts +252 -0
  91. package/templates/docker/src/api/routes/admin-compliance.ts +352 -0
  92. package/templates/docker/src/api/routes/admin-domains.ts +334 -0
  93. package/templates/docker/src/api/routes/admin-integrations.ts +2667 -0
  94. package/templates/docker/src/api/routes/admin-ip-allowlist.ts +261 -0
  95. package/templates/docker/src/api/routes/admin-learned-patterns.ts +525 -0
  96. package/templates/docker/src/api/routes/admin-model-config.ts +252 -0
  97. package/templates/docker/src/api/routes/admin-onboarding-emails.ts +145 -0
  98. package/templates/docker/src/api/routes/admin-orgs.ts +710 -0
  99. package/templates/docker/src/api/routes/admin-prompts.ts +694 -0
  100. package/templates/docker/src/api/routes/admin-residency.ts +570 -0
  101. package/templates/docker/src/api/routes/admin-roles.ts +296 -0
  102. package/templates/docker/src/api/routes/admin-router.ts +120 -0
  103. package/templates/docker/src/api/routes/admin-sandbox.ts +417 -0
  104. package/templates/docker/src/api/routes/admin-scim.ts +262 -0
  105. package/templates/docker/src/api/routes/admin-sso.ts +545 -0
  106. package/templates/docker/src/api/routes/admin-suggestions.ts +176 -0
  107. package/templates/docker/src/api/routes/admin-usage.ts +310 -0
  108. package/templates/docker/src/api/routes/admin.ts +4156 -898
  109. package/templates/docker/src/api/routes/auth-preamble.ts +105 -0
  110. package/templates/docker/src/api/routes/billing.ts +397 -0
  111. package/templates/docker/src/api/routes/chat.ts +597 -334
  112. package/templates/docker/src/api/routes/conversations.ts +987 -132
  113. package/templates/docker/src/api/routes/demo.ts +673 -0
  114. package/templates/docker/src/api/routes/discord.ts +274 -0
  115. package/templates/docker/src/api/routes/ee-error-handler.ts +32 -0
  116. package/templates/docker/src/api/routes/health.ts +129 -14
  117. package/templates/docker/src/api/routes/middleware.ts +244 -0
  118. package/templates/docker/src/api/routes/onboarding-emails.ts +134 -0
  119. package/templates/docker/src/api/routes/onboarding.ts +1109 -0
  120. package/templates/docker/src/api/routes/openapi.ts +184 -1597
  121. package/templates/docker/src/api/routes/platform-admin.ts +760 -0
  122. package/templates/docker/src/api/routes/platform-backups.ts +436 -0
  123. package/templates/docker/src/api/routes/platform-domains.ts +235 -0
  124. package/templates/docker/src/api/routes/platform-residency.ts +257 -0
  125. package/templates/docker/src/api/routes/platform-sla.ts +379 -0
  126. package/templates/docker/src/api/routes/prompts.ts +221 -0
  127. package/templates/docker/src/api/routes/public-branding.ts +106 -0
  128. package/templates/docker/src/api/routes/query.ts +330 -219
  129. package/templates/docker/src/api/routes/scheduled-tasks.ts +393 -297
  130. package/templates/docker/src/api/routes/semantic.ts +179 -0
  131. package/templates/docker/src/api/routes/sessions.ts +210 -0
  132. package/templates/docker/src/api/routes/shared-domains.ts +98 -0
  133. package/templates/docker/src/api/routes/shared-schemas.ts +139 -0
  134. package/templates/docker/src/api/routes/slack.ts +209 -52
  135. package/templates/docker/src/api/routes/suggestions.ts +233 -0
  136. package/templates/docker/src/api/routes/tables.ts +67 -0
  137. package/templates/docker/src/api/routes/teams.ts +222 -0
  138. package/templates/docker/src/api/routes/validate-sql.ts +188 -0
  139. package/templates/docker/src/api/routes/validation-hook.ts +62 -0
  140. package/templates/docker/src/api/routes/widget-loader.ts +356 -0
  141. package/templates/docker/src/api/routes/widget.ts +428 -0
  142. package/templates/docker/src/api/routes/wizard.ts +852 -0
  143. package/templates/docker/src/api/server.ts +187 -69
  144. package/templates/docker/src/app/error.tsx +5 -2
  145. package/templates/docker/src/app/globals.css +1 -1
  146. package/templates/docker/src/app/layout.tsx +7 -2
  147. package/templates/docker/src/app/page.tsx +39 -5
  148. package/templates/docker/src/components/data-table/data-table-column-header.tsx +99 -0
  149. package/templates/docker/src/components/data-table/data-table-date-filter.tsx +225 -0
  150. package/templates/docker/src/components/data-table/data-table-expandable.tsx +125 -0
  151. package/templates/docker/src/components/data-table/data-table-faceted-filter.tsx +189 -0
  152. package/templates/docker/src/components/data-table/data-table-pagination.tsx +112 -0
  153. package/templates/docker/src/components/data-table/data-table-range-filter.tsx +122 -0
  154. package/templates/docker/src/components/data-table/data-table-slider-filter.tsx +256 -0
  155. package/templates/docker/src/components/data-table/data-table-sort-list.tsx +407 -0
  156. package/templates/docker/src/components/data-table/data-table-toolbar.tsx +149 -0
  157. package/templates/docker/src/components/data-table/data-table-view-options.tsx +89 -0
  158. package/templates/docker/src/components/data-table/data-table.tsx +105 -0
  159. package/templates/docker/src/components/form-dialog.tsx +135 -0
  160. package/templates/docker/src/components/ui/accordion.tsx +66 -0
  161. package/templates/docker/src/components/ui/calendar.tsx +220 -0
  162. package/templates/docker/src/components/ui/checkbox.tsx +32 -0
  163. package/templates/docker/src/components/ui/faceted.tsx +283 -0
  164. package/templates/docker/src/components/ui/form.tsx +167 -0
  165. package/templates/docker/src/components/ui/label.tsx +24 -0
  166. package/templates/docker/src/components/ui/popover.tsx +89 -0
  167. package/templates/docker/src/components/ui/progress.tsx +31 -0
  168. package/templates/docker/src/components/ui/scroll-area.tsx +6 -2
  169. package/templates/docker/src/components/ui/slider.tsx +63 -0
  170. package/templates/docker/src/components/ui/sortable.tsx +581 -0
  171. package/templates/docker/src/components/ui/switch.tsx +35 -0
  172. package/templates/docker/src/components/ui/textarea.tsx +18 -0
  173. package/templates/docker/src/config/data-table.ts +82 -0
  174. package/templates/docker/src/env-check.ts +74 -0
  175. package/templates/docker/src/hooks/use-callback-ref.ts +27 -0
  176. package/templates/docker/src/hooks/use-data-table.ts +316 -0
  177. package/templates/docker/src/hooks/use-debounced-callback.ts +28 -0
  178. package/templates/docker/src/lib/action-types.ts +7 -41
  179. package/templates/docker/src/lib/agent-query.ts +4 -2
  180. package/templates/docker/src/lib/agent.ts +363 -31
  181. package/templates/docker/src/lib/auth/admin-permissions.ts +38 -0
  182. package/templates/docker/src/lib/auth/audit.ts +19 -4
  183. package/templates/docker/src/lib/auth/byot.ts +3 -3
  184. package/templates/docker/src/lib/auth/client.ts +33 -3
  185. package/templates/docker/src/lib/auth/detect.ts +29 -8
  186. package/templates/docker/src/lib/auth/managed.ts +104 -14
  187. package/templates/docker/src/lib/auth/middleware.ts +53 -6
  188. package/templates/docker/src/lib/auth/migrate.ts +140 -15
  189. package/templates/docker/src/lib/auth/oauth-state.ts +123 -0
  190. package/templates/docker/src/lib/auth/org-permissions.ts +55 -0
  191. package/templates/docker/src/lib/auth/permissions.ts +26 -19
  192. package/templates/docker/src/lib/auth/server.ts +355 -9
  193. package/templates/docker/src/lib/auth/simple-key.ts +3 -3
  194. package/templates/docker/src/lib/auth/types.ts +15 -21
  195. package/templates/docker/src/lib/billing/enforcement.ts +368 -0
  196. package/templates/docker/src/lib/billing/plans.ts +155 -0
  197. package/templates/docker/src/lib/cache/index.ts +92 -0
  198. package/templates/docker/src/lib/cache/keys.ts +30 -0
  199. package/templates/docker/src/lib/cache/lru.ts +79 -0
  200. package/templates/docker/src/lib/cache/types.ts +31 -0
  201. package/templates/docker/src/lib/compose-refs.ts +62 -0
  202. package/templates/docker/src/lib/config.ts +563 -11
  203. package/templates/docker/src/lib/connection-types.ts +9 -0
  204. package/templates/docker/src/lib/conversation-types.ts +1 -25
  205. package/templates/docker/src/lib/conversations.ts +345 -14
  206. package/templates/docker/src/lib/data-table.ts +61 -0
  207. package/templates/docker/src/lib/db/connection.ts +793 -39
  208. package/templates/docker/src/lib/db/internal.ts +985 -139
  209. package/templates/docker/src/lib/db/migrate.ts +295 -0
  210. package/templates/docker/src/lib/db/migrations/0000_baseline.sql +703 -0
  211. package/templates/docker/src/lib/db/migrations/0001_teams_installations.sql +14 -0
  212. package/templates/docker/src/lib/db/migrations/0002_discord_installations.sql +14 -0
  213. package/templates/docker/src/lib/db/migrations/0003_telegram_installations.sql +15 -0
  214. package/templates/docker/src/lib/db/migrations/0004_sandbox_credentials.sql +18 -0
  215. package/templates/docker/src/lib/db/migrations/0005_oauth_state.sql +16 -0
  216. package/templates/docker/src/lib/db/migrations/0006_byot_credentials.sql +14 -0
  217. package/templates/docker/src/lib/db/migrations/0007_gchat_installations.sql +15 -0
  218. package/templates/docker/src/lib/db/migrations/0008_github_installations.sql +14 -0
  219. package/templates/docker/src/lib/db/migrations/0009_linear_installations.sql +15 -0
  220. package/templates/docker/src/lib/db/migrations/0010_whatsapp_installations.sql +14 -0
  221. package/templates/docker/src/lib/db/migrations/0011_email_installations.sql +16 -0
  222. package/templates/docker/src/lib/db/migrations/0012_region_migrations.sql +25 -0
  223. package/templates/docker/src/lib/db/schema.ts +1120 -0
  224. package/templates/docker/src/lib/db/source-rate-limit.ts +89 -139
  225. package/templates/docker/src/lib/demo.ts +308 -0
  226. package/templates/docker/src/lib/discord/store.ts +225 -0
  227. package/templates/docker/src/lib/effect/ai.ts +243 -0
  228. package/templates/docker/src/lib/effect/errors.ts +234 -0
  229. package/templates/docker/src/lib/effect/hono.ts +454 -0
  230. package/templates/docker/src/lib/effect/index.ts +137 -0
  231. package/templates/docker/src/lib/effect/layers.ts +496 -0
  232. package/templates/docker/src/lib/effect/services.ts +776 -0
  233. package/templates/docker/src/lib/effect/sql.ts +178 -0
  234. package/templates/docker/src/lib/effect/toolkit.ts +123 -0
  235. package/templates/docker/src/lib/email/delivery.ts +232 -0
  236. package/templates/docker/src/lib/email/engine.ts +349 -0
  237. package/templates/docker/src/lib/email/hooks.ts +107 -0
  238. package/templates/docker/src/lib/email/index.ts +16 -0
  239. package/templates/docker/src/lib/email/scheduler.ts +72 -0
  240. package/templates/docker/src/lib/email/sequence.ts +73 -0
  241. package/templates/docker/src/lib/email/store.ts +163 -0
  242. package/templates/docker/src/lib/email/templates.ts +215 -0
  243. package/templates/docker/src/lib/format.ts +67 -0
  244. package/templates/docker/src/lib/gchat/store.ts +202 -0
  245. package/templates/docker/src/lib/github/store.ts +197 -0
  246. package/templates/docker/src/lib/id.ts +29 -0
  247. package/templates/docker/src/lib/integrations/types.ts +166 -0
  248. package/templates/docker/src/lib/learn/pattern-analyzer.ts +224 -0
  249. package/templates/docker/src/lib/learn/pattern-cache.ts +229 -0
  250. package/templates/docker/src/lib/learn/pattern-proposer.ts +87 -0
  251. package/templates/docker/src/lib/learn/suggestion-helpers.ts +34 -0
  252. package/templates/docker/src/lib/learn/suggestions.ts +139 -0
  253. package/templates/docker/src/lib/linear/store.ts +200 -0
  254. package/templates/docker/src/lib/logger.ts +35 -3
  255. package/templates/docker/src/lib/metering.ts +272 -0
  256. package/templates/docker/src/lib/parsers.ts +99 -0
  257. package/templates/docker/src/lib/plugins/hooks.ts +13 -11
  258. package/templates/docker/src/lib/plugins/index.ts +3 -1
  259. package/templates/docker/src/lib/plugins/registry.ts +58 -6
  260. package/templates/docker/src/lib/plugins/settings.ts +147 -0
  261. package/templates/docker/src/lib/plugins/wiring.ts +6 -9
  262. package/templates/docker/src/lib/profiler.ts +1665 -0
  263. package/templates/docker/src/lib/providers.ts +188 -13
  264. package/templates/docker/src/lib/rls.ts +172 -60
  265. package/templates/docker/src/lib/sandbox/credentials.ts +206 -0
  266. package/templates/docker/src/lib/sandbox/validate.ts +179 -0
  267. package/templates/docker/src/lib/scheduled-task-types.ts +26 -94
  268. package/templates/docker/src/lib/scheduled-tasks.ts +174 -34
  269. package/templates/docker/src/lib/scheduler/delivery.ts +248 -150
  270. package/templates/docker/src/lib/scheduler/engine.ts +190 -154
  271. package/templates/docker/src/lib/scheduler/executor.ts +74 -23
  272. package/templates/docker/src/lib/scheduler/preview.ts +72 -0
  273. package/templates/docker/src/lib/security/abuse.ts +463 -0
  274. package/templates/docker/src/lib/semantic/diff.ts +267 -0
  275. package/templates/docker/src/lib/semantic/entities.ts +167 -0
  276. package/templates/docker/src/lib/semantic/files.ts +283 -0
  277. package/templates/docker/src/lib/semantic/index.ts +27 -0
  278. package/templates/docker/src/lib/{semantic-index.ts → semantic/search.ts} +80 -9
  279. package/templates/docker/src/lib/semantic/sync.ts +581 -0
  280. package/templates/docker/src/lib/{semantic.ts → semantic/whitelist.ts} +189 -3
  281. package/templates/docker/src/lib/settings.ts +817 -0
  282. package/templates/docker/src/lib/sidecar-types.ts +13 -0
  283. package/templates/docker/src/lib/slack/store.ts +134 -25
  284. package/templates/docker/src/lib/startup.ts +528 -362
  285. package/templates/docker/src/lib/teams/store.ts +216 -0
  286. package/templates/docker/src/lib/telegram/store.ts +202 -0
  287. package/templates/docker/src/lib/telemetry.ts +40 -0
  288. package/templates/docker/src/lib/tools/actions/audit.ts +8 -5
  289. package/templates/docker/src/lib/tools/actions/email.ts +3 -1
  290. package/templates/docker/src/lib/tools/actions/handler.ts +276 -93
  291. package/templates/docker/src/lib/tools/actions/jira.ts +2 -2
  292. package/templates/docker/src/lib/tools/backends/detect.ts +16 -0
  293. package/templates/docker/src/lib/tools/backends/index.ts +11 -0
  294. package/templates/docker/src/lib/tools/backends/nsjail.ts +213 -0
  295. package/templates/docker/src/lib/tools/backends/shared.ts +103 -0
  296. package/templates/docker/src/lib/tools/backends/types.ts +26 -0
  297. package/templates/docker/src/lib/tools/explore-nsjail.ts +7 -228
  298. package/templates/docker/src/lib/tools/explore-sandbox.ts +4 -29
  299. package/templates/docker/src/lib/tools/explore-sidecar.ts +18 -2
  300. package/templates/docker/src/lib/tools/explore.ts +246 -54
  301. package/templates/docker/src/lib/tools/index.ts +17 -0
  302. package/templates/docker/src/lib/tools/python-nsjail.ts +11 -139
  303. package/templates/docker/src/lib/tools/python-sandbox.ts +9 -132
  304. package/templates/docker/src/lib/tools/python-sidecar.ts +184 -3
  305. package/templates/docker/src/lib/tools/python-stream.ts +33 -0
  306. package/templates/docker/src/lib/tools/python-wrapper.ts +129 -0
  307. package/templates/docker/src/lib/tools/python.ts +115 -15
  308. package/templates/docker/src/lib/tools/registry.ts +14 -2
  309. package/templates/docker/src/lib/tools/sql.ts +778 -362
  310. package/templates/docker/src/lib/tracing.ts +16 -0
  311. package/templates/docker/src/lib/whatsapp/store.ts +198 -0
  312. package/templates/docker/src/lib/workspace.ts +89 -0
  313. package/templates/docker/src/progress.ts +121 -0
  314. package/templates/docker/src/types/data-table.ts +48 -0
  315. package/templates/docker/src/ui/atlas-chat-reexport.ts +3 -0
  316. package/templates/docker/src/ui/components/actions/action-approval-card.tsx +26 -19
  317. package/templates/docker/src/ui/components/actions/action-status-badge.tsx +3 -3
  318. package/templates/docker/src/ui/components/admin/admin-layout.tsx +57 -39
  319. package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +213 -35
  320. package/templates/docker/src/ui/components/admin/delivery-status-badge.tsx +53 -0
  321. package/templates/docker/src/ui/components/admin/empty-state.tsx +27 -6
  322. package/templates/docker/src/ui/components/admin/entity-detail.tsx +3 -52
  323. package/templates/docker/src/ui/components/admin/error-banner.tsx +2 -2
  324. package/templates/docker/src/ui/components/admin/feature-disabled.tsx +28 -5
  325. package/templates/docker/src/ui/components/admin-content-wrapper.tsx +87 -0
  326. package/templates/docker/src/ui/components/atlas-chat.tsx +449 -166
  327. package/templates/docker/src/ui/components/branding-head.tsx +41 -0
  328. package/templates/docker/src/ui/components/chart/chart-detection.ts +62 -5
  329. package/templates/docker/src/ui/components/chart/result-chart.tsx +316 -125
  330. package/templates/docker/src/ui/components/chat/api-key-bar.tsx +4 -4
  331. package/templates/docker/src/ui/components/chat/data-table.tsx +45 -4
  332. package/templates/docker/src/ui/components/chat/error-banner.tsx +86 -5
  333. package/templates/docker/src/ui/components/chat/follow-up-chips.tsx +29 -0
  334. package/templates/docker/src/ui/components/chat/markdown.tsx +24 -0
  335. package/templates/docker/src/ui/components/chat/prompt-library.tsx +206 -0
  336. package/templates/docker/src/ui/components/chat/python-result-card.tsx +106 -78
  337. package/templates/docker/src/ui/components/chat/result-card-base.tsx +101 -0
  338. package/templates/docker/src/ui/components/chat/share-dialog.tsx +377 -0
  339. package/templates/docker/src/ui/components/chat/sql-result-card.tsx +94 -73
  340. package/templates/docker/src/ui/components/chat/suggestion-chips.tsx +46 -0
  341. package/templates/docker/src/ui/components/chat/tool-part.tsx +16 -4
  342. package/templates/docker/src/ui/components/conversations/conversation-item.tsx +48 -17
  343. package/templates/docker/src/ui/components/conversations/conversation-list.tsx +38 -24
  344. package/templates/docker/src/ui/components/conversations/conversation-sidebar.tsx +66 -7
  345. package/templates/docker/src/ui/components/conversations/delete-confirmation.tsx +9 -2
  346. package/templates/docker/src/ui/components/error-boundary.tsx +66 -0
  347. package/templates/docker/src/ui/components/notebook/delete-cell-dialog.tsx +48 -0
  348. package/templates/docker/src/ui/components/notebook/fork-branch-selector.tsx +68 -0
  349. package/templates/docker/src/ui/components/notebook/notebook-cell-input.tsx +76 -0
  350. package/templates/docker/src/ui/components/notebook/notebook-cell-output.tsx +58 -0
  351. package/templates/docker/src/ui/components/notebook/notebook-cell-toolbar.tsx +91 -0
  352. package/templates/docker/src/ui/components/notebook/notebook-cell.tsx +119 -0
  353. package/templates/docker/src/ui/components/notebook/notebook-empty-state.tsx +19 -0
  354. package/templates/docker/src/ui/components/notebook/notebook-export.ts +287 -0
  355. package/templates/docker/src/ui/components/notebook/notebook-input-bar.tsx +49 -0
  356. package/templates/docker/src/ui/components/notebook/notebook-shell.tsx +266 -0
  357. package/templates/docker/src/ui/components/notebook/notebook-text-cell.tsx +152 -0
  358. package/templates/docker/src/ui/components/notebook/types.ts +39 -0
  359. package/templates/docker/src/ui/components/notebook/use-keyboard-nav.ts +109 -0
  360. package/templates/docker/src/ui/components/notebook/use-notebook.ts +684 -0
  361. package/templates/docker/src/ui/components/org-switcher.tsx +111 -0
  362. package/templates/docker/src/ui/components/region-picker.tsx +103 -0
  363. package/templates/docker/src/ui/components/schema-explorer/schema-explorer.tsx +522 -0
  364. package/templates/docker/src/ui/components/social-icons.tsx +26 -0
  365. package/templates/docker/src/ui/components/tour/guided-tour.tsx +81 -0
  366. package/templates/docker/src/ui/components/tour/index.ts +5 -0
  367. package/templates/docker/src/ui/components/tour/nav-bar.tsx +100 -0
  368. package/templates/docker/src/ui/components/tour/tour-overlay.tsx +298 -0
  369. package/templates/docker/src/ui/components/tour/tour-steps.ts +43 -0
  370. package/templates/docker/src/ui/components/tour/types.ts +21 -0
  371. package/templates/docker/src/ui/components/tour/use-tour.ts +193 -0
  372. package/templates/docker/src/ui/context-reexport.ts +3 -0
  373. package/templates/docker/src/ui/hooks/theme-init-script.ts +17 -0
  374. package/templates/docker/src/ui/hooks/use-admin-fetch.ts +38 -30
  375. package/templates/docker/src/ui/hooks/use-admin-mutation.ts +188 -0
  376. package/templates/docker/src/ui/hooks/use-atlas-transport.ts +225 -0
  377. package/templates/docker/src/ui/hooks/use-branding.ts +68 -0
  378. package/templates/docker/src/ui/hooks/use-conversations.ts +106 -83
  379. package/templates/docker/src/ui/hooks/use-dark-mode.ts +134 -10
  380. package/templates/docker/src/ui/hooks/use-deploy-mode.ts +36 -0
  381. package/templates/docker/src/ui/hooks/use-platform-admin-guard.ts +49 -0
  382. package/templates/docker/src/ui/lib/action-types.ts +11 -63
  383. package/templates/docker/src/ui/lib/admin-schemas.ts +744 -0
  384. package/templates/docker/src/ui/lib/fetch-client.ts +84 -0
  385. package/templates/docker/src/ui/lib/fetch-error.ts +54 -0
  386. package/templates/docker/src/ui/lib/helpers.ts +94 -1
  387. package/templates/docker/src/ui/lib/types.ts +149 -140
  388. package/templates/docker/tsconfig.json +4 -2
  389. package/templates/nextjs-standalone/bin/__tests__/duckdb-ingest.test.ts +17 -14
  390. package/templates/nextjs-standalone/bin/__tests__/failure-threshold.test.ts +148 -0
  391. package/templates/nextjs-standalone/bin/__tests__/fatal-error-propagation.test.ts +267 -0
  392. package/templates/nextjs-standalone/bin/__tests__/profiler-heuristics.test.ts +5 -5
  393. package/templates/nextjs-standalone/bin/__tests__/schema-drift.test.ts +39 -0
  394. package/templates/nextjs-standalone/bin/atlas.ts +981 -1819
  395. package/templates/nextjs-standalone/bin/benchmark.ts +14 -16
  396. package/templates/nextjs-standalone/bin/enrich.ts +7 -2
  397. package/templates/nextjs-standalone/brand.css +13 -0
  398. package/templates/nextjs-standalone/data/cybersec-semantic/catalog.yml +222 -0
  399. package/templates/nextjs-standalone/data/cybersec-semantic/entities/alerts.yml +195 -0
  400. package/templates/nextjs-standalone/data/cybersec-semantic/entities/assets.yml +191 -0
  401. package/templates/nextjs-standalone/data/cybersec-semantic/entities/compliance_assessments.yml +170 -0
  402. package/templates/nextjs-standalone/data/cybersec-semantic/entities/incidents.yml +219 -0
  403. package/templates/nextjs-standalone/data/cybersec-semantic/entities/organizations.yml +136 -0
  404. package/templates/nextjs-standalone/data/cybersec-semantic/entities/plans.yml +114 -0
  405. package/templates/nextjs-standalone/data/cybersec-semantic/entities/remediation_actions.yml +212 -0
  406. package/templates/nextjs-standalone/data/cybersec-semantic/entities/scan_results.yml +215 -0
  407. package/templates/nextjs-standalone/data/cybersec-semantic/entities/scans.yml +180 -0
  408. package/templates/nextjs-standalone/data/cybersec-semantic/entities/subscriptions.yml +184 -0
  409. package/templates/nextjs-standalone/data/cybersec-semantic/entities/users.yml +140 -0
  410. package/templates/nextjs-standalone/data/cybersec-semantic/entities/vulnerabilities.yml +154 -0
  411. package/templates/nextjs-standalone/data/cybersec-semantic/glossary.yml +207 -0
  412. package/templates/nextjs-standalone/data/cybersec-semantic/metrics/business.yml +148 -0
  413. package/templates/nextjs-standalone/data/cybersec-semantic/metrics/compliance.yml +138 -0
  414. package/templates/nextjs-standalone/data/cybersec-semantic/metrics/security.yml +181 -0
  415. package/templates/nextjs-standalone/data/cybersec.sql +8 -8
  416. package/templates/nextjs-standalone/data/demo.sql +3 -0
  417. package/templates/nextjs-standalone/data/ecommerce-semantic/catalog.yml +221 -0
  418. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/categories.yml +91 -0
  419. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/customers.yml +133 -0
  420. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/email_campaigns.yml +119 -0
  421. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/inventory_levels.yml +153 -0
  422. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/order_items.yml +159 -0
  423. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/orders.yml +199 -0
  424. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/payments.yml +140 -0
  425. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/product_reviews.yml +155 -0
  426. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/products.yml +178 -0
  427. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/promotions.yml +171 -0
  428. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/returns.yml +144 -0
  429. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/sellers.yml +124 -0
  430. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/shipments.yml +159 -0
  431. package/templates/nextjs-standalone/data/ecommerce-semantic/glossary.yml +193 -0
  432. package/templates/nextjs-standalone/data/ecommerce-semantic/metrics/customers.yml +116 -0
  433. package/templates/nextjs-standalone/data/ecommerce-semantic/metrics/operations.yml +131 -0
  434. package/templates/nextjs-standalone/data/ecommerce-semantic/metrics/revenue.yml +120 -0
  435. package/templates/nextjs-standalone/docs/deploy.md +2 -1
  436. package/templates/nextjs-standalone/ee/src/__mocks__/internal.ts +170 -0
  437. package/templates/nextjs-standalone/ee/src/audit/purge-scheduler.ts +113 -0
  438. package/templates/nextjs-standalone/ee/src/audit/retention.ts +467 -0
  439. package/templates/nextjs-standalone/ee/src/auth/ip-allowlist.ts +367 -0
  440. package/templates/nextjs-standalone/ee/src/auth/roles.ts +562 -0
  441. package/templates/nextjs-standalone/ee/src/auth/scim.ts +343 -0
  442. package/templates/nextjs-standalone/ee/src/auth/sso.ts +538 -0
  443. package/templates/nextjs-standalone/ee/src/backups/engine.ts +355 -0
  444. package/templates/nextjs-standalone/ee/src/backups/index.ts +26 -0
  445. package/templates/nextjs-standalone/ee/src/backups/restore.ts +169 -0
  446. package/templates/nextjs-standalone/ee/src/backups/scheduler.ts +153 -0
  447. package/templates/nextjs-standalone/ee/src/backups/verify.ts +124 -0
  448. package/templates/nextjs-standalone/ee/src/branding/white-label.ts +228 -0
  449. package/templates/nextjs-standalone/ee/src/compliance/masking.ts +477 -0
  450. package/templates/nextjs-standalone/ee/src/compliance/patterns.ts +16 -0
  451. package/templates/nextjs-standalone/ee/src/compliance/pii-detection.ts +217 -0
  452. package/templates/nextjs-standalone/ee/src/compliance/reports.ts +402 -0
  453. package/templates/nextjs-standalone/ee/src/deploy-mode.ts +37 -0
  454. package/templates/nextjs-standalone/ee/src/governance/approval.ts +699 -0
  455. package/templates/nextjs-standalone/ee/src/index.ts +74 -0
  456. package/templates/nextjs-standalone/ee/src/platform/domains.ts +562 -0
  457. package/templates/nextjs-standalone/ee/src/platform/model-routing.ts +382 -0
  458. package/templates/nextjs-standalone/ee/src/platform/residency.ts +265 -0
  459. package/templates/nextjs-standalone/ee/src/sla/alerting.ts +382 -0
  460. package/templates/nextjs-standalone/ee/src/sla/index.ts +12 -0
  461. package/templates/nextjs-standalone/ee/src/sla/metrics.ts +275 -0
  462. package/templates/nextjs-standalone/ee/src/test-setup.ts +1 -0
  463. package/templates/nextjs-standalone/next.config.ts +1 -1
  464. package/templates/nextjs-standalone/package.json +50 -30
  465. package/templates/nextjs-standalone/src/api/index.ts +336 -24
  466. package/templates/nextjs-standalone/src/api/routes/actions.ts +443 -176
  467. package/templates/nextjs-standalone/src/api/routes/admin-abuse.ts +219 -0
  468. package/templates/nextjs-standalone/src/api/routes/admin-approval.ts +418 -0
  469. package/templates/nextjs-standalone/src/api/routes/admin-audit-retention.ts +405 -0
  470. package/templates/nextjs-standalone/src/api/routes/admin-auth.ts +122 -0
  471. package/templates/nextjs-standalone/src/api/routes/admin-branding.ts +252 -0
  472. package/templates/nextjs-standalone/src/api/routes/admin-compliance.ts +352 -0
  473. package/templates/nextjs-standalone/src/api/routes/admin-domains.ts +334 -0
  474. package/templates/nextjs-standalone/src/api/routes/admin-integrations.ts +2667 -0
  475. package/templates/nextjs-standalone/src/api/routes/admin-ip-allowlist.ts +261 -0
  476. package/templates/nextjs-standalone/src/api/routes/admin-learned-patterns.ts +525 -0
  477. package/templates/nextjs-standalone/src/api/routes/admin-model-config.ts +252 -0
  478. package/templates/nextjs-standalone/src/api/routes/admin-onboarding-emails.ts +145 -0
  479. package/templates/nextjs-standalone/src/api/routes/admin-orgs.ts +710 -0
  480. package/templates/nextjs-standalone/src/api/routes/admin-prompts.ts +694 -0
  481. package/templates/nextjs-standalone/src/api/routes/admin-residency.ts +570 -0
  482. package/templates/nextjs-standalone/src/api/routes/admin-roles.ts +296 -0
  483. package/templates/nextjs-standalone/src/api/routes/admin-router.ts +120 -0
  484. package/templates/nextjs-standalone/src/api/routes/admin-sandbox.ts +417 -0
  485. package/templates/nextjs-standalone/src/api/routes/admin-scim.ts +262 -0
  486. package/templates/nextjs-standalone/src/api/routes/admin-sso.ts +545 -0
  487. package/templates/nextjs-standalone/src/api/routes/admin-suggestions.ts +176 -0
  488. package/templates/nextjs-standalone/src/api/routes/admin-usage.ts +310 -0
  489. package/templates/nextjs-standalone/src/api/routes/admin.ts +4156 -898
  490. package/templates/nextjs-standalone/src/api/routes/auth-preamble.ts +105 -0
  491. package/templates/nextjs-standalone/src/api/routes/billing.ts +397 -0
  492. package/templates/nextjs-standalone/src/api/routes/chat.ts +597 -334
  493. package/templates/nextjs-standalone/src/api/routes/conversations.ts +987 -132
  494. package/templates/nextjs-standalone/src/api/routes/demo.ts +673 -0
  495. package/templates/nextjs-standalone/src/api/routes/discord.ts +274 -0
  496. package/templates/nextjs-standalone/src/api/routes/ee-error-handler.ts +32 -0
  497. package/templates/nextjs-standalone/src/api/routes/health.ts +129 -14
  498. package/templates/nextjs-standalone/src/api/routes/middleware.ts +244 -0
  499. package/templates/nextjs-standalone/src/api/routes/onboarding-emails.ts +134 -0
  500. package/templates/nextjs-standalone/src/api/routes/onboarding.ts +1109 -0
  501. package/templates/nextjs-standalone/src/api/routes/openapi.ts +184 -1597
  502. package/templates/nextjs-standalone/src/api/routes/platform-admin.ts +760 -0
  503. package/templates/nextjs-standalone/src/api/routes/platform-backups.ts +436 -0
  504. package/templates/nextjs-standalone/src/api/routes/platform-domains.ts +235 -0
  505. package/templates/nextjs-standalone/src/api/routes/platform-residency.ts +257 -0
  506. package/templates/nextjs-standalone/src/api/routes/platform-sla.ts +379 -0
  507. package/templates/nextjs-standalone/src/api/routes/prompts.ts +221 -0
  508. package/templates/nextjs-standalone/src/api/routes/public-branding.ts +106 -0
  509. package/templates/nextjs-standalone/src/api/routes/query.ts +330 -219
  510. package/templates/nextjs-standalone/src/api/routes/scheduled-tasks.ts +393 -297
  511. package/templates/nextjs-standalone/src/api/routes/semantic.ts +179 -0
  512. package/templates/nextjs-standalone/src/api/routes/sessions.ts +210 -0
  513. package/templates/nextjs-standalone/src/api/routes/shared-domains.ts +98 -0
  514. package/templates/nextjs-standalone/src/api/routes/shared-schemas.ts +139 -0
  515. package/templates/nextjs-standalone/src/api/routes/slack.ts +209 -52
  516. package/templates/nextjs-standalone/src/api/routes/suggestions.ts +233 -0
  517. package/templates/nextjs-standalone/src/api/routes/tables.ts +67 -0
  518. package/templates/nextjs-standalone/src/api/routes/teams.ts +222 -0
  519. package/templates/nextjs-standalone/src/api/routes/validate-sql.ts +188 -0
  520. package/templates/nextjs-standalone/src/api/routes/validation-hook.ts +62 -0
  521. package/templates/nextjs-standalone/src/api/routes/widget-loader.ts +356 -0
  522. package/templates/nextjs-standalone/src/api/routes/widget.ts +428 -0
  523. package/templates/nextjs-standalone/src/api/routes/wizard.ts +852 -0
  524. package/templates/nextjs-standalone/src/api/server.ts +187 -69
  525. package/templates/nextjs-standalone/src/app/error.tsx +5 -2
  526. package/templates/nextjs-standalone/src/app/globals.css +1 -1
  527. package/templates/nextjs-standalone/src/app/layout.tsx +7 -2
  528. package/templates/nextjs-standalone/src/app/page.tsx +39 -5
  529. package/templates/nextjs-standalone/src/components/data-table/data-table-column-header.tsx +99 -0
  530. package/templates/nextjs-standalone/src/components/data-table/data-table-date-filter.tsx +225 -0
  531. package/templates/nextjs-standalone/src/components/data-table/data-table-expandable.tsx +125 -0
  532. package/templates/nextjs-standalone/src/components/data-table/data-table-faceted-filter.tsx +189 -0
  533. package/templates/nextjs-standalone/src/components/data-table/data-table-pagination.tsx +112 -0
  534. package/templates/nextjs-standalone/src/components/data-table/data-table-range-filter.tsx +122 -0
  535. package/templates/nextjs-standalone/src/components/data-table/data-table-slider-filter.tsx +256 -0
  536. package/templates/nextjs-standalone/src/components/data-table/data-table-sort-list.tsx +407 -0
  537. package/templates/nextjs-standalone/src/components/data-table/data-table-toolbar.tsx +149 -0
  538. package/templates/nextjs-standalone/src/components/data-table/data-table-view-options.tsx +89 -0
  539. package/templates/nextjs-standalone/src/components/data-table/data-table.tsx +105 -0
  540. package/templates/nextjs-standalone/src/components/form-dialog.tsx +135 -0
  541. package/templates/nextjs-standalone/src/components/ui/accordion.tsx +66 -0
  542. package/templates/nextjs-standalone/src/components/ui/calendar.tsx +220 -0
  543. package/templates/nextjs-standalone/src/components/ui/checkbox.tsx +32 -0
  544. package/templates/nextjs-standalone/src/components/ui/faceted.tsx +283 -0
  545. package/templates/nextjs-standalone/src/components/ui/form.tsx +167 -0
  546. package/templates/nextjs-standalone/src/components/ui/label.tsx +24 -0
  547. package/templates/nextjs-standalone/src/components/ui/popover.tsx +89 -0
  548. package/templates/nextjs-standalone/src/components/ui/progress.tsx +31 -0
  549. package/templates/nextjs-standalone/src/components/ui/scroll-area.tsx +6 -2
  550. package/templates/nextjs-standalone/src/components/ui/slider.tsx +63 -0
  551. package/templates/nextjs-standalone/src/components/ui/sortable.tsx +581 -0
  552. package/templates/nextjs-standalone/src/components/ui/switch.tsx +35 -0
  553. package/templates/nextjs-standalone/src/components/ui/textarea.tsx +18 -0
  554. package/templates/nextjs-standalone/src/config/data-table.ts +82 -0
  555. package/templates/nextjs-standalone/src/env-check.ts +74 -0
  556. package/templates/nextjs-standalone/src/hooks/use-callback-ref.ts +27 -0
  557. package/templates/nextjs-standalone/src/hooks/use-data-table.ts +316 -0
  558. package/templates/nextjs-standalone/src/hooks/use-debounced-callback.ts +28 -0
  559. package/templates/nextjs-standalone/src/lib/action-types.ts +7 -41
  560. package/templates/nextjs-standalone/src/lib/agent-query.ts +4 -2
  561. package/templates/nextjs-standalone/src/lib/agent.ts +363 -31
  562. package/templates/nextjs-standalone/src/lib/api-url.ts +2 -3
  563. package/templates/nextjs-standalone/src/lib/auth/admin-permissions.ts +38 -0
  564. package/templates/nextjs-standalone/src/lib/auth/audit.ts +19 -4
  565. package/templates/nextjs-standalone/src/lib/auth/byot.ts +3 -3
  566. package/templates/nextjs-standalone/src/lib/auth/detect.ts +29 -8
  567. package/templates/nextjs-standalone/src/lib/auth/managed.ts +104 -14
  568. package/templates/nextjs-standalone/src/lib/auth/middleware.ts +53 -6
  569. package/templates/nextjs-standalone/src/lib/auth/migrate.ts +140 -15
  570. package/templates/nextjs-standalone/src/lib/auth/oauth-state.ts +123 -0
  571. package/templates/nextjs-standalone/src/lib/auth/org-permissions.ts +55 -0
  572. package/templates/nextjs-standalone/src/lib/auth/permissions.ts +26 -19
  573. package/templates/nextjs-standalone/src/lib/auth/server.ts +355 -9
  574. package/templates/nextjs-standalone/src/lib/auth/simple-key.ts +3 -3
  575. package/templates/nextjs-standalone/src/lib/auth/types.ts +15 -21
  576. package/templates/nextjs-standalone/src/lib/billing/enforcement.ts +368 -0
  577. package/templates/nextjs-standalone/src/lib/billing/plans.ts +155 -0
  578. package/templates/nextjs-standalone/src/lib/cache/index.ts +92 -0
  579. package/templates/nextjs-standalone/src/lib/cache/keys.ts +30 -0
  580. package/templates/nextjs-standalone/src/lib/cache/lru.ts +79 -0
  581. package/templates/nextjs-standalone/src/lib/cache/types.ts +31 -0
  582. package/templates/nextjs-standalone/src/lib/compose-refs.ts +62 -0
  583. package/templates/nextjs-standalone/src/lib/config.ts +563 -11
  584. package/templates/nextjs-standalone/src/lib/connection-types.ts +9 -0
  585. package/templates/nextjs-standalone/src/lib/conversation-types.ts +1 -25
  586. package/templates/nextjs-standalone/src/lib/conversations.ts +345 -14
  587. package/templates/nextjs-standalone/src/lib/data-table.ts +61 -0
  588. package/templates/nextjs-standalone/src/lib/db/connection.ts +793 -39
  589. package/templates/nextjs-standalone/src/lib/db/internal.ts +985 -139
  590. package/templates/nextjs-standalone/src/lib/db/migrate.ts +295 -0
  591. package/templates/nextjs-standalone/src/lib/db/migrations/0000_baseline.sql +703 -0
  592. package/templates/nextjs-standalone/src/lib/db/migrations/0001_teams_installations.sql +14 -0
  593. package/templates/nextjs-standalone/src/lib/db/migrations/0002_discord_installations.sql +14 -0
  594. package/templates/nextjs-standalone/src/lib/db/migrations/0003_telegram_installations.sql +15 -0
  595. package/templates/nextjs-standalone/src/lib/db/migrations/0004_sandbox_credentials.sql +18 -0
  596. package/templates/nextjs-standalone/src/lib/db/migrations/0005_oauth_state.sql +16 -0
  597. package/templates/nextjs-standalone/src/lib/db/migrations/0006_byot_credentials.sql +14 -0
  598. package/templates/nextjs-standalone/src/lib/db/migrations/0007_gchat_installations.sql +15 -0
  599. package/templates/nextjs-standalone/src/lib/db/migrations/0008_github_installations.sql +14 -0
  600. package/templates/nextjs-standalone/src/lib/db/migrations/0009_linear_installations.sql +15 -0
  601. package/templates/nextjs-standalone/src/lib/db/migrations/0010_whatsapp_installations.sql +14 -0
  602. package/templates/nextjs-standalone/src/lib/db/migrations/0011_email_installations.sql +16 -0
  603. package/templates/nextjs-standalone/src/lib/db/migrations/0012_region_migrations.sql +25 -0
  604. package/templates/nextjs-standalone/src/lib/db/schema.ts +1120 -0
  605. package/templates/nextjs-standalone/src/lib/db/source-rate-limit.ts +89 -139
  606. package/templates/nextjs-standalone/src/lib/demo.ts +308 -0
  607. package/templates/nextjs-standalone/src/lib/discord/store.ts +225 -0
  608. package/templates/nextjs-standalone/src/lib/effect/ai.ts +243 -0
  609. package/templates/nextjs-standalone/src/lib/effect/errors.ts +234 -0
  610. package/templates/nextjs-standalone/src/lib/effect/hono.ts +454 -0
  611. package/templates/nextjs-standalone/src/lib/effect/index.ts +137 -0
  612. package/templates/nextjs-standalone/src/lib/effect/layers.ts +496 -0
  613. package/templates/nextjs-standalone/src/lib/effect/services.ts +776 -0
  614. package/templates/nextjs-standalone/src/lib/effect/sql.ts +178 -0
  615. package/templates/nextjs-standalone/src/lib/effect/toolkit.ts +123 -0
  616. package/templates/nextjs-standalone/src/lib/email/delivery.ts +232 -0
  617. package/templates/nextjs-standalone/src/lib/email/engine.ts +349 -0
  618. package/templates/nextjs-standalone/src/lib/email/hooks.ts +107 -0
  619. package/templates/nextjs-standalone/src/lib/email/index.ts +16 -0
  620. package/templates/nextjs-standalone/src/lib/email/scheduler.ts +72 -0
  621. package/templates/nextjs-standalone/src/lib/email/sequence.ts +73 -0
  622. package/templates/nextjs-standalone/src/lib/email/store.ts +163 -0
  623. package/templates/nextjs-standalone/src/lib/email/templates.ts +215 -0
  624. package/templates/nextjs-standalone/src/lib/format.test.ts +117 -0
  625. package/templates/nextjs-standalone/src/lib/format.ts +67 -0
  626. package/templates/nextjs-standalone/src/lib/gchat/store.ts +202 -0
  627. package/templates/nextjs-standalone/src/lib/github/store.ts +197 -0
  628. package/templates/nextjs-standalone/src/lib/id.ts +29 -0
  629. package/templates/nextjs-standalone/src/lib/integrations/types.ts +166 -0
  630. package/templates/nextjs-standalone/src/lib/learn/pattern-analyzer.ts +224 -0
  631. package/templates/nextjs-standalone/src/lib/learn/pattern-cache.ts +229 -0
  632. package/templates/nextjs-standalone/src/lib/learn/pattern-proposer.ts +87 -0
  633. package/templates/nextjs-standalone/src/lib/learn/suggestion-helpers.ts +34 -0
  634. package/templates/nextjs-standalone/src/lib/learn/suggestions.ts +139 -0
  635. package/templates/nextjs-standalone/src/lib/linear/store.ts +200 -0
  636. package/templates/nextjs-standalone/src/lib/logger.ts +35 -3
  637. package/templates/nextjs-standalone/src/lib/metering.ts +272 -0
  638. package/templates/nextjs-standalone/src/lib/parsers.ts +99 -0
  639. package/templates/nextjs-standalone/src/lib/plugins/hooks.ts +13 -11
  640. package/templates/nextjs-standalone/src/lib/plugins/index.ts +3 -1
  641. package/templates/nextjs-standalone/src/lib/plugins/registry.ts +58 -6
  642. package/templates/nextjs-standalone/src/lib/plugins/settings.ts +147 -0
  643. package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +6 -9
  644. package/templates/nextjs-standalone/src/lib/profiler.ts +1665 -0
  645. package/templates/nextjs-standalone/src/lib/providers.ts +188 -13
  646. package/templates/nextjs-standalone/src/lib/rls.ts +172 -60
  647. package/templates/nextjs-standalone/src/lib/sandbox/credentials.ts +206 -0
  648. package/templates/nextjs-standalone/src/lib/sandbox/validate.ts +179 -0
  649. package/templates/nextjs-standalone/src/lib/scheduled-task-types.ts +26 -94
  650. package/templates/nextjs-standalone/src/lib/scheduled-tasks.ts +174 -34
  651. package/templates/nextjs-standalone/src/lib/scheduler/delivery.ts +248 -150
  652. package/templates/nextjs-standalone/src/lib/scheduler/engine.ts +190 -154
  653. package/templates/nextjs-standalone/src/lib/scheduler/executor.ts +74 -23
  654. package/templates/nextjs-standalone/src/lib/scheduler/preview.ts +72 -0
  655. package/templates/nextjs-standalone/src/lib/security/abuse.ts +463 -0
  656. package/templates/nextjs-standalone/src/lib/semantic/diff.ts +267 -0
  657. package/templates/nextjs-standalone/src/lib/semantic/entities.ts +167 -0
  658. package/templates/nextjs-standalone/src/lib/semantic/files.ts +283 -0
  659. package/templates/nextjs-standalone/src/lib/semantic/index.ts +27 -0
  660. package/templates/nextjs-standalone/src/lib/{semantic-index.ts → semantic/search.ts} +80 -9
  661. package/templates/nextjs-standalone/src/lib/semantic/sync.ts +581 -0
  662. package/templates/nextjs-standalone/src/lib/{semantic.ts → semantic/whitelist.ts} +189 -3
  663. package/templates/nextjs-standalone/src/lib/settings.ts +817 -0
  664. package/templates/nextjs-standalone/src/lib/sidecar-types.ts +13 -0
  665. package/templates/nextjs-standalone/src/lib/slack/store.ts +134 -25
  666. package/templates/nextjs-standalone/src/lib/startup.ts +528 -362
  667. package/templates/nextjs-standalone/src/lib/teams/store.ts +216 -0
  668. package/templates/nextjs-standalone/src/lib/telegram/store.ts +202 -0
  669. package/templates/nextjs-standalone/src/lib/telemetry.ts +40 -0
  670. package/templates/nextjs-standalone/src/lib/tools/actions/audit.ts +8 -5
  671. package/templates/nextjs-standalone/src/lib/tools/actions/email.ts +3 -1
  672. package/templates/nextjs-standalone/src/lib/tools/actions/handler.ts +276 -93
  673. package/templates/nextjs-standalone/src/lib/tools/actions/jira.ts +2 -2
  674. package/templates/nextjs-standalone/src/lib/tools/backends/detect.ts +16 -0
  675. package/templates/nextjs-standalone/src/lib/tools/backends/index.ts +11 -0
  676. package/templates/nextjs-standalone/src/lib/tools/backends/nsjail.ts +213 -0
  677. package/templates/nextjs-standalone/src/lib/tools/backends/shared.ts +103 -0
  678. package/templates/nextjs-standalone/src/lib/tools/backends/types.ts +26 -0
  679. package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +7 -228
  680. package/templates/nextjs-standalone/src/lib/tools/explore-sandbox.ts +4 -29
  681. package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +18 -2
  682. package/templates/nextjs-standalone/src/lib/tools/explore.ts +246 -54
  683. package/templates/nextjs-standalone/src/lib/tools/index.ts +17 -0
  684. package/templates/nextjs-standalone/src/lib/tools/python-nsjail.ts +11 -139
  685. package/templates/nextjs-standalone/src/lib/tools/python-sandbox.ts +9 -132
  686. package/templates/nextjs-standalone/src/lib/tools/python-sidecar.ts +184 -3
  687. package/templates/nextjs-standalone/src/lib/tools/python-stream.ts +33 -0
  688. package/templates/nextjs-standalone/src/lib/tools/python-wrapper.ts +129 -0
  689. package/templates/nextjs-standalone/src/lib/tools/python.ts +115 -15
  690. package/templates/nextjs-standalone/src/lib/tools/registry.ts +14 -2
  691. package/templates/nextjs-standalone/src/lib/tools/sql.ts +778 -362
  692. package/templates/nextjs-standalone/src/lib/tracing.ts +16 -0
  693. package/templates/nextjs-standalone/src/lib/whatsapp/store.ts +198 -0
  694. package/templates/nextjs-standalone/src/lib/workspace.ts +89 -0
  695. package/templates/nextjs-standalone/src/progress.ts +121 -0
  696. package/templates/nextjs-standalone/src/types/data-table.ts +48 -0
  697. package/templates/nextjs-standalone/src/ui/atlas-chat-reexport.ts +3 -0
  698. package/templates/nextjs-standalone/src/ui/components/actions/action-approval-card.tsx +26 -19
  699. package/templates/nextjs-standalone/src/ui/components/actions/action-status-badge.tsx +3 -3
  700. package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +57 -39
  701. package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +213 -35
  702. package/templates/nextjs-standalone/src/ui/components/admin/delivery-status-badge.tsx +53 -0
  703. package/templates/nextjs-standalone/src/ui/components/admin/empty-state.tsx +27 -6
  704. package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +3 -52
  705. package/templates/nextjs-standalone/src/ui/components/admin/error-banner.tsx +2 -2
  706. package/templates/nextjs-standalone/src/ui/components/admin/feature-disabled.tsx +28 -5
  707. package/templates/nextjs-standalone/src/ui/components/admin-content-wrapper.tsx +87 -0
  708. package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +449 -166
  709. package/templates/nextjs-standalone/src/ui/components/branding-head.tsx +41 -0
  710. package/templates/nextjs-standalone/src/ui/components/chart/chart-detection.ts +62 -5
  711. package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +316 -125
  712. package/templates/nextjs-standalone/src/ui/components/chat/api-key-bar.tsx +4 -4
  713. package/templates/nextjs-standalone/src/ui/components/chat/data-table.tsx +45 -4
  714. package/templates/nextjs-standalone/src/ui/components/chat/error-banner.tsx +86 -5
  715. package/templates/nextjs-standalone/src/ui/components/chat/follow-up-chips.tsx +29 -0
  716. package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +24 -0
  717. package/templates/nextjs-standalone/src/ui/components/chat/prompt-library.tsx +206 -0
  718. package/templates/nextjs-standalone/src/ui/components/chat/python-result-card.tsx +106 -78
  719. package/templates/nextjs-standalone/src/ui/components/chat/result-card-base.tsx +101 -0
  720. package/templates/nextjs-standalone/src/ui/components/chat/share-dialog.tsx +377 -0
  721. package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +94 -73
  722. package/templates/nextjs-standalone/src/ui/components/chat/suggestion-chips.tsx +46 -0
  723. package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +16 -4
  724. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +48 -17
  725. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-list.tsx +38 -24
  726. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-sidebar.tsx +66 -7
  727. package/templates/nextjs-standalone/src/ui/components/conversations/delete-confirmation.tsx +9 -2
  728. package/templates/nextjs-standalone/src/ui/components/error-boundary.tsx +66 -0
  729. package/templates/nextjs-standalone/src/ui/components/notebook/delete-cell-dialog.tsx +48 -0
  730. package/templates/nextjs-standalone/src/ui/components/notebook/fork-branch-selector.tsx +68 -0
  731. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell-input.tsx +76 -0
  732. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell-output.tsx +58 -0
  733. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell-toolbar.tsx +91 -0
  734. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell.tsx +119 -0
  735. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-empty-state.tsx +19 -0
  736. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-export.ts +287 -0
  737. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-input-bar.tsx +49 -0
  738. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-shell.tsx +266 -0
  739. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-text-cell.tsx +152 -0
  740. package/templates/nextjs-standalone/src/ui/components/notebook/types.ts +39 -0
  741. package/templates/nextjs-standalone/src/ui/components/notebook/use-keyboard-nav.ts +109 -0
  742. package/templates/nextjs-standalone/src/ui/components/notebook/use-notebook.ts +684 -0
  743. package/templates/nextjs-standalone/src/ui/components/org-switcher.tsx +111 -0
  744. package/templates/nextjs-standalone/src/ui/components/region-picker.tsx +103 -0
  745. package/templates/nextjs-standalone/src/ui/components/schema-explorer/schema-explorer.tsx +522 -0
  746. package/templates/nextjs-standalone/src/ui/components/social-icons.tsx +26 -0
  747. package/templates/nextjs-standalone/src/ui/components/tour/guided-tour.tsx +81 -0
  748. package/templates/nextjs-standalone/src/ui/components/tour/index.ts +5 -0
  749. package/templates/nextjs-standalone/src/ui/components/tour/nav-bar.tsx +100 -0
  750. package/templates/nextjs-standalone/src/ui/components/tour/tour-overlay.tsx +298 -0
  751. package/templates/nextjs-standalone/src/ui/components/tour/tour-steps.ts +43 -0
  752. package/templates/nextjs-standalone/src/ui/components/tour/types.ts +21 -0
  753. package/templates/nextjs-standalone/src/ui/components/tour/use-tour.ts +193 -0
  754. package/templates/nextjs-standalone/src/ui/context-reexport.ts +3 -0
  755. package/templates/nextjs-standalone/src/ui/hooks/theme-init-script.ts +17 -0
  756. package/templates/nextjs-standalone/src/ui/hooks/use-admin-fetch.ts +38 -30
  757. package/templates/nextjs-standalone/src/ui/hooks/use-admin-mutation.ts +188 -0
  758. package/templates/nextjs-standalone/src/ui/hooks/use-atlas-transport.ts +225 -0
  759. package/templates/nextjs-standalone/src/ui/hooks/use-branding.ts +68 -0
  760. package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +106 -83
  761. package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +134 -10
  762. package/templates/nextjs-standalone/src/ui/hooks/use-deploy-mode.ts +36 -0
  763. package/templates/nextjs-standalone/src/ui/hooks/use-platform-admin-guard.ts +49 -0
  764. package/templates/nextjs-standalone/src/ui/lib/action-types.ts +11 -63
  765. package/templates/nextjs-standalone/src/ui/lib/admin-schemas.ts +744 -0
  766. package/templates/nextjs-standalone/src/ui/lib/fetch-client.ts +84 -0
  767. package/templates/nextjs-standalone/src/ui/lib/fetch-error.ts +54 -0
  768. package/templates/nextjs-standalone/src/ui/lib/helpers.ts +94 -1
  769. package/templates/nextjs-standalone/src/ui/lib/types.ts +149 -140
  770. package/templates/nextjs-standalone/tsconfig.json +3 -2
  771. package/templates/docker/src/api/__tests__/actions.test.ts +0 -683
  772. package/templates/docker/src/api/__tests__/admin.test.ts +0 -820
  773. package/templates/docker/src/api/__tests__/auth.test.ts +0 -165
  774. package/templates/docker/src/api/__tests__/chat.test.ts +0 -376
  775. package/templates/docker/src/api/__tests__/conversations.test.ts +0 -555
  776. package/templates/docker/src/api/__tests__/cors.test.ts +0 -135
  777. package/templates/docker/src/api/__tests__/health-plugin.test.ts +0 -176
  778. package/templates/docker/src/api/__tests__/health.test.ts +0 -283
  779. package/templates/docker/src/api/__tests__/query.test.ts +0 -891
  780. package/templates/docker/src/api/__tests__/scheduled-tasks.test.ts +0 -601
  781. package/templates/docker/src/api/__tests__/slack.test.ts +0 -847
  782. package/templates/docker/src/lib/__tests__/agent-cache.test.ts +0 -439
  783. package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +0 -131
  784. package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +0 -166
  785. package/templates/docker/src/lib/__tests__/agent-integration.test.ts +0 -516
  786. package/templates/docker/src/lib/__tests__/config-actions.test.ts +0 -166
  787. package/templates/docker/src/lib/__tests__/config.test.ts +0 -1113
  788. package/templates/docker/src/lib/__tests__/conversations.test.ts +0 -589
  789. package/templates/docker/src/lib/__tests__/errors.test.ts +0 -256
  790. package/templates/docker/src/lib/__tests__/logger.test.ts +0 -200
  791. package/templates/docker/src/lib/__tests__/plugin-aware-validation.test.ts +0 -321
  792. package/templates/docker/src/lib/__tests__/providers.test.ts +0 -130
  793. package/templates/docker/src/lib/__tests__/rls.test.ts +0 -435
  794. package/templates/docker/src/lib/__tests__/scheduled-task-types.test.ts +0 -124
  795. package/templates/docker/src/lib/__tests__/scheduled-tasks.test.ts +0 -550
  796. package/templates/docker/src/lib/__tests__/semantic-index.test.ts +0 -547
  797. package/templates/docker/src/lib/__tests__/semantic-multisource.test.ts +0 -544
  798. package/templates/docker/src/lib/__tests__/semantic.test.ts +0 -363
  799. package/templates/docker/src/lib/__tests__/startup-actions.test.ts +0 -461
  800. package/templates/docker/src/lib/__tests__/startup-first-run.test.ts +0 -429
  801. package/templates/docker/src/lib/__tests__/startup.test.ts +0 -470
  802. package/templates/docker/src/lib/__tests__/tracing.test.ts +0 -28
  803. package/templates/docker/src/lib/auth/__tests__/audit.test.ts +0 -418
  804. package/templates/docker/src/lib/auth/__tests__/byot-integration.test.ts +0 -222
  805. package/templates/docker/src/lib/auth/__tests__/byot.test.ts +0 -366
  806. package/templates/docker/src/lib/auth/__tests__/detect.test.ts +0 -190
  807. package/templates/docker/src/lib/auth/__tests__/managed.test.ts +0 -173
  808. package/templates/docker/src/lib/auth/__tests__/middleware.test.ts +0 -456
  809. package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +0 -203
  810. package/templates/docker/src/lib/auth/__tests__/permissions.test.ts +0 -225
  811. package/templates/docker/src/lib/auth/__tests__/server.test.ts +0 -34
  812. package/templates/docker/src/lib/auth/__tests__/simple-key.test.ts +0 -176
  813. package/templates/docker/src/lib/auth/__tests__/types.test.ts +0 -44
  814. package/templates/docker/src/lib/db/__tests__/connection.test.ts +0 -144
  815. package/templates/docker/src/lib/db/__tests__/internal.test.ts +0 -387
  816. package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +0 -190
  817. package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -137
  818. package/templates/docker/src/lib/db/__tests__/registry.test.ts +0 -398
  819. package/templates/docker/src/lib/db/__tests__/source-rate-limit.test.ts +0 -130
  820. package/templates/docker/src/lib/errors.ts +0 -154
  821. package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +0 -204
  822. package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +0 -529
  823. package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +0 -875
  824. package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +0 -373
  825. package/templates/docker/src/lib/plugins/__tests__/tools.test.ts +0 -49
  826. package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +0 -799
  827. package/templates/docker/src/lib/scheduler/__tests__/delivery.test.ts +0 -192
  828. package/templates/docker/src/lib/scheduler/__tests__/engine.test.ts +0 -248
  829. package/templates/docker/src/lib/scheduler/__tests__/format-email.test.ts +0 -96
  830. package/templates/docker/src/lib/scheduler/__tests__/format-slack.test.ts +0 -78
  831. package/templates/docker/src/lib/scheduler/__tests__/format-webhook.test.ts +0 -78
  832. package/templates/docker/src/lib/scheduler/index.ts +0 -7
  833. package/templates/docker/src/lib/slack/__tests__/api.test.ts +0 -160
  834. package/templates/docker/src/lib/slack/__tests__/format.test.ts +0 -237
  835. package/templates/docker/src/lib/slack/__tests__/store.test.ts +0 -188
  836. package/templates/docker/src/lib/slack/__tests__/threads.test.ts +0 -112
  837. package/templates/docker/src/lib/slack/__tests__/verify.test.ts +0 -111
  838. package/templates/docker/src/lib/tools/__tests__/action-permissions.test.ts +0 -594
  839. package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +0 -240
  840. package/templates/docker/src/lib/tools/__tests__/explore-backend.test.ts +0 -267
  841. package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +0 -506
  842. package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +0 -374
  843. package/templates/docker/src/lib/tools/__tests__/explore-sdk-compat.test.ts +0 -82
  844. package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +0 -210
  845. package/templates/docker/src/lib/tools/__tests__/python-nsjail.test.ts +0 -515
  846. package/templates/docker/src/lib/tools/__tests__/python-sandbox.test.ts +0 -397
  847. package/templates/docker/src/lib/tools/__tests__/python-sidecar.test.ts +0 -365
  848. package/templates/docker/src/lib/tools/__tests__/python.test.ts +0 -331
  849. package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +0 -132
  850. package/templates/docker/src/lib/tools/__tests__/registry.test.ts +0 -242
  851. package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +0 -227
  852. package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +0 -100
  853. package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +0 -227
  854. package/templates/docker/src/lib/tools/__tests__/sql.test.ts +0 -709
  855. package/templates/docker/src/lib/tools/actions/__tests__/audit.test.ts +0 -211
  856. package/templates/docker/src/lib/tools/actions/__tests__/email.test.ts +0 -378
  857. package/templates/docker/src/lib/tools/actions/__tests__/handler.test.ts +0 -681
  858. package/templates/docker/src/lib/tools/actions/__tests__/jira.test.ts +0 -427
  859. package/templates/docker/src/test-setup.ts +0 -38
  860. package/templates/docker/src/types/vercel-sandbox.d.ts +0 -61
  861. package/templates/docker/src/ui/components/chat/managed-auth-card.tsx +0 -116
  862. package/templates/nextjs-standalone/src/api/__tests__/actions.test.ts +0 -683
  863. package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +0 -820
  864. package/templates/nextjs-standalone/src/api/__tests__/auth.test.ts +0 -165
  865. package/templates/nextjs-standalone/src/api/__tests__/chat.test.ts +0 -376
  866. package/templates/nextjs-standalone/src/api/__tests__/conversations.test.ts +0 -555
  867. package/templates/nextjs-standalone/src/api/__tests__/cors.test.ts +0 -135
  868. package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +0 -176
  869. package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +0 -283
  870. package/templates/nextjs-standalone/src/api/__tests__/query.test.ts +0 -891
  871. package/templates/nextjs-standalone/src/api/__tests__/scheduled-tasks.test.ts +0 -601
  872. package/templates/nextjs-standalone/src/api/__tests__/slack.test.ts +0 -847
  873. package/templates/nextjs-standalone/src/app/global-error.tsx +0 -68
  874. package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +0 -439
  875. package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +0 -131
  876. package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +0 -166
  877. package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +0 -516
  878. package/templates/nextjs-standalone/src/lib/__tests__/config-actions.test.ts +0 -166
  879. package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +0 -1113
  880. package/templates/nextjs-standalone/src/lib/__tests__/conversations.test.ts +0 -589
  881. package/templates/nextjs-standalone/src/lib/__tests__/errors.test.ts +0 -256
  882. package/templates/nextjs-standalone/src/lib/__tests__/logger.test.ts +0 -200
  883. package/templates/nextjs-standalone/src/lib/__tests__/plugin-aware-validation.test.ts +0 -321
  884. package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +0 -130
  885. package/templates/nextjs-standalone/src/lib/__tests__/rls.test.ts +0 -435
  886. package/templates/nextjs-standalone/src/lib/__tests__/scheduled-task-types.test.ts +0 -124
  887. package/templates/nextjs-standalone/src/lib/__tests__/scheduled-tasks.test.ts +0 -550
  888. package/templates/nextjs-standalone/src/lib/__tests__/semantic-index.test.ts +0 -547
  889. package/templates/nextjs-standalone/src/lib/__tests__/semantic-multisource.test.ts +0 -544
  890. package/templates/nextjs-standalone/src/lib/__tests__/semantic.test.ts +0 -363
  891. package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +0 -461
  892. package/templates/nextjs-standalone/src/lib/__tests__/startup-first-run.test.ts +0 -429
  893. package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +0 -470
  894. package/templates/nextjs-standalone/src/lib/__tests__/tracing.test.ts +0 -28
  895. package/templates/nextjs-standalone/src/lib/auth/__tests__/audit.test.ts +0 -418
  896. package/templates/nextjs-standalone/src/lib/auth/__tests__/byot-integration.test.ts +0 -222
  897. package/templates/nextjs-standalone/src/lib/auth/__tests__/byot.test.ts +0 -366
  898. package/templates/nextjs-standalone/src/lib/auth/__tests__/detect.test.ts +0 -190
  899. package/templates/nextjs-standalone/src/lib/auth/__tests__/managed.test.ts +0 -173
  900. package/templates/nextjs-standalone/src/lib/auth/__tests__/middleware.test.ts +0 -456
  901. package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +0 -203
  902. package/templates/nextjs-standalone/src/lib/auth/__tests__/permissions.test.ts +0 -225
  903. package/templates/nextjs-standalone/src/lib/auth/__tests__/server.test.ts +0 -34
  904. package/templates/nextjs-standalone/src/lib/auth/__tests__/simple-key.test.ts +0 -176
  905. package/templates/nextjs-standalone/src/lib/auth/__tests__/types.test.ts +0 -44
  906. package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +0 -144
  907. package/templates/nextjs-standalone/src/lib/db/__tests__/internal.test.ts +0 -387
  908. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +0 -190
  909. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -137
  910. package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +0 -398
  911. package/templates/nextjs-standalone/src/lib/db/__tests__/source-rate-limit.test.ts +0 -130
  912. package/templates/nextjs-standalone/src/lib/errors.ts +0 -154
  913. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +0 -204
  914. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +0 -529
  915. package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +0 -875
  916. package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +0 -373
  917. package/templates/nextjs-standalone/src/lib/plugins/__tests__/tools.test.ts +0 -49
  918. package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +0 -799
  919. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/delivery.test.ts +0 -192
  920. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/engine.test.ts +0 -248
  921. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-email.test.ts +0 -96
  922. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-slack.test.ts +0 -78
  923. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-webhook.test.ts +0 -78
  924. package/templates/nextjs-standalone/src/lib/scheduler/index.ts +0 -7
  925. package/templates/nextjs-standalone/src/lib/slack/__tests__/api.test.ts +0 -160
  926. package/templates/nextjs-standalone/src/lib/slack/__tests__/format.test.ts +0 -237
  927. package/templates/nextjs-standalone/src/lib/slack/__tests__/store.test.ts +0 -188
  928. package/templates/nextjs-standalone/src/lib/slack/__tests__/threads.test.ts +0 -112
  929. package/templates/nextjs-standalone/src/lib/slack/__tests__/verify.test.ts +0 -111
  930. package/templates/nextjs-standalone/src/lib/tools/__tests__/action-permissions.test.ts +0 -594
  931. package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +0 -240
  932. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-backend.test.ts +0 -267
  933. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +0 -506
  934. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +0 -374
  935. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sdk-compat.test.ts +0 -82
  936. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +0 -210
  937. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-nsjail.test.ts +0 -515
  938. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sandbox.test.ts +0 -397
  939. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sidecar.test.ts +0 -365
  940. package/templates/nextjs-standalone/src/lib/tools/__tests__/python.test.ts +0 -331
  941. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +0 -132
  942. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +0 -242
  943. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +0 -227
  944. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +0 -100
  945. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +0 -227
  946. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +0 -709
  947. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/audit.test.ts +0 -211
  948. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/email.test.ts +0 -378
  949. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/handler.test.ts +0 -681
  950. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/jira.test.ts +0 -427
  951. package/templates/nextjs-standalone/src/test-setup.ts +0 -38
  952. package/templates/nextjs-standalone/src/ui/components/chat/managed-auth-card.tsx +0 -116
@@ -15,22 +15,89 @@
15
15
 
16
16
  import { tool } from "ai";
17
17
  import { z } from "zod";
18
+ import { Effect } from "effect";
18
19
  import { Parser } from "node-sql-parser";
19
- import { connections, detectDBType } from "@atlas/api/lib/db/connection";
20
+ import { connections, detectDBType, ConnectionNotRegisteredError, NoDatasourceConfiguredError, PoolCapacityExceededError } from "@atlas/api/lib/db/connection";
20
21
  import type { DBConnection, DBType } from "@atlas/api/lib/db/connection";
21
- import { getWhitelistedTables } from "@atlas/api/lib/semantic";
22
+ import { getWhitelistedTables, getOrgWhitelistedTables } from "@atlas/api/lib/semantic";
22
23
  import { logQueryAudit } from "@atlas/api/lib/auth/audit";
23
24
  import { SENSITIVE_PATTERNS } from "@atlas/api/lib/security";
24
25
  import { withSpan } from "@atlas/api/lib/tracing";
25
26
  import { createLogger, getRequestContext } from "@atlas/api/lib/logger";
26
- import { acquireSourceSlot, decrementSourceConcurrency } from "@atlas/api/lib/db/source-rate-limit";
27
+ import { withSourceSlot } from "@atlas/api/lib/db/source-rate-limit";
27
28
  import { getConfig } from "@atlas/api/lib/config";
28
- import { resolveRLSFilters, injectRLSConditions } from "@atlas/api/lib/rls";
29
+ import { resolveRLSFilters, injectRLSConditions, type RLSFilterGroup } from "@atlas/api/lib/rls";
30
+ import { getSetting, getSettingAuto } from "@atlas/api/lib/settings";
31
+ import { getCache, buildCacheKey, cacheEnabled, getDefaultTtl } from "@atlas/api/lib/cache/index";
32
+ import { proposePatternIfNovel } from "@atlas/api/lib/learn/pattern-proposer";
33
+ import {
34
+ ConnectionNotFoundError, PoolExhaustedError, NoDatasourceError,
35
+ QueryExecutionError, RateLimitExceededError, ConcurrencyLimitError,
36
+ RLSError, PluginRejectedError,
37
+ } from "@atlas/api/lib/effect/errors";
29
38
 
30
39
  const log = createLogger("sql");
31
40
 
32
41
  const parser = new Parser();
33
42
 
43
+ // ── Classification ──────────────────────────────────────────────────
44
+
45
+ interface SQLClassification {
46
+ readonly tablesAccessed: string[];
47
+ readonly columnsAccessed: string[];
48
+ }
49
+
50
+ type SQLValidationResult =
51
+ | { valid: true; error?: undefined; classification: SQLClassification }
52
+ | { valid: false; error: string; classification?: undefined };
53
+
54
+ /**
55
+ * Extract table and column references from validated SQL.
56
+ *
57
+ * Uses node-sql-parser's tableList/columnList helpers.
58
+ * CTE names are excluded from tablesAccessed.
59
+ * SELECT * is stored as ["*"] in columnsAccessed.
60
+ * Best-effort: returns empty arrays on extraction failure.
61
+ */
62
+ export function extractClassification(
63
+ sql: string,
64
+ dialect: string,
65
+ cteNames: Set<string>,
66
+ ): SQLClassification {
67
+ try {
68
+ const tableRefs = parser.tableList(sql, { database: dialect });
69
+ const tablesAccessed = [...new Set(
70
+ tableRefs
71
+ .map((ref) => {
72
+ const parts = ref.split("::");
73
+ return parts.pop()?.toLowerCase() ?? "";
74
+ })
75
+ .filter((t) => t && !cteNames.has(t)),
76
+ )];
77
+
78
+ const columnRefs = parser.columnList(sql, { database: dialect });
79
+ const columnsAccessed = [...new Set(
80
+ columnRefs
81
+ .map((ref) => {
82
+ const parts = ref.split("::");
83
+ const col = parts.pop() ?? "";
84
+ // node-sql-parser uses "(.*)" for SELECT *
85
+ if (col === "(.*)") return "*";
86
+ return col.toLowerCase();
87
+ })
88
+ .filter(Boolean),
89
+ )];
90
+
91
+ return { tablesAccessed, columnsAccessed };
92
+ } catch (err) {
93
+ log.warn(
94
+ { err: err instanceof Error ? err : new Error(String(err)), sql: sql.slice(0, 200), dialect },
95
+ "Classification extraction failed — storing empty arrays",
96
+ );
97
+ return { tablesAccessed: [], columnsAccessed: [] };
98
+ }
99
+ }
100
+
34
101
  /**
35
102
  * Strip SQL comments for regex guard testing.
36
103
  *
@@ -130,7 +197,7 @@ function getExtraPatterns(dbType: DBType | string, connectionId?: string): RegEx
130
197
  }
131
198
  }
132
199
 
133
- export function validateSQL(sql: string, connectionId?: string): { valid: boolean; error?: string } {
200
+ export function validateSQL(sql: string, connectionId?: string): SQLValidationResult {
134
201
  // Resolve DB type for this connection.
135
202
  // When an explicit connectionId is given but not found, return a validation
136
203
  // error instead of silently falling back — wrong parser mode is a security risk.
@@ -139,14 +206,14 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
139
206
  try {
140
207
  dbType = connections.getDBType(connectionId);
141
208
  } catch (err) {
142
- log.debug({ err, connectionId }, "getDBType failed for connectionId");
209
+ log.warn({ err, connectionId }, "getDBType failed for connectionId");
143
210
  return { valid: false, error: `Connection "${connectionId}" is not registered.` };
144
211
  }
145
212
  } else {
146
213
  try {
147
214
  dbType = detectDBType();
148
215
  } catch (err) {
149
- log.debug({ err }, "detectDBType failed — no valid datasource configured");
216
+ log.warn({ err }, "detectDBType failed — no valid datasource configured");
150
217
  return { valid: false, error: "No valid datasource configured. Set ATLAS_DATASOURCE_URL to a PostgreSQL or MySQL connection string, or register a datasource plugin." };
151
218
  }
152
219
  }
@@ -196,12 +263,9 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
196
263
  error: `Only SELECT statements are allowed, got: ${stmt.type}`,
197
264
  };
198
265
  }
199
- // CTE extraction: node-sql-parser doesn't expose .with in its type definitions,
200
- // but the property exists at runtime for SELECT statements with CTEs.
201
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
202
- if (Array.isArray((stmt as any).with)) {
203
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
204
- for (const cte of (stmt as any).with) {
266
+ // Extract CTE names so they can be excluded from the table whitelist check
267
+ if (Array.isArray(stmt.with)) {
268
+ for (const cte of stmt.with) {
205
269
  const name = cte?.name?.value ?? cte?.name;
206
270
  if (typeof name === "string") cteNames.add(name.toLowerCase());
207
271
  }
@@ -215,11 +279,15 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
215
279
  };
216
280
  }
217
281
 
218
- // 3. Table whitelist check
219
- if (process.env.ATLAS_TABLE_WHITELIST !== "false") {
282
+ // 3. Table whitelist check — use getSettingAuto for SaaS hot-reload
283
+ const whitelistSetting = getSettingAuto("ATLAS_TABLE_WHITELIST") ?? process.env.ATLAS_TABLE_WHITELIST;
284
+ if (whitelistSetting !== "false") {
220
285
  try {
221
286
  const tables = parser.tableList(trimmed, { database: parserDatabase(dbType, connectionId) });
222
- const allowed = getWhitelistedTables(connectionId);
287
+ const orgId = getRequestContext()?.user?.activeOrganizationId;
288
+ const allowed = orgId
289
+ ? getOrgWhitelistedTables(orgId, connectionId)
290
+ : getWhitelistedTables(connectionId);
223
291
 
224
292
  for (const ref of tables) {
225
293
  // tableList returns "select::schema::table" format
@@ -249,9 +317,10 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
249
317
  }
250
318
  }
251
319
  }
252
- } catch {
320
+ } catch (err) {
253
321
  // Table extraction uses the same parser that just succeeded in step 2.
254
322
  // If it fails here, reject to avoid bypassing the whitelist.
323
+ log.warn({ err, sql: trimmed.slice(0, 200) }, "Table extraction failed after successful AST parse");
255
324
  return {
256
325
  valid: false,
257
326
  error: "Could not verify table permissions. Rewrite using standard SQL syntax.",
@@ -259,265 +328,207 @@ export function validateSQL(sql: string, connectionId?: string): { valid: boolea
259
328
  }
260
329
  }
261
330
 
262
- return { valid: true };
331
+ // 4. Extract classification data (best-effort, never blocks validation)
332
+ const classification = extractClassification(
333
+ trimmed,
334
+ parserDatabase(dbType, connectionId),
335
+ cteNames,
336
+ );
337
+
338
+ return { valid: true, classification };
263
339
  }
264
340
 
265
- const ROW_LIMIT = parseInt(process.env.ATLAS_ROW_LIMIT ?? "1000", 10);
266
- const QUERY_TIMEOUT = parseInt(
267
- process.env.ATLAS_QUERY_TIMEOUT ?? "30000",
268
- 10
269
- );
341
+ let lastWarnedRowLimit: string | undefined;
270
342
 
271
- export const executeSQL = tool({
272
- description: `Execute a read-only SQL query against the database. Only SELECT statements are allowed.
343
+ /** Read row limit from settings cache (DB override > env var > default). Called per-query so admin changes take effect without restart. */
344
+ function getRowLimit(): number {
345
+ const raw = getSetting("ATLAS_ROW_LIMIT") ?? "1000";
346
+ const n = parseInt(raw, 10);
347
+ if (!Number.isFinite(n) || n <= 0) {
348
+ if (raw !== lastWarnedRowLimit) {
349
+ log.warn({ value: raw }, "Invalid ATLAS_ROW_LIMIT value; using default 1000");
350
+ lastWarnedRowLimit = raw;
351
+ }
352
+ return 1000;
353
+ }
354
+ return n;
355
+ }
273
356
 
274
- Rules:
275
- - Always read the relevant entity schema from the semantic layer BEFORE writing SQL
276
- - Use exact column names from the schema — never guess
277
- - Use canonical metric SQL from metrics/*.yml when available
278
- - Include a LIMIT clause for large result sets
279
- - If a query fails, fix the issue — do not retry the same SQL`,
357
+ let lastWarnedQueryTimeout: string | undefined;
280
358
 
281
- inputSchema: z.object({
282
- sql: z.string().describe("The SELECT query to execute"),
283
- explanation: z
284
- .string()
285
- .describe("Brief explanation of what this query does and why"),
286
- connectionId: z
287
- .string()
288
- .optional()
289
- .describe(
290
- "Target connection ID. Check the entity YAML's `connection` field to determine which source a table belongs to. Omit for the default connection.",
291
- ),
292
- }),
359
+ /** Read query timeout from settings cache (DB override > env var > default). Called per-query so admin changes take effect without restart. */
360
+ function getQueryTimeout(): number {
361
+ const raw = getSetting("ATLAS_QUERY_TIMEOUT") ?? "30000";
362
+ const n = parseInt(raw, 10);
363
+ if (!Number.isFinite(n) || n <= 0) {
364
+ if (raw !== lastWarnedQueryTimeout) {
365
+ log.warn({ value: raw }, "Invalid ATLAS_QUERY_TIMEOUT value; using default 30000ms");
366
+ lastWarnedQueryTimeout = raw;
367
+ }
368
+ return 30000;
369
+ }
370
+ return n;
371
+ }
293
372
 
294
- execute: async ({ sql, explanation, connectionId }) => {
295
- const connId = connectionId ?? "default";
373
+ // ── Effect Pipeline ──────────────────────────────────────────────────
296
374
 
297
- // Validate connection exists before proceeding.
298
- // Use getDefault() for "default" to trigger lazy initialization from
299
- // ATLAS_DATASOURCE_URL — plain get("default") throws on fresh startup.
300
- let db: DBConnection;
301
- let dbType: DBType;
302
- try {
303
- if (connId === "default") {
304
- db = connections.getDefault();
305
- dbType = connections.getDBType(connId);
306
- } else {
307
- db = connections.get(connId);
308
- dbType = connections.getDBType(connId);
309
- }
310
- } catch {
311
- return {
312
- success: false,
313
- error: `Connection "${connId}" is not registered. Available: ${connections.list().join(", ") || "(none)"}`,
314
- };
315
- }
375
+ type CustomValidator = (sql: string) => { valid: boolean; reason?: string } | Promise<{ valid: boolean; reason?: string }>;
316
376
 
317
- const targetHost = connections.getTargetHost(connId);
377
+ /** Union of all errors the pipeline can produce in the error channel. */
378
+ type PipelineError =
379
+ | ConnectionNotFoundError
380
+ | PoolExhaustedError
381
+ | NoDatasourceError
382
+ | RateLimitExceededError
383
+ | ConcurrencyLimitError
384
+ | RLSError
385
+ | PluginRejectedError
386
+ | QueryExecutionError;
318
387
 
319
- // Check for a custom validator (non-SQL datasource plugins like SOQL, GraphQL).
320
- // When present, it completely replaces the standard SQL validation pipeline.
321
- // If absent, validateSQL is used instead — validators are mutually exclusive.
322
- const customValidator = connections.getValidator(connId);
323
- const normalizedSql = sql.trim().replace(/;\s*$/, "").trimEnd();
324
- if (customValidator) {
325
- let result: { valid: boolean; reason?: string };
326
- try {
327
- result = customValidator(normalizedSql);
328
- } catch (err) {
329
- const message = err instanceof Error ? err.message : String(err);
330
- log.error({ err, connectionId: connId, sql: normalizedSql.slice(0, 200) }, "Custom validator threw an exception");
331
- logQueryAudit({
332
- sql: normalizedSql.slice(0, 2000),
333
- durationMs: 0,
334
- rowCount: null,
335
- success: false,
336
- error: `Custom validator error: ${message}`,
337
- sourceId: connId,
338
- sourceType: dbType,
339
- });
340
- return { success: false, error: `Query validation failed for connection "${connId}": internal validator error` };
341
- }
342
- if (typeof result?.valid !== "boolean") {
343
- log.error({ connectionId: connId, returnValue: result }, "Custom validator returned invalid shape");
344
- logQueryAudit({
345
- sql: normalizedSql.slice(0, 2000),
346
- durationMs: 0,
347
- rowCount: null,
348
- success: false,
349
- error: "Custom validator returned invalid result",
350
- sourceId: connId,
351
- sourceType: dbType,
388
+ /** Resolve the database connection. Fails with tagged connection errors. */
389
+ function resolveConnectionEffect(
390
+ connId: string,
391
+ orgId: string | undefined,
392
+ ): Effect.Effect<
393
+ { db: DBConnection; dbType: DBType },
394
+ ConnectionNotFoundError | PoolExhaustedError | NoDatasourceError
395
+ > {
396
+ return Effect.try({
397
+ try: () => {
398
+ let db: DBConnection;
399
+ if (orgId) db = connections.getForOrg(orgId, connId);
400
+ else if (connId === "default") db = connections.getDefault();
401
+ else db = connections.get(connId);
402
+ const dbType = connections.getDBType(connId);
403
+ return { db, dbType };
404
+ },
405
+ catch: (err) => {
406
+ if (err instanceof ConnectionNotRegisteredError) {
407
+ return new ConnectionNotFoundError({
408
+ message: `Connection "${connId}" is not registered. Available: ${connections.list().join(", ") || "(none)"}`,
409
+ connectionId: connId,
410
+ available: connections.list(),
352
411
  });
353
- return { success: false, error: `Query validation misconfigured for connection "${connId}"` };
354
412
  }
355
- if (!result.valid) {
356
- logQueryAudit({
357
- sql: normalizedSql.slice(0, 2000),
358
- durationMs: 0,
359
- rowCount: null,
360
- success: false,
361
- error: `Validation rejected: ${result.reason ?? "Query rejected by custom validator"}`,
362
- sourceId: connId,
363
- sourceType: dbType,
364
- });
365
- return { success: false, error: result.reason ?? "Query rejected by custom validator" };
413
+ if (err instanceof NoDatasourceConfiguredError) {
414
+ return new NoDatasourceError({ message: (err as Error).message });
366
415
  }
367
- } else {
368
- const validation = validateSQL(sql, connId);
369
- if (!validation.valid) {
370
- logQueryAudit({
371
- sql: sql.slice(0, 2000),
372
- durationMs: 0,
373
- rowCount: null,
374
- success: false,
375
- error: `Validation rejected: ${validation.error}`,
376
- sourceId: connId,
377
- sourceType: dbType,
416
+ if (err instanceof PoolCapacityExceededError) {
417
+ log.warn({ connectionId: connId, orgId }, "Org pool capacity exceeded");
418
+ return new PoolExhaustedError({
419
+ message: "Connection pool capacity reached — the system is handling many concurrent tenants. Try again shortly.",
420
+ current: err.currentSlots,
421
+ max: err.maxTotalConnections,
378
422
  });
379
- return { success: false, error: validation.error };
380
423
  }
381
- }
382
-
383
- // Per-source rate limiting — atomic check-and-acquire
384
- const slot = acquireSourceSlot(connId);
385
- if (!slot.acquired) {
386
- logQueryAudit({
387
- sql: sql.slice(0, 2000),
388
- durationMs: 0,
389
- rowCount: null,
390
- success: false,
391
- error: `Rate limited: ${slot.reason}`,
392
- sourceId: connId,
393
- sourceType: dbType,
394
- targetHost,
424
+ const message = err instanceof Error ? err.message : String(err);
425
+ log.error({ err, connectionId: connId }, "Unexpected error during connection lookup");
426
+ return new ConnectionNotFoundError({
427
+ message: `Connection "${connId}" failed to initialize: ${message}`,
428
+ connectionId: connId,
429
+ available: connections.list(),
395
430
  });
396
- return {
397
- success: false,
398
- error: slot.reason ?? "Rate limited",
399
- ...(slot.retryAfterMs != null && { retryAfterMs: slot.retryAfterMs }),
400
- };
431
+ },
432
+ });
433
+ }
434
+
435
+ /**
436
+ * Run query validation (custom validator or standard SQL).
437
+ * Returns a result object — validation rejection is a normal outcome, not an error channel event.
438
+ * `auditError` preserves specific error detail for audit logs.
439
+ */
440
+ function runQueryValidationEffect(
441
+ sql: string,
442
+ connId: string,
443
+ dbType: DBType | string,
444
+ customValidator: CustomValidator | undefined,
445
+ ): Effect.Effect<{ ok: true; classification?: SQLClassification } | { ok: false; error: string; auditError: string }> {
446
+ if (!customValidator) {
447
+ const validation = validateSQL(sql, connId);
448
+ if (!validation.valid) {
449
+ return Effect.succeed({ ok: false as const, error: validation.error, auditError: `Validation rejected: ${validation.error}` });
401
450
  }
451
+ return Effect.succeed({ ok: true as const, classification: validation.classification });
452
+ }
402
453
 
403
- const { dispatchHook, dispatchMutableHook } = await import("@atlas/api/lib/plugins/hooks");
404
- let mutatedSql: string;
454
+ // Custom validator (async) errors are caught and returned as result values, not thrown
455
+ return Effect.promise(async () => {
456
+ let result: { valid: boolean; reason?: string };
405
457
  try {
406
- const hookCtx = { sql, connectionId: connId } as const;
407
- mutatedSql = await dispatchMutableHook(
408
- "beforeQuery",
409
- hookCtx,
410
- "sql",
411
- );
458
+ result = await customValidator(sql);
412
459
  } catch (err) {
413
460
  const message = err instanceof Error ? err.message : String(err);
414
- decrementSourceConcurrency(connId);
415
- logQueryAudit({
416
- sql: sql.slice(0, 2000),
417
- durationMs: 0,
418
- rowCount: null,
419
- success: false,
420
- error: `Plugin rejected: ${message}`,
421
- sourceId: connId,
422
- sourceType: dbType,
423
- targetHost,
424
- });
425
- return { success: false, error: `Query rejected by plugin: ${message}` };
461
+ log.error({ err, connectionId: connId, sql: sql.slice(0, 200) }, "Custom validator threw an exception");
462
+ return { ok: false as const, error: `Query validation failed for connection "${connId}": internal validator error`, auditError: `Custom validator error: ${message}` };
463
+ }
464
+ if (typeof result?.valid !== "boolean") {
465
+ log.error({ connectionId: connId, returnValue: result }, "Custom validator returned invalid shape");
466
+ return { ok: false as const, error: `Query validation misconfigured for connection "${connId}"`, auditError: "Custom validator returned invalid result" };
467
+ }
468
+ if (!result.valid) {
469
+ const reason = result.reason ?? "Query rejected by custom validator";
470
+ return { ok: false as const, error: reason, auditError: `Validation rejected: ${reason}` };
426
471
  }
472
+ return { ok: true as const, classification: undefined as SQLClassification | undefined };
473
+ });
474
+ }
427
475
 
428
- // Re-validate if a plugin rewrote the SQL a plugin could introduce DML,
429
- // disallowed tables, or invalid syntax that would bypass the initial validation
430
- let normalizedMutated = mutatedSql.trim().replace(/;\s*$/, "").trimEnd();
431
- if (normalizedMutated !== normalizedSql) {
432
- if (customValidator) {
433
- let reresult: { valid: boolean; reason?: string };
434
- try {
435
- reresult = customValidator(normalizedMutated);
436
- } catch (err) {
437
- decrementSourceConcurrency(connId);
438
- const message = err instanceof Error ? err.message : String(err);
439
- log.error({ err, connectionId: connId, sql: normalizedMutated.slice(0, 200) }, "Custom validator threw during re-validation of plugin-mutated query");
440
- logQueryAudit({
441
- sql: normalizedMutated.slice(0, 2000),
442
- durationMs: 0,
443
- rowCount: null,
444
- success: false,
445
- error: `Custom validator error on rewritten query: ${message}`,
446
- sourceId: connId,
447
- sourceType: dbType,
448
- targetHost,
449
- });
450
- return { success: false, error: `Re-validation failed for connection "${connId}": internal validator error` };
451
- }
452
- if (typeof reresult?.valid !== "boolean") {
453
- decrementSourceConcurrency(connId);
454
- log.error({ connectionId: connId, returnValue: reresult }, "Custom validator returned invalid shape during re-validation");
455
- logQueryAudit({
456
- sql: normalizedMutated.slice(0, 2000),
457
- durationMs: 0,
458
- rowCount: null,
459
- success: false,
460
- error: "Custom validator returned invalid result during re-validation",
461
- sourceId: connId,
462
- sourceType: dbType,
463
- targetHost,
464
- });
465
- return { success: false, error: `Query validation misconfigured for connection "${connId}"` };
466
- }
467
- if (!reresult.valid) {
468
- decrementSourceConcurrency(connId);
469
- logQueryAudit({
470
- sql: normalizedMutated.slice(0, 2000),
471
- durationMs: 0,
472
- rowCount: null,
473
- success: false,
474
- error: `Plugin-rewritten SQL failed validation: ${reresult.reason ?? "Query rejected by custom validator"}`,
475
- sourceId: connId,
476
- sourceType: dbType,
477
- targetHost,
478
- });
479
- return { success: false, error: `Plugin-rewritten SQL failed validation: ${reresult.reason ?? "Query rejected by custom validator"}` };
476
+ /** Apply RLS conditions. Returns the (possibly modified) SQL. Fails with RLSError. */
477
+ function applyRLSEffect(
478
+ sql: string,
479
+ connId: string,
480
+ dbType: DBType | string,
481
+ targetHost: string | undefined,
482
+ ): Effect.Effect<string, RLSError> {
483
+ return Effect.gen(function* () {
484
+ const config = getConfig();
485
+ let rlsConfig = config?.rls;
486
+
487
+ // In SaaS mode only, overlay settings-based RLS config for hot-reload.
488
+ // Only activates when there is a DB override for ATLAS_RLS_ENABLED — env
489
+ // vars and defaults are handled by the boot-time config and don't trigger
490
+ // the overlay, preserving multi-policy configs from atlas.config.ts.
491
+ if (config?.deployMode === "saas") {
492
+ const rlsEnabledSetting = getSettingAuto("ATLAS_RLS_ENABLED");
493
+ if (rlsEnabledSetting !== undefined) {
494
+ if (rlsEnabledSetting !== "true") {
495
+ // Explicitly disabled via settings — skip RLS
496
+ return sql;
480
497
  }
481
- } else {
482
- const revalidation = validateSQL(mutatedSql, connId);
483
- if (!revalidation.valid) {
484
- decrementSourceConcurrency(connId);
485
- logQueryAudit({
486
- sql: mutatedSql.slice(0, 2000),
487
- durationMs: 0,
488
- rowCount: null,
489
- success: false,
490
- error: `Plugin-rewritten SQL failed validation: ${revalidation.error}`,
491
- sourceId: connId,
492
- sourceType: dbType,
493
- targetHost,
498
+ // Setting says enabled — build/overlay config from settings
499
+ const column = getSettingAuto("ATLAS_RLS_COLUMN");
500
+ const claim = getSettingAuto("ATLAS_RLS_CLAIM");
501
+ if (column && claim) {
502
+ rlsConfig = {
503
+ enabled: true,
504
+ policies: [{ tables: ["*"], column, claim }],
505
+ combineWith: rlsConfig?.combineWith ?? "and",
506
+ };
507
+ } else {
508
+ // RLS enabled but missing required config — fail closed
509
+ log.error(
510
+ { column: !!column, claim: !!claim },
511
+ "RLS enabled via settings but ATLAS_RLS_COLUMN or ATLAS_RLS_CLAIM is missing — blocking query",
512
+ );
513
+ return yield* new RLSError({
514
+ message: "Row-level security is enabled but not fully configured. Contact your administrator.",
515
+ phase: "filter",
494
516
  });
495
- return { success: false, error: `Plugin-rewritten SQL failed validation: ${revalidation.error}` };
496
517
  }
497
518
  }
498
519
  }
499
520
 
500
- // --- RLS: inject WHERE conditions based on user claims ---
501
- // Applied after validation + plugin hooks so plugins cannot strip RLS.
502
- // Skipped for custom validators (non-SQL languages like SOQL).
503
- const config = getConfig();
504
- const rlsConfig = config?.rls;
505
- if (rlsConfig?.enabled && !customValidator) {
506
- if (!config) {
507
- // Config not loaded — fail-closed rather than risk missing RLS.
508
- decrementSourceConcurrency(connId);
509
- log.error("getConfig() returned null during RLS-enabled SQL execution — config not loaded");
510
- return { success: false, error: "Server configuration not initialized. Please retry." };
511
- }
512
- const ctx = getRequestContext();
513
- const user = ctx?.user;
521
+ if (!rlsConfig?.enabled) return sql;
514
522
 
515
- // Extract tables from the (possibly plugin-mutated) SQL
516
- let queriedTables: Set<string>;
517
- try {
523
+ const ctx = getRequestContext();
524
+ const user = ctx?.user;
525
+
526
+ // Extract tables
527
+ const queriedTables = yield* Effect.try({
528
+ try: () => {
518
529
  const dialect = parserDatabase(dbType, connId);
519
- const tableRefs = parser.tableList(normalizedMutated, { database: dialect });
520
- queriedTables = new Set(
530
+ const tableRefs = parser.tableList(sql, { database: dialect });
531
+ return new Set(
521
532
  tableRefs
522
533
  .map((ref) => {
523
534
  const parts = ref.split("::");
@@ -525,156 +536,561 @@ Rules:
525
536
  })
526
537
  .filter(Boolean),
527
538
  );
528
- } catch (tableErr) {
529
- decrementSourceConcurrency(connId);
539
+ },
540
+ catch: (tableErr) => {
530
541
  const tableErrMsg = tableErr instanceof Error ? tableErr.message : String(tableErr);
531
- log.error({ err: tableErr, sql: normalizedMutated.slice(0, 200) }, "RLS: failed to extract table list from query");
542
+ log.error({ err: tableErr, sql: sql.slice(0, 200) }, "RLS: failed to extract table list from query");
532
543
  logQueryAudit({
533
- sql: normalizedMutated.slice(0, 2000),
534
- durationMs: 0,
535
- rowCount: null,
536
- success: false,
544
+ sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
537
545
  error: `RLS: could not extract tables from query: ${tableErrMsg}`,
538
- sourceId: connId,
539
- sourceType: dbType,
540
- targetHost,
546
+ sourceId: connId, sourceType: dbType, targetHost,
541
547
  });
542
- return { success: false, error: "Query could not be analyzed for row-level security. Rewrite using standard SQL." };
543
- }
544
-
545
- const filterResult = resolveRLSFilters(user, queriedTables, rlsConfig);
546
- if ("error" in filterResult) {
547
- decrementSourceConcurrency(connId);
548
- log.warn({ error: filterResult.error, userId: user?.id }, "RLS filter resolution failed — query blocked");
549
- logQueryAudit({
550
- sql: normalizedMutated.slice(0, 2000),
551
- durationMs: 0,
552
- rowCount: null,
553
- success: false,
554
- error: `RLS blocked: ${filterResult.error}`,
555
- sourceId: connId,
556
- sourceType: dbType,
557
- targetHost,
548
+ return new RLSError({
549
+ message: "Query could not be analyzed for row-level security. Rewrite using standard SQL.",
550
+ phase: "extraction",
558
551
  });
559
- return { success: false, error: filterResult.error };
560
- }
552
+ },
553
+ });
561
554
 
562
- if (filterResult.filters.length > 0) {
563
- try {
564
- normalizedMutated = injectRLSConditions(normalizedMutated, filterResult.filters, dbType);
565
- log.debug(
566
- { filters: filterResult.filters.length, userId: user?.id },
567
- "RLS conditions injected",
568
- );
569
- } catch (err) {
570
- decrementSourceConcurrency(connId);
555
+ // Resolve filters
556
+ const filterResult = resolveRLSFilters(user, queriedTables, rlsConfig);
557
+ if ("error" in filterResult) {
558
+ log.warn({ error: filterResult.error, userId: user?.id }, "RLS filter resolution failed — query blocked");
559
+ logQueryAudit({
560
+ sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
561
+ error: `RLS blocked: ${filterResult.error}`,
562
+ sourceId: connId, sourceType: dbType, targetHost,
563
+ });
564
+ return yield* new RLSError({ message: filterResult.error, phase: "filter" });
565
+ }
566
+
567
+ // Inject conditions
568
+ const hasFilters = filterResult.groups.some((g: RLSFilterGroup) => g.filters.length > 0);
569
+ if (hasFilters) {
570
+ const injected = yield* Effect.try({
571
+ try: () => injectRLSConditions(sql, filterResult.groups, filterResult.combineWith, dbType),
572
+ catch: (err) => {
571
573
  const msg = err instanceof Error ? err.message : String(err);
572
574
  log.error({ err, userId: user?.id }, "RLS injection failed — query blocked");
573
575
  logQueryAudit({
574
- sql: normalizedMutated.slice(0, 2000),
575
- durationMs: 0,
576
- rowCount: null,
577
- success: false,
576
+ sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
578
577
  error: `RLS injection failed: ${msg}`,
579
- sourceId: connId,
580
- sourceType: dbType,
581
- targetHost,
578
+ sourceId: connId, sourceType: dbType, targetHost,
582
579
  });
583
- return { success: false, error: "Query could not be processed for row-level security." };
584
- }
585
- }
580
+ return new RLSError({ message: "Query could not be processed for row-level security.", phase: "injection" });
581
+ },
582
+ });
583
+ log.debug(
584
+ { groups: filterResult.groups.length, combineWith: filterResult.combineWith, userId: user?.id },
585
+ "RLS conditions injected",
586
+ );
587
+ return injected;
586
588
  }
587
589
 
588
- // Auto-append LIMIT if not present.
589
- // Custom validators are responsible for their own pagination — non-SQL
590
- // languages (SOQL, GraphQL) may not support the LIMIT keyword.
591
- let querySql = normalizedMutated;
592
- if (!customValidator && !/\bLIMIT\b/i.test(querySql)) {
593
- querySql += ` LIMIT ${ROW_LIMIT}`;
594
- }
590
+ return sql;
591
+ });
592
+ }
595
593
 
596
- // Includes connection acquisition time; the OTel span inside withSpan
597
- // covers only the actual query execution against the database.
598
- const start = performance.now();
599
- try {
600
- const result = await withSpan(
594
+ /**
595
+ * Execute a validated query with tracing, cache write, audit logging, plugin hooks,
596
+ * and error filtering. Called inside withSourceSlot — concurrency release is automatic.
597
+ */
598
+ function executeAndAuditEffect(opts: {
599
+ db: DBConnection;
600
+ dbType: DBType;
601
+ connId: string;
602
+ orgId: string | undefined;
603
+ targetHost: string | undefined;
604
+ querySql: string;
605
+ queryTimeout: number;
606
+ rowLimit: number;
607
+ explanation: string;
608
+ classification: SQLClassification | undefined;
609
+ cacheKey: string | null;
610
+ hookMetadata: Record<string, unknown>;
611
+ dispatchHook: (event: "afterQuery", ctx: Record<string, unknown>) => Promise<void>;
612
+ }): Effect.Effect<Record<string, unknown>, QueryExecutionError> {
613
+ const {
614
+ db, dbType, connId, orgId, targetHost, querySql, queryTimeout,
615
+ rowLimit, explanation, classification, cacheKey, hookMetadata, dispatchHook,
616
+ } = opts;
617
+
618
+ const start = performance.now();
619
+
620
+ return Effect.tryPromise({
621
+ try: () =>
622
+ withSpan(
601
623
  "atlas.sql.execute",
602
- {
603
- "db.system": dbType,
604
- "db.statement": querySql.slice(0, 200),
605
- },
606
- () => db.query(querySql, QUERY_TIMEOUT),
607
- );
624
+ { "db.system": dbType, "atlas.connection_id": connId },
625
+ () => db.query(querySql, queryTimeout),
626
+ (r) => ({ "atlas.row_count": r.rows.length, "atlas.column_count": r.columns.length }),
627
+ ),
628
+ catch: (err) => {
608
629
  const durationMs = Math.round(performance.now() - start);
609
- const truncated = result.rows.length >= ROW_LIMIT;
630
+ const message = err instanceof Error ? err.message : "Unknown database error";
631
+
632
+ connections.recordQuery(connId, durationMs, orgId);
633
+ connections.recordError(connId, orgId);
634
+
635
+ // SLA metric (fire-and-forget, enterprise feature)
636
+ if (orgId) {
637
+ import("@atlas/ee/sla/index")
638
+ .then(({ recordQueryMetric }) => recordQueryMetric(orgId, durationMs, true))
639
+ .catch((slaErr) => {
640
+ // Dynamic import failure = ee not installed (expected in non-enterprise).
641
+ // Runtime error from recordQueryMetric = log warning for diagnostics.
642
+ if (slaErr instanceof Error && !slaErr.message.includes("Cannot find module")) {
643
+ log.warn({ err: slaErr.message, connectionId: connId }, "SLA metric recording failed");
644
+ }
645
+ });
646
+ }
610
647
 
611
648
  try {
612
649
  logQueryAudit({
613
- sql: querySql,
614
- durationMs,
615
- rowCount: result.rows.length,
616
- success: true,
617
- sourceId: connId,
618
- sourceType: dbType,
619
- targetHost,
650
+ sql: querySql, durationMs, rowCount: null, success: false, error: message,
651
+ sourceId: connId, sourceType: dbType, targetHost,
652
+ tablesAccessed: classification?.tablesAccessed,
653
+ columnsAccessed: classification?.columnsAccessed,
620
654
  });
621
655
  } catch (auditErr) {
622
656
  log.warn({ err: auditErr }, "Failed to write query audit log");
623
657
  }
624
658
 
625
- await dispatchHook("afterQuery", {
626
- sql: querySql,
627
- connectionId: connId,
628
- result: { columns: result.columns, rows: result.rows },
629
- durationMs,
630
- });
659
+ // Filter sensitive errors before returning to the agent
660
+ if (SENSITIVE_PATTERNS.test(message)) {
661
+ return new QueryExecutionError({ message: "Database query failed — check server logs for details." });
662
+ }
663
+ const dbErr = err as { hint?: string; position?: string };
664
+ let detail = message;
665
+ if (dbErr.hint) detail += ` — Hint: ${dbErr.hint}`;
666
+ if (dbErr.position) detail += ` (at character ${dbErr.position})`;
667
+ return new QueryExecutionError({ message: detail, hint: dbErr.hint, position: dbErr.position });
668
+ },
669
+ }).pipe(
670
+ // Success path: metrics, cache, audit, hooks, masking
671
+ Effect.flatMap((result) =>
672
+ Effect.tryPromise({
673
+ try: async () => {
674
+ const durationMs = Math.round(performance.now() - start);
675
+ const truncated = result.rows.length >= rowLimit;
676
+
677
+ connections.recordQuery(connId, durationMs, orgId);
678
+ connections.recordSuccess(connId, orgId);
679
+
680
+ // SLA metric (fire-and-forget, enterprise feature)
681
+ if (orgId) {
682
+ try {
683
+ const { recordQueryMetric } = await import("@atlas/ee/sla/index");
684
+ recordQueryMetric(orgId, durationMs, false);
685
+ } catch (err) {
686
+ // Dynamic import failure = ee not installed (expected in non-enterprise).
687
+ // Runtime error from recordQueryMetric = log warning for diagnostics.
688
+ if (err instanceof Error && !err.message.includes("Cannot find module")) {
689
+ log.warn({ err: err.message, connectionId: connId }, "SLA metric recording failed");
690
+ }
691
+ }
692
+ }
693
+
694
+ // Cache write (fail open)
695
+ if (cacheKey) {
696
+ try {
697
+ getCache().set(cacheKey, {
698
+ columns: result.columns, rows: result.rows,
699
+ cachedAt: Date.now(), ttl: getDefaultTtl(),
700
+ });
701
+ } catch (cacheErr) {
702
+ log.error({ err: cacheErr, connectionId: connId }, "Cache write failed — result not cached");
703
+ }
704
+ }
705
+
706
+ try {
707
+ logQueryAudit({
708
+ sql: querySql, durationMs, rowCount: result.rows.length, success: true,
709
+ sourceId: connId, sourceType: dbType, targetHost,
710
+ tablesAccessed: classification?.tablesAccessed,
711
+ columnsAccessed: classification?.columnsAccessed,
712
+ });
713
+ } catch (auditErr) {
714
+ log.warn({ err: auditErr }, "Failed to write query audit log");
715
+ }
716
+
717
+ try {
718
+ await dispatchHook("afterQuery", {
719
+ sql: querySql, connectionId: connId,
720
+ result: { columns: result.columns, rows: result.rows },
721
+ durationMs,
722
+ });
723
+ } catch (hookErr) {
724
+ log.warn(
725
+ { err: hookErr instanceof Error ? hookErr.message : String(hookErr), connectionId: connId },
726
+ "afterQuery hook failed — query result unaffected",
727
+ );
728
+ }
631
729
 
730
+ // Pattern learning (fire-and-forget)
731
+ proposePatternIfNovel({
732
+ sql: querySql, dialect: parserDatabase(dbType, connId), connectionId: connId,
733
+ });
734
+
735
+ // PII masking (fails open)
736
+ let maskedRows = result.rows;
737
+ let maskingApplied = false;
738
+ if (classification?.tablesAccessed.length && orgId) {
739
+ try {
740
+ const { applyMasking } = await import("@atlas/ee/compliance/masking");
741
+ const maskCtx = getRequestContext();
742
+ maskedRows = await applyMasking({
743
+ columns: result.columns, rows: result.rows,
744
+ tablesAccessed: classification.tablesAccessed,
745
+ orgId, userRole: maskCtx?.user?.role,
746
+ });
747
+ maskingApplied = maskedRows !== result.rows;
748
+ } catch (err) {
749
+ log.warn(
750
+ { err: err instanceof Error ? err.message : String(err), connectionId: connId },
751
+ "PII masking failed — returning unmasked results",
752
+ );
753
+ }
754
+ }
755
+
756
+ const hasHookMeta = Object.keys(hookMetadata).length > 0;
757
+ return {
758
+ success: true,
759
+ explanation,
760
+ row_count: maskedRows.length,
761
+ columns: result.columns,
762
+ rows: maskedRows,
763
+ truncated,
764
+ cached: false,
765
+ maskingApplied,
766
+ ...(hasHookMeta && { metadata: hookMetadata }),
767
+ } as Record<string, unknown>;
768
+ },
769
+ catch: (err) => {
770
+ // Query succeeded but post-processing failed — return the error
771
+ // rather than losing the completed query result as an unrecoverable defect.
772
+ const message = err instanceof Error ? err.message : String(err);
773
+ log.error({ err, connectionId: connId }, "Post-query processing failed after successful execution");
774
+ return new QueryExecutionError({ message: `Query succeeded but post-processing failed: ${message}` });
775
+ },
776
+ }),
777
+ ),
778
+ );
779
+ }
780
+
781
+ /** Map a pipeline error to the tool's {success: false} response format. Exhaustive over PipelineError. */
782
+ function pipelineErrorToResponse(error: PipelineError): Record<string, unknown> {
783
+ switch (error._tag) {
784
+ case "RateLimitExceededError":
632
785
  return {
633
- success: true,
634
- explanation,
635
- row_count: result.rows.length,
636
- columns: result.columns,
637
- rows: result.rows,
638
- truncated,
786
+ success: false,
787
+ error: error.message,
788
+ ...(error.retryAfterMs != null && { retryAfterMs: error.retryAfterMs }),
639
789
  };
640
- } catch (err) {
641
- const durationMs = Math.round(performance.now() - start);
642
- const message =
643
- err instanceof Error ? err.message : "Unknown database error";
790
+ case "ConcurrencyLimitError":
791
+ case "ConnectionNotFoundError":
792
+ case "PoolExhaustedError":
793
+ case "NoDatasourceError":
794
+ case "RLSError":
795
+ case "PluginRejectedError":
796
+ case "QueryExecutionError":
797
+ return { success: false, error: error.message };
798
+ default: {
799
+ const _exhaustive: never = error;
800
+ return { success: false, error: `Unknown pipeline error: ${(_exhaustive as { message: string }).message}` };
801
+ }
802
+ }
803
+ }
644
804
 
645
- try {
805
+ export const executeSQL = tool({
806
+ description: `Execute a read-only SQL query against the database. Only SELECT statements are allowed.
807
+
808
+ Rules:
809
+ - Always read the relevant entity schema from the semantic layer BEFORE writing SQL
810
+ - Use exact column names from the schema — never guess
811
+ - Use canonical metric SQL from metrics/*.yml when available
812
+ - Include a LIMIT clause for large result sets
813
+ - If a query fails, fix the issue — do not retry the same SQL`,
814
+
815
+ inputSchema: z.object({
816
+ sql: z.string().describe("The SELECT query to execute"),
817
+ explanation: z
818
+ .string()
819
+ .describe("Brief explanation of what this query does and why"),
820
+ connectionId: z
821
+ .string()
822
+ .optional()
823
+ .describe(
824
+ "Target connection ID. Check the entity YAML's `connection` field to determine which source a table belongs to. Omit for the default connection.",
825
+ ),
826
+ }),
827
+
828
+ execute: async ({ sql, explanation, connectionId }) => {
829
+ const connId = connectionId ?? "default";
830
+
831
+ // The full pipeline runs as an Effect.gen program. Tagged errors flow through
832
+ // the error channel; expected rejections (validation, approval, cache) return
833
+ // as {success: false} values. At the boundary, catchAll maps errors to responses.
834
+ const pipeline = Effect.gen(function* () {
835
+ // Resolve org context for tenant-scoped pool isolation
836
+ const reqCtx = getRequestContext();
837
+ const orgId = connections.isOrgPoolingEnabled()
838
+ ? reqCtx?.user?.activeOrganizationId
839
+ : undefined;
840
+
841
+ // Step 1: Resolve connection (tagged errors)
842
+ const { db, dbType } = yield* resolveConnectionEffect(connId, orgId);
843
+
844
+ const targetHost = connections.getTargetHost(connId);
845
+ const customValidator = connections.getValidator(connId);
846
+ const normalizedSql = sql.trim().replace(/;\s*$/, "").trimEnd();
847
+
848
+ // Step 2: Validate (custom validator or standard SQL validation)
849
+ const initial = yield* runQueryValidationEffect(normalizedSql, connId, dbType, customValidator);
850
+ if (!initial.ok) {
646
851
  logQueryAudit({
647
- sql: querySql,
648
- durationMs,
649
- rowCount: null,
650
- success: false,
651
- error: message,
652
- sourceId: connId,
653
- sourceType: dbType,
654
- targetHost,
852
+ sql: normalizedSql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
853
+ error: initial.auditError, sourceId: connId, sourceType: dbType,
655
854
  });
656
- } catch (auditErr) {
657
- log.warn({ err: auditErr }, "Failed to write query audit log");
855
+ return { success: false, error: initial.error };
658
856
  }
857
+ // Classification is only populated for standard SQL (validateSQL path).
858
+ // Custom validators (SOQL, GraphQL) bypass node-sql-parser so classification
859
+ // stays undefined — their audit entries store NULL for tables/columns_accessed.
860
+ const classification = initial.classification;
659
861
 
660
- // Block errors that might expose connection details or internal state
661
- if (SENSITIVE_PATTERNS.test(message)) {
662
- return { success: false, error: "Database query failed — check server logs for details." };
663
- }
862
+ // Step 3: Enterprise approval check (fail-open for availability, hard-fail for request creation)
863
+ if (classification) {
864
+ const approvalResult = yield* Effect.tryPromise({
865
+ try: async () => {
866
+ // Phase 1: check availability (fail open)
867
+ let approvalMatch: { required: boolean; matchedRules: { id: string; name: string }[] } | null = null;
868
+ try {
869
+ const { checkApprovalRequired } = await import("@atlas/ee/governance/approval");
870
+ const checkReqCtx = getRequestContext();
871
+ const checkOrgId = checkReqCtx?.user?.activeOrganizationId;
872
+ approvalMatch = await checkApprovalRequired(
873
+ checkOrgId, classification.tablesAccessed, classification.columnsAccessed,
874
+ );
875
+ } catch (err) {
876
+ log.warn(
877
+ { err: err instanceof Error ? err.message : String(err), connectionId: connId },
878
+ "Approval check failed — proceeding without approval gate",
879
+ );
880
+ }
664
881
 
665
- // Surface the full DB error to the agent for self-correction
666
- // (includes column-not-found, syntax, timeout, type mismatch, etc.)
667
- const dbErr = err as { hint?: string; position?: string };
668
- let detail = message;
669
- if (dbErr.hint) {
670
- detail += ` — Hint: ${dbErr.hint}`;
882
+ // Phase 2: create request (hard fail governance bypass is worse than a failed query)
883
+ if (approvalMatch?.required) {
884
+ const { createApprovalRequest, hasApprovedRequest } = await import("@atlas/ee/governance/approval");
885
+ const reqCtxForApproval = getRequestContext();
886
+ const approvalOrgId = reqCtxForApproval?.user?.activeOrganizationId;
887
+ const userId = reqCtxForApproval?.user?.id;
888
+ const userEmail = reqCtxForApproval?.user?.label ?? null;
889
+
890
+ if (!userId || !approvalOrgId) {
891
+ log.warn(
892
+ { connectionId: connId, orgId: approvalOrgId },
893
+ "Approval required but user identity unavailable — blocking query",
894
+ );
895
+ return {
896
+ success: false,
897
+ error: "This query requires approval but the requester identity could not be determined. Please sign in and try again.",
898
+ };
899
+ }
900
+
901
+ const alreadyApproved = await hasApprovedRequest(approvalOrgId, userId, normalizedSql);
902
+ if (!alreadyApproved) {
903
+ const firstRule = approvalMatch.matchedRules[0];
904
+ const approvalReq = await createApprovalRequest({
905
+ orgId: approvalOrgId,
906
+ ruleId: firstRule.id,
907
+ ruleName: firstRule.name,
908
+ requesterId: userId,
909
+ requesterEmail: userEmail,
910
+ querySql: normalizedSql,
911
+ explanation,
912
+ connectionId: connId,
913
+ tablesAccessed: classification.tablesAccessed,
914
+ columnsAccessed: classification.columnsAccessed,
915
+ });
916
+ logQueryAudit({
917
+ sql: normalizedSql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
918
+ error: `Approval required: ${firstRule.name}`,
919
+ sourceId: connId, sourceType: dbType, targetHost,
920
+ });
921
+ return {
922
+ success: false,
923
+ approval_required: true,
924
+ approval_request_id: approvalReq.id,
925
+ matched_rules: approvalMatch.matchedRules.map((r: { name: string }) => r.name),
926
+ message: `This query requires approval before execution. Rule: "${firstRule.name}". ` +
927
+ `An approval request has been submitted (ID: ${approvalReq.id}). ` +
928
+ `An admin must approve it before the query can run.`,
929
+ };
930
+ }
931
+ }
932
+ return null; // proceed to execution
933
+ },
934
+ catch: (err) => {
935
+ // Phase 2 failure — governance bypass is worse than a failed query.
936
+ // Surface as a typed error so it reaches the agent as {success: false}.
937
+ const message = err instanceof Error ? err.message : String(err);
938
+ log.error({ err, connectionId: connId }, "Approval request creation failed — blocking query");
939
+ return new QueryExecutionError({ message: `Approval workflow failed: ${message}` });
940
+ },
941
+ });
942
+ if (approvalResult !== null) return approvalResult;
671
943
  }
672
- if (dbErr.position) {
673
- detail += ` (at character ${dbErr.position})`;
944
+
945
+ // Step 4: Cache check (short-circuit on hit)
946
+ let cacheKey: string | null = null;
947
+ if (cacheEnabled()) {
948
+ try {
949
+ const ctx = getRequestContext();
950
+ const cacheOrgId = ctx?.user?.activeOrganizationId;
951
+ const claims = ctx?.user?.claims;
952
+ cacheKey = buildCacheKey(normalizedSql, connId, cacheOrgId, claims);
953
+ const cached = getCache().get(cacheKey);
954
+ if (cached) {
955
+ logQueryAudit({
956
+ sql: normalizedSql.slice(0, 2000), durationMs: 0, rowCount: cached.rows.length,
957
+ success: true, sourceId: connId, sourceType: dbType, targetHost,
958
+ });
959
+ // Apply PII masking to cached results (same as live query path)
960
+ const cacheResponse = yield* Effect.tryPromise({
961
+ try: async () => {
962
+ let cachedRows = cached.rows;
963
+ let cachedMaskingApplied = false;
964
+ if (classification?.tablesAccessed.length && orgId) {
965
+ try {
966
+ const { applyMasking } = await import("@atlas/ee/compliance/masking");
967
+ cachedRows = await applyMasking({
968
+ columns: cached.columns, rows: cached.rows,
969
+ tablesAccessed: classification.tablesAccessed,
970
+ orgId, userRole: ctx?.user?.role,
971
+ });
972
+ cachedMaskingApplied = cachedRows !== cached.rows;
973
+ } catch (err) {
974
+ log.warn(
975
+ { err: err instanceof Error ? err.message : String(err), connectionId: connId },
976
+ "PII masking failed on cached results — returning unmasked results",
977
+ );
978
+ }
979
+ }
980
+ return {
981
+ success: true, explanation, row_count: cachedRows.length,
982
+ columns: cached.columns, rows: cachedRows,
983
+ truncated: cachedRows.length >= getRowLimit(), cached: true,
984
+ maskingApplied: cachedMaskingApplied,
985
+ };
986
+ },
987
+ catch: (err) => {
988
+ const message = err instanceof Error ? err.message : String(err);
989
+ log.error({ err, connectionId: connId }, "Cache response processing failed");
990
+ return new QueryExecutionError({ message: `Cache response processing failed: ${message}` });
991
+ },
992
+ });
993
+ return cacheResponse;
994
+ }
995
+ } catch (cacheErr) {
996
+ log.error({ err: cacheErr, connectionId: connId }, "Cache read failed — executing query against database");
997
+ cacheKey = null;
998
+ }
674
999
  }
675
- return { success: false, error: detail };
676
- } finally {
677
- decrementSourceConcurrency(connId);
678
- }
1000
+
1001
+ // Step 5: Execute inside a rate-limit slot (concurrency release is automatic)
1002
+ return yield* withSourceSlot(connId,
1003
+ Effect.gen(function* () {
1004
+ // Plugin beforeQuery hook (may rewrite SQL)
1005
+ const { dispatchHook, dispatchMutableHook } = yield* Effect.tryPromise({
1006
+ try: () => import("@atlas/api/lib/plugins/hooks"),
1007
+ catch: (err) => {
1008
+ const message = err instanceof Error ? err.message : String(err);
1009
+ log.error({ err, connectionId: connId }, "Failed to load plugin hooks module");
1010
+ return new PluginRejectedError({ message: `Plugin system unavailable: ${message}`, connectionId: connId });
1011
+ },
1012
+ });
1013
+ const hookMetadata: Record<string, unknown> = {};
1014
+ const hookCtx = { sql, connectionId: connId, metadata: hookMetadata };
1015
+ const mutatedSql = yield* Effect.tryPromise({
1016
+ try: () => dispatchMutableHook("beforeQuery", hookCtx, "sql"),
1017
+ catch: (err) => {
1018
+ const message = err instanceof Error ? err.message : String(err);
1019
+ return new PluginRejectedError({
1020
+ message: `Query rejected by plugin: ${message}`,
1021
+ connectionId: connId,
1022
+ });
1023
+ },
1024
+ }).pipe(
1025
+ Effect.tapError((error) =>
1026
+ Effect.sync(() =>
1027
+ logQueryAudit({
1028
+ sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
1029
+ error: `Plugin rejected: ${error.message}`,
1030
+ sourceId: connId, sourceType: dbType, targetHost,
1031
+ }),
1032
+ ),
1033
+ ),
1034
+ );
1035
+
1036
+ // Re-validate if plugin rewrote the SQL
1037
+ let normalizedMutated = mutatedSql.trim().replace(/;\s*$/, "").trimEnd();
1038
+ if (normalizedMutated !== normalizedSql) {
1039
+ const revalidation = yield* runQueryValidationEffect(normalizedMutated, connId, dbType, customValidator);
1040
+ if (!revalidation.ok) {
1041
+ logQueryAudit({
1042
+ sql: normalizedMutated.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
1043
+ error: `Plugin-rewritten SQL failed validation: ${revalidation.auditError}`,
1044
+ sourceId: connId, sourceType: dbType, targetHost,
1045
+ });
1046
+ return { success: false, error: `Plugin-rewritten SQL failed validation: ${revalidation.error}` };
1047
+ }
1048
+ }
1049
+
1050
+ // RLS: inject WHERE conditions (skipped for custom validators / non-SQL languages)
1051
+ if (!customValidator) {
1052
+ normalizedMutated = yield* applyRLSEffect(normalizedMutated, connId, dbType, targetHost);
1053
+ }
1054
+
1055
+ // Auto-append LIMIT if not present
1056
+ const rowLimit = getRowLimit();
1057
+ const queryTimeout = getQueryTimeout();
1058
+ let querySql = normalizedMutated;
1059
+ if (!customValidator && !/\bLIMIT\b/i.test(querySql)) {
1060
+ querySql += ` LIMIT ${rowLimit}`;
1061
+ }
1062
+
1063
+ // Execute the query
1064
+ return yield* executeAndAuditEffect({
1065
+ db, dbType, connId, orgId, targetHost, querySql, queryTimeout,
1066
+ rowLimit, explanation, classification, cacheKey: cacheKey ?? null,
1067
+ hookMetadata, dispatchHook,
1068
+ });
1069
+ }),
1070
+ ).pipe(
1071
+ // Audit log rate-limit rejections (inner errors have their own audit handling)
1072
+ Effect.tapError((error) => {
1073
+ if (error._tag === "RateLimitExceededError" || error._tag === "ConcurrencyLimitError") {
1074
+ return Effect.sync(() =>
1075
+ logQueryAudit({
1076
+ sql: sql.slice(0, 2000), durationMs: 0, rowCount: null, success: false,
1077
+ error: `Rate limited: ${error.message}`,
1078
+ sourceId: connId, sourceType: dbType, targetHost,
1079
+ }),
1080
+ );
1081
+ }
1082
+ return Effect.void;
1083
+ }),
1084
+ );
1085
+ });
1086
+
1087
+ // Run the pipeline, mapping tagged errors to {success: false} tool responses
1088
+ return Effect.runPromise(
1089
+ pipeline.pipe(
1090
+ Effect.catchAll((error: PipelineError) =>
1091
+ Effect.succeed(pipelineErrorToResponse(error)),
1092
+ ),
1093
+ ),
1094
+ );
679
1095
  },
680
1096
  });