@useatlas/create 0.0.1 → 0.0.3

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 (298) 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 +11 -11
  7. package/templates/docker/bin/atlas.ts +120 -56
  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 +4 -41
  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 +38 -40
  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 +104 -1
  90. package/templates/docker/src/lib/plugins/registry.ts +14 -8
  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-sdk-compat.test.ts +1 -1
  101. package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
  102. package/templates/docker/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
  103. package/templates/docker/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
  104. package/templates/docker/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
  105. package/templates/docker/src/lib/tools/__tests__/python.test.ts +331 -0
  106. package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
  107. package/templates/docker/src/lib/tools/__tests__/registry.test.ts +38 -31
  108. package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
  109. package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
  110. package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
  111. package/templates/docker/src/lib/tools/__tests__/sql.test.ts +5 -308
  112. package/templates/docker/src/lib/tools/explore-nsjail.ts +17 -12
  113. package/templates/docker/src/lib/tools/explore-sidecar.ts +25 -0
  114. package/templates/docker/src/lib/tools/explore.ts +28 -32
  115. package/templates/docker/src/lib/tools/python-nsjail.ts +396 -0
  116. package/templates/docker/src/lib/tools/python-sandbox.ts +476 -0
  117. package/templates/docker/src/lib/tools/python-sidecar.ts +150 -0
  118. package/templates/docker/src/lib/tools/python.ts +367 -0
  119. package/templates/docker/src/lib/tools/registry.ts +49 -22
  120. package/templates/docker/src/lib/tools/sql.ts +88 -88
  121. package/templates/docker/src/types/vercel-sandbox.d.ts +7 -0
  122. package/templates/docker/src/ui/components/admin/admin-layout.tsx +77 -8
  123. package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +25 -17
  124. package/templates/docker/src/ui/components/admin/change-password-dialog.tsx +128 -0
  125. package/templates/docker/src/ui/components/admin/entity-detail.tsx +3 -3
  126. package/templates/docker/src/ui/components/admin/semantic-file-tree.tsx +159 -0
  127. package/templates/docker/src/ui/components/atlas-chat.tsx +64 -12
  128. package/templates/docker/src/ui/components/chart/result-chart.tsx +25 -15
  129. package/templates/docker/src/ui/components/chat/markdown.tsx +88 -42
  130. package/templates/docker/src/ui/components/chat/python-result-card.tsx +244 -0
  131. package/templates/docker/src/ui/components/chat/sql-block.tsx +39 -15
  132. package/templates/docker/src/ui/components/chat/sql-result-card.tsx +6 -1
  133. package/templates/docker/src/ui/components/chat/tool-part.tsx +12 -3
  134. package/templates/docker/src/ui/components/chat/typing-indicator.tsx +5 -2
  135. package/templates/docker/src/ui/components/conversations/conversation-item.tsx +25 -20
  136. package/templates/docker/src/ui/context.tsx +1 -1
  137. package/templates/docker/src/ui/hooks/use-conversations.ts +3 -3
  138. package/templates/docker/src/ui/hooks/use-dark-mode.ts +17 -10
  139. package/templates/docker/tsconfig.json +2 -2
  140. package/templates/nextjs-standalone/.env.example +1 -1
  141. package/templates/nextjs-standalone/bin/__tests__/plugin-cli.test.ts +11 -11
  142. package/templates/nextjs-standalone/bin/atlas.ts +120 -56
  143. package/templates/nextjs-standalone/data/demo-semantic/catalog.yml +51 -27
  144. package/templates/nextjs-standalone/data/demo-semantic/entities/accounts.yml +95 -103
  145. package/templates/nextjs-standalone/data/demo-semantic/entities/companies.yml +88 -152
  146. package/templates/nextjs-standalone/data/demo-semantic/entities/people.yml +82 -95
  147. package/templates/nextjs-standalone/data/demo-semantic/glossary.yml +104 -8
  148. package/templates/nextjs-standalone/data/demo-semantic/metrics/accounts.yml +62 -23
  149. package/templates/nextjs-standalone/data/demo-semantic/metrics/companies.yml +52 -78
  150. package/templates/nextjs-standalone/docs/deploy.md +4 -41
  151. package/templates/nextjs-standalone/package.json +11 -2
  152. package/templates/nextjs-standalone/scripts/migrate-auth.ts +25 -0
  153. package/templates/nextjs-standalone/scripts/seed-demo.ts +94 -0
  154. package/templates/nextjs-standalone/semantic/catalog.yml +62 -3
  155. package/templates/nextjs-standalone/semantic/entities/accounts.yml +162 -0
  156. package/templates/nextjs-standalone/semantic/entities/companies.yml +143 -0
  157. package/templates/nextjs-standalone/semantic/entities/people.yml +132 -0
  158. package/templates/nextjs-standalone/semantic/glossary.yml +116 -4
  159. package/templates/nextjs-standalone/semantic/metrics/accounts.yml +77 -0
  160. package/templates/nextjs-standalone/semantic/metrics/companies.yml +63 -0
  161. package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +7 -7
  162. package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +7 -0
  163. package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +30 -8
  164. package/templates/nextjs-standalone/src/api/routes/admin.ts +549 -8
  165. package/templates/nextjs-standalone/src/api/routes/chat.ts +5 -20
  166. package/templates/nextjs-standalone/src/api/routes/health.ts +39 -27
  167. package/templates/nextjs-standalone/src/api/routes/openapi.ts +1329 -74
  168. package/templates/nextjs-standalone/src/api/routes/query.ts +2 -1
  169. package/templates/nextjs-standalone/src/api/server.ts +27 -0
  170. package/templates/nextjs-standalone/src/app/api/[...route]/route.ts +2 -2
  171. package/templates/nextjs-standalone/src/app/globals.css +13 -12
  172. package/templates/nextjs-standalone/src/app/layout.tsx +9 -2
  173. package/templates/nextjs-standalone/src/components/ui/alert-dialog.tsx +196 -0
  174. package/templates/nextjs-standalone/src/components/ui/badge.tsx +48 -0
  175. package/templates/nextjs-standalone/src/components/ui/button.tsx +64 -0
  176. package/templates/nextjs-standalone/src/components/ui/card.tsx +92 -0
  177. package/templates/nextjs-standalone/src/components/ui/collapsible.tsx +33 -0
  178. package/templates/nextjs-standalone/src/components/ui/command.tsx +184 -0
  179. package/templates/nextjs-standalone/src/components/ui/dialog.tsx +158 -0
  180. package/templates/nextjs-standalone/src/components/ui/dropdown-menu.tsx +257 -0
  181. package/templates/nextjs-standalone/src/components/ui/input.tsx +21 -0
  182. package/templates/nextjs-standalone/src/components/ui/scroll-area.tsx +58 -0
  183. package/templates/nextjs-standalone/src/components/ui/select.tsx +190 -0
  184. package/templates/nextjs-standalone/src/components/ui/separator.tsx +28 -0
  185. package/templates/nextjs-standalone/src/components/ui/sheet.tsx +143 -0
  186. package/templates/nextjs-standalone/src/components/ui/sidebar.tsx +726 -0
  187. package/templates/nextjs-standalone/src/components/ui/skeleton.tsx +13 -0
  188. package/templates/nextjs-standalone/src/components/ui/table.tsx +116 -0
  189. package/templates/nextjs-standalone/src/components/ui/tabs.tsx +91 -0
  190. package/templates/nextjs-standalone/src/components/ui/toggle-group.tsx +83 -0
  191. package/templates/nextjs-standalone/src/components/ui/toggle.tsx +47 -0
  192. package/templates/nextjs-standalone/src/components/ui/tooltip.tsx +57 -0
  193. package/templates/nextjs-standalone/src/hooks/use-mobile.ts +19 -0
  194. package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +2 -0
  195. package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +17 -0
  196. package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +2 -0
  197. package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +2 -0
  198. package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +69 -19
  199. package/templates/nextjs-standalone/src/lib/__tests__/plugin-aware-validation.test.ts +321 -0
  200. package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +32 -1
  201. package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +9 -0
  202. package/templates/nextjs-standalone/src/lib/__tests__/startup-first-run.test.ts +429 -0
  203. package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +5 -0
  204. package/templates/nextjs-standalone/src/lib/agent-query.ts +5 -23
  205. package/templates/nextjs-standalone/src/lib/agent.ts +32 -112
  206. package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +5 -3
  207. package/templates/nextjs-standalone/src/lib/auth/middleware.ts +30 -4
  208. package/templates/nextjs-standalone/src/lib/auth/migrate.ts +97 -0
  209. package/templates/nextjs-standalone/src/lib/auth/server.ts +12 -1
  210. package/templates/nextjs-standalone/src/lib/config.ts +38 -40
  211. package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +89 -14
  212. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +1 -18
  213. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -19
  214. package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +11 -208
  215. package/templates/nextjs-standalone/src/lib/db/connection.ts +87 -265
  216. package/templates/nextjs-standalone/src/lib/db/internal.ts +6 -1
  217. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +3 -1
  218. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +2 -2
  219. package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +355 -1
  220. package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +32 -5
  221. package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +228 -14
  222. package/templates/nextjs-standalone/src/lib/plugins/index.ts +4 -1
  223. package/templates/nextjs-standalone/src/lib/plugins/migrate.ts +104 -1
  224. package/templates/nextjs-standalone/src/lib/plugins/registry.ts +14 -8
  225. package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +113 -4
  226. package/templates/nextjs-standalone/src/lib/providers.ts +6 -1
  227. package/templates/nextjs-standalone/src/lib/security.ts +24 -0
  228. package/templates/nextjs-standalone/src/lib/semantic.ts +2 -0
  229. package/templates/nextjs-standalone/src/lib/sidecar-types.ts +12 -1
  230. package/templates/nextjs-standalone/src/lib/startup.ts +71 -101
  231. package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +2 -0
  232. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +32 -18
  233. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +14 -14
  234. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sdk-compat.test.ts +1 -1
  235. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
  236. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
  237. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
  238. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
  239. package/templates/nextjs-standalone/src/lib/tools/__tests__/python.test.ts +331 -0
  240. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
  241. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +38 -31
  242. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
  243. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
  244. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
  245. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +5 -308
  246. package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +17 -12
  247. package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +25 -0
  248. package/templates/nextjs-standalone/src/lib/tools/explore.ts +28 -32
  249. package/templates/nextjs-standalone/src/lib/tools/python-nsjail.ts +396 -0
  250. package/templates/nextjs-standalone/src/lib/tools/python-sandbox.ts +476 -0
  251. package/templates/nextjs-standalone/src/lib/tools/python-sidecar.ts +150 -0
  252. package/templates/nextjs-standalone/src/lib/tools/python.ts +367 -0
  253. package/templates/nextjs-standalone/src/lib/tools/registry.ts +49 -22
  254. package/templates/nextjs-standalone/src/lib/tools/sql.ts +88 -88
  255. package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +77 -8
  256. package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +25 -17
  257. package/templates/nextjs-standalone/src/ui/components/admin/change-password-dialog.tsx +128 -0
  258. package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +3 -3
  259. package/templates/nextjs-standalone/src/ui/components/admin/semantic-file-tree.tsx +159 -0
  260. package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +64 -12
  261. package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +25 -15
  262. package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +88 -42
  263. package/templates/nextjs-standalone/src/ui/components/chat/python-result-card.tsx +244 -0
  264. package/templates/nextjs-standalone/src/ui/components/chat/sql-block.tsx +39 -15
  265. package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +6 -1
  266. package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +12 -3
  267. package/templates/nextjs-standalone/src/ui/components/chat/typing-indicator.tsx +5 -2
  268. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +25 -20
  269. package/templates/nextjs-standalone/src/ui/context.tsx +1 -1
  270. package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +3 -3
  271. package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +17 -10
  272. package/templates/nextjs-standalone/tsconfig.json +0 -1
  273. package/templates/nextjs-standalone/vercel.json +4 -1
  274. package/templates/docker/render.yaml +0 -34
  275. package/templates/docker/semantic/entities/.gitkeep +0 -0
  276. package/templates/docker/semantic/metrics/.gitkeep +0 -0
  277. package/templates/docker/src/lib/db/__tests__/duckdb.test.ts +0 -141
  278. package/templates/docker/src/lib/db/__tests__/salesforce.test.ts +0 -339
  279. package/templates/docker/src/lib/db/__tests__/snowflake.test.ts +0 -217
  280. package/templates/docker/src/lib/db/duckdb.ts +0 -122
  281. package/templates/docker/src/lib/db/salesforce.ts +0 -342
  282. package/templates/docker/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
  283. package/templates/docker/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
  284. package/templates/docker/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
  285. package/templates/docker/src/lib/tools/salesforce.ts +0 -138
  286. package/templates/docker/src/lib/tools/soql-validation.ts +0 -172
  287. package/templates/nextjs-standalone/semantic/entities/.gitkeep +0 -0
  288. package/templates/nextjs-standalone/semantic/metrics/.gitkeep +0 -0
  289. package/templates/nextjs-standalone/src/lib/db/__tests__/duckdb.test.ts +0 -141
  290. package/templates/nextjs-standalone/src/lib/db/__tests__/salesforce.test.ts +0 -339
  291. package/templates/nextjs-standalone/src/lib/db/__tests__/snowflake.test.ts +0 -217
  292. package/templates/nextjs-standalone/src/lib/db/duckdb.ts +0 -122
  293. package/templates/nextjs-standalone/src/lib/db/salesforce.ts +0 -342
  294. package/templates/nextjs-standalone/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
  295. package/templates/nextjs-standalone/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
  296. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
  297. package/templates/nextjs-standalone/src/lib/tools/salesforce.ts +0 -138
  298. package/templates/nextjs-standalone/src/lib/tools/soql-validation.ts +0 -172
