@useatlas/create 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/README.md +4 -18
  2. package/index.ts +191 -31
  3. package/package.json +1 -1
  4. package/templates/docker/.env.example +3 -3
  5. package/templates/docker/Dockerfile.sidecar +28 -0
  6. package/templates/docker/bin/__tests__/plugin-cli.test.ts +9 -9
  7. package/templates/docker/bin/atlas.ts +108 -44
  8. package/templates/docker/data/demo-semantic/catalog.yml +51 -27
  9. package/templates/docker/data/demo-semantic/entities/accounts.yml +95 -103
  10. package/templates/docker/data/demo-semantic/entities/companies.yml +88 -152
  11. package/templates/docker/data/demo-semantic/entities/people.yml +82 -95
  12. package/templates/docker/data/demo-semantic/glossary.yml +104 -8
  13. package/templates/docker/data/demo-semantic/metrics/accounts.yml +62 -23
  14. package/templates/docker/data/demo-semantic/metrics/companies.yml +52 -78
  15. package/templates/docker/docker-compose.yml +1 -1
  16. package/templates/docker/docs/deploy.md +2 -39
  17. package/templates/docker/package.json +17 -1
  18. package/templates/docker/semantic/catalog.yml +62 -3
  19. package/templates/docker/semantic/entities/accounts.yml +162 -0
  20. package/templates/docker/semantic/entities/companies.yml +143 -0
  21. package/templates/docker/semantic/entities/people.yml +132 -0
  22. package/templates/docker/semantic/glossary.yml +116 -4
  23. package/templates/docker/semantic/metrics/accounts.yml +77 -0
  24. package/templates/docker/semantic/metrics/companies.yml +63 -0
  25. package/templates/docker/sidecar/Dockerfile +5 -6
  26. package/templates/docker/sidecar/railway.json +1 -2
  27. package/templates/docker/src/api/__tests__/admin.test.ts +7 -7
  28. package/templates/docker/src/api/__tests__/health-plugin.test.ts +7 -0
  29. package/templates/docker/src/api/__tests__/health.test.ts +30 -8
  30. package/templates/docker/src/api/routes/admin.ts +549 -8
  31. package/templates/docker/src/api/routes/chat.ts +5 -20
  32. package/templates/docker/src/api/routes/health.ts +39 -27
  33. package/templates/docker/src/api/routes/openapi.ts +1329 -74
  34. package/templates/docker/src/api/routes/query.ts +2 -1
  35. package/templates/docker/src/api/server.ts +27 -0
  36. package/templates/docker/src/app/api/[...route]/route.ts +2 -2
  37. package/templates/docker/src/app/globals.css +13 -12
  38. package/templates/docker/src/app/layout.tsx +9 -2
  39. package/templates/docker/src/components/ui/alert-dialog.tsx +196 -0
  40. package/templates/docker/src/components/ui/badge.tsx +48 -0
  41. package/templates/docker/src/components/ui/button.tsx +64 -0
  42. package/templates/docker/src/components/ui/card.tsx +92 -0
  43. package/templates/docker/src/components/ui/collapsible.tsx +33 -0
  44. package/templates/docker/src/components/ui/command.tsx +184 -0
  45. package/templates/docker/src/components/ui/dialog.tsx +158 -0
  46. package/templates/docker/src/components/ui/dropdown-menu.tsx +257 -0
  47. package/templates/docker/src/components/ui/input.tsx +21 -0
  48. package/templates/docker/src/components/ui/scroll-area.tsx +58 -0
  49. package/templates/docker/src/components/ui/select.tsx +190 -0
  50. package/templates/docker/src/components/ui/separator.tsx +28 -0
  51. package/templates/docker/src/components/ui/sheet.tsx +143 -0
  52. package/templates/docker/src/components/ui/sidebar.tsx +726 -0
  53. package/templates/docker/src/components/ui/skeleton.tsx +13 -0
  54. package/templates/docker/src/components/ui/table.tsx +116 -0
  55. package/templates/docker/src/components/ui/tabs.tsx +91 -0
  56. package/templates/docker/src/components/ui/toggle-group.tsx +83 -0
  57. package/templates/docker/src/components/ui/toggle.tsx +47 -0
  58. package/templates/docker/src/components/ui/tooltip.tsx +57 -0
  59. package/templates/docker/src/hooks/use-mobile.ts +19 -0
  60. package/templates/docker/src/lib/__tests__/agent-cache.test.ts +2 -0
  61. package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +17 -0
  62. package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +2 -0
  63. package/templates/docker/src/lib/__tests__/agent-integration.test.ts +2 -0
  64. package/templates/docker/src/lib/__tests__/config.test.ts +69 -19
  65. package/templates/docker/src/lib/__tests__/plugin-aware-validation.test.ts +321 -0
  66. package/templates/docker/src/lib/__tests__/providers.test.ts +32 -1
  67. package/templates/docker/src/lib/__tests__/startup-actions.test.ts +9 -0
  68. package/templates/docker/src/lib/__tests__/startup-first-run.test.ts +429 -0
  69. package/templates/docker/src/lib/__tests__/startup.test.ts +5 -0
  70. package/templates/docker/src/lib/agent-query.ts +5 -23
  71. package/templates/docker/src/lib/agent.ts +32 -112
  72. package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +5 -3
  73. package/templates/docker/src/lib/auth/middleware.ts +30 -4
  74. package/templates/docker/src/lib/auth/migrate.ts +97 -0
  75. package/templates/docker/src/lib/auth/server.ts +12 -1
  76. package/templates/docker/src/lib/config.ts +37 -39
  77. package/templates/docker/src/lib/db/__tests__/connection.test.ts +89 -14
  78. package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +1 -18
  79. package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -19
  80. package/templates/docker/src/lib/db/__tests__/registry.test.ts +11 -208
  81. package/templates/docker/src/lib/db/connection.ts +87 -265
  82. package/templates/docker/src/lib/db/internal.ts +6 -1
  83. package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +3 -1
  84. package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +2 -2
  85. package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +355 -1
  86. package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +32 -5
  87. package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +228 -14
  88. package/templates/docker/src/lib/plugins/index.ts +4 -1
  89. package/templates/docker/src/lib/plugins/migrate.ts +103 -0
  90. package/templates/docker/src/lib/plugins/registry.ts +12 -6
  91. package/templates/docker/src/lib/plugins/wiring.ts +113 -4
  92. package/templates/docker/src/lib/providers.ts +6 -1
  93. package/templates/docker/src/lib/security.ts +24 -0
  94. package/templates/docker/src/lib/semantic.ts +2 -0
  95. package/templates/docker/src/lib/sidecar-types.ts +12 -1
  96. package/templates/docker/src/lib/startup.ts +71 -101
  97. package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +2 -0
  98. package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +32 -18
  99. package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +14 -14
  100. package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
  101. package/templates/docker/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
  102. package/templates/docker/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
  103. package/templates/docker/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
  104. package/templates/docker/src/lib/tools/__tests__/python.test.ts +331 -0
  105. package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
  106. package/templates/docker/src/lib/tools/__tests__/registry.test.ts +38 -31
  107. package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
  108. package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
  109. package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
  110. package/templates/docker/src/lib/tools/__tests__/sql.test.ts +5 -308
  111. package/templates/docker/src/lib/tools/explore-nsjail.ts +17 -12
  112. package/templates/docker/src/lib/tools/explore-sidecar.ts +25 -0
  113. package/templates/docker/src/lib/tools/explore.ts +28 -32
  114. package/templates/docker/src/lib/tools/python-nsjail.ts +396 -0
  115. package/templates/docker/src/lib/tools/python-sandbox.ts +476 -0
  116. package/templates/docker/src/lib/tools/python-sidecar.ts +150 -0
  117. package/templates/docker/src/lib/tools/python.ts +367 -0
  118. package/templates/docker/src/lib/tools/registry.ts +49 -22
  119. package/templates/docker/src/lib/tools/sql.ts +88 -88
  120. package/templates/docker/src/types/vercel-sandbox.d.ts +7 -0
  121. package/templates/docker/src/ui/components/admin/admin-layout.tsx +77 -8
  122. package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +25 -17
  123. package/templates/docker/src/ui/components/admin/change-password-dialog.tsx +128 -0
  124. package/templates/docker/src/ui/components/admin/entity-detail.tsx +3 -3
  125. package/templates/docker/src/ui/components/admin/semantic-file-tree.tsx +159 -0
  126. package/templates/docker/src/ui/components/atlas-chat.tsx +64 -12
  127. package/templates/docker/src/ui/components/chart/result-chart.tsx +25 -15
  128. package/templates/docker/src/ui/components/chat/markdown.tsx +88 -42
  129. package/templates/docker/src/ui/components/chat/python-result-card.tsx +244 -0
  130. package/templates/docker/src/ui/components/chat/sql-block.tsx +39 -15
  131. package/templates/docker/src/ui/components/chat/sql-result-card.tsx +6 -1
  132. package/templates/docker/src/ui/components/chat/tool-part.tsx +12 -3
  133. package/templates/docker/src/ui/components/chat/typing-indicator.tsx +5 -2
  134. package/templates/docker/src/ui/components/conversations/conversation-item.tsx +25 -20
  135. package/templates/docker/src/ui/context.tsx +1 -1
  136. package/templates/docker/src/ui/hooks/use-conversations.ts +3 -3
  137. package/templates/docker/src/ui/hooks/use-dark-mode.ts +17 -10
  138. package/templates/docker/tsconfig.json +2 -2
  139. package/templates/nextjs-standalone/.env.example +1 -1
  140. package/templates/nextjs-standalone/bin/__tests__/plugin-cli.test.ts +9 -9
  141. package/templates/nextjs-standalone/bin/atlas.ts +108 -44
  142. package/templates/nextjs-standalone/data/demo-semantic/catalog.yml +51 -27
  143. package/templates/nextjs-standalone/data/demo-semantic/entities/accounts.yml +95 -103
  144. package/templates/nextjs-standalone/data/demo-semantic/entities/companies.yml +88 -152
  145. package/templates/nextjs-standalone/data/demo-semantic/entities/people.yml +82 -95
  146. package/templates/nextjs-standalone/data/demo-semantic/glossary.yml +104 -8
  147. package/templates/nextjs-standalone/data/demo-semantic/metrics/accounts.yml +62 -23
  148. package/templates/nextjs-standalone/data/demo-semantic/metrics/companies.yml +52 -78
  149. package/templates/nextjs-standalone/docs/deploy.md +2 -39
  150. package/templates/nextjs-standalone/package.json +11 -2
  151. package/templates/nextjs-standalone/scripts/migrate-auth.ts +25 -0
  152. package/templates/nextjs-standalone/scripts/seed-demo.ts +94 -0
  153. package/templates/nextjs-standalone/semantic/catalog.yml +62 -3
  154. package/templates/nextjs-standalone/semantic/entities/accounts.yml +162 -0
  155. package/templates/nextjs-standalone/semantic/entities/companies.yml +143 -0
  156. package/templates/nextjs-standalone/semantic/entities/people.yml +132 -0
  157. package/templates/nextjs-standalone/semantic/glossary.yml +116 -4
  158. package/templates/nextjs-standalone/semantic/metrics/accounts.yml +77 -0
  159. package/templates/nextjs-standalone/semantic/metrics/companies.yml +63 -0
  160. package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +7 -7
  161. package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +7 -0
  162. package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +30 -8
  163. package/templates/nextjs-standalone/src/api/routes/admin.ts +549 -8
  164. package/templates/nextjs-standalone/src/api/routes/chat.ts +5 -20
  165. package/templates/nextjs-standalone/src/api/routes/health.ts +39 -27
  166. package/templates/nextjs-standalone/src/api/routes/openapi.ts +1329 -74
  167. package/templates/nextjs-standalone/src/api/routes/query.ts +2 -1
  168. package/templates/nextjs-standalone/src/api/server.ts +27 -0
  169. package/templates/nextjs-standalone/src/app/api/[...route]/route.ts +2 -2
  170. package/templates/nextjs-standalone/src/app/globals.css +13 -12
  171. package/templates/nextjs-standalone/src/app/layout.tsx +9 -2
  172. package/templates/nextjs-standalone/src/components/ui/alert-dialog.tsx +196 -0
  173. package/templates/nextjs-standalone/src/components/ui/badge.tsx +48 -0
  174. package/templates/nextjs-standalone/src/components/ui/button.tsx +64 -0
  175. package/templates/nextjs-standalone/src/components/ui/card.tsx +92 -0
  176. package/templates/nextjs-standalone/src/components/ui/collapsible.tsx +33 -0
  177. package/templates/nextjs-standalone/src/components/ui/command.tsx +184 -0
  178. package/templates/nextjs-standalone/src/components/ui/dialog.tsx +158 -0
  179. package/templates/nextjs-standalone/src/components/ui/dropdown-menu.tsx +257 -0
  180. package/templates/nextjs-standalone/src/components/ui/input.tsx +21 -0
  181. package/templates/nextjs-standalone/src/components/ui/scroll-area.tsx +58 -0
  182. package/templates/nextjs-standalone/src/components/ui/select.tsx +190 -0
  183. package/templates/nextjs-standalone/src/components/ui/separator.tsx +28 -0
  184. package/templates/nextjs-standalone/src/components/ui/sheet.tsx +143 -0
  185. package/templates/nextjs-standalone/src/components/ui/sidebar.tsx +726 -0
  186. package/templates/nextjs-standalone/src/components/ui/skeleton.tsx +13 -0
  187. package/templates/nextjs-standalone/src/components/ui/table.tsx +116 -0
  188. package/templates/nextjs-standalone/src/components/ui/tabs.tsx +91 -0
  189. package/templates/nextjs-standalone/src/components/ui/toggle-group.tsx +83 -0
  190. package/templates/nextjs-standalone/src/components/ui/toggle.tsx +47 -0
  191. package/templates/nextjs-standalone/src/components/ui/tooltip.tsx +57 -0
  192. package/templates/nextjs-standalone/src/hooks/use-mobile.ts +19 -0
  193. package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +2 -0
  194. package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +17 -0
  195. package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +2 -0
  196. package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +2 -0
  197. package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +69 -19
  198. package/templates/nextjs-standalone/src/lib/__tests__/plugin-aware-validation.test.ts +321 -0
  199. package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +32 -1
  200. package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +9 -0
  201. package/templates/nextjs-standalone/src/lib/__tests__/startup-first-run.test.ts +429 -0
  202. package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +5 -0
  203. package/templates/nextjs-standalone/src/lib/agent-query.ts +5 -23
  204. package/templates/nextjs-standalone/src/lib/agent.ts +32 -112
  205. package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +5 -3
  206. package/templates/nextjs-standalone/src/lib/auth/middleware.ts +30 -4
  207. package/templates/nextjs-standalone/src/lib/auth/migrate.ts +97 -0
  208. package/templates/nextjs-standalone/src/lib/auth/server.ts +12 -1
  209. package/templates/nextjs-standalone/src/lib/config.ts +37 -39
  210. package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +89 -14
  211. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +1 -18
  212. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -19
  213. package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +11 -208
  214. package/templates/nextjs-standalone/src/lib/db/connection.ts +87 -265
  215. package/templates/nextjs-standalone/src/lib/db/internal.ts +6 -1
  216. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +3 -1
  217. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +2 -2
  218. package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +355 -1
  219. package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +32 -5
  220. package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +228 -14
  221. package/templates/nextjs-standalone/src/lib/plugins/index.ts +4 -1
  222. package/templates/nextjs-standalone/src/lib/plugins/migrate.ts +103 -0
  223. package/templates/nextjs-standalone/src/lib/plugins/registry.ts +12 -6
  224. package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +113 -4
  225. package/templates/nextjs-standalone/src/lib/providers.ts +6 -1
  226. package/templates/nextjs-standalone/src/lib/security.ts +24 -0
  227. package/templates/nextjs-standalone/src/lib/semantic.ts +2 -0
  228. package/templates/nextjs-standalone/src/lib/sidecar-types.ts +12 -1
  229. package/templates/nextjs-standalone/src/lib/startup.ts +71 -101
  230. package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +2 -0
  231. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +32 -18
  232. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +14 -14
  233. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
  234. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
  235. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
  236. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
  237. package/templates/nextjs-standalone/src/lib/tools/__tests__/python.test.ts +331 -0
  238. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
  239. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +38 -31
  240. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
  241. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
  242. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
  243. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +5 -308
  244. package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +17 -12
  245. package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +25 -0
  246. package/templates/nextjs-standalone/src/lib/tools/explore.ts +28 -32
  247. package/templates/nextjs-standalone/src/lib/tools/python-nsjail.ts +396 -0
  248. package/templates/nextjs-standalone/src/lib/tools/python-sandbox.ts +476 -0
  249. package/templates/nextjs-standalone/src/lib/tools/python-sidecar.ts +150 -0
  250. package/templates/nextjs-standalone/src/lib/tools/python.ts +367 -0
  251. package/templates/nextjs-standalone/src/lib/tools/registry.ts +49 -22
  252. package/templates/nextjs-standalone/src/lib/tools/sql.ts +88 -88
  253. package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +77 -8
  254. package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +25 -17
  255. package/templates/nextjs-standalone/src/ui/components/admin/change-password-dialog.tsx +128 -0
  256. package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +3 -3
  257. package/templates/nextjs-standalone/src/ui/components/admin/semantic-file-tree.tsx +159 -0
  258. package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +64 -12
  259. package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +25 -15
  260. package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +88 -42
  261. package/templates/nextjs-standalone/src/ui/components/chat/python-result-card.tsx +244 -0
  262. package/templates/nextjs-standalone/src/ui/components/chat/sql-block.tsx +39 -15
  263. package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +6 -1
  264. package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +12 -3
  265. package/templates/nextjs-standalone/src/ui/components/chat/typing-indicator.tsx +5 -2
  266. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +25 -20
  267. package/templates/nextjs-standalone/src/ui/context.tsx +1 -1
  268. package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +3 -3
  269. package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +17 -10
  270. package/templates/nextjs-standalone/tsconfig.json +0 -1
  271. package/templates/nextjs-standalone/vercel.json +4 -1
  272. package/templates/docker/render.yaml +0 -34
  273. package/templates/docker/semantic/entities/.gitkeep +0 -0
  274. package/templates/docker/semantic/metrics/.gitkeep +0 -0
  275. package/templates/docker/src/lib/db/__tests__/duckdb.test.ts +0 -141
  276. package/templates/docker/src/lib/db/__tests__/salesforce.test.ts +0 -339
  277. package/templates/docker/src/lib/db/__tests__/snowflake.test.ts +0 -217
  278. package/templates/docker/src/lib/db/duckdb.ts +0 -122
  279. package/templates/docker/src/lib/db/salesforce.ts +0 -342
  280. package/templates/docker/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
  281. package/templates/docker/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
  282. package/templates/docker/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
  283. package/templates/docker/src/lib/tools/salesforce.ts +0 -138
  284. package/templates/docker/src/lib/tools/soql-validation.ts +0 -172
  285. package/templates/nextjs-standalone/semantic/entities/.gitkeep +0 -0
  286. package/templates/nextjs-standalone/semantic/metrics/.gitkeep +0 -0
  287. package/templates/nextjs-standalone/src/lib/db/__tests__/duckdb.test.ts +0 -141
  288. package/templates/nextjs-standalone/src/lib/db/__tests__/salesforce.test.ts +0 -339
  289. package/templates/nextjs-standalone/src/lib/db/__tests__/snowflake.test.ts +0 -217
  290. package/templates/nextjs-standalone/src/lib/db/duckdb.ts +0 -122
  291. package/templates/nextjs-standalone/src/lib/db/salesforce.ts +0 -342
  292. package/templates/nextjs-standalone/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
  293. package/templates/nextjs-standalone/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
  294. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
  295. package/templates/nextjs-standalone/src/lib/tools/salesforce.ts +0 -138
  296. package/templates/nextjs-standalone/src/lib/tools/soql-validation.ts +0 -172
