@useatlas/create 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (515) hide show
  1. package/README.md +231 -0
  2. package/index.ts +829 -0
  3. package/package.json +38 -0
  4. package/templates/docker/.env.example +67 -0
  5. package/templates/docker/Dockerfile +52 -0
  6. package/templates/docker/bin/__tests__/benchmark.test.ts +598 -0
  7. package/templates/docker/bin/__tests__/duckdb-ingest.test.ts +171 -0
  8. package/templates/docker/bin/__tests__/eval.test.ts +434 -0
  9. package/templates/docker/bin/__tests__/matview-partition.test.ts +615 -0
  10. package/templates/docker/bin/__tests__/multi-source.test.ts +113 -0
  11. package/templates/docker/bin/__tests__/plugin-cli.test.ts +322 -0
  12. package/templates/docker/bin/__tests__/profiler-heuristics.test.ts +608 -0
  13. package/templates/docker/bin/__tests__/query.test.ts +240 -0
  14. package/templates/docker/bin/__tests__/schema-drift.test.ts +542 -0
  15. package/templates/docker/bin/__tests__/view-yaml-generation.test.ts +146 -0
  16. package/templates/docker/bin/atlas.ts +5044 -0
  17. package/templates/docker/bin/benchmark.ts +695 -0
  18. package/templates/docker/bin/enrich.ts +559 -0
  19. package/templates/docker/bin/eval.ts +770 -0
  20. package/templates/docker/bin/smoke.ts +438 -0
  21. package/templates/docker/data/.gitkeep +0 -0
  22. package/templates/docker/data/cybersec.sql +1961 -0
  23. package/templates/docker/data/demo-semantic/catalog.yml +40 -0
  24. package/templates/docker/data/demo-semantic/entities/accounts.yml +170 -0
  25. package/templates/docker/data/demo-semantic/entities/companies.yml +207 -0
  26. package/templates/docker/data/demo-semantic/entities/people.yml +145 -0
  27. package/templates/docker/data/demo-semantic/glossary.yml +22 -0
  28. package/templates/docker/data/demo-semantic/metrics/accounts.yml +38 -0
  29. package/templates/docker/data/demo-semantic/metrics/companies.yml +89 -0
  30. package/templates/docker/data/demo.sql +373 -0
  31. package/templates/docker/data/ecommerce.sql +1690 -0
  32. package/templates/docker/data/init-demo-db.sql +8 -0
  33. package/templates/docker/docker-compose.yml +34 -0
  34. package/templates/docker/docs/deploy.md +390 -0
  35. package/templates/docker/eslint.config.mjs +18 -0
  36. package/templates/docker/gitignore +5 -0
  37. package/templates/docker/next.config.ts +9 -0
  38. package/templates/docker/package.json +59 -0
  39. package/templates/docker/postcss.config.mjs +8 -0
  40. package/templates/docker/public/.gitkeep +0 -0
  41. package/templates/docker/public/favicon.svg +4 -0
  42. package/templates/docker/railway.json +13 -0
  43. package/templates/docker/render.yaml +34 -0
  44. package/templates/docker/semantic/catalog.yml +5 -0
  45. package/templates/docker/semantic/entities/.gitkeep +0 -0
  46. package/templates/docker/semantic/glossary.yml +6 -0
  47. package/templates/docker/semantic/metrics/.gitkeep +0 -0
  48. package/templates/docker/sidecar/Dockerfile +28 -0
  49. package/templates/docker/sidecar/railway.json +14 -0
  50. package/templates/docker/sidecar/server.ts +188 -0
  51. package/templates/docker/src/api/__tests__/actions.test.ts +683 -0
  52. package/templates/docker/src/api/__tests__/admin.test.ts +820 -0
  53. package/templates/docker/src/api/__tests__/auth.test.ts +165 -0
  54. package/templates/docker/src/api/__tests__/chat.test.ts +376 -0
  55. package/templates/docker/src/api/__tests__/conversations.test.ts +555 -0
  56. package/templates/docker/src/api/__tests__/cors.test.ts +135 -0
  57. package/templates/docker/src/api/__tests__/health-plugin.test.ts +169 -0
  58. package/templates/docker/src/api/__tests__/health.test.ts +261 -0
  59. package/templates/docker/src/api/__tests__/query.test.ts +891 -0
  60. package/templates/docker/src/api/__tests__/scheduled-tasks.test.ts +601 -0
  61. package/templates/docker/src/api/__tests__/slack.test.ts +847 -0
  62. package/templates/docker/src/api/index.ts +117 -0
  63. package/templates/docker/src/api/routes/actions.ts +274 -0
  64. package/templates/docker/src/api/routes/admin.ts +757 -0
  65. package/templates/docker/src/api/routes/auth.ts +48 -0
  66. package/templates/docker/src/api/routes/chat.ts +465 -0
  67. package/templates/docker/src/api/routes/conversations.ts +266 -0
  68. package/templates/docker/src/api/routes/health.ts +287 -0
  69. package/templates/docker/src/api/routes/openapi.ts +390 -0
  70. package/templates/docker/src/api/routes/query.ts +318 -0
  71. package/templates/docker/src/api/routes/scheduled-tasks.ts +467 -0
  72. package/templates/docker/src/api/routes/slack.ts +611 -0
  73. package/templates/docker/src/api/server.ts +226 -0
  74. package/templates/docker/src/app/api/[...route]/route.ts +33 -0
  75. package/templates/docker/src/app/error.tsx +24 -0
  76. package/templates/docker/src/app/globals.css +126 -0
  77. package/templates/docker/src/app/layout.tsx +19 -0
  78. package/templates/docker/src/app/page.tsx +14 -0
  79. package/templates/docker/src/global.d.ts +1 -0
  80. package/templates/docker/src/lib/__tests__/agent-cache.test.ts +437 -0
  81. package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +114 -0
  82. package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +164 -0
  83. package/templates/docker/src/lib/__tests__/agent-integration.test.ts +514 -0
  84. package/templates/docker/src/lib/__tests__/config-actions.test.ts +166 -0
  85. package/templates/docker/src/lib/__tests__/config.test.ts +1063 -0
  86. package/templates/docker/src/lib/__tests__/conversations.test.ts +589 -0
  87. package/templates/docker/src/lib/__tests__/errors.test.ts +256 -0
  88. package/templates/docker/src/lib/__tests__/logger.test.ts +200 -0
  89. package/templates/docker/src/lib/__tests__/providers.test.ts +99 -0
  90. package/templates/docker/src/lib/__tests__/rls.test.ts +435 -0
  91. package/templates/docker/src/lib/__tests__/scheduled-task-types.test.ts +124 -0
  92. package/templates/docker/src/lib/__tests__/scheduled-tasks.test.ts +550 -0
  93. package/templates/docker/src/lib/__tests__/semantic-index.test.ts +547 -0
  94. package/templates/docker/src/lib/__tests__/semantic-multisource.test.ts +544 -0
  95. package/templates/docker/src/lib/__tests__/semantic.test.ts +363 -0
  96. package/templates/docker/src/lib/__tests__/startup-actions.test.ts +452 -0
  97. package/templates/docker/src/lib/__tests__/startup.test.ts +465 -0
  98. package/templates/docker/src/lib/__tests__/tracing.test.ts +28 -0
  99. package/templates/docker/src/lib/action-types.ts +95 -0
  100. package/templates/docker/src/lib/agent-query.ts +178 -0
  101. package/templates/docker/src/lib/agent.ts +505 -0
  102. package/templates/docker/src/lib/api-url.ts +2 -0
  103. package/templates/docker/src/lib/auth/__tests__/audit.test.ts +418 -0
  104. package/templates/docker/src/lib/auth/__tests__/byot-integration.test.ts +222 -0
  105. package/templates/docker/src/lib/auth/__tests__/byot.test.ts +366 -0
  106. package/templates/docker/src/lib/auth/__tests__/detect.test.ts +190 -0
  107. package/templates/docker/src/lib/auth/__tests__/managed.test.ts +173 -0
  108. package/templates/docker/src/lib/auth/__tests__/middleware.test.ts +456 -0
  109. package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +201 -0
  110. package/templates/docker/src/lib/auth/__tests__/permissions.test.ts +225 -0
  111. package/templates/docker/src/lib/auth/__tests__/server.test.ts +34 -0
  112. package/templates/docker/src/lib/auth/__tests__/simple-key.test.ts +176 -0
  113. package/templates/docker/src/lib/auth/__tests__/types.test.ts +44 -0
  114. package/templates/docker/src/lib/auth/audit.ts +89 -0
  115. package/templates/docker/src/lib/auth/byot.ts +158 -0
  116. package/templates/docker/src/lib/auth/client.ts +35 -0
  117. package/templates/docker/src/lib/auth/detect.ts +83 -0
  118. package/templates/docker/src/lib/auth/managed.ts +73 -0
  119. package/templates/docker/src/lib/auth/middleware.ts +208 -0
  120. package/templates/docker/src/lib/auth/migrate.ts +111 -0
  121. package/templates/docker/src/lib/auth/permissions.ts +156 -0
  122. package/templates/docker/src/lib/auth/server.ts +142 -0
  123. package/templates/docker/src/lib/auth/simple-key.ts +92 -0
  124. package/templates/docker/src/lib/auth/types.ts +49 -0
  125. package/templates/docker/src/lib/config.ts +704 -0
  126. package/templates/docker/src/lib/conversation-types.ts +29 -0
  127. package/templates/docker/src/lib/conversations.ts +270 -0
  128. package/templates/docker/src/lib/db/__tests__/connection.test.ts +69 -0
  129. package/templates/docker/src/lib/db/__tests__/duckdb.test.ts +141 -0
  130. package/templates/docker/src/lib/db/__tests__/internal.test.ts +387 -0
  131. package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +207 -0
  132. package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +156 -0
  133. package/templates/docker/src/lib/db/__tests__/registry.test.ts +595 -0
  134. package/templates/docker/src/lib/db/__tests__/salesforce.test.ts +339 -0
  135. package/templates/docker/src/lib/db/__tests__/snowflake.test.ts +217 -0
  136. package/templates/docker/src/lib/db/__tests__/source-rate-limit.test.ts +130 -0
  137. package/templates/docker/src/lib/db/connection.ts +753 -0
  138. package/templates/docker/src/lib/db/duckdb.ts +122 -0
  139. package/templates/docker/src/lib/db/internal.ts +273 -0
  140. package/templates/docker/src/lib/db/salesforce.ts +342 -0
  141. package/templates/docker/src/lib/db/source-rate-limit.ts +191 -0
  142. package/templates/docker/src/lib/errors.ts +154 -0
  143. package/templates/docker/src/lib/logger.ts +98 -0
  144. package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +202 -0
  145. package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +529 -0
  146. package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +521 -0
  147. package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +346 -0
  148. package/templates/docker/src/lib/plugins/__tests__/tools.test.ts +49 -0
  149. package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +585 -0
  150. package/templates/docker/src/lib/plugins/hooks.ts +162 -0
  151. package/templates/docker/src/lib/plugins/index.ts +9 -0
  152. package/templates/docker/src/lib/plugins/migrate.ts +309 -0
  153. package/templates/docker/src/lib/plugins/registry.ts +231 -0
  154. package/templates/docker/src/lib/plugins/tools.ts +39 -0
  155. package/templates/docker/src/lib/plugins/wiring.ts +291 -0
  156. package/templates/docker/src/lib/providers.ts +102 -0
  157. package/templates/docker/src/lib/rls.ts +321 -0
  158. package/templates/docker/src/lib/scheduled-task-types.ts +132 -0
  159. package/templates/docker/src/lib/scheduled-tasks.ts +475 -0
  160. package/templates/docker/src/lib/scheduler/__tests__/delivery.test.ts +192 -0
  161. package/templates/docker/src/lib/scheduler/__tests__/engine.test.ts +248 -0
  162. package/templates/docker/src/lib/scheduler/__tests__/format-email.test.ts +96 -0
  163. package/templates/docker/src/lib/scheduler/__tests__/format-slack.test.ts +78 -0
  164. package/templates/docker/src/lib/scheduler/__tests__/format-webhook.test.ts +78 -0
  165. package/templates/docker/src/lib/scheduler/delivery.ts +248 -0
  166. package/templates/docker/src/lib/scheduler/engine.ts +317 -0
  167. package/templates/docker/src/lib/scheduler/executor.ts +73 -0
  168. package/templates/docker/src/lib/scheduler/format-email.ts +109 -0
  169. package/templates/docker/src/lib/scheduler/format-slack.ts +35 -0
  170. package/templates/docker/src/lib/scheduler/format-webhook.ts +37 -0
  171. package/templates/docker/src/lib/scheduler/index.ts +7 -0
  172. package/templates/docker/src/lib/security.ts +11 -0
  173. package/templates/docker/src/lib/semantic-index.ts +503 -0
  174. package/templates/docker/src/lib/semantic.ts +387 -0
  175. package/templates/docker/src/lib/sidecar-types.ts +16 -0
  176. package/templates/docker/src/lib/slack/__tests__/api.test.ts +160 -0
  177. package/templates/docker/src/lib/slack/__tests__/format.test.ts +237 -0
  178. package/templates/docker/src/lib/slack/__tests__/store.test.ts +188 -0
  179. package/templates/docker/src/lib/slack/__tests__/threads.test.ts +112 -0
  180. package/templates/docker/src/lib/slack/__tests__/verify.test.ts +111 -0
  181. package/templates/docker/src/lib/slack/api.ts +102 -0
  182. package/templates/docker/src/lib/slack/format.ts +209 -0
  183. package/templates/docker/src/lib/slack/store.ts +107 -0
  184. package/templates/docker/src/lib/slack/threads.ts +64 -0
  185. package/templates/docker/src/lib/slack/verify.ts +71 -0
  186. package/templates/docker/src/lib/startup.ts +730 -0
  187. package/templates/docker/src/lib/tools/__tests__/action-permissions.test.ts +594 -0
  188. package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +238 -0
  189. package/templates/docker/src/lib/tools/__tests__/explore-backend.test.ts +267 -0
  190. package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +492 -0
  191. package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +374 -0
  192. package/templates/docker/src/lib/tools/__tests__/explore-sdk-compat.test.ts +82 -0
  193. package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +208 -0
  194. package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +144 -0
  195. package/templates/docker/src/lib/tools/__tests__/registry.test.ts +235 -0
  196. package/templates/docker/src/lib/tools/__tests__/salesforce-tool.test.ts +154 -0
  197. package/templates/docker/src/lib/tools/__tests__/soql-validation.test.ts +303 -0
  198. package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +225 -0
  199. package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +98 -0
  200. package/templates/docker/src/lib/tools/__tests__/sql-duckdb.test.ts +233 -0
  201. package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +225 -0
  202. package/templates/docker/src/lib/tools/__tests__/sql.test.ts +1012 -0
  203. package/templates/docker/src/lib/tools/actions/__tests__/audit.test.ts +211 -0
  204. package/templates/docker/src/lib/tools/actions/__tests__/email.test.ts +378 -0
  205. package/templates/docker/src/lib/tools/actions/__tests__/handler.test.ts +681 -0
  206. package/templates/docker/src/lib/tools/actions/__tests__/jira.test.ts +427 -0
  207. package/templates/docker/src/lib/tools/actions/audit.ts +47 -0
  208. package/templates/docker/src/lib/tools/actions/email.ts +191 -0
  209. package/templates/docker/src/lib/tools/actions/handler.ts +591 -0
  210. package/templates/docker/src/lib/tools/actions/index.ts +23 -0
  211. package/templates/docker/src/lib/tools/actions/jira.ts +220 -0
  212. package/templates/docker/src/lib/tools/explore-nsjail.ts +343 -0
  213. package/templates/docker/src/lib/tools/explore-sandbox.ts +264 -0
  214. package/templates/docker/src/lib/tools/explore-sidecar.ts +163 -0
  215. package/templates/docker/src/lib/tools/explore.ts +379 -0
  216. package/templates/docker/src/lib/tools/registry.ts +221 -0
  217. package/templates/docker/src/lib/tools/salesforce.ts +138 -0
  218. package/templates/docker/src/lib/tools/soql-validation.ts +172 -0
  219. package/templates/docker/src/lib/tools/sql.ts +680 -0
  220. package/templates/docker/src/lib/tracing.ts +40 -0
  221. package/templates/docker/src/lib/utils.ts +6 -0
  222. package/templates/docker/src/test-setup.ts +38 -0
  223. package/templates/docker/src/types/vercel-sandbox.d.ts +54 -0
  224. package/templates/docker/src/ui/components/actions/action-approval-card.tsx +295 -0
  225. package/templates/docker/src/ui/components/actions/action-status-badge.tsx +50 -0
  226. package/templates/docker/src/ui/components/admin/admin-layout.tsx +26 -0
  227. package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +96 -0
  228. package/templates/docker/src/ui/components/admin/empty-state.tsx +24 -0
  229. package/templates/docker/src/ui/components/admin/entity-detail.tsx +233 -0
  230. package/templates/docker/src/ui/components/admin/entity-list.tsx +96 -0
  231. package/templates/docker/src/ui/components/admin/error-banner.tsx +22 -0
  232. package/templates/docker/src/ui/components/admin/feature-disabled.tsx +44 -0
  233. package/templates/docker/src/ui/components/admin/health-badge.tsx +30 -0
  234. package/templates/docker/src/ui/components/admin/loading-state.tsx +14 -0
  235. package/templates/docker/src/ui/components/admin/stat-card.tsx +32 -0
  236. package/templates/docker/src/ui/components/atlas-chat.tsx +370 -0
  237. package/templates/docker/src/ui/components/chart/chart-detection.ts +261 -0
  238. package/templates/docker/src/ui/components/chart/result-chart.tsx +375 -0
  239. package/templates/docker/src/ui/components/chat/api-key-bar.tsx +66 -0
  240. package/templates/docker/src/ui/components/chat/copy-button.tsx +25 -0
  241. package/templates/docker/src/ui/components/chat/data-table.tsx +102 -0
  242. package/templates/docker/src/ui/components/chat/error-banner.tsx +32 -0
  243. package/templates/docker/src/ui/components/chat/explore-card.tsx +41 -0
  244. package/templates/docker/src/ui/components/chat/loading-card.tsx +10 -0
  245. package/templates/docker/src/ui/components/chat/managed-auth-card.tsx +116 -0
  246. package/templates/docker/src/ui/components/chat/markdown.tsx +72 -0
  247. package/templates/docker/src/ui/components/chat/sql-block.tsx +30 -0
  248. package/templates/docker/src/ui/components/chat/sql-result-card.tsx +144 -0
  249. package/templates/docker/src/ui/components/chat/starter-prompts.ts +6 -0
  250. package/templates/docker/src/ui/components/chat/tool-part.tsx +40 -0
  251. package/templates/docker/src/ui/components/chat/typing-indicator.tsx +19 -0
  252. package/templates/docker/src/ui/components/conversations/conversation-item.tsx +120 -0
  253. package/templates/docker/src/ui/components/conversations/conversation-list.tsx +66 -0
  254. package/templates/docker/src/ui/components/conversations/conversation-sidebar.tsx +78 -0
  255. package/templates/docker/src/ui/components/conversations/delete-confirmation.tsx +27 -0
  256. package/templates/docker/src/ui/context.tsx +78 -0
  257. package/templates/docker/src/ui/hooks/use-admin-fetch.ts +104 -0
  258. package/templates/docker/src/ui/hooks/use-conversations.ts +184 -0
  259. package/templates/docker/src/ui/hooks/use-dark-mode.ts +17 -0
  260. package/templates/docker/src/ui/lib/action-types.ts +63 -0
  261. package/templates/docker/src/ui/lib/helpers.ts +104 -0
  262. package/templates/docker/src/ui/lib/types.ts +145 -0
  263. package/templates/docker/tsconfig.json +41 -0
  264. package/templates/docker/vercel.json +3 -0
  265. package/templates/nextjs-standalone/.env.example +68 -0
  266. package/templates/nextjs-standalone/bin/__tests__/benchmark.test.ts +598 -0
  267. package/templates/nextjs-standalone/bin/__tests__/duckdb-ingest.test.ts +171 -0
  268. package/templates/nextjs-standalone/bin/__tests__/eval.test.ts +434 -0
  269. package/templates/nextjs-standalone/bin/__tests__/matview-partition.test.ts +615 -0
  270. package/templates/nextjs-standalone/bin/__tests__/multi-source.test.ts +113 -0
  271. package/templates/nextjs-standalone/bin/__tests__/plugin-cli.test.ts +322 -0
  272. package/templates/nextjs-standalone/bin/__tests__/profiler-heuristics.test.ts +608 -0
  273. package/templates/nextjs-standalone/bin/__tests__/query.test.ts +240 -0
  274. package/templates/nextjs-standalone/bin/__tests__/schema-drift.test.ts +542 -0
  275. package/templates/nextjs-standalone/bin/__tests__/view-yaml-generation.test.ts +146 -0
  276. package/templates/nextjs-standalone/bin/atlas.ts +5044 -0
  277. package/templates/nextjs-standalone/bin/benchmark.ts +695 -0
  278. package/templates/nextjs-standalone/bin/enrich.ts +559 -0
  279. package/templates/nextjs-standalone/bin/eval.ts +770 -0
  280. package/templates/nextjs-standalone/bin/smoke.ts +438 -0
  281. package/templates/nextjs-standalone/data/.gitkeep +0 -0
  282. package/templates/nextjs-standalone/data/cybersec.sql +1961 -0
  283. package/templates/nextjs-standalone/data/demo-semantic/catalog.yml +40 -0
  284. package/templates/nextjs-standalone/data/demo-semantic/entities/accounts.yml +170 -0
  285. package/templates/nextjs-standalone/data/demo-semantic/entities/companies.yml +207 -0
  286. package/templates/nextjs-standalone/data/demo-semantic/entities/people.yml +145 -0
  287. package/templates/nextjs-standalone/data/demo-semantic/glossary.yml +22 -0
  288. package/templates/nextjs-standalone/data/demo-semantic/metrics/accounts.yml +38 -0
  289. package/templates/nextjs-standalone/data/demo-semantic/metrics/companies.yml +89 -0
  290. package/templates/nextjs-standalone/data/demo.sql +373 -0
  291. package/templates/nextjs-standalone/data/ecommerce.sql +1690 -0
  292. package/templates/nextjs-standalone/data/init-demo-db.sql +8 -0
  293. package/templates/nextjs-standalone/docs/deploy.md +390 -0
  294. package/templates/nextjs-standalone/eslint.config.mjs +18 -0
  295. package/templates/nextjs-standalone/gitignore +5 -0
  296. package/templates/nextjs-standalone/next.config.ts +10 -0
  297. package/templates/nextjs-standalone/package.json +63 -0
  298. package/templates/nextjs-standalone/postcss.config.mjs +8 -0
  299. package/templates/nextjs-standalone/semantic/catalog.yml +5 -0
  300. package/templates/nextjs-standalone/semantic/entities/.gitkeep +0 -0
  301. package/templates/nextjs-standalone/semantic/glossary.yml +6 -0
  302. package/templates/nextjs-standalone/semantic/metrics/.gitkeep +0 -0
  303. package/templates/nextjs-standalone/src/api/__tests__/actions.test.ts +683 -0
  304. package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +820 -0
  305. package/templates/nextjs-standalone/src/api/__tests__/auth.test.ts +165 -0
  306. package/templates/nextjs-standalone/src/api/__tests__/chat.test.ts +376 -0
  307. package/templates/nextjs-standalone/src/api/__tests__/conversations.test.ts +555 -0
  308. package/templates/nextjs-standalone/src/api/__tests__/cors.test.ts +135 -0
  309. package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +169 -0
  310. package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +261 -0
  311. package/templates/nextjs-standalone/src/api/__tests__/query.test.ts +891 -0
  312. package/templates/nextjs-standalone/src/api/__tests__/scheduled-tasks.test.ts +601 -0
  313. package/templates/nextjs-standalone/src/api/__tests__/slack.test.ts +847 -0
  314. package/templates/nextjs-standalone/src/api/index.ts +117 -0
  315. package/templates/nextjs-standalone/src/api/routes/actions.ts +274 -0
  316. package/templates/nextjs-standalone/src/api/routes/admin.ts +757 -0
  317. package/templates/nextjs-standalone/src/api/routes/auth.ts +48 -0
  318. package/templates/nextjs-standalone/src/api/routes/chat.ts +465 -0
  319. package/templates/nextjs-standalone/src/api/routes/conversations.ts +266 -0
  320. package/templates/nextjs-standalone/src/api/routes/health.ts +287 -0
  321. package/templates/nextjs-standalone/src/api/routes/openapi.ts +390 -0
  322. package/templates/nextjs-standalone/src/api/routes/query.ts +318 -0
  323. package/templates/nextjs-standalone/src/api/routes/scheduled-tasks.ts +467 -0
  324. package/templates/nextjs-standalone/src/api/routes/slack.ts +611 -0
  325. package/templates/nextjs-standalone/src/api/server.ts +226 -0
  326. package/templates/nextjs-standalone/src/app/api/[...route]/route.ts +33 -0
  327. package/templates/nextjs-standalone/src/app/error.tsx +24 -0
  328. package/templates/nextjs-standalone/src/app/global-error.tsx +68 -0
  329. package/templates/nextjs-standalone/src/app/globals.css +126 -0
  330. package/templates/nextjs-standalone/src/app/layout.tsx +19 -0
  331. package/templates/nextjs-standalone/src/app/page.tsx +14 -0
  332. package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +437 -0
  333. package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +114 -0
  334. package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +164 -0
  335. package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +514 -0
  336. package/templates/nextjs-standalone/src/lib/__tests__/config-actions.test.ts +166 -0
  337. package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +1063 -0
  338. package/templates/nextjs-standalone/src/lib/__tests__/conversations.test.ts +589 -0
  339. package/templates/nextjs-standalone/src/lib/__tests__/errors.test.ts +256 -0
  340. package/templates/nextjs-standalone/src/lib/__tests__/logger.test.ts +200 -0
  341. package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +99 -0
  342. package/templates/nextjs-standalone/src/lib/__tests__/rls.test.ts +435 -0
  343. package/templates/nextjs-standalone/src/lib/__tests__/scheduled-task-types.test.ts +124 -0
  344. package/templates/nextjs-standalone/src/lib/__tests__/scheduled-tasks.test.ts +550 -0
  345. package/templates/nextjs-standalone/src/lib/__tests__/semantic-index.test.ts +547 -0
  346. package/templates/nextjs-standalone/src/lib/__tests__/semantic-multisource.test.ts +544 -0
  347. package/templates/nextjs-standalone/src/lib/__tests__/semantic.test.ts +363 -0
  348. package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +452 -0
  349. package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +465 -0
  350. package/templates/nextjs-standalone/src/lib/__tests__/tracing.test.ts +28 -0
  351. package/templates/nextjs-standalone/src/lib/action-types.ts +95 -0
  352. package/templates/nextjs-standalone/src/lib/agent-query.ts +178 -0
  353. package/templates/nextjs-standalone/src/lib/agent.ts +505 -0
  354. package/templates/nextjs-standalone/src/lib/api-url.ts +3 -0
  355. package/templates/nextjs-standalone/src/lib/auth/__tests__/audit.test.ts +418 -0
  356. package/templates/nextjs-standalone/src/lib/auth/__tests__/byot-integration.test.ts +222 -0
  357. package/templates/nextjs-standalone/src/lib/auth/__tests__/byot.test.ts +366 -0
  358. package/templates/nextjs-standalone/src/lib/auth/__tests__/detect.test.ts +190 -0
  359. package/templates/nextjs-standalone/src/lib/auth/__tests__/managed.test.ts +173 -0
  360. package/templates/nextjs-standalone/src/lib/auth/__tests__/middleware.test.ts +456 -0
  361. package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +201 -0
  362. package/templates/nextjs-standalone/src/lib/auth/__tests__/permissions.test.ts +225 -0
  363. package/templates/nextjs-standalone/src/lib/auth/__tests__/server.test.ts +34 -0
  364. package/templates/nextjs-standalone/src/lib/auth/__tests__/simple-key.test.ts +176 -0
  365. package/templates/nextjs-standalone/src/lib/auth/__tests__/types.test.ts +44 -0
  366. package/templates/nextjs-standalone/src/lib/auth/audit.ts +89 -0
  367. package/templates/nextjs-standalone/src/lib/auth/byot.ts +158 -0
  368. package/templates/nextjs-standalone/src/lib/auth/client.ts +23 -0
  369. package/templates/nextjs-standalone/src/lib/auth/detect.ts +83 -0
  370. package/templates/nextjs-standalone/src/lib/auth/managed.ts +73 -0
  371. package/templates/nextjs-standalone/src/lib/auth/middleware.ts +208 -0
  372. package/templates/nextjs-standalone/src/lib/auth/migrate.ts +111 -0
  373. package/templates/nextjs-standalone/src/lib/auth/permissions.ts +156 -0
  374. package/templates/nextjs-standalone/src/lib/auth/server.ts +142 -0
  375. package/templates/nextjs-standalone/src/lib/auth/simple-key.ts +92 -0
  376. package/templates/nextjs-standalone/src/lib/auth/types.ts +49 -0
  377. package/templates/nextjs-standalone/src/lib/config.ts +704 -0
  378. package/templates/nextjs-standalone/src/lib/conversation-types.ts +29 -0
  379. package/templates/nextjs-standalone/src/lib/conversations.ts +270 -0
  380. package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +69 -0
  381. package/templates/nextjs-standalone/src/lib/db/__tests__/duckdb.test.ts +141 -0
  382. package/templates/nextjs-standalone/src/lib/db/__tests__/internal.test.ts +387 -0
  383. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +207 -0
  384. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +156 -0
  385. package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +595 -0
  386. package/templates/nextjs-standalone/src/lib/db/__tests__/salesforce.test.ts +339 -0
  387. package/templates/nextjs-standalone/src/lib/db/__tests__/snowflake.test.ts +217 -0
  388. package/templates/nextjs-standalone/src/lib/db/__tests__/source-rate-limit.test.ts +130 -0
  389. package/templates/nextjs-standalone/src/lib/db/connection.ts +753 -0
  390. package/templates/nextjs-standalone/src/lib/db/duckdb.ts +122 -0
  391. package/templates/nextjs-standalone/src/lib/db/internal.ts +273 -0
  392. package/templates/nextjs-standalone/src/lib/db/salesforce.ts +342 -0
  393. package/templates/nextjs-standalone/src/lib/db/source-rate-limit.ts +191 -0
  394. package/templates/nextjs-standalone/src/lib/errors.ts +154 -0
  395. package/templates/nextjs-standalone/src/lib/logger.ts +98 -0
  396. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +202 -0
  397. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +529 -0
  398. package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +521 -0
  399. package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +346 -0
  400. package/templates/nextjs-standalone/src/lib/plugins/__tests__/tools.test.ts +49 -0
  401. package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +585 -0
  402. package/templates/nextjs-standalone/src/lib/plugins/hooks.ts +162 -0
  403. package/templates/nextjs-standalone/src/lib/plugins/index.ts +9 -0
  404. package/templates/nextjs-standalone/src/lib/plugins/migrate.ts +309 -0
  405. package/templates/nextjs-standalone/src/lib/plugins/registry.ts +231 -0
  406. package/templates/nextjs-standalone/src/lib/plugins/tools.ts +39 -0
  407. package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +291 -0
  408. package/templates/nextjs-standalone/src/lib/providers.ts +102 -0
  409. package/templates/nextjs-standalone/src/lib/rls.ts +321 -0
  410. package/templates/nextjs-standalone/src/lib/scheduled-task-types.ts +132 -0
  411. package/templates/nextjs-standalone/src/lib/scheduled-tasks.ts +475 -0
  412. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/delivery.test.ts +192 -0
  413. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/engine.test.ts +248 -0
  414. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-email.test.ts +96 -0
  415. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-slack.test.ts +78 -0
  416. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-webhook.test.ts +78 -0
  417. package/templates/nextjs-standalone/src/lib/scheduler/delivery.ts +248 -0
  418. package/templates/nextjs-standalone/src/lib/scheduler/engine.ts +317 -0
  419. package/templates/nextjs-standalone/src/lib/scheduler/executor.ts +73 -0
  420. package/templates/nextjs-standalone/src/lib/scheduler/format-email.ts +109 -0
  421. package/templates/nextjs-standalone/src/lib/scheduler/format-slack.ts +35 -0
  422. package/templates/nextjs-standalone/src/lib/scheduler/format-webhook.ts +37 -0
  423. package/templates/nextjs-standalone/src/lib/scheduler/index.ts +7 -0
  424. package/templates/nextjs-standalone/src/lib/security.ts +11 -0
  425. package/templates/nextjs-standalone/src/lib/semantic-index.ts +503 -0
  426. package/templates/nextjs-standalone/src/lib/semantic.ts +387 -0
  427. package/templates/nextjs-standalone/src/lib/sidecar-types.ts +16 -0
  428. package/templates/nextjs-standalone/src/lib/slack/__tests__/api.test.ts +160 -0
  429. package/templates/nextjs-standalone/src/lib/slack/__tests__/format.test.ts +237 -0
  430. package/templates/nextjs-standalone/src/lib/slack/__tests__/store.test.ts +188 -0
  431. package/templates/nextjs-standalone/src/lib/slack/__tests__/threads.test.ts +112 -0
  432. package/templates/nextjs-standalone/src/lib/slack/__tests__/verify.test.ts +111 -0
  433. package/templates/nextjs-standalone/src/lib/slack/api.ts +102 -0
  434. package/templates/nextjs-standalone/src/lib/slack/format.ts +209 -0
  435. package/templates/nextjs-standalone/src/lib/slack/store.ts +107 -0
  436. package/templates/nextjs-standalone/src/lib/slack/threads.ts +64 -0
  437. package/templates/nextjs-standalone/src/lib/slack/verify.ts +71 -0
  438. package/templates/nextjs-standalone/src/lib/startup.ts +730 -0
  439. package/templates/nextjs-standalone/src/lib/tools/__tests__/action-permissions.test.ts +594 -0
  440. package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +238 -0
  441. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-backend.test.ts +267 -0
  442. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +492 -0
  443. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +374 -0
  444. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sdk-compat.test.ts +82 -0
  445. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +208 -0
  446. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +144 -0
  447. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +235 -0
  448. package/templates/nextjs-standalone/src/lib/tools/__tests__/salesforce-tool.test.ts +154 -0
  449. package/templates/nextjs-standalone/src/lib/tools/__tests__/soql-validation.test.ts +303 -0
  450. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +225 -0
  451. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +98 -0
  452. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-duckdb.test.ts +233 -0
  453. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +225 -0
  454. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +1012 -0
  455. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/audit.test.ts +211 -0
  456. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/email.test.ts +378 -0
  457. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/handler.test.ts +681 -0
  458. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/jira.test.ts +427 -0
  459. package/templates/nextjs-standalone/src/lib/tools/actions/audit.ts +47 -0
  460. package/templates/nextjs-standalone/src/lib/tools/actions/email.ts +191 -0
  461. package/templates/nextjs-standalone/src/lib/tools/actions/handler.ts +591 -0
  462. package/templates/nextjs-standalone/src/lib/tools/actions/index.ts +23 -0
  463. package/templates/nextjs-standalone/src/lib/tools/actions/jira.ts +220 -0
  464. package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +343 -0
  465. package/templates/nextjs-standalone/src/lib/tools/explore-sandbox.ts +264 -0
  466. package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +163 -0
  467. package/templates/nextjs-standalone/src/lib/tools/explore.ts +379 -0
  468. package/templates/nextjs-standalone/src/lib/tools/registry.ts +221 -0
  469. package/templates/nextjs-standalone/src/lib/tools/salesforce.ts +138 -0
  470. package/templates/nextjs-standalone/src/lib/tools/soql-validation.ts +172 -0
  471. package/templates/nextjs-standalone/src/lib/tools/sql.ts +680 -0
  472. package/templates/nextjs-standalone/src/lib/tracing.ts +40 -0
  473. package/templates/nextjs-standalone/src/lib/utils.ts +6 -0
  474. package/templates/nextjs-standalone/src/test-setup.ts +38 -0
  475. package/templates/nextjs-standalone/src/ui/components/actions/action-approval-card.tsx +295 -0
  476. package/templates/nextjs-standalone/src/ui/components/actions/action-status-badge.tsx +50 -0
  477. package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +26 -0
  478. package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +96 -0
  479. package/templates/nextjs-standalone/src/ui/components/admin/empty-state.tsx +24 -0
  480. package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +233 -0
  481. package/templates/nextjs-standalone/src/ui/components/admin/entity-list.tsx +96 -0
  482. package/templates/nextjs-standalone/src/ui/components/admin/error-banner.tsx +22 -0
  483. package/templates/nextjs-standalone/src/ui/components/admin/feature-disabled.tsx +44 -0
  484. package/templates/nextjs-standalone/src/ui/components/admin/health-badge.tsx +30 -0
  485. package/templates/nextjs-standalone/src/ui/components/admin/loading-state.tsx +14 -0
  486. package/templates/nextjs-standalone/src/ui/components/admin/stat-card.tsx +32 -0
  487. package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +370 -0
  488. package/templates/nextjs-standalone/src/ui/components/chart/chart-detection.ts +261 -0
  489. package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +375 -0
  490. package/templates/nextjs-standalone/src/ui/components/chat/api-key-bar.tsx +66 -0
  491. package/templates/nextjs-standalone/src/ui/components/chat/copy-button.tsx +25 -0
  492. package/templates/nextjs-standalone/src/ui/components/chat/data-table.tsx +102 -0
  493. package/templates/nextjs-standalone/src/ui/components/chat/error-banner.tsx +32 -0
  494. package/templates/nextjs-standalone/src/ui/components/chat/explore-card.tsx +41 -0
  495. package/templates/nextjs-standalone/src/ui/components/chat/loading-card.tsx +10 -0
  496. package/templates/nextjs-standalone/src/ui/components/chat/managed-auth-card.tsx +116 -0
  497. package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +72 -0
  498. package/templates/nextjs-standalone/src/ui/components/chat/sql-block.tsx +30 -0
  499. package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +144 -0
  500. package/templates/nextjs-standalone/src/ui/components/chat/starter-prompts.ts +6 -0
  501. package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +40 -0
  502. package/templates/nextjs-standalone/src/ui/components/chat/typing-indicator.tsx +19 -0
  503. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +120 -0
  504. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-list.tsx +66 -0
  505. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-sidebar.tsx +78 -0
  506. package/templates/nextjs-standalone/src/ui/components/conversations/delete-confirmation.tsx +27 -0
  507. package/templates/nextjs-standalone/src/ui/context.tsx +78 -0
  508. package/templates/nextjs-standalone/src/ui/hooks/use-admin-fetch.ts +104 -0
  509. package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +184 -0
  510. package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +17 -0
  511. package/templates/nextjs-standalone/src/ui/lib/action-types.ts +63 -0
  512. package/templates/nextjs-standalone/src/ui/lib/helpers.ts +104 -0
  513. package/templates/nextjs-standalone/src/ui/lib/types.ts +145 -0
  514. package/templates/nextjs-standalone/tsconfig.json +32 -0
  515. package/templates/nextjs-standalone/vercel.json +4 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Conversation persistence types for Atlas.