@@ -1,17 +1,15 @@
1
1
  /**
2
2
  * Database connection factory and registry.
3
3
  *
4
- * Supports PostgreSQL (via `pg` Pool), MySQL (via `mysql2/promise`),
5
- * ClickHouse (via `@clickhouse/client` HTTP transport),
6
- * Snowflake (via `snowflake-sdk` pool), DuckDB (via `@duckdb/node-api`
7
- * in-process engine), and Salesforce (via `jsforce`).
4
+ * Core adapters: PostgreSQL (via `pg` Pool) and MySQL (via `mysql2/promise`).
5
+ * Additional databases (ClickHouse, Snowflake, DuckDB, Salesforce) are
6
+ * supported via datasource plugins see `plugins/` directory.
7
+ *
8
8
  * Database type is detected from the connection URL format:
9
9
  * - `postgresql://` or `postgres://` → PostgreSQL
10
10
  * - `mysql://` or `mysql2://` → MySQL
11
- * - `clickhouse://` or `clickhouses://` → ClickHouse
12
- * - `snowflake://` Snowflake
13
- * - `duckdb://` → DuckDB (in-process)
14
- * - `salesforce://` → Salesforce (SOQL — uses separate DataSource API)
11
+ *
12
+ * Non-core URL schemes require a registered datasource plugin.
15
13
  *
16
14
  * Connections are managed via ConnectionRegistry. The default connection
17
15
  * auto-initializes from ATLAS_DATASOURCE_URL on first access.
@@ -19,10 +17,27 @@
19
17
 
20
18
  import { createLogger } from "@atlas/api/lib/logger";
21
19
  import { _resetWhitelists } from "@atlas/api/lib/semantic";
22
- import { createDuckDBConnection, parseDuckDBUrl } from "./duckdb";
23
20
 
24
21
  const log = createLogger("db");
25
22
 
23
+ /**
24
+ * Resolve the analytics datasource URL from env vars.
25
+ *
26
+ * Priority:
27
+ * 1. ATLAS_DATASOURCE_URL (explicit — always wins)
28
+ * 2. DATABASE_URL_UNPOOLED / DATABASE_URL (when ATLAS_DEMO_DATA=true — share
29
+ * the Neon-provisioned DB for both internal and analytics)
30
+ *
31
+ * Returns undefined when no datasource is configured.
32
+ */
33
+ export function resolveDatasourceUrl(): string | undefined {
34
+ if (process.env.ATLAS_DATASOURCE_URL) return process.env.ATLAS_DATASOURCE_URL;
35
+ if (process.env.ATLAS_DEMO_DATA === "true") {
36
+ return process.env.DATABASE_URL_UNPOOLED || process.env.DATABASE_URL;
37
+ }
38
+ return undefined;
39
+ }
40
+
26
41
  export interface QueryResult {
27
42
  columns: string[];
28
43
  rows: Record<string, unknown>[];
@@ -33,7 +48,7 @@ export interface DBConnection {
33
48
  close(): Promise<void>;
34
49
  }
35
50
 
36
- export type DBType = "postgres" | "mysql" | "clickhouse" | "snowflake" | "duckdb" | "salesforce";
51
+ export type DBType = "postgres" | "mysql" | (string & {});
37
52
 
38
53
  export type HealthStatus = "healthy" | "degraded" | "unhealthy";
39
54
 
@@ -65,7 +80,8 @@ export function extractTargetHost(url: string): string {
65
80
  try {
66
81
  // Normalize known schemes to http:// so URL parser can handle them
67
82
  const normalized = url
68
- .replace(/^(postgresql|postgres|mysql|mysql2|clickhouse|clickhouses|snowflake|duckdb|salesforce):\/\//, "http://");
83
+ .replace(/^(postgresql|postgres|mysql|mysql2):\/\//, "http://")
84
+ .replace(/^[a-z][a-z0-9+.-]*:\/\//, "http://");
69
85
  const parsed = new URL(normalized);
70
86
  return parsed.hostname || "(unknown)";
71
87
  } catch {
@@ -73,50 +89,18 @@ export function extractTargetHost(url: string): string {
73
89
  }
74
90
  }
75
91
 
76
- /**
77
- * Rewrite a `clickhouse://` or `clickhouses://` URL to `http://` or `https://`
78
- * for the @clickhouse/client HTTP transport.
79
- *
80
- * - `clickhouses://` → `https://` (TLS)
81
- * - `clickhouse://` → `http://` (plain)
82
- *
83
- * Warns if port 8443 (the conventional ClickHouse TLS port) is used with
84
- * the plain `clickhouse://` scheme, since TLS is likely intended.
85
- */
86
- export function rewriteClickHouseUrl(url: string): string {
87
- if (url.startsWith("clickhouses://")) {
88
- return url.replace(/^clickhouses:\/\//, "https://");
89
- }
90
- // Warn on probable TLS-port + plain-scheme mismatch
91
- try {
92
- const parsed = new URL(url.replace(/^clickhouse:\/\//, "http://"));
93
- if (parsed.port === "8443") {
94
- log.warn(
95
- "clickhouse:// with port 8443 detected — did you mean clickhouses:// (TLS)? " +
96
- "Port 8443 is the conventional ClickHouse TLS port."
97
- );
98
- }
99
- } catch {
100
- // URL parsing failure is handled downstream; skip warning
101
- }
102
- return url.replace(/^clickhouse:\/\//, "http://");
103
- }
104
-
105
92
  /**
106
93
  * Detect database type from a connection string or ATLAS_DATASOURCE_URL.
107
- * PostgreSQL URLs start with `postgresql://` or `postgres://`.
108
- * MySQL URLs start with `mysql://` or `mysql2://`.
109
- * ClickHouse URLs start with `clickhouse://` or `clickhouses://`.
110
- * Snowflake URLs start with `snowflake://`.
111
- * DuckDB URLs start with `duckdb://`.
112
- * Salesforce URLs start with `salesforce://`.
113
- * Throws if the URL does not match a supported database type.
94
+ *
95
+ * Core types: `postgresql://` or `postgres://` → "postgres", `mysql://` or
96
+ * `mysql2://` "mysql". Unknown URL schemes throw with a migration hint
97
+ * suggesting the appropriate datasource plugin.
114
98
  */
115
99
  export function detectDBType(url?: string): DBType {
116
- const connStr = url ?? process.env.ATLAS_DATASOURCE_URL ?? "";
100
+ const connStr = url ?? resolveDatasourceUrl() ?? "";
117
101
  if (!connStr) {
118
102
  throw new Error(
119
- "No database URL provided. Set ATLAS_DATASOURCE_URL to a PostgreSQL (postgresql://...), MySQL (mysql://...), ClickHouse (clickhouse://... or clickhouses://...), Snowflake (snowflake://...), DuckDB (duckdb://...), or Salesforce (salesforce://...) connection string."
103
+ "No database URL provided. Set ATLAS_DATASOURCE_URL to a PostgreSQL (postgresql://...) or MySQL (mysql://...) connection string, or register a datasource plugin for other databases."
120
104
  );
121
105
  }
122
106
  if (connStr.startsWith("postgresql://") || connStr.startsWith("postgres://")) {
@@ -125,29 +109,22 @@ export function detectDBType(url?: string): DBType {
125
109
  if (connStr.startsWith("mysql://") || connStr.startsWith("mysql2://")) {
126
110
  return "mysql";
127
111
  }
128
- if (connStr.startsWith("clickhouse://") || connStr.startsWith("clickhouses://")) {
129
- return "clickhouse";
130
- }
131
- if (connStr.startsWith("snowflake://")) {
132
- return "snowflake";
133
- }
134
- if (connStr.startsWith("duckdb://")) {
135
- return "duckdb";
136
- }
137
- if (connStr.startsWith("salesforce://")) {
138
- return "salesforce";
139
- }
140
- const scheme = connStr.split("://")[0] || "(empty)";
112
+ const rawScheme = connStr.split("://")[0] || "(empty)";
113
+ // Normalize TLS variants (e.g. clickhouses → clickhouse) for the plugin hint
114
+ const baseScheme = rawScheme.replace(/s$/, "");
141
115
  throw new Error(
142
- `Unsupported database URL scheme "${scheme}://". ` +
143
- "ATLAS_DATASOURCE_URL must start with postgresql://, postgres://, mysql://, mysql2://, clickhouse://, clickhouses://, snowflake://, duckdb://, or salesforce://."
116
+ `Unsupported database URL scheme "${rawScheme}://". ` +
117
+ `This adapter is now a plugin. Install the appropriate datasource plugin ` +
118
+ `(e.g. @useatlas/${baseScheme}) and add it to the plugins array in atlas.config.ts. ` +
119
+ `Ensure the plugin is listed before any datasources that use it. ` +
120
+ `Core adapters support postgresql:// and mysql:// only.`
144
121
  );
145
122
  }
146
123
 
147
124
  export interface ConnectionConfig {
148
- /** Database connection string (postgresql://, mysql://, clickhouse://, snowflake://, duckdb://, or salesforce://). */
125
+ /** Database connection string (postgresql:// or mysql:// for core; other schemes via plugins). */
149
126
  url: string;
150
- /** PostgreSQL schema name (sets search_path). Ignored for MySQL, ClickHouse, Snowflake, and DuckDB. */
127
+ /** PostgreSQL schema name (sets search_path). Ignored for MySQL and plugin-managed connections. */
151
128
  schema?: string;
152
129
  /** Human-readable description shown in the agent system prompt. */
153
130
  description?: string;
@@ -173,8 +150,18 @@ function createPostgresDB(config: ConnectionConfig): DBConnection {
173
150
  );
174
151
  }
175
152
 
153
+ // Normalize sslmode: pg v8 treats 'require' as 'verify-full' but warns about it.
154
+ // Explicitly rewrite to 'verify-full' to suppress the deprecation warning.
155
+ let connString = config.url;
156
+ if (connString) {
157
+ connString = connString.replace(
158
+ /([?&])sslmode=require(?=&|$)/,
159
+ "$1sslmode=verify-full",
160
+ );
161
+ }
162
+
176
163
  const pool = new Pool({
177
- connectionString: config.url,
164
+ connectionString: connString,
178
165
  max: config.maxConnections ?? 10,
179
166
  idleTimeoutMillis: config.idleTimeoutMs ?? 30000,
180
167
  });
@@ -267,207 +254,31 @@ function createMySQLDB(config: ConnectionConfig): DBConnection {
267
254
  };
268
255
  }
269
256
 
270
- function createClickHouseDB(config: ConnectionConfig): DBConnection {
271
- let createClient: (opts: Record<string, unknown>) => unknown;
272
- try {
273
- // eslint-disable-next-line @typescript-eslint/no-require-imports
274
- ({ createClient } = require("@clickhouse/client"));
275
- } catch {
276
- throw new Error(
277
- "ClickHouse support requires the @clickhouse/client package. Install it with: bun add @clickhouse/client"
278
- );
279
- }
280
-
281
- const httpUrl = rewriteClickHouseUrl(config.url);
282
-
283
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
284
- const client = (createClient as any)({ url: httpUrl });
285
-
286
- return {
287
- async query(sql: string, timeoutMs = 30000) {
288
- let result;
289
- try {
290
- result = await client.query({
291
- query: sql,
292
- format: "JSON",
293
- clickhouse_settings: {
294
- max_execution_time: Math.ceil(timeoutMs / 1000),
295
- readonly: 1,
296
- },
297
- });
298
- } catch (err) {
299
- throw new Error(`ClickHouse query failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
300
- }
301
- const json = await result.json();
302
- if (!json.meta || !Array.isArray(json.meta)) {
303
- throw new Error(
304
- "ClickHouse query returned an unexpected response: missing or invalid 'meta' field. " +
305
- "Ensure the query uses JSON format and returns a valid result set."
306
- );
307
- }
308
- const columns = (json.meta as { name: string }[]).map((m: { name: string }) => m.name);
309
- return { columns, rows: json.data as Record<string, unknown>[] };
310
- },
311
- async close() {
312
- try {
313
- await client.close();
314
- } catch (err) {
315
- log.warn(
316
- { err: err instanceof Error ? err.message : String(err) },
317
- "Failed to close ClickHouse client"
318
- );
319
- }
320
- },
321
- };
322
- }
323
-
324
- /**
325
- * Parse a Snowflake connection URL into SDK ConnectionOptions.
326
- * Format: snowflake://user:pass@account/database/schema?warehouse=WH&role=ROLE
327
- *
328
- * - `account` can be a plain account identifier (e.g. `xy12345`) or a
329
- * fully-qualified account locator (e.g. `xy12345.us-east-1`).
330
- * - `/database` and `/database/schema` path segments are optional.
331
- * - Query parameters: `warehouse`, `role` (case-insensitive).
332
- */
333
- export function parseSnowflakeURL(url: string): {
334
- account: string;
335
- username: string;
336
- password: string;
337
- database?: string;
338
- schema?: string;
339
- warehouse?: string;
340
- role?: string;
341
- } {
342
- const parsed = new URL(url);
343
- if (parsed.protocol !== "snowflake:") {
344
- throw new Error(`Invalid Snowflake URL: expected snowflake:// scheme, got "${parsed.protocol}"`);
345
- }
346
-
347
- const account = parsed.hostname;
348
- if (!account) {
349
- throw new Error("Invalid Snowflake URL: missing account identifier in hostname.");
350
- }
351
-
352
- const username = decodeURIComponent(parsed.username);
353
- const password = decodeURIComponent(parsed.password);
354
- if (!username) {
355
- throw new Error("Invalid Snowflake URL: missing username.");
356
- }
357
-
358
- // Path segments: /database or /database/schema
359
- const pathSegments = parsed.pathname.split("/").filter(Boolean);
360
- const database = pathSegments[0] || undefined;
361
- const schema = pathSegments[1] || undefined;
362
-
363
- const warehouse = parsed.searchParams.get("warehouse") ?? undefined;
364
- const role = parsed.searchParams.get("role") ?? undefined;
365
-
366
- return { account, username, password, database, schema, warehouse, role };
367
- }
368
-
369
- function createSnowflakeDB(config: ConnectionConfig): DBConnection {
370
- // eslint-disable-next-line @typescript-eslint/no-require-imports
371
- const snowflake = require("snowflake-sdk") as typeof import("snowflake-sdk");
372
-
373
- // Suppress noisy SDK logging
374
- snowflake.configure({ logLevel: "ERROR" });
375
-
376
- const opts = parseSnowflakeURL(config.url);
377
-
378
- const pool = snowflake.createPool(
379
- {
380
- account: opts.account,
381
- username: opts.username,
382
- password: opts.password,
383
- database: opts.database,
384
- schema: opts.schema,
385
- warehouse: opts.warehouse,
386
- role: opts.role,
387
- application: "Atlas",
388
- },
389
- { max: config.maxConnections ?? 10, min: 0 },
390
- );
391
-
392
- log.warn(
393
- "Snowflake has no session-level read-only mode — Atlas enforces SELECT-only " +
394
- "via SQL validation (regex + AST). For defense-in-depth, configure the " +
395
- "Snowflake connection with a role granted SELECT privileges only " +
396
- "(e.g. GRANT SELECT ON ALL TABLES IN SCHEMA <schema> TO ROLE atlas_readonly).",
397
- );
398
-
399
- return {
400
- async query(sql: string, timeoutMs = 30000) {
401
- const timeoutSec = Math.max(1, Math.floor(timeoutMs / 1000));
402
- return pool.use(async (conn) => {
403
- // Set session-level statement timeout (seconds)
404
- await new Promise<void>((resolve, reject) => {
405
- conn.execute({
406
- sqlText: `ALTER SESSION SET STATEMENT_TIMEOUT_IN_SECONDS = ${timeoutSec}`,
407
- complete: (err) => (err ? reject(err) : resolve()),
408
- });
409
- });
410
-
411
- // Tag all Atlas queries for audit trail in QUERY_HISTORY (best-effort —
412
- // insufficient privileges or transient errors should not block the query)
413
- try {
414
- await new Promise<void>((resolve, reject) => {
415
- conn.execute({
416
- sqlText: `ALTER SESSION SET QUERY_TAG = 'atlas:readonly'`,
417
- complete: (err) => (err ? reject(err) : resolve()),
418
- });
419
- });
420
- } catch (tagErr) {
421
- log.warn(`Failed to set QUERY_TAG on Snowflake session — query will proceed without audit tag: ${tagErr instanceof Error ? tagErr.message : String(tagErr)}`);
422
- }
423
-
424
- // Execute the actual query
425
- return new Promise<QueryResult>((resolve, reject) => {
426
- conn.execute({
427
- sqlText: sql,
428
- complete: (err, stmt, rows) => {
429
- if (err) return reject(err);
430
- const columns = (stmt?.getColumns() ?? []).map((c) => c.getName());
431
- const resultRows = (rows ?? []) as Record<string, unknown>[];
432
- resolve({ columns, rows: resultRows });
433
- },
434
- });
435
- });
436
- });
437
- },
438
- async close() {
439
- await pool.drain();
440
- await pool.clear();
441
- },
442
- };
443
- }
444
-
445
257
  function createConnection(dbType: DBType, config: ConnectionConfig): DBConnection {
446
258
  switch (dbType) {
447
259
  case "postgres":
448
260
  return createPostgresDB(config);
449
261
  case "mysql":
450
262
  return createMySQLDB(config);
451
- case "clickhouse":
452
- return createClickHouseDB(config);
453
- case "snowflake":
454
- return createSnowflakeDB(config);
455
- case "duckdb":
456
- return createDuckDBConnection(parseDuckDBUrl(config.url));
457
- case "salesforce":
263
+ default:
458
264
  throw new Error(
459
- "Salesforce uses SOQL, not SQL. Use the Salesforce DataSource API instead. " +
460
- "See packages/api/src/lib/db/salesforce.ts for the Salesforce adapter."
265
+ `Unsupported database type "${dbType}". ` +
266
+ `This adapter is now a plugin. Install the appropriate datasource plugin ` +
267
+ `and add it to the plugins array in atlas.config.ts.`
461
268
  );
462
- default: {
463
- const _exhaustive: never = dbType;
464
- throw new Error(`Unknown database type: ${_exhaustive}`);
465
- }
466
269
  }
467
270
  }
468
271
 
469
272
  // --- Connection Registry ---
470
273
 
274
+ /** Optional plugin metadata for parser dialect and forbidden patterns. */
275
+ export interface ConnectionPluginMeta {
276
+ /** node-sql-parser dialect string (e.g. "PostgresQL", "BigQuery"). */
277
+ parserDialect?: string;
278
+ /** Additional regex patterns to block beyond the base DML/DDL guard. */
279
+ forbiddenPatterns?: RegExp[];
280
+ }
281
+
471
282
  interface RegistryEntry {
472
283
  conn: DBConnection;
473
284
  dbType: DBType;
@@ -480,6 +291,8 @@ interface RegistryEntry {
480
291
  firstFailureAt: number | null;
481
292
  /** Custom query validator (mirrors QueryValidationResult from plugin-sdk). */
482
293
  validate?: (query: string) => { valid: boolean; reason?: string };
294
+ /** Plugin-provided metadata for SQL validation. */
295
+ pluginMeta?: ConnectionPluginMeta;
483
296
  }
484
297
 
485
298
  /**
@@ -500,13 +313,9 @@ export class ConnectionRegistry {
500
313
  private _totalPoolSlots(): number {
501
314
  let total = 0;
502
315
  for (const entry of this.entries.values()) {
503
- // ClickHouse uses a stateless HTTP client and DuckDB is in-process —
504
- // neither maintains a connection pool, so count them as 1 slot each.
505
- if (entry.dbType === "clickhouse" || entry.dbType === "duckdb") {
506
- total += 1;
507
- } else {
508
- total += entry.config?.maxConnections ?? 10;
509
- }
316
+ // Direct-registered connections (plugins) don't have config and manage
317
+ // their own pooling count as 1 slot instead of the default 10.
318
+ total += entry.config?.maxConnections ?? (entry.targetHost === "(direct)" ? 1 : 10);
510
319
  }
511
320
  return total;
512
321
  }
@@ -568,6 +377,7 @@ export class ConnectionRegistry {
568
377
  dbType: DBType,
569
378
  description?: string,
570
379
  validate?: (query: string) => { valid: boolean; reason?: string },
380
+ meta?: ConnectionPluginMeta,
571
381
  ): void {
572
382
  const existing = this.entries.get(id);
573
383
  this.entries.set(id, {
@@ -580,6 +390,7 @@ export class ConnectionRegistry {
580
390
  lastHealth: null,
581
391
  firstFailureAt: null,
582
392
  validate,
393
+ pluginMeta: meta,
583
394
  });
584
395
  if (existing) {
585
396
  existing.conn.close().catch((err) => {
@@ -615,15 +426,26 @@ export class ConnectionRegistry {
615
426
  return this.entries.get(id)?.validate;
616
427
  }
617
428
 
429
+ /** Return the plugin-provided parser dialect for a connection, if any. */
430
+ getParserDialect(id: string): string | undefined {
431
+ return this.entries.get(id)?.pluginMeta?.parserDialect;
432
+ }
433
+
434
+ /** Return plugin-provided forbidden patterns for a connection. Empty array if none. */
435
+ getForbiddenPatterns(id: string): RegExp[] {
436
+ return this.entries.get(id)?.pluginMeta?.forbiddenPatterns ?? [];
437
+ }
438
+
618
439
  getDefault(): DBConnection {
619
440
  if (!this.entries.has("default")) {
620
- if (!process.env.ATLAS_DATASOURCE_URL) {
441
+ const url = resolveDatasourceUrl();
442
+ if (!url) {
621
443
  throw new Error(
622
- "No analytics datasource configured. Set ATLAS_DATASOURCE_URL to a PostgreSQL, MySQL, ClickHouse, Snowflake, DuckDB, or Salesforce connection string."
444
+ "No analytics datasource configured. Set ATLAS_DATASOURCE_URL to a PostgreSQL or MySQL connection string, or register a datasource plugin."
623
445
  );
624
446
  }
625
447
  this.register("default", {
626
- url: process.env.ATLAS_DATASOURCE_URL,
448
+ url,
627
449
  schema: process.env.ATLAS_SCHEMA,
628
450
  });
629
451
  }
@@ -34,8 +34,13 @@ export function getInternalDB(): InternalPool {
34
34
  }
35
35
  // eslint-disable-next-line @typescript-eslint/no-require-imports
36
36
  const { Pool } = require("pg");
37
+ // Normalize sslmode: pg v8 treats 'require' as 'verify-full' but warns.
38
+ const connString = process.env.DATABASE_URL!.replace(
39
+ /([?&])sslmode=require(?=&|$)/,
40
+ "$1sslmode=verify-full",
41
+ );
37
42
  _pool = new Pool({
38
- connectionString: process.env.DATABASE_URL,
43
+ connectionString: connString,
39
44
  max: 5,
40
45
  idleTimeoutMillis: 30000,
41
46
  }) as InternalPool;
@@ -35,6 +35,8 @@ mock.module("@atlas/api/lib/db/connection", () => ({
35
35
  getDBType: () => "postgres",
36
36
  getTargetHost: () => "localhost",
37
37
  getValidator: () => undefined,
38
+ getParserDialect: () => undefined,
39
+ getForbiddenPatterns: () => [],
38
40
  list: () => ["default"],
39
41
  },
40
42
  detectDBType: () => "postgres",
@@ -94,7 +96,7 @@ function makeHookPlugin(
94
96
  ): PluginLike {
95
97
  return {
96
98
  id,
97
- type: "context" as PluginLike["type"],
99
+ types: ["context"] as PluginLike["types"],
98
100
  version: "1.0.0",
99
101
  hooks,
100
102
  };
@@ -18,7 +18,7 @@ function makeHookPlugin(
18
18
  ): PluginLike {
19
19
  return {
20
20
  id,
21
- type: (opts?.type ?? "context") as PluginLike["type"],
21
+ types: [opts?.type ?? "context"] as PluginLike["types"],
22
22
  version: "1.0.0",
23
23
  hooks,
24
24
  ...(opts?.unhealthy
@@ -140,7 +140,7 @@ describe("dispatchHook", () => {
140
140
  test("plugins without hooks object are silently skipped", async () => {
141
141
  registry.register({
142
142
  id: "no-hooks",
143
- type: "context",
143
+ types: ["context"],
144
144
  version: "1.0.0",
145
145
  });
146
146
  await registry.initializeAll(minimalCtx);