@@ -0,0 +1,429 @@
1
+ import { describe, it, expect, beforeEach, afterEach, mock } from "bun:test";
2
+ import { resetAuthModeCache } from "@atlas/api/lib/auth/detect";
3
+
4
+ // ---------------------------------------------------------------------------
5
+ // Control variables for mocks — mutated per-test in beforeEach
6
+ // ---------------------------------------------------------------------------
7
+
8
+ let mockDatasourceUrl: string | null = null;
9
+ let mockSemanticFiles: string[] | Error = ["orders.yml"];
10
+ let mockPgConnectError: Error | null = null;
11
+ let mockMysqlConnectError: Error | null = null;
12
+ let mockConfigResult: Record<string, unknown> | null = { source: "env" };
13
+ let mockConfigLoadError: Error | null = null;
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Mocks — must be set up before importing the module under test
17
+ // ---------------------------------------------------------------------------
18
+
19
+ mock.module("fs", () => ({
20
+ existsSync: () => false,
21
+ readdirSync: () => {
22
+ if (mockSemanticFiles instanceof Error) throw mockSemanticFiles;
23
+ return mockSemanticFiles;
24
+ },
25
+ }));
26
+
27
+ mock.module("@atlas/api/lib/db/connection", () => ({
28
+ detectDBType: (url: string) => {
29
+ if (url.startsWith("mysql")) return "mysql";
30
+ return "postgres";
31
+ },
32
+ resolveDatasourceUrl: () => mockDatasourceUrl,
33
+ }));
34
+
35
+ mock.module("@atlas/api/lib/providers", () => ({
36
+ getDefaultProvider: () => "anthropic",
37
+ }));
38
+
39
+ mock.module("pg", () => ({
40
+ Pool: class MockPool {
41
+ async connect() {
42
+ if (mockPgConnectError) throw mockPgConnectError;
43
+ return {
44
+ release: () => {},
45
+ query: async () => ({ rows: [{ "?column?": 1 }] }),
46
+ };
47
+ }
48
+ async end() {}
49
+ },
50
+ }));
51
+
52
+ mock.module("mysql2/promise", () => ({
53
+ createPool: () => ({
54
+ getConnection: async () => {
55
+ if (mockMysqlConnectError) throw mockMysqlConnectError;
56
+ return { release: () => {} };
57
+ },
58
+ end: async () => {},
59
+ }),
60
+ }));
61
+
62
+ mock.module("@atlas/api/lib/config", () => ({
63
+ getConfig: () => mockConfigResult,
64
+ loadConfig: async () => {
65
+ if (mockConfigLoadError) throw mockConfigLoadError;
66
+ mockConfigResult = { source: "env" };
67
+ return mockConfigResult;
68
+ },
69
+ }));
70
+
71
+ mock.module("@atlas/api/lib/tools/explore-nsjail", () => ({
72
+ findNsjailBinary: () => null,
73
+ testNsjailCapabilities: async () => ({ ok: true }),
74
+ isNsjailAvailable: () => false,
75
+ }));
76
+
77
+ mock.module("@atlas/api/lib/tools/explore", () => ({
78
+ markNsjailFailed: () => {},
79
+ markSidecarFailed: () => {},
80
+ getExploreBackendType: () => "just-bash",
81
+ getActiveSandboxPluginId: () => null,
82
+ invalidateExploreBackend: () => {},
83
+ }));
84
+
85
+ mock.module("@atlas/api/lib/auth/migrate", () => ({
86
+ getMigrationError: () => null,
87
+ }));
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // Import under test (AFTER mocks)
91
+ // ---------------------------------------------------------------------------
92
+
93
+ const { validateEnvironment, getStartupWarnings, resetStartupCache } =
94
+ await import("@atlas/api/lib/startup");
95
+
96
+ const { maskConnectionUrl } = await import("@atlas/api/lib/security");
97
+
98
+ // ---------------------------------------------------------------------------
99
+ // Env snapshot — capture/restore only the vars this test touches
100
+ // ---------------------------------------------------------------------------
101
+
102
+ const MANAGED_VARS = [
103
+ "ATLAS_DATASOURCE_URL", "DATABASE_URL", "ATLAS_API_KEY", "ATLAS_PROVIDER",
104
+ "ATLAS_AUTH_MODE", "BETTER_AUTH_SECRET", "BETTER_AUTH_URL",
105
+ "BETTER_AUTH_TRUSTED_ORIGINS", "ATLAS_AUTH_JWKS_URL", "ATLAS_AUTH_ISSUER",
106
+ "ATLAS_AUTH_AUDIENCE", "ATLAS_SANDBOX", "ATLAS_SANDBOX_URL",
107
+ "ATLAS_RUNTIME", "VERCEL", "ANTHROPIC_API_KEY", "OPENAI_API_KEY",
108
+ "AWS_ACCESS_KEY_ID", "AI_GATEWAY_API_KEY", "ATLAS_DEMO_DATA",
109
+ ] as const;
110
+
111
+ const saved: Record<string, string | undefined> = {};
112
+
113
+ beforeEach(() => {
114
+ for (const key of MANAGED_VARS) saved[key] = process.env[key];
115
+ resetStartupCache();
116
+ resetAuthModeCache();
117
+
118
+ // Clean all managed vars
119
+ for (const key of MANAGED_VARS) delete process.env[key];
120
+
121
+ // Default: ollama (no key needed), no datasource, semantic layer present, config loaded
122
+ process.env.ATLAS_PROVIDER = "ollama";
123
+ mockDatasourceUrl = null;
124
+ mockSemanticFiles = ["orders.yml"];
125
+ mockPgConnectError = null;
126
+ mockMysqlConnectError = null;
127
+ mockConfigResult = { source: "env" };
128
+ mockConfigLoadError = null;
129
+ });
130
+
131
+ afterEach(() => {
132
+ for (const key of MANAGED_VARS) {
133
+ if (saved[key] !== undefined) process.env[key] = saved[key];
134
+ else delete process.env[key];
135
+ }
136
+ resetStartupCache();
137
+ resetAuthModeCache();
138
+ });
139
+
140
+ // ---------------------------------------------------------------------------
141
+ // 1. Missing LLM provider API key
142
+ // ---------------------------------------------------------------------------
143
+
144
+ describe("first-run: missing LLM provider API key", () => {
145
+ it("includes env var name and signup URL for anthropic", async () => {
146
+ process.env.ATLAS_PROVIDER = "anthropic";
147
+ delete process.env.ANTHROPIC_API_KEY;
148
+
149
+ const errors = await validateEnvironment();
150
+ const err = errors.find((e) => e.code === "MISSING_API_KEY");
151
+ expect(err).toBeDefined();
152
+ expect(err!.message).toContain("ANTHROPIC_API_KEY");
153
+ expect(err!.message).toContain(".env");
154
+ expect(err!.message).toContain("console.anthropic.com");
155
+ });
156
+
157
+ it("includes env var name and signup URL for openai", async () => {
158
+ process.env.ATLAS_PROVIDER = "openai";
159
+ delete process.env.OPENAI_API_KEY;
160
+
161
+ const errors = await validateEnvironment();
162
+ const err = errors.find((e) => e.code === "MISSING_API_KEY");
163
+ expect(err).toBeDefined();
164
+ expect(err!.message).toContain("OPENAI_API_KEY");
165
+ expect(err!.message).toContain("platform.openai.com");
166
+ });
167
+
168
+ it("includes env var name and signup URL for gateway", async () => {
169
+ process.env.ATLAS_PROVIDER = "gateway";
170
+ delete process.env.AI_GATEWAY_API_KEY;
171
+
172
+ const errors = await validateEnvironment();
173
+ const err = errors.find((e) => e.code === "MISSING_API_KEY");
174
+ expect(err).toBeDefined();
175
+ expect(err!.message).toContain("AI_GATEWAY_API_KEY");
176
+ expect(err!.message).toContain("vercel.com");
177
+ });
178
+
179
+ it("includes env var name without signup URL for bedrock", async () => {
180
+ process.env.ATLAS_PROVIDER = "bedrock";
181
+ delete process.env.AWS_ACCESS_KEY_ID;
182
+
183
+ const errors = await validateEnvironment();
184
+ const err = errors.find((e) => e.code === "MISSING_API_KEY");
185
+ expect(err).toBeDefined();
186
+ expect(err!.message).toContain("AWS_ACCESS_KEY_ID");
187
+ expect(err!.message).toContain(".env");
188
+ });
189
+
190
+ it("no error when using ollama (no key required)", async () => {
191
+ process.env.ATLAS_PROVIDER = "ollama";
192
+
193
+ const errors = await validateEnvironment();
194
+ expect(errors.find((e) => e.code === "MISSING_API_KEY")).toBeUndefined();
195
+ });
196
+
197
+ it("no error when API key is set", async () => {
198
+ process.env.ATLAS_PROVIDER = "anthropic";
199
+ process.env.ANTHROPIC_API_KEY = "sk-ant-test-key";
200
+
201
+ const errors = await validateEnvironment();
202
+ expect(errors.find((e) => e.code === "MISSING_API_KEY")).toBeUndefined();
203
+ });
204
+ });
205
+
206
+ // ---------------------------------------------------------------------------
207
+ // 2. Missing datasource URL
208
+ // ---------------------------------------------------------------------------
209
+
210
+ describe("first-run: missing datasource URL", () => {
211
+ it("warns with format examples when ATLAS_DATASOURCE_URL not set", async () => {
212
+ mockDatasourceUrl = null;
213
+
214
+ await validateEnvironment();
215
+ const warnings = getStartupWarnings();
216
+ expect(
217
+ warnings.some((w) =>
218
+ w.includes("ATLAS_DATASOURCE_URL") && w.includes("postgresql://"),
219
+ ),
220
+ ).toBe(true);
221
+ });
222
+
223
+ it("errors when DATABASE_URL is set but ATLAS_DATASOURCE_URL is not", async () => {
224
+ mockDatasourceUrl = null;
225
+ process.env.DATABASE_URL = "postgresql://atlas:atlas@localhost:5432/atlas";
226
+
227
+ const errors = await validateEnvironment();
228
+ const err = errors.find((e) => e.code === "MISSING_DATASOURCE_URL");
229
+ expect(err).toBeDefined();
230
+ expect(err!.message).toContain("ATLAS_DATASOURCE_URL");
231
+ });
232
+ });
233
+
234
+ // ---------------------------------------------------------------------------
235
+ // 3. Empty semantic layer
236
+ // ---------------------------------------------------------------------------
237
+
238
+ describe("first-run: empty semantic layer", () => {
239
+ it("suggests running atlas init when no entities found", async () => {
240
+ mockSemanticFiles = [];
241
+
242
+ const errors = await validateEnvironment();
243
+ const err = errors.find((e) => e.code === "MISSING_SEMANTIC_LAYER");
244
+ expect(err).toBeDefined();
245
+ expect(err!.message).toContain("atlas");
246
+ expect(err!.message).toContain("init");
247
+ });
248
+
249
+ it("suggests --demo option for demo data", async () => {
250
+ mockSemanticFiles = [];
251
+
252
+ const errors = await validateEnvironment();
253
+ const err = errors.find((e) => e.code === "MISSING_SEMANTIC_LAYER");
254
+ expect(err).toBeDefined();
255
+ expect(err!.message).toContain("--demo");
256
+ });
257
+ });
258
+
259
+ // ---------------------------------------------------------------------------
260
+ // 4. Database unreachable — masked URLs
261
+ // ---------------------------------------------------------------------------
262
+
263
+ describe("first-run: database unreachable", () => {
264
+ // Note: mock.module("pg") does not intercept require("pg") (native binding).
265
+ // MySQL tests verify the masked URL integration; maskConnectionUrl is unit-tested below.
266
+
267
+ it("shows masked URL in mysql connection error", async () => {
268
+ mockDatasourceUrl = "mysql://admin:p4ssw0rd@mysql.example.com:3306/appdb";
269
+ mockMysqlConnectError = new Error("connect ECONNREFUSED");
270
+
271
+ const errors = await validateEnvironment();
272
+ const err = errors.find((e) => e.code === "DB_UNREACHABLE");
273
+ expect(err).toBeDefined();
274
+ expect(err!.message).toContain("***@mysql.example.com:3306");
275
+ expect(err!.message).not.toContain("p4ssw0rd");
276
+ expect(err!.message).not.toContain("admin:p4ssw0rd");
277
+ });
278
+
279
+ it("does not leak connection credentials in mysql error messages", async () => {
280
+ mockDatasourceUrl = "mysql://user:MyS3cretPass@host:3306/db";
281
+ mockMysqlConnectError = new Error("timeout expired");
282
+
283
+ const errors = await validateEnvironment();
284
+ const err = errors.find((e) => e.code === "DB_UNREACHABLE");
285
+ expect(err).toBeDefined();
286
+ expect(err!.message).not.toContain("MyS3cretPass");
287
+ expect(err!.message).not.toContain("user:MyS3cretPass");
288
+ });
289
+
290
+ it("includes ECONNREFUSED hint for mysql", async () => {
291
+ mockDatasourceUrl = "mysql://user:pass@host:3306/db";
292
+ mockMysqlConnectError = new Error("connect ECONNREFUSED 127.0.0.1:3306");
293
+
294
+ const errors = await validateEnvironment();
295
+ const err = errors.find((e) => e.code === "DB_UNREACHABLE");
296
+ expect(err).toBeDefined();
297
+ expect(err!.message).toContain("connection was refused");
298
+ });
299
+
300
+ it("reports malformed postgres URL without leaking credentials", async () => {
301
+ mockDatasourceUrl = "not-a-valid-url";
302
+
303
+ const errors = await validateEnvironment();
304
+ const err = errors.find((e) => e.code === "DB_UNREACHABLE");
305
+ expect(err).toBeDefined();
306
+ expect(err!.message).toContain("malformed");
307
+ });
308
+ });
309
+
310
+ // ---------------------------------------------------------------------------
311
+ // 4b. maskConnectionUrl — unit tests
312
+ // ---------------------------------------------------------------------------
313
+
314
+ describe("maskConnectionUrl", () => {
315
+ it("masks username and password in postgresql URL", () => {
316
+ expect(maskConnectionUrl("postgresql://user:s3cret@host:5432/db")).toBe(
317
+ "postgresql://***@host:5432/db",
318
+ );
319
+ });
320
+
321
+ it("masks username and password in mysql URL", () => {
322
+ expect(maskConnectionUrl("mysql://admin:p4ss@host:3306/db")).toBe(
323
+ "mysql://***@host:3306/db",
324
+ );
325
+ });
326
+
327
+ it("preserves URL without credentials", () => {
328
+ expect(maskConnectionUrl("postgresql://host:5432/db")).toBe(
329
+ "postgresql://host:5432/db",
330
+ );
331
+ });
332
+
333
+ it("masks username-only URLs", () => {
334
+ const result = maskConnectionUrl("postgresql://user@host:5432/db");
335
+ expect(result).toContain("***@host:5432");
336
+ expect(result).not.toContain("user@");
337
+ });
338
+
339
+ it("returns <invalid-url> for unparseable URLs", () => {
340
+ expect(maskConnectionUrl("not-a-url")).toBe("<invalid-url>");
341
+ });
342
+
343
+ it("preserves non-sensitive query parameters", () => {
344
+ const result = maskConnectionUrl("postgresql://user:pass@host:5432/db?sslmode=require");
345
+ expect(result).toContain("sslmode=require");
346
+ expect(result).not.toContain("pass");
347
+ });
348
+
349
+ it("masks sensitive query parameters", () => {
350
+ const result = maskConnectionUrl("postgresql://user:pass@host:5432/db?password=secret&sslmode=require");
351
+ expect(result).not.toContain("secret");
352
+ expect(result).toContain("password=***");
353
+ expect(result).toContain("sslmode=require");
354
+ });
355
+ });
356
+
357
+ // ---------------------------------------------------------------------------
358
+ // 5. Invalid atlas.config.ts
359
+ // ---------------------------------------------------------------------------
360
+
361
+ describe("first-run: invalid atlas.config.ts", () => {
362
+ it("shows Zod validation error with field path", async () => {
363
+ mockConfigResult = null;
364
+ mockConfigLoadError = new Error(
365
+ "Invalid atlas.config.ts:\n - datasources.default.url: Datasource URL must not be empty",
366
+ );
367
+
368
+ const errors = await validateEnvironment();
369
+ const err = errors.find((e) => e.code === "INVALID_CONFIG");
370
+ expect(err).toBeDefined();
371
+ expect(err!.message).toContain("datasources.default.url");
372
+ expect(err!.message).toContain("Datasource URL must not be empty");
373
+ });
374
+
375
+ it("no error when config is already loaded", async () => {
376
+ mockConfigResult = { source: "file" };
377
+ mockConfigLoadError = null;
378
+
379
+ const errors = await validateEnvironment();
380
+ expect(errors.find((e) => e.code === "INVALID_CONFIG")).toBeUndefined();
381
+ });
382
+
383
+ it("no error when no config file exists (env var fallback)", async () => {
384
+ mockConfigResult = null;
385
+ mockConfigLoadError = null;
386
+
387
+ const errors = await validateEnvironment();
388
+ expect(errors.find((e) => e.code === "INVALID_CONFIG")).toBeUndefined();
389
+ });
390
+ });
391
+
392
+ // ---------------------------------------------------------------------------
393
+ // 6. Auth misconfiguration
394
+ // ---------------------------------------------------------------------------
395
+
396
+ describe("first-run: auth misconfiguration", () => {
397
+ it("shows current length and generation hint for weak BETTER_AUTH_SECRET", async () => {
398
+ process.env.BETTER_AUTH_SECRET = "too-short";
399
+
400
+ const errors = await validateEnvironment();
401
+ const err = errors.find((e) => e.code === "WEAK_AUTH_SECRET");
402
+ expect(err).toBeDefined();
403
+ expect(err!.message).toContain("currently 9");
404
+ expect(err!.message).toContain("openssl rand");
405
+ });
406
+
407
+ it("shows specific guidance for BYOT mode missing ATLAS_AUTH_ISSUER", async () => {
408
+ process.env.ATLAS_AUTH_JWKS_URL =
409
+ "https://idp.example.com/.well-known/jwks.json";
410
+ delete process.env.ATLAS_AUTH_ISSUER;
411
+
412
+ const errors = await validateEnvironment();
413
+ const err = errors.find((e) => e.code === "MISSING_AUTH_ISSUER");
414
+ expect(err).toBeDefined();
415
+ expect(err!.message).toContain("ATLAS_AUTH_ISSUER");
416
+ expect(err!.message).toContain("issuer URL");
417
+ });
418
+
419
+ it("shows guidance when ATLAS_AUTH_MODE is explicit but prereq is missing", async () => {
420
+ process.env.ATLAS_AUTH_MODE = "managed";
421
+ delete process.env.BETTER_AUTH_SECRET;
422
+
423
+ const errors = await validateEnvironment();
424
+ const err = errors.find((e) => e.code === "MISSING_AUTH_PREREQ");
425
+ expect(err).toBeDefined();
426
+ expect(err!.message).toContain("BETTER_AUTH_SECRET");
427
+ expect(err!.message).toContain("32 characters");
428
+ });
429
+ });
@@ -15,6 +15,11 @@ mock.module("fs", () => ({
15
15
  // Mock db/connection — avoid real DB imports
16
16
  mock.module("@atlas/api/lib/db/connection", () => ({
17
17
  detectDBType: () => "postgres",
18
+ resolveDatasourceUrl: () => process.env.ATLAS_DATASOURCE_URL || null,
19
+ }));
20
+
21
+ mock.module("@atlas/api/lib/providers", () => ({
22
+ getDefaultProvider: () => "anthropic",
18
23
  }));
19
24
 
20
25
  // Mock explore-nsjail — controllable sandbox capability check
@@ -30,9 +30,8 @@ export interface AgentQueryResult {
30
30
  /**
31
31
  * Run the Atlas agent on a single question and return structured results.
32
32
  *
33
- * Creates a UIMessage from the question, optionally loads Salesforce tools,
34
- * invokes the agent loop, and extracts SQL queries, data, and the final
35
- * answer from tool results.
33
+ * Creates a UIMessage from the question, invokes the agent loop, and
34
+ * extracts SQL queries, data, and the final answer from tool results.
36
35
  */
37
36
  export async function executeAgentQuery(
38
37
  question: string,
@@ -57,32 +56,15 @@ export async function executeAgentQuery(
57
56
  },
58
57
  ];
59
58
 
60
- // Optionally include Salesforce tools and actions
59
+ // Optionally include action tools
61
60
  let toolRegistry;
62
61
  const includeActions = process.env.ATLAS_ACTIONS_ENABLED === "true";
63
- let includeSalesforce = false;
64
- try {
65
- const { listSalesforceSources } = await import(
66
- "@atlas/api/lib/db/salesforce"
67
- );
68
- includeSalesforce = listSalesforceSources().length > 0;
69
- } catch (err: unknown) {
70
- const code = (err as { code?: string })?.code;
71
- const isModuleNotFound =
72
- code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND";
73
- if (!isModuleNotFound) {
74
- log.error(
75
- { err: err instanceof Error ? err : new Error(String(err)) },
76
- "Failed to initialize Salesforce tool registry — falling back to default tools",
77
- );
78
- }
79
- }
80
- if (includeSalesforce || includeActions) {
62
+ if (includeActions) {
81
63
  try {
82
64
  const { buildRegistry } = await import(
83
65
  "@atlas/api/lib/tools/registry"
84
66
  );
85
- toolRegistry = await buildRegistry({ includeSalesforce, includeActions });
67
+ toolRegistry = await buildRegistry({ includeActions });
86
68
  } catch (err) {
87
69
  log.error(
88
70
  { err: err instanceof Error ? err : new Error(String(err)) },