3
+ */
4
+
5
+ export type MessageRole = "user" | "assistant" | "system" | "tool";
6
+ export type Surface = "web" | "api" | "mcp" | "slack";
7
+
8
+ export interface Conversation {
9
+ id: string;
10
+ userId: string | null;
11
+ title: string | null;
12
+ surface: Surface;
13
+ connectionId: string | null;
14
+ starred: boolean;
15
+ createdAt: string;
16
+ updatedAt: string;
17
+ }
18
+
19
+ export interface Message {
20
+ id: string;
21
+ conversationId: string;
22
+ role: MessageRole;
23
+ content: unknown;
24
+ createdAt: string;
25
+ }
26
+
27
+ export interface ConversationWithMessages extends Conversation {
28
+ messages: Message[];
29
+ }
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Conversation persistence — CRUD operations for conversations and messages.
3
+ *
4
+ * Functions that need callers to distinguish failure modes (get, delete, star)
5
+ * return discriminated union results (CrudResult / CrudDataResult). Functions
6
+ * that are fire-and-forget (createConversation, addMessage) still return
7
+ * null/void. Failures are logged but never propagate as exceptions.
8
+ */
9
+
10
+ import { createLogger } from "@atlas/api/lib/logger";
11
+ import {
12
+ hasInternalDB,
13
+ internalQuery,
14
+ internalExecute,
15
+ } from "@atlas/api/lib/db/internal";
16
+
17
+ const log = createLogger("conversations");
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Types
21
+ // ---------------------------------------------------------------------------
22
+
23
+ import type { MessageRole, Surface, Conversation, Message, ConversationWithMessages } from "@atlas/api/lib/conversation-types";
24
+ export type { MessageRole, Surface, Conversation, Message, ConversationWithMessages };
25
+
26
+ /** Failure reason for CRUD operations that need to distinguish no-DB / not-found / error. */
27
+ export type CrudFailReason = "no_db" | "not_found" | "error";
28
+
29
+ /** Discriminated union result for mutation CRUD ops (star, delete). */
30
+ export type CrudResult = { ok: true } | { ok: false; reason: CrudFailReason };
31
+
32
+ /** Discriminated union result for CRUD ops that return data on success. */
33
+ export type CrudDataResult<T> = { ok: true; data: T } | { ok: false; reason: CrudFailReason };
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Helpers
37
+ // ---------------------------------------------------------------------------
38
+
39
+ function rowToConversation(r: Record<string, unknown>): Conversation {
40
+ return {
41
+ id: r.id as string,
42
+ userId: (r.user_id as string) ?? null,
43
+ title: (r.title as string) ?? null,
44
+ surface: (r.surface as Surface) ?? "web",
45
+ connectionId: (r.connection_id as string) ?? null,
46
+ starred: r.starred === true,
47
+ createdAt: String(r.created_at),
48
+ updatedAt: String(r.updated_at),
49
+ };
50
+ }
51
+
52
+ /** Generate a short title from the first user question. */
53
+ export function generateTitle(question: string): string {
54
+ const cleaned = question.replace(/[\r\n]+/g, " ").trim();
55
+ if (!cleaned) return "New conversation";
56
+ if (cleaned.length <= 80) return cleaned;
57
+ return cleaned.slice(0, 77) + "...";
58
+ }
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // CRUD
62
+ // ---------------------------------------------------------------------------
63
+
64
+ /** Create a new conversation. Returns { id } or null if unavailable. */
65
+ export async function createConversation(opts: {
66
+ id?: string;
67
+ userId?: string | null;
68
+ title?: string | null;
69
+ surface?: string;
70
+ connectionId?: string | null;
71
+ }): Promise<{ id: string } | null> {
72
+ if (!hasInternalDB()) return null;
73
+ try {
74
+ const rows = opts.id
75
+ ? await internalQuery<{ id: string }>(
76
+ `INSERT INTO conversations (id, user_id, title, surface, connection_id)
77
+ VALUES ($1, $2, $3, $4, $5)
78
+ RETURNING id`,
79
+ [
80
+ opts.id,
81
+ opts.userId ?? null,
82
+ opts.title ?? null,
83
+ opts.surface ?? "web",
84
+ opts.connectionId ?? null,
85
+ ],
86
+ )
87
+ : await internalQuery<{ id: string }>(
88
+ `INSERT INTO conversations (user_id, title, surface, connection_id)
89
+ VALUES ($1, $2, $3, $4)
90
+ RETURNING id`,
91
+ [
92
+ opts.userId ?? null,
93
+ opts.title ?? null,
94
+ opts.surface ?? "web",
95
+ opts.connectionId ?? null,
96
+ ],
97
+ );
98
+ return rows[0] ?? null;
99
+ } catch (err) {
100
+ log.error({ err: err instanceof Error ? err.message : String(err) }, "createConversation failed");
101
+ return null;
102
+ }
103
+ }
104
+
105
+ /** Fire-and-forget — inserts the message and bumps updated_at in two separate non-transactional writes. */
106
+ export function addMessage(opts: {
107
+ conversationId: string;
108
+ role: MessageRole;
109
+ content: unknown;
110
+ }): void {
111
+ if (!hasInternalDB()) return;
112
+ // internalExecute is fire-and-forget — async errors are logged internally.
113
+ // Two separate non-transactional writes (partial success is possible).
114
+ internalExecute(
115
+ `INSERT INTO messages (conversation_id, role, content) VALUES ($1, $2, $3)`,
116
+ [opts.conversationId, opts.role, JSON.stringify(opts.content)],
117
+ );
118
+ internalExecute(
119
+ `UPDATE conversations SET updated_at = now() WHERE id = $1`,
120
+ [opts.conversationId],
121
+ );
122
+ }
123
+
124
+ /** Fetches a conversation with its messages. When userId is provided, enforces ownership (AND user_id = $2); when omitted, fetches without ownership check. */
125
+ export async function getConversation(
126
+ id: string,
127
+ userId?: string | null,
128
+ ): Promise<CrudDataResult<ConversationWithMessages>> {
129
+ if (!hasInternalDB()) return { ok: false, reason: "no_db" };
130
+ try {
131
+ const convRows = userId
132
+ ? await internalQuery<Record<string, unknown>>(
133
+ `SELECT id, user_id, title, surface, connection_id, starred, created_at, updated_at
134
+ FROM conversations WHERE id = $1 AND user_id = $2`,
135
+ [id, userId],
136
+ )
137
+ : await internalQuery<Record<string, unknown>>(
138
+ `SELECT id, user_id, title, surface, connection_id, starred, created_at, updated_at
139
+ FROM conversations WHERE id = $1`,
140
+ [id],
141
+ );
142
+
143
+ if (convRows.length === 0) return { ok: false, reason: "not_found" };
144
+
145
+ const msgRows = await internalQuery<Record<string, unknown>>(
146
+ `SELECT id, conversation_id, role, content, created_at
147
+ FROM messages WHERE conversation_id = $1 ORDER BY created_at ASC`,
148
+ [id],
149
+ );
150
+
151
+ return {
152
+ ok: true,
153
+ data: {
154
+ ...rowToConversation(convRows[0]),
155
+ messages: msgRows.map((m) => ({
156
+ id: m.id as string,
157
+ conversationId: m.conversation_id as string,
158
+ role: m.role as MessageRole,
159
+ content: m.content,
160
+ createdAt: String(m.created_at),
161
+ })),
162
+ },
163
+ };
164
+ } catch (err) {
165
+ log.error({ err: err instanceof Error ? err.message : String(err) }, "getConversation failed");
166
+ return { ok: false, reason: "error" };
167
+ }
168
+ }
169
+
170
+ /** List conversations (metadata only, no messages). Auth-scoped when userId is provided. */
171
+ export async function listConversations(opts?: {
172
+ userId?: string | null;
173
+ starred?: boolean;
174
+ limit?: number;
175
+ offset?: number;
176
+ }): Promise<{ conversations: Conversation[]; total: number }> {
177
+ const empty = { conversations: [], total: 0 };
178
+ if (!hasInternalDB()) return empty;
179
+
180
+ const limit = opts?.limit ?? 20;
181
+ const offset = opts?.offset ?? 0;
182
+
183
+ try {
184
+ // Build WHERE clause dynamically
185
+ const conditions: string[] = [];
186
+ const params: unknown[] = [];
187
+ let paramIdx = 1;
188
+
189
+ if (opts?.userId) {
190
+ conditions.push(`user_id = $${paramIdx++}`);
191
+ params.push(opts.userId);
192
+ }
193
+ if (opts?.starred !== undefined) {
194
+ conditions.push(`starred = $${paramIdx++}`);
195
+ params.push(opts.starred);
196
+ }
197
+
198
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
199
+
200
+ const countRows = await internalQuery<Record<string, unknown>>(
201
+ `SELECT COUNT(*)::int AS total FROM conversations ${where}`,
202
+ params,
203
+ );
204
+ const dataRows = await internalQuery<Record<string, unknown>>(
205
+ `SELECT id, user_id, title, surface, connection_id, starred, created_at, updated_at
206
+ FROM conversations ${where}
207
+ ORDER BY updated_at DESC LIMIT $${paramIdx++} OFFSET $${paramIdx++}`,
208
+ [...params, limit, offset],
209
+ );
210
+
211
+ const total = (countRows[0]?.total as number) ?? 0;
212
+
213
+ return {
214
+ conversations: dataRows.map(rowToConversation),
215
+ total,
216
+ };
217
+ } catch (err) {
218
+ log.error({ err: err instanceof Error ? err.message : String(err) }, "listConversations failed");
219
+ return empty;
220
+ }
221
+ }
222
+
223
+ /** Set the starred flag on a conversation. Auth-scoped when userId is provided. */
224
+ export async function starConversation(
225
+ id: string,
226
+ starred: boolean,
227
+ userId?: string | null,
228
+ ): Promise<CrudResult> {
229
+ if (!hasInternalDB()) return { ok: false, reason: "no_db" };
230
+ try {
231
+ const rows = userId
232
+ ? await internalQuery<{ id: string }>(
233
+ `UPDATE conversations SET starred = $1, updated_at = now()
234
+ WHERE id = $2 AND user_id = $3 RETURNING id`,
235
+ [starred, id, userId],
236
+ )
237
+ : await internalQuery<{ id: string }>(
238
+ `UPDATE conversations SET starred = $1, updated_at = now()
239
+ WHERE id = $2 RETURNING id`,
240
+ [starred, id],
241
+ );
242
+ return rows.length > 0 ? { ok: true } : { ok: false, reason: "not_found" };
243
+ } catch (err) {
244
+ log.error({ err: err instanceof Error ? err.message : String(err) }, "starConversation failed");
245
+ return { ok: false, reason: "error" };
246
+ }
247
+ }
248
+
249
+ /** Delete a conversation (CASCADE deletes messages). Auth-scoped when userId is provided. */
250
+ export async function deleteConversation(
251
+ id: string,
252
+ userId?: string | null,
253
+ ): Promise<CrudResult> {
254
+ if (!hasInternalDB()) return { ok: false, reason: "no_db" };
255
+ try {
256
+ const rows = userId
257
+ ? await internalQuery<{ id: string }>(
258
+ `DELETE FROM conversations WHERE id = $1 AND user_id = $2 RETURNING id`,
259
+ [id, userId],
260
+ )
261
+ : await internalQuery<{ id: string }>(
262
+ `DELETE FROM conversations WHERE id = $1 RETURNING id`,
263
+ [id],
264
+ );
265
+ return rows.length > 0 ? { ok: true } : { ok: false, reason: "not_found" };
266
+ } catch (err) {
267
+ log.error({ err: err instanceof Error ? err.message : String(err) }, "deleteConversation failed");
268
+ return { ok: false, reason: "error" };
269
+ }
270
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Tests for detectDBType from connection.ts.
3
+ *
4
+ * sql.test.ts registers a global mock.module for @/lib/db/connection which
5
+ * persists across bun's test runner. To test the real implementation, we
6
+ * import the source file via a cache-busting query string that bypasses the mock.
7
+ */
8
+ import { describe, it, expect, beforeEach } from "bun:test";
9
+ import { resolve } from "path";
10
+
11
+ const modulePath = resolve(__dirname, "../connection.ts");
12
+ const mod = await import(`${modulePath}?t=${Date.now()}`);
13
+ const detectDBType = mod.detectDBType as (url?: string) => "postgres" | "mysql" | "duckdb";
14
+
15
+ describe("detectDBType", () => {
16
+ const origDatabaseUrl = process.env.ATLAS_DATASOURCE_URL;
17
+
18
+ beforeEach(() => {
19
+ if (origDatabaseUrl !== undefined) {
20
+ process.env.ATLAS_DATASOURCE_URL = origDatabaseUrl;
21
+ } else {
22
+ delete process.env.ATLAS_DATASOURCE_URL;
23
+ }
24
+ });
25
+
26
+ it("detects postgresql:// as postgres", () => {
27
+ expect(detectDBType("postgresql://user:pass@localhost:5432/db")).toBe("postgres");
28
+ });
29
+
30
+ it("detects postgres:// as postgres", () => {
31
+ expect(detectDBType("postgres://user:pass@localhost:5432/db")).toBe("postgres");
32
+ });
33
+
34
+ it("detects mysql:// as mysql", () => {
35
+ expect(detectDBType("mysql://user:pass@localhost:3306/db")).toBe("mysql");
36
+ });
37
+
38
+ it("detects mysql2:// as mysql", () => {
39
+ expect(detectDBType("mysql2://user:pass@localhost:3306/db")).toBe("mysql");
40
+ });
41
+
42
+ it("uses ATLAS_DATASOURCE_URL env var when no argument provided", () => {
43
+ process.env.ATLAS_DATASOURCE_URL = "mysql://test@localhost/db";
44
+ expect(detectDBType()).toBe("mysql");
45
+ });
46
+
47
+ it("throws when ATLAS_DATASOURCE_URL is unset and no argument provided", () => {
48
+ delete process.env.ATLAS_DATASOURCE_URL;
49
+ expect(() => detectDBType()).toThrow("No database URL provided");
50
+ });
51
+
52
+ it("throws for empty string argument", () => {
53
+ expect(() => detectDBType("")).toThrow("No database URL provided");
54
+ });
55
+
56
+ it("detects duckdb:// as duckdb", () => {
57
+ expect(detectDBType("duckdb://:memory:")).toBe("duckdb");
58
+ });
59
+
60
+ it("detects duckdb://path as duckdb", () => {
61
+ expect(detectDBType("duckdb:///tmp/test.duckdb")).toBe("duckdb");
62
+ });
63
+
64
+ it("unrecognized URL throws an error", () => {
65
+ expect(() => detectDBType("file:./data/test.db")).toThrow(
66
+ "Unsupported database URL"
67
+ );
68
+ });
69
+ });
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Tests for the DuckDB adapter (duckdb.ts) and DuckDB URL parsing.
3
+ *
4
+ * Uses a real in-memory DuckDB instance (no mocks) to verify end-to-end
5
+ * query execution, column extraction, and close behavior.
6
+ */
7
+ import { describe, it, expect, afterEach } from "bun:test";
8
+ import { parseDuckDBUrl, createDuckDBConnection } from "../duckdb";
9
+ import type { DBConnection } from "../connection";
10
+ import * as fs from "fs";
11
+ import * as path from "path";
12
+ import * as os from "os";
13
+
14
+ describe("parseDuckDBUrl", () => {
15
+ it("parses duckdb://:memory: as in-memory", () => {
16
+ const config = parseDuckDBUrl("duckdb://:memory:");
17
+ expect(config.path).toBe(":memory:");
18
+ });
19
+
20
+ it("parses bare duckdb:// as in-memory", () => {
21
+ const config = parseDuckDBUrl("duckdb://");
22
+ expect(config.path).toBe(":memory:");
23
+ });
24
+
25
+ it("parses duckdb:///absolute/path.duckdb", () => {
26
+ const config = parseDuckDBUrl("duckdb:///tmp/test.duckdb");
27
+ expect(config.path).toBe("/tmp/test.duckdb");
28
+ });
29
+
30
+ it("parses duckdb://relative/path.duckdb", () => {
31
+ const config = parseDuckDBUrl("duckdb://data/test.duckdb");
32
+ expect(config.path).toBe("data/test.duckdb");
33
+ });
34
+
35
+ it("throws for non-duckdb:// URL", () => {
36
+ expect(() => parseDuckDBUrl("postgresql://localhost/db")).toThrow("Invalid DuckDB URL");
37
+ });
38
+ });
39
+
40
+ describe("createDuckDBConnection", () => {
41
+ let conn: DBConnection | null = null;
42
+
43
+ afterEach(async () => {
44
+ if (conn) {
45
+ await conn.close();
46
+ conn = null;
47
+ }
48
+ });
49
+
50
+ it("creates a connection and runs a simple query", async () => {
51
+ conn = createDuckDBConnection({ path: ":memory:", readOnly: false });
52
+ const result = await conn.query("SELECT 42 AS answer");
53
+ expect(result.columns).toEqual(["answer"]);
54
+ expect(result.rows).toHaveLength(1);
55
+ expect(result.rows[0].answer).toBe(42);
56
+ });
57
+
58
+ it("returns correct columns and rows for multi-column queries", async () => {
59
+ conn = createDuckDBConnection({ path: ":memory:", readOnly: false });
60
+ const result = await conn.query("SELECT 1 AS a, 'hello' AS b, true AS c");
61
+ expect(result.columns).toEqual(["a", "b", "c"]);
62
+ expect(result.rows).toHaveLength(1);
63
+ expect(result.rows[0].a).toBe(1);
64
+ expect(result.rows[0].b).toBe("hello");
65
+ expect(result.rows[0].c).toBe(true);
66
+ });
67
+
68
+ it("handles empty result sets", async () => {
69
+ conn = createDuckDBConnection({ path: ":memory:", readOnly: false });
70
+ const result = await conn.query("SELECT 1 AS n WHERE false");
71
+ expect(result.columns).toEqual(["n"]);
72
+ expect(result.rows).toHaveLength(0);
73
+ });
74
+
75
+ it("supports CREATE TABLE and SELECT in read-write mode", async () => {
76
+ conn = createDuckDBConnection({ path: ":memory:", readOnly: false });
77
+ await conn.query("CREATE TABLE test (id INTEGER, name VARCHAR)");
78
+ await conn.query("INSERT INTO test VALUES (1, 'alice'), (2, 'bob')");
79
+ const result = await conn.query("SELECT * FROM test ORDER BY id");
80
+ expect(result.columns).toEqual(["id", "name"]);
81
+ expect(result.rows).toHaveLength(2);
82
+ expect(result.rows[0].name).toBe("alice");
83
+ expect(result.rows[1].name).toBe("bob");
84
+ });
85
+
86
+ it("supports VALUES clause for inline data", async () => {
87
+ conn = createDuckDBConnection({ path: ":memory:", readOnly: false });
88
+ const result = await conn.query(
89
+ "SELECT * FROM (VALUES (1, 'a'), (2, 'b'), (3, 'c')) AS t(id, letter)"
90
+ );
91
+ expect(result.rows).toHaveLength(3);
92
+ });
93
+
94
+ it("close is idempotent", async () => {
95
+ conn = createDuckDBConnection({ path: ":memory:", readOnly: false });
96
+ await conn.query("SELECT 1");
97
+ await conn.close();
98
+ await conn.close(); // Should not throw
99
+ conn = null; // Prevent afterEach from closing again
100
+ });
101
+
102
+ it("enforces read-only mode for file-based databases", async () => {
103
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "atlas-duckdb-ro-"));
104
+ try {
105
+ const dbPath = path.join(tmpDir, "test.duckdb");
106
+
107
+ // Create and populate the database first (read-write)
108
+ const rwConn = createDuckDBConnection({ path: dbPath, readOnly: false });
109
+ await rwConn.query("CREATE TABLE test (id INTEGER)");
110
+ await rwConn.query("INSERT INTO test VALUES (1)");
111
+ await rwConn.close();
112
+
113
+ // Open in read-only mode (default for file-based)
114
+ conn = createDuckDBConnection({ path: dbPath });
115
+ const result = await conn.query("SELECT * FROM test");
116
+ expect(result.rows).toHaveLength(1);
117
+
118
+ // Write operations should fail
119
+ expect(conn.query("INSERT INTO test VALUES (2)")).rejects.toThrow();
120
+ } finally {
121
+ fs.rmSync(tmpDir, { recursive: true, force: true });
122
+ }
123
+ });
124
+
125
+ it("respects timeoutMs parameter", async () => {
126
+ conn = createDuckDBConnection({ path: ":memory:", readOnly: false });
127
+ // A very short timeout on a query that takes some time
128
+ await expect(
129
+ conn.query("SELECT COUNT(*) FROM generate_series(1, 100000000)", 1)
130
+ ).rejects.toThrow("timed out");
131
+ });
132
+
133
+ it("can recover after close by re-initializing", async () => {
134
+ conn = createDuckDBConnection({ path: ":memory:", readOnly: false });
135
+ await conn.query("SELECT 1");
136
+ await conn.close();
137
+ // After close + retry, lazy init should re-create the connection
138
+ const result = await conn.query("SELECT 42 AS answer");
139
+ expect(result.rows[0].answer).toBe(42);
140
+ });
141
+ });