@useatlas/create 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (952) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/index.ts +253 -36
  4. package/package.json +4 -4
  5. package/templates/docker/Dockerfile +1 -1
  6. package/templates/docker/Dockerfile.sidecar +1 -1
  7. package/templates/docker/bin/__tests__/duckdb-ingest.test.ts +17 -14
  8. package/templates/docker/bin/__tests__/failure-threshold.test.ts +148 -0
  9. package/templates/docker/bin/__tests__/fatal-error-propagation.test.ts +267 -0
  10. package/templates/docker/bin/__tests__/profiler-heuristics.test.ts +5 -5
  11. package/templates/docker/bin/__tests__/schema-drift.test.ts +39 -0
  12. package/templates/docker/bin/atlas.ts +981 -1819
  13. package/templates/docker/bin/benchmark.ts +14 -16
  14. package/templates/docker/bin/enrich.ts +7 -2
  15. package/templates/docker/brand.css +13 -0
  16. package/templates/docker/data/cybersec-semantic/catalog.yml +222 -0
  17. package/templates/docker/data/cybersec-semantic/entities/alerts.yml +195 -0
  18. package/templates/docker/data/cybersec-semantic/entities/assets.yml +191 -0
  19. package/templates/docker/data/cybersec-semantic/entities/compliance_assessments.yml +170 -0
  20. package/templates/docker/data/cybersec-semantic/entities/incidents.yml +219 -0
  21. package/templates/docker/data/cybersec-semantic/entities/organizations.yml +136 -0
  22. package/templates/docker/data/cybersec-semantic/entities/plans.yml +114 -0
  23. package/templates/docker/data/cybersec-semantic/entities/remediation_actions.yml +212 -0
  24. package/templates/docker/data/cybersec-semantic/entities/scan_results.yml +215 -0
  25. package/templates/docker/data/cybersec-semantic/entities/scans.yml +180 -0
  26. package/templates/docker/data/cybersec-semantic/entities/subscriptions.yml +184 -0
  27. package/templates/docker/data/cybersec-semantic/entities/users.yml +140 -0
  28. package/templates/docker/data/cybersec-semantic/entities/vulnerabilities.yml +154 -0
  29. package/templates/docker/data/cybersec-semantic/glossary.yml +207 -0
  30. package/templates/docker/data/cybersec-semantic/metrics/business.yml +148 -0
  31. package/templates/docker/data/cybersec-semantic/metrics/compliance.yml +138 -0
  32. package/templates/docker/data/cybersec-semantic/metrics/security.yml +181 -0
  33. package/templates/docker/data/cybersec.sql +8 -8
  34. package/templates/docker/data/demo.sql +3 -0
  35. package/templates/docker/data/ecommerce-semantic/catalog.yml +221 -0
  36. package/templates/docker/data/ecommerce-semantic/entities/categories.yml +91 -0
  37. package/templates/docker/data/ecommerce-semantic/entities/customers.yml +133 -0
  38. package/templates/docker/data/ecommerce-semantic/entities/email_campaigns.yml +119 -0
  39. package/templates/docker/data/ecommerce-semantic/entities/inventory_levels.yml +153 -0
  40. package/templates/docker/data/ecommerce-semantic/entities/order_items.yml +159 -0
  41. package/templates/docker/data/ecommerce-semantic/entities/orders.yml +199 -0
  42. package/templates/docker/data/ecommerce-semantic/entities/payments.yml +140 -0
  43. package/templates/docker/data/ecommerce-semantic/entities/product_reviews.yml +155 -0
  44. package/templates/docker/data/ecommerce-semantic/entities/products.yml +178 -0
  45. package/templates/docker/data/ecommerce-semantic/entities/promotions.yml +171 -0
  46. package/templates/docker/data/ecommerce-semantic/entities/returns.yml +144 -0
  47. package/templates/docker/data/ecommerce-semantic/entities/sellers.yml +124 -0
  48. package/templates/docker/data/ecommerce-semantic/entities/shipments.yml +159 -0
  49. package/templates/docker/data/ecommerce-semantic/glossary.yml +193 -0
  50. package/templates/docker/data/ecommerce-semantic/metrics/customers.yml +116 -0
  51. package/templates/docker/data/ecommerce-semantic/metrics/operations.yml +131 -0
  52. package/templates/docker/data/ecommerce-semantic/metrics/revenue.yml +120 -0
  53. package/templates/docker/docs/deploy.md +2 -1
  54. package/templates/docker/ee/src/__mocks__/internal.ts +170 -0
  55. package/templates/docker/ee/src/audit/purge-scheduler.ts +113 -0
  56. package/templates/docker/ee/src/audit/retention.ts +467 -0
  57. package/templates/docker/ee/src/auth/ip-allowlist.ts +367 -0
  58. package/templates/docker/ee/src/auth/roles.ts +562 -0
  59. package/templates/docker/ee/src/auth/scim.ts +343 -0
  60. package/templates/docker/ee/src/auth/sso.ts +538 -0
  61. package/templates/docker/ee/src/backups/engine.ts +355 -0
  62. package/templates/docker/ee/src/backups/index.ts +26 -0
  63. package/templates/docker/ee/src/backups/restore.ts +169 -0
  64. package/templates/docker/ee/src/backups/scheduler.ts +153 -0
  65. package/templates/docker/ee/src/backups/verify.ts +124 -0
  66. package/templates/docker/ee/src/branding/white-label.ts +228 -0
  67. package/templates/docker/ee/src/compliance/masking.ts +477 -0
  68. package/templates/docker/ee/src/compliance/patterns.ts +16 -0
  69. package/templates/docker/ee/src/compliance/pii-detection.ts +217 -0
  70. package/templates/docker/ee/src/compliance/reports.ts +402 -0
  71. package/templates/docker/ee/src/deploy-mode.ts +37 -0
  72. package/templates/docker/ee/src/governance/approval.ts +699 -0
  73. package/templates/docker/ee/src/index.ts +74 -0
  74. package/templates/docker/ee/src/platform/domains.ts +562 -0
  75. package/templates/docker/ee/src/platform/model-routing.ts +382 -0
  76. package/templates/docker/ee/src/platform/residency.ts +265 -0
  77. package/templates/docker/ee/src/sla/alerting.ts +382 -0
  78. package/templates/docker/ee/src/sla/index.ts +12 -0
  79. package/templates/docker/ee/src/sla/metrics.ts +275 -0
  80. package/templates/docker/ee/src/test-setup.ts +1 -0
  81. package/templates/docker/next.config.ts +4 -1
  82. package/templates/docker/package.json +49 -29
  83. package/templates/docker/sidecar/Dockerfile +1 -1
  84. package/templates/docker/src/api/index.ts +336 -24
  85. package/templates/docker/src/api/routes/actions.ts +443 -176
  86. package/templates/docker/src/api/routes/admin-abuse.ts +219 -0
  87. package/templates/docker/src/api/routes/admin-approval.ts +418 -0
  88. package/templates/docker/src/api/routes/admin-audit-retention.ts +405 -0
  89. package/templates/docker/src/api/routes/admin-auth.ts +122 -0
  90. package/templates/docker/src/api/routes/admin-branding.ts +252 -0
  91. package/templates/docker/src/api/routes/admin-compliance.ts +352 -0
  92. package/templates/docker/src/api/routes/admin-domains.ts +334 -0
  93. package/templates/docker/src/api/routes/admin-integrations.ts +2667 -0
  94. package/templates/docker/src/api/routes/admin-ip-allowlist.ts +261 -0
  95. package/templates/docker/src/api/routes/admin-learned-patterns.ts +525 -0
  96. package/templates/docker/src/api/routes/admin-model-config.ts +252 -0
  97. package/templates/docker/src/api/routes/admin-onboarding-emails.ts +145 -0
  98. package/templates/docker/src/api/routes/admin-orgs.ts +710 -0
  99. package/templates/docker/src/api/routes/admin-prompts.ts +694 -0
  100. package/templates/docker/src/api/routes/admin-residency.ts +570 -0
  101. package/templates/docker/src/api/routes/admin-roles.ts +296 -0
  102. package/templates/docker/src/api/routes/admin-router.ts +120 -0
  103. package/templates/docker/src/api/routes/admin-sandbox.ts +417 -0
  104. package/templates/docker/src/api/routes/admin-scim.ts +262 -0
  105. package/templates/docker/src/api/routes/admin-sso.ts +545 -0
  106. package/templates/docker/src/api/routes/admin-suggestions.ts +176 -0
  107. package/templates/docker/src/api/routes/admin-usage.ts +310 -0
  108. package/templates/docker/src/api/routes/admin.ts +4156 -898
  109. package/templates/docker/src/api/routes/auth-preamble.ts +105 -0
  110. package/templates/docker/src/api/routes/billing.ts +397 -0
  111. package/templates/docker/src/api/routes/chat.ts +597 -334
  112. package/templates/docker/src/api/routes/conversations.ts +987 -132
  113. package/templates/docker/src/api/routes/demo.ts +673 -0
  114. package/templates/docker/src/api/routes/discord.ts +274 -0
  115. package/templates/docker/src/api/routes/ee-error-handler.ts +32 -0
  116. package/templates/docker/src/api/routes/health.ts +129 -14
  117. package/templates/docker/src/api/routes/middleware.ts +244 -0
  118. package/templates/docker/src/api/routes/onboarding-emails.ts +134 -0
  119. package/templates/docker/src/api/routes/onboarding.ts +1109 -0
  120. package/templates/docker/src/api/routes/openapi.ts +184 -1597
  121. package/templates/docker/src/api/routes/platform-admin.ts +760 -0
  122. package/templates/docker/src/api/routes/platform-backups.ts +436 -0
  123. package/templates/docker/src/api/routes/platform-domains.ts +235 -0
  124. package/templates/docker/src/api/routes/platform-residency.ts +257 -0
  125. package/templates/docker/src/api/routes/platform-sla.ts +379 -0
  126. package/templates/docker/src/api/routes/prompts.ts +221 -0
  127. package/templates/docker/src/api/routes/public-branding.ts +106 -0
  128. package/templates/docker/src/api/routes/query.ts +330 -219
  129. package/templates/docker/src/api/routes/scheduled-tasks.ts +393 -297
  130. package/templates/docker/src/api/routes/semantic.ts +179 -0
  131. package/templates/docker/src/api/routes/sessions.ts +210 -0
  132. package/templates/docker/src/api/routes/shared-domains.ts +98 -0
  133. package/templates/docker/src/api/routes/shared-schemas.ts +139 -0
  134. package/templates/docker/src/api/routes/slack.ts +209 -52
  135. package/templates/docker/src/api/routes/suggestions.ts +233 -0
  136. package/templates/docker/src/api/routes/tables.ts +67 -0
  137. package/templates/docker/src/api/routes/teams.ts +222 -0
  138. package/templates/docker/src/api/routes/validate-sql.ts +188 -0
  139. package/templates/docker/src/api/routes/validation-hook.ts +62 -0
  140. package/templates/docker/src/api/routes/widget-loader.ts +356 -0
  141. package/templates/docker/src/api/routes/widget.ts +428 -0
  142. package/templates/docker/src/api/routes/wizard.ts +852 -0
  143. package/templates/docker/src/api/server.ts +187 -69
  144. package/templates/docker/src/app/error.tsx +5 -2
  145. package/templates/docker/src/app/globals.css +1 -1
  146. package/templates/docker/src/app/layout.tsx +7 -2
  147. package/templates/docker/src/app/page.tsx +39 -5
  148. package/templates/docker/src/components/data-table/data-table-column-header.tsx +99 -0
  149. package/templates/docker/src/components/data-table/data-table-date-filter.tsx +225 -0
  150. package/templates/docker/src/components/data-table/data-table-expandable.tsx +125 -0
  151. package/templates/docker/src/components/data-table/data-table-faceted-filter.tsx +189 -0
  152. package/templates/docker/src/components/data-table/data-table-pagination.tsx +112 -0
  153. package/templates/docker/src/components/data-table/data-table-range-filter.tsx +122 -0
  154. package/templates/docker/src/components/data-table/data-table-slider-filter.tsx +256 -0
  155. package/templates/docker/src/components/data-table/data-table-sort-list.tsx +407 -0
  156. package/templates/docker/src/components/data-table/data-table-toolbar.tsx +149 -0
  157. package/templates/docker/src/components/data-table/data-table-view-options.tsx +89 -0
  158. package/templates/docker/src/components/data-table/data-table.tsx +105 -0
  159. package/templates/docker/src/components/form-dialog.tsx +135 -0
  160. package/templates/docker/src/components/ui/accordion.tsx +66 -0
  161. package/templates/docker/src/components/ui/calendar.tsx +220 -0
  162. package/templates/docker/src/components/ui/checkbox.tsx +32 -0
  163. package/templates/docker/src/components/ui/faceted.tsx +283 -0
  164. package/templates/docker/src/components/ui/form.tsx +167 -0
  165. package/templates/docker/src/components/ui/label.tsx +24 -0
  166. package/templates/docker/src/components/ui/popover.tsx +89 -0
  167. package/templates/docker/src/components/ui/progress.tsx +31 -0
  168. package/templates/docker/src/components/ui/scroll-area.tsx +6 -2
  169. package/templates/docker/src/components/ui/slider.tsx +63 -0
  170. package/templates/docker/src/components/ui/sortable.tsx +581 -0
  171. package/templates/docker/src/components/ui/switch.tsx +35 -0
  172. package/templates/docker/src/components/ui/textarea.tsx +18 -0
  173. package/templates/docker/src/config/data-table.ts +82 -0
  174. package/templates/docker/src/env-check.ts +74 -0
  175. package/templates/docker/src/hooks/use-callback-ref.ts +27 -0
  176. package/templates/docker/src/hooks/use-data-table.ts +316 -0
  177. package/templates/docker/src/hooks/use-debounced-callback.ts +28 -0
  178. package/templates/docker/src/lib/action-types.ts +7 -41
  179. package/templates/docker/src/lib/agent-query.ts +4 -2
  180. package/templates/docker/src/lib/agent.ts +363 -31
  181. package/templates/docker/src/lib/auth/admin-permissions.ts +38 -0
  182. package/templates/docker/src/lib/auth/audit.ts +19 -4
  183. package/templates/docker/src/lib/auth/byot.ts +3 -3
  184. package/templates/docker/src/lib/auth/client.ts +33 -3
  185. package/templates/docker/src/lib/auth/detect.ts +29 -8
  186. package/templates/docker/src/lib/auth/managed.ts +104 -14
  187. package/templates/docker/src/lib/auth/middleware.ts +53 -6
  188. package/templates/docker/src/lib/auth/migrate.ts +140 -15
  189. package/templates/docker/src/lib/auth/oauth-state.ts +123 -0
  190. package/templates/docker/src/lib/auth/org-permissions.ts +55 -0
  191. package/templates/docker/src/lib/auth/permissions.ts +26 -19
  192. package/templates/docker/src/lib/auth/server.ts +355 -9
  193. package/templates/docker/src/lib/auth/simple-key.ts +3 -3
  194. package/templates/docker/src/lib/auth/types.ts +15 -21
  195. package/templates/docker/src/lib/billing/enforcement.ts +368 -0
  196. package/templates/docker/src/lib/billing/plans.ts +155 -0
  197. package/templates/docker/src/lib/cache/index.ts +92 -0
  198. package/templates/docker/src/lib/cache/keys.ts +30 -0
  199. package/templates/docker/src/lib/cache/lru.ts +79 -0
  200. package/templates/docker/src/lib/cache/types.ts +31 -0
  201. package/templates/docker/src/lib/compose-refs.ts +62 -0
  202. package/templates/docker/src/lib/config.ts +563 -11
  203. package/templates/docker/src/lib/connection-types.ts +9 -0
  204. package/templates/docker/src/lib/conversation-types.ts +1 -25
  205. package/templates/docker/src/lib/conversations.ts +345 -14
  206. package/templates/docker/src/lib/data-table.ts +61 -0
  207. package/templates/docker/src/lib/db/connection.ts +793 -39
  208. package/templates/docker/src/lib/db/internal.ts +985 -139
  209. package/templates/docker/src/lib/db/migrate.ts +295 -0
  210. package/templates/docker/src/lib/db/migrations/0000_baseline.sql +703 -0
  211. package/templates/docker/src/lib/db/migrations/0001_teams_installations.sql +14 -0
  212. package/templates/docker/src/lib/db/migrations/0002_discord_installations.sql +14 -0
  213. package/templates/docker/src/lib/db/migrations/0003_telegram_installations.sql +15 -0
  214. package/templates/docker/src/lib/db/migrations/0004_sandbox_credentials.sql +18 -0
  215. package/templates/docker/src/lib/db/migrations/0005_oauth_state.sql +16 -0
  216. package/templates/docker/src/lib/db/migrations/0006_byot_credentials.sql +14 -0
  217. package/templates/docker/src/lib/db/migrations/0007_gchat_installations.sql +15 -0
  218. package/templates/docker/src/lib/db/migrations/0008_github_installations.sql +14 -0
  219. package/templates/docker/src/lib/db/migrations/0009_linear_installations.sql +15 -0
  220. package/templates/docker/src/lib/db/migrations/0010_whatsapp_installations.sql +14 -0
  221. package/templates/docker/src/lib/db/migrations/0011_email_installations.sql +16 -0
  222. package/templates/docker/src/lib/db/migrations/0012_region_migrations.sql +25 -0
  223. package/templates/docker/src/lib/db/schema.ts +1120 -0
  224. package/templates/docker/src/lib/db/source-rate-limit.ts +89 -139
  225. package/templates/docker/src/lib/demo.ts +308 -0
  226. package/templates/docker/src/lib/discord/store.ts +225 -0
  227. package/templates/docker/src/lib/effect/ai.ts +243 -0
  228. package/templates/docker/src/lib/effect/errors.ts +234 -0
  229. package/templates/docker/src/lib/effect/hono.ts +454 -0
  230. package/templates/docker/src/lib/effect/index.ts +137 -0
  231. package/templates/docker/src/lib/effect/layers.ts +496 -0
  232. package/templates/docker/src/lib/effect/services.ts +776 -0
  233. package/templates/docker/src/lib/effect/sql.ts +178 -0
  234. package/templates/docker/src/lib/effect/toolkit.ts +123 -0
  235. package/templates/docker/src/lib/email/delivery.ts +232 -0
  236. package/templates/docker/src/lib/email/engine.ts +349 -0
  237. package/templates/docker/src/lib/email/hooks.ts +107 -0
  238. package/templates/docker/src/lib/email/index.ts +16 -0
  239. package/templates/docker/src/lib/email/scheduler.ts +72 -0
  240. package/templates/docker/src/lib/email/sequence.ts +73 -0
  241. package/templates/docker/src/lib/email/store.ts +163 -0
  242. package/templates/docker/src/lib/email/templates.ts +215 -0
  243. package/templates/docker/src/lib/format.ts +67 -0
  244. package/templates/docker/src/lib/gchat/store.ts +202 -0
  245. package/templates/docker/src/lib/github/store.ts +197 -0
  246. package/templates/docker/src/lib/id.ts +29 -0
  247. package/templates/docker/src/lib/integrations/types.ts +166 -0
  248. package/templates/docker/src/lib/learn/pattern-analyzer.ts +224 -0
  249. package/templates/docker/src/lib/learn/pattern-cache.ts +229 -0
  250. package/templates/docker/src/lib/learn/pattern-proposer.ts +87 -0
  251. package/templates/docker/src/lib/learn/suggestion-helpers.ts +34 -0
  252. package/templates/docker/src/lib/learn/suggestions.ts +139 -0
  253. package/templates/docker/src/lib/linear/store.ts +200 -0
  254. package/templates/docker/src/lib/logger.ts +35 -3
  255. package/templates/docker/src/lib/metering.ts +272 -0
  256. package/templates/docker/src/lib/parsers.ts +99 -0
  257. package/templates/docker/src/lib/plugins/hooks.ts +13 -11
  258. package/templates/docker/src/lib/plugins/index.ts +3 -1
  259. package/templates/docker/src/lib/plugins/registry.ts +58 -6
  260. package/templates/docker/src/lib/plugins/settings.ts +147 -0
  261. package/templates/docker/src/lib/plugins/wiring.ts +6 -9
  262. package/templates/docker/src/lib/profiler.ts +1665 -0
  263. package/templates/docker/src/lib/providers.ts +188 -13
  264. package/templates/docker/src/lib/rls.ts +172 -60
  265. package/templates/docker/src/lib/sandbox/credentials.ts +206 -0
  266. package/templates/docker/src/lib/sandbox/validate.ts +179 -0
  267. package/templates/docker/src/lib/scheduled-task-types.ts +26 -94
  268. package/templates/docker/src/lib/scheduled-tasks.ts +174 -34
  269. package/templates/docker/src/lib/scheduler/delivery.ts +248 -150
  270. package/templates/docker/src/lib/scheduler/engine.ts +190 -154
  271. package/templates/docker/src/lib/scheduler/executor.ts +74 -23
  272. package/templates/docker/src/lib/scheduler/preview.ts +72 -0
  273. package/templates/docker/src/lib/security/abuse.ts +463 -0
  274. package/templates/docker/src/lib/semantic/diff.ts +267 -0
  275. package/templates/docker/src/lib/semantic/entities.ts +167 -0
  276. package/templates/docker/src/lib/semantic/files.ts +283 -0
  277. package/templates/docker/src/lib/semantic/index.ts +27 -0
  278. package/templates/docker/src/lib/{semantic-index.ts → semantic/search.ts} +80 -9
  279. package/templates/docker/src/lib/semantic/sync.ts +581 -0
  280. package/templates/docker/src/lib/{semantic.ts → semantic/whitelist.ts} +189 -3
  281. package/templates/docker/src/lib/settings.ts +817 -0
  282. package/templates/docker/src/lib/sidecar-types.ts +13 -0
  283. package/templates/docker/src/lib/slack/store.ts +134 -25
  284. package/templates/docker/src/lib/startup.ts +528 -362
  285. package/templates/docker/src/lib/teams/store.ts +216 -0
  286. package/templates/docker/src/lib/telegram/store.ts +202 -0
  287. package/templates/docker/src/lib/telemetry.ts +40 -0
  288. package/templates/docker/src/lib/tools/actions/audit.ts +8 -5
  289. package/templates/docker/src/lib/tools/actions/email.ts +3 -1
  290. package/templates/docker/src/lib/tools/actions/handler.ts +276 -93
  291. package/templates/docker/src/lib/tools/actions/jira.ts +2 -2
  292. package/templates/docker/src/lib/tools/backends/detect.ts +16 -0
  293. package/templates/docker/src/lib/tools/backends/index.ts +11 -0
  294. package/templates/docker/src/lib/tools/backends/nsjail.ts +213 -0
  295. package/templates/docker/src/lib/tools/backends/shared.ts +103 -0
  296. package/templates/docker/src/lib/tools/backends/types.ts +26 -0
  297. package/templates/docker/src/lib/tools/explore-nsjail.ts +7 -228
  298. package/templates/docker/src/lib/tools/explore-sandbox.ts +4 -29
  299. package/templates/docker/src/lib/tools/explore-sidecar.ts +18 -2
  300. package/templates/docker/src/lib/tools/explore.ts +246 -54
  301. package/templates/docker/src/lib/tools/index.ts +17 -0
  302. package/templates/docker/src/lib/tools/python-nsjail.ts +11 -139
  303. package/templates/docker/src/lib/tools/python-sandbox.ts +9 -132
  304. package/templates/docker/src/lib/tools/python-sidecar.ts +184 -3
  305. package/templates/docker/src/lib/tools/python-stream.ts +33 -0
  306. package/templates/docker/src/lib/tools/python-wrapper.ts +129 -0
  307. package/templates/docker/src/lib/tools/python.ts +115 -15
  308. package/templates/docker/src/lib/tools/registry.ts +14 -2
  309. package/templates/docker/src/lib/tools/sql.ts +778 -362
  310. package/templates/docker/src/lib/tracing.ts +16 -0
  311. package/templates/docker/src/lib/whatsapp/store.ts +198 -0
  312. package/templates/docker/src/lib/workspace.ts +89 -0
  313. package/templates/docker/src/progress.ts +121 -0
  314. package/templates/docker/src/types/data-table.ts +48 -0
  315. package/templates/docker/src/ui/atlas-chat-reexport.ts +3 -0
  316. package/templates/docker/src/ui/components/actions/action-approval-card.tsx +26 -19
  317. package/templates/docker/src/ui/components/actions/action-status-badge.tsx +3 -3
  318. package/templates/docker/src/ui/components/admin/admin-layout.tsx +57 -39
  319. package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +213 -35
  320. package/templates/docker/src/ui/components/admin/delivery-status-badge.tsx +53 -0
  321. package/templates/docker/src/ui/components/admin/empty-state.tsx +27 -6
  322. package/templates/docker/src/ui/components/admin/entity-detail.tsx +3 -52
  323. package/templates/docker/src/ui/components/admin/error-banner.tsx +2 -2
  324. package/templates/docker/src/ui/components/admin/feature-disabled.tsx +28 -5
  325. package/templates/docker/src/ui/components/admin-content-wrapper.tsx +87 -0
  326. package/templates/docker/src/ui/components/atlas-chat.tsx +449 -166
  327. package/templates/docker/src/ui/components/branding-head.tsx +41 -0
  328. package/templates/docker/src/ui/components/chart/chart-detection.ts +62 -5
  329. package/templates/docker/src/ui/components/chart/result-chart.tsx +316 -125
  330. package/templates/docker/src/ui/components/chat/api-key-bar.tsx +4 -4
  331. package/templates/docker/src/ui/components/chat/data-table.tsx +45 -4
  332. package/templates/docker/src/ui/components/chat/error-banner.tsx +86 -5
  333. package/templates/docker/src/ui/components/chat/follow-up-chips.tsx +29 -0
  334. package/templates/docker/src/ui/components/chat/markdown.tsx +24 -0
  335. package/templates/docker/src/ui/components/chat/prompt-library.tsx +206 -0
  336. package/templates/docker/src/ui/components/chat/python-result-card.tsx +106 -78
  337. package/templates/docker/src/ui/components/chat/result-card-base.tsx +101 -0
  338. package/templates/docker/src/ui/components/chat/share-dialog.tsx +377 -0
  339. package/templates/docker/src/ui/components/chat/sql-result-card.tsx +94 -73
  340. package/templates/docker/src/ui/components/chat/suggestion-chips.tsx +46 -0
  341. package/templates/docker/src/ui/components/chat/tool-part.tsx +16 -4
  342. package/templates/docker/src/ui/components/conversations/conversation-item.tsx +48 -17
  343. package/templates/docker/src/ui/components/conversations/conversation-list.tsx +38 -24
  344. package/templates/docker/src/ui/components/conversations/conversation-sidebar.tsx +66 -7
  345. package/templates/docker/src/ui/components/conversations/delete-confirmation.tsx +9 -2
  346. package/templates/docker/src/ui/components/error-boundary.tsx +66 -0
  347. package/templates/docker/src/ui/components/notebook/delete-cell-dialog.tsx +48 -0
  348. package/templates/docker/src/ui/components/notebook/fork-branch-selector.tsx +68 -0
  349. package/templates/docker/src/ui/components/notebook/notebook-cell-input.tsx +76 -0
  350. package/templates/docker/src/ui/components/notebook/notebook-cell-output.tsx +58 -0
  351. package/templates/docker/src/ui/components/notebook/notebook-cell-toolbar.tsx +91 -0
  352. package/templates/docker/src/ui/components/notebook/notebook-cell.tsx +119 -0
  353. package/templates/docker/src/ui/components/notebook/notebook-empty-state.tsx +19 -0
  354. package/templates/docker/src/ui/components/notebook/notebook-export.ts +287 -0
  355. package/templates/docker/src/ui/components/notebook/notebook-input-bar.tsx +49 -0
  356. package/templates/docker/src/ui/components/notebook/notebook-shell.tsx +266 -0
  357. package/templates/docker/src/ui/components/notebook/notebook-text-cell.tsx +152 -0
  358. package/templates/docker/src/ui/components/notebook/types.ts +39 -0
  359. package/templates/docker/src/ui/components/notebook/use-keyboard-nav.ts +109 -0
  360. package/templates/docker/src/ui/components/notebook/use-notebook.ts +684 -0
  361. package/templates/docker/src/ui/components/org-switcher.tsx +111 -0
  362. package/templates/docker/src/ui/components/region-picker.tsx +103 -0
  363. package/templates/docker/src/ui/components/schema-explorer/schema-explorer.tsx +522 -0
  364. package/templates/docker/src/ui/components/social-icons.tsx +26 -0
  365. package/templates/docker/src/ui/components/tour/guided-tour.tsx +81 -0
  366. package/templates/docker/src/ui/components/tour/index.ts +5 -0
  367. package/templates/docker/src/ui/components/tour/nav-bar.tsx +100 -0
  368. package/templates/docker/src/ui/components/tour/tour-overlay.tsx +298 -0
  369. package/templates/docker/src/ui/components/tour/tour-steps.ts +43 -0
  370. package/templates/docker/src/ui/components/tour/types.ts +21 -0
  371. package/templates/docker/src/ui/components/tour/use-tour.ts +193 -0
  372. package/templates/docker/src/ui/context-reexport.ts +3 -0
  373. package/templates/docker/src/ui/hooks/theme-init-script.ts +17 -0
  374. package/templates/docker/src/ui/hooks/use-admin-fetch.ts +38 -30
  375. package/templates/docker/src/ui/hooks/use-admin-mutation.ts +188 -0
  376. package/templates/docker/src/ui/hooks/use-atlas-transport.ts +225 -0
  377. package/templates/docker/src/ui/hooks/use-branding.ts +68 -0
  378. package/templates/docker/src/ui/hooks/use-conversations.ts +106 -83
  379. package/templates/docker/src/ui/hooks/use-dark-mode.ts +134 -10
  380. package/templates/docker/src/ui/hooks/use-deploy-mode.ts +36 -0
  381. package/templates/docker/src/ui/hooks/use-platform-admin-guard.ts +49 -0
  382. package/templates/docker/src/ui/lib/action-types.ts +11 -63
  383. package/templates/docker/src/ui/lib/admin-schemas.ts +744 -0
  384. package/templates/docker/src/ui/lib/fetch-client.ts +84 -0
  385. package/templates/docker/src/ui/lib/fetch-error.ts +54 -0
  386. package/templates/docker/src/ui/lib/helpers.ts +94 -1
  387. package/templates/docker/src/ui/lib/types.ts +149 -140
  388. package/templates/docker/tsconfig.json +4 -2
  389. package/templates/nextjs-standalone/bin/__tests__/duckdb-ingest.test.ts +17 -14
  390. package/templates/nextjs-standalone/bin/__tests__/failure-threshold.test.ts +148 -0
  391. package/templates/nextjs-standalone/bin/__tests__/fatal-error-propagation.test.ts +267 -0
  392. package/templates/nextjs-standalone/bin/__tests__/profiler-heuristics.test.ts +5 -5
  393. package/templates/nextjs-standalone/bin/__tests__/schema-drift.test.ts +39 -0
  394. package/templates/nextjs-standalone/bin/atlas.ts +981 -1819
  395. package/templates/nextjs-standalone/bin/benchmark.ts +14 -16
  396. package/templates/nextjs-standalone/bin/enrich.ts +7 -2
  397. package/templates/nextjs-standalone/brand.css +13 -0
  398. package/templates/nextjs-standalone/data/cybersec-semantic/catalog.yml +222 -0
  399. package/templates/nextjs-standalone/data/cybersec-semantic/entities/alerts.yml +195 -0
  400. package/templates/nextjs-standalone/data/cybersec-semantic/entities/assets.yml +191 -0
  401. package/templates/nextjs-standalone/data/cybersec-semantic/entities/compliance_assessments.yml +170 -0
  402. package/templates/nextjs-standalone/data/cybersec-semantic/entities/incidents.yml +219 -0
  403. package/templates/nextjs-standalone/data/cybersec-semantic/entities/organizations.yml +136 -0
  404. package/templates/nextjs-standalone/data/cybersec-semantic/entities/plans.yml +114 -0
  405. package/templates/nextjs-standalone/data/cybersec-semantic/entities/remediation_actions.yml +212 -0
  406. package/templates/nextjs-standalone/data/cybersec-semantic/entities/scan_results.yml +215 -0
  407. package/templates/nextjs-standalone/data/cybersec-semantic/entities/scans.yml +180 -0
  408. package/templates/nextjs-standalone/data/cybersec-semantic/entities/subscriptions.yml +184 -0
  409. package/templates/nextjs-standalone/data/cybersec-semantic/entities/users.yml +140 -0
  410. package/templates/nextjs-standalone/data/cybersec-semantic/entities/vulnerabilities.yml +154 -0
  411. package/templates/nextjs-standalone/data/cybersec-semantic/glossary.yml +207 -0
  412. package/templates/nextjs-standalone/data/cybersec-semantic/metrics/business.yml +148 -0
  413. package/templates/nextjs-standalone/data/cybersec-semantic/metrics/compliance.yml +138 -0
  414. package/templates/nextjs-standalone/data/cybersec-semantic/metrics/security.yml +181 -0
  415. package/templates/nextjs-standalone/data/cybersec.sql +8 -8
  416. package/templates/nextjs-standalone/data/demo.sql +3 -0
  417. package/templates/nextjs-standalone/data/ecommerce-semantic/catalog.yml +221 -0
  418. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/categories.yml +91 -0
  419. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/customers.yml +133 -0
  420. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/email_campaigns.yml +119 -0
  421. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/inventory_levels.yml +153 -0
  422. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/order_items.yml +159 -0
  423. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/orders.yml +199 -0
  424. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/payments.yml +140 -0
  425. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/product_reviews.yml +155 -0
  426. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/products.yml +178 -0
  427. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/promotions.yml +171 -0
  428. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/returns.yml +144 -0
  429. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/sellers.yml +124 -0
  430. package/templates/nextjs-standalone/data/ecommerce-semantic/entities/shipments.yml +159 -0
  431. package/templates/nextjs-standalone/data/ecommerce-semantic/glossary.yml +193 -0
  432. package/templates/nextjs-standalone/data/ecommerce-semantic/metrics/customers.yml +116 -0
  433. package/templates/nextjs-standalone/data/ecommerce-semantic/metrics/operations.yml +131 -0
  434. package/templates/nextjs-standalone/data/ecommerce-semantic/metrics/revenue.yml +120 -0
  435. package/templates/nextjs-standalone/docs/deploy.md +2 -1
  436. package/templates/nextjs-standalone/ee/src/__mocks__/internal.ts +170 -0
  437. package/templates/nextjs-standalone/ee/src/audit/purge-scheduler.ts +113 -0
  438. package/templates/nextjs-standalone/ee/src/audit/retention.ts +467 -0
  439. package/templates/nextjs-standalone/ee/src/auth/ip-allowlist.ts +367 -0
  440. package/templates/nextjs-standalone/ee/src/auth/roles.ts +562 -0
  441. package/templates/nextjs-standalone/ee/src/auth/scim.ts +343 -0
  442. package/templates/nextjs-standalone/ee/src/auth/sso.ts +538 -0
  443. package/templates/nextjs-standalone/ee/src/backups/engine.ts +355 -0
  444. package/templates/nextjs-standalone/ee/src/backups/index.ts +26 -0
  445. package/templates/nextjs-standalone/ee/src/backups/restore.ts +169 -0
  446. package/templates/nextjs-standalone/ee/src/backups/scheduler.ts +153 -0
  447. package/templates/nextjs-standalone/ee/src/backups/verify.ts +124 -0
  448. package/templates/nextjs-standalone/ee/src/branding/white-label.ts +228 -0
  449. package/templates/nextjs-standalone/ee/src/compliance/masking.ts +477 -0
  450. package/templates/nextjs-standalone/ee/src/compliance/patterns.ts +16 -0
  451. package/templates/nextjs-standalone/ee/src/compliance/pii-detection.ts +217 -0
  452. package/templates/nextjs-standalone/ee/src/compliance/reports.ts +402 -0
  453. package/templates/nextjs-standalone/ee/src/deploy-mode.ts +37 -0
  454. package/templates/nextjs-standalone/ee/src/governance/approval.ts +699 -0
  455. package/templates/nextjs-standalone/ee/src/index.ts +74 -0
  456. package/templates/nextjs-standalone/ee/src/platform/domains.ts +562 -0
  457. package/templates/nextjs-standalone/ee/src/platform/model-routing.ts +382 -0
  458. package/templates/nextjs-standalone/ee/src/platform/residency.ts +265 -0
  459. package/templates/nextjs-standalone/ee/src/sla/alerting.ts +382 -0
  460. package/templates/nextjs-standalone/ee/src/sla/index.ts +12 -0
  461. package/templates/nextjs-standalone/ee/src/sla/metrics.ts +275 -0
  462. package/templates/nextjs-standalone/ee/src/test-setup.ts +1 -0
  463. package/templates/nextjs-standalone/next.config.ts +1 -1
  464. package/templates/nextjs-standalone/package.json +50 -30
  465. package/templates/nextjs-standalone/src/api/index.ts +336 -24
  466. package/templates/nextjs-standalone/src/api/routes/actions.ts +443 -176
  467. package/templates/nextjs-standalone/src/api/routes/admin-abuse.ts +219 -0
  468. package/templates/nextjs-standalone/src/api/routes/admin-approval.ts +418 -0
  469. package/templates/nextjs-standalone/src/api/routes/admin-audit-retention.ts +405 -0
  470. package/templates/nextjs-standalone/src/api/routes/admin-auth.ts +122 -0
  471. package/templates/nextjs-standalone/src/api/routes/admin-branding.ts +252 -0
  472. package/templates/nextjs-standalone/src/api/routes/admin-compliance.ts +352 -0
  473. package/templates/nextjs-standalone/src/api/routes/admin-domains.ts +334 -0
  474. package/templates/nextjs-standalone/src/api/routes/admin-integrations.ts +2667 -0
  475. package/templates/nextjs-standalone/src/api/routes/admin-ip-allowlist.ts +261 -0
  476. package/templates/nextjs-standalone/src/api/routes/admin-learned-patterns.ts +525 -0
  477. package/templates/nextjs-standalone/src/api/routes/admin-model-config.ts +252 -0
  478. package/templates/nextjs-standalone/src/api/routes/admin-onboarding-emails.ts +145 -0
  479. package/templates/nextjs-standalone/src/api/routes/admin-orgs.ts +710 -0
  480. package/templates/nextjs-standalone/src/api/routes/admin-prompts.ts +694 -0
  481. package/templates/nextjs-standalone/src/api/routes/admin-residency.ts +570 -0
  482. package/templates/nextjs-standalone/src/api/routes/admin-roles.ts +296 -0
  483. package/templates/nextjs-standalone/src/api/routes/admin-router.ts +120 -0
  484. package/templates/nextjs-standalone/src/api/routes/admin-sandbox.ts +417 -0
  485. package/templates/nextjs-standalone/src/api/routes/admin-scim.ts +262 -0
  486. package/templates/nextjs-standalone/src/api/routes/admin-sso.ts +545 -0
  487. package/templates/nextjs-standalone/src/api/routes/admin-suggestions.ts +176 -0
  488. package/templates/nextjs-standalone/src/api/routes/admin-usage.ts +310 -0
  489. package/templates/nextjs-standalone/src/api/routes/admin.ts +4156 -898
  490. package/templates/nextjs-standalone/src/api/routes/auth-preamble.ts +105 -0
  491. package/templates/nextjs-standalone/src/api/routes/billing.ts +397 -0
  492. package/templates/nextjs-standalone/src/api/routes/chat.ts +597 -334
  493. package/templates/nextjs-standalone/src/api/routes/conversations.ts +987 -132
  494. package/templates/nextjs-standalone/src/api/routes/demo.ts +673 -0
  495. package/templates/nextjs-standalone/src/api/routes/discord.ts +274 -0
  496. package/templates/nextjs-standalone/src/api/routes/ee-error-handler.ts +32 -0
  497. package/templates/nextjs-standalone/src/api/routes/health.ts +129 -14
  498. package/templates/nextjs-standalone/src/api/routes/middleware.ts +244 -0
  499. package/templates/nextjs-standalone/src/api/routes/onboarding-emails.ts +134 -0
  500. package/templates/nextjs-standalone/src/api/routes/onboarding.ts +1109 -0
  501. package/templates/nextjs-standalone/src/api/routes/openapi.ts +184 -1597
  502. package/templates/nextjs-standalone/src/api/routes/platform-admin.ts +760 -0
  503. package/templates/nextjs-standalone/src/api/routes/platform-backups.ts +436 -0
  504. package/templates/nextjs-standalone/src/api/routes/platform-domains.ts +235 -0
  505. package/templates/nextjs-standalone/src/api/routes/platform-residency.ts +257 -0
  506. package/templates/nextjs-standalone/src/api/routes/platform-sla.ts +379 -0
  507. package/templates/nextjs-standalone/src/api/routes/prompts.ts +221 -0
  508. package/templates/nextjs-standalone/src/api/routes/public-branding.ts +106 -0
  509. package/templates/nextjs-standalone/src/api/routes/query.ts +330 -219
  510. package/templates/nextjs-standalone/src/api/routes/scheduled-tasks.ts +393 -297
  511. package/templates/nextjs-standalone/src/api/routes/semantic.ts +179 -0
  512. package/templates/nextjs-standalone/src/api/routes/sessions.ts +210 -0
  513. package/templates/nextjs-standalone/src/api/routes/shared-domains.ts +98 -0
  514. package/templates/nextjs-standalone/src/api/routes/shared-schemas.ts +139 -0
  515. package/templates/nextjs-standalone/src/api/routes/slack.ts +209 -52
  516. package/templates/nextjs-standalone/src/api/routes/suggestions.ts +233 -0
  517. package/templates/nextjs-standalone/src/api/routes/tables.ts +67 -0
  518. package/templates/nextjs-standalone/src/api/routes/teams.ts +222 -0
  519. package/templates/nextjs-standalone/src/api/routes/validate-sql.ts +188 -0
  520. package/templates/nextjs-standalone/src/api/routes/validation-hook.ts +62 -0
  521. package/templates/nextjs-standalone/src/api/routes/widget-loader.ts +356 -0
  522. package/templates/nextjs-standalone/src/api/routes/widget.ts +428 -0
  523. package/templates/nextjs-standalone/src/api/routes/wizard.ts +852 -0
  524. package/templates/nextjs-standalone/src/api/server.ts +187 -69
  525. package/templates/nextjs-standalone/src/app/error.tsx +5 -2
  526. package/templates/nextjs-standalone/src/app/globals.css +1 -1
  527. package/templates/nextjs-standalone/src/app/layout.tsx +7 -2
  528. package/templates/nextjs-standalone/src/app/page.tsx +39 -5
  529. package/templates/nextjs-standalone/src/components/data-table/data-table-column-header.tsx +99 -0
  530. package/templates/nextjs-standalone/src/components/data-table/data-table-date-filter.tsx +225 -0
  531. package/templates/nextjs-standalone/src/components/data-table/data-table-expandable.tsx +125 -0
  532. package/templates/nextjs-standalone/src/components/data-table/data-table-faceted-filter.tsx +189 -0
  533. package/templates/nextjs-standalone/src/components/data-table/data-table-pagination.tsx +112 -0
  534. package/templates/nextjs-standalone/src/components/data-table/data-table-range-filter.tsx +122 -0
  535. package/templates/nextjs-standalone/src/components/data-table/data-table-slider-filter.tsx +256 -0
  536. package/templates/nextjs-standalone/src/components/data-table/data-table-sort-list.tsx +407 -0
  537. package/templates/nextjs-standalone/src/components/data-table/data-table-toolbar.tsx +149 -0
  538. package/templates/nextjs-standalone/src/components/data-table/data-table-view-options.tsx +89 -0
  539. package/templates/nextjs-standalone/src/components/data-table/data-table.tsx +105 -0
  540. package/templates/nextjs-standalone/src/components/form-dialog.tsx +135 -0
  541. package/templates/nextjs-standalone/src/components/ui/accordion.tsx +66 -0
  542. package/templates/nextjs-standalone/src/components/ui/calendar.tsx +220 -0
  543. package/templates/nextjs-standalone/src/components/ui/checkbox.tsx +32 -0
  544. package/templates/nextjs-standalone/src/components/ui/faceted.tsx +283 -0
  545. package/templates/nextjs-standalone/src/components/ui/form.tsx +167 -0
  546. package/templates/nextjs-standalone/src/components/ui/label.tsx +24 -0
  547. package/templates/nextjs-standalone/src/components/ui/popover.tsx +89 -0
  548. package/templates/nextjs-standalone/src/components/ui/progress.tsx +31 -0
  549. package/templates/nextjs-standalone/src/components/ui/scroll-area.tsx +6 -2
  550. package/templates/nextjs-standalone/src/components/ui/slider.tsx +63 -0
  551. package/templates/nextjs-standalone/src/components/ui/sortable.tsx +581 -0
  552. package/templates/nextjs-standalone/src/components/ui/switch.tsx +35 -0
  553. package/templates/nextjs-standalone/src/components/ui/textarea.tsx +18 -0
  554. package/templates/nextjs-standalone/src/config/data-table.ts +82 -0
  555. package/templates/nextjs-standalone/src/env-check.ts +74 -0
  556. package/templates/nextjs-standalone/src/hooks/use-callback-ref.ts +27 -0
  557. package/templates/nextjs-standalone/src/hooks/use-data-table.ts +316 -0
  558. package/templates/nextjs-standalone/src/hooks/use-debounced-callback.ts +28 -0
  559. package/templates/nextjs-standalone/src/lib/action-types.ts +7 -41
  560. package/templates/nextjs-standalone/src/lib/agent-query.ts +4 -2
  561. package/templates/nextjs-standalone/src/lib/agent.ts +363 -31
  562. package/templates/nextjs-standalone/src/lib/api-url.ts +2 -3
  563. package/templates/nextjs-standalone/src/lib/auth/admin-permissions.ts +38 -0
  564. package/templates/nextjs-standalone/src/lib/auth/audit.ts +19 -4
  565. package/templates/nextjs-standalone/src/lib/auth/byot.ts +3 -3
  566. package/templates/nextjs-standalone/src/lib/auth/detect.ts +29 -8
  567. package/templates/nextjs-standalone/src/lib/auth/managed.ts +104 -14
  568. package/templates/nextjs-standalone/src/lib/auth/middleware.ts +53 -6
  569. package/templates/nextjs-standalone/src/lib/auth/migrate.ts +140 -15
  570. package/templates/nextjs-standalone/src/lib/auth/oauth-state.ts +123 -0
  571. package/templates/nextjs-standalone/src/lib/auth/org-permissions.ts +55 -0
  572. package/templates/nextjs-standalone/src/lib/auth/permissions.ts +26 -19
  573. package/templates/nextjs-standalone/src/lib/auth/server.ts +355 -9
  574. package/templates/nextjs-standalone/src/lib/auth/simple-key.ts +3 -3
  575. package/templates/nextjs-standalone/src/lib/auth/types.ts +15 -21
  576. package/templates/nextjs-standalone/src/lib/billing/enforcement.ts +368 -0
  577. package/templates/nextjs-standalone/src/lib/billing/plans.ts +155 -0
  578. package/templates/nextjs-standalone/src/lib/cache/index.ts +92 -0
  579. package/templates/nextjs-standalone/src/lib/cache/keys.ts +30 -0
  580. package/templates/nextjs-standalone/src/lib/cache/lru.ts +79 -0
  581. package/templates/nextjs-standalone/src/lib/cache/types.ts +31 -0
  582. package/templates/nextjs-standalone/src/lib/compose-refs.ts +62 -0
  583. package/templates/nextjs-standalone/src/lib/config.ts +563 -11
  584. package/templates/nextjs-standalone/src/lib/connection-types.ts +9 -0
  585. package/templates/nextjs-standalone/src/lib/conversation-types.ts +1 -25
  586. package/templates/nextjs-standalone/src/lib/conversations.ts +345 -14
  587. package/templates/nextjs-standalone/src/lib/data-table.ts +61 -0
  588. package/templates/nextjs-standalone/src/lib/db/connection.ts +793 -39
  589. package/templates/nextjs-standalone/src/lib/db/internal.ts +985 -139
  590. package/templates/nextjs-standalone/src/lib/db/migrate.ts +295 -0
  591. package/templates/nextjs-standalone/src/lib/db/migrations/0000_baseline.sql +703 -0
  592. package/templates/nextjs-standalone/src/lib/db/migrations/0001_teams_installations.sql +14 -0
  593. package/templates/nextjs-standalone/src/lib/db/migrations/0002_discord_installations.sql +14 -0
  594. package/templates/nextjs-standalone/src/lib/db/migrations/0003_telegram_installations.sql +15 -0
  595. package/templates/nextjs-standalone/src/lib/db/migrations/0004_sandbox_credentials.sql +18 -0
  596. package/templates/nextjs-standalone/src/lib/db/migrations/0005_oauth_state.sql +16 -0
  597. package/templates/nextjs-standalone/src/lib/db/migrations/0006_byot_credentials.sql +14 -0
  598. package/templates/nextjs-standalone/src/lib/db/migrations/0007_gchat_installations.sql +15 -0
  599. package/templates/nextjs-standalone/src/lib/db/migrations/0008_github_installations.sql +14 -0
  600. package/templates/nextjs-standalone/src/lib/db/migrations/0009_linear_installations.sql +15 -0
  601. package/templates/nextjs-standalone/src/lib/db/migrations/0010_whatsapp_installations.sql +14 -0
  602. package/templates/nextjs-standalone/src/lib/db/migrations/0011_email_installations.sql +16 -0
  603. package/templates/nextjs-standalone/src/lib/db/migrations/0012_region_migrations.sql +25 -0
  604. package/templates/nextjs-standalone/src/lib/db/schema.ts +1120 -0
  605. package/templates/nextjs-standalone/src/lib/db/source-rate-limit.ts +89 -139
  606. package/templates/nextjs-standalone/src/lib/demo.ts +308 -0
  607. package/templates/nextjs-standalone/src/lib/discord/store.ts +225 -0
  608. package/templates/nextjs-standalone/src/lib/effect/ai.ts +243 -0
  609. package/templates/nextjs-standalone/src/lib/effect/errors.ts +234 -0
  610. package/templates/nextjs-standalone/src/lib/effect/hono.ts +454 -0
  611. package/templates/nextjs-standalone/src/lib/effect/index.ts +137 -0
  612. package/templates/nextjs-standalone/src/lib/effect/layers.ts +496 -0
  613. package/templates/nextjs-standalone/src/lib/effect/services.ts +776 -0
  614. package/templates/nextjs-standalone/src/lib/effect/sql.ts +178 -0
  615. package/templates/nextjs-standalone/src/lib/effect/toolkit.ts +123 -0
  616. package/templates/nextjs-standalone/src/lib/email/delivery.ts +232 -0
  617. package/templates/nextjs-standalone/src/lib/email/engine.ts +349 -0
  618. package/templates/nextjs-standalone/src/lib/email/hooks.ts +107 -0
  619. package/templates/nextjs-standalone/src/lib/email/index.ts +16 -0
  620. package/templates/nextjs-standalone/src/lib/email/scheduler.ts +72 -0
  621. package/templates/nextjs-standalone/src/lib/email/sequence.ts +73 -0
  622. package/templates/nextjs-standalone/src/lib/email/store.ts +163 -0
  623. package/templates/nextjs-standalone/src/lib/email/templates.ts +215 -0
  624. package/templates/nextjs-standalone/src/lib/format.test.ts +117 -0
  625. package/templates/nextjs-standalone/src/lib/format.ts +67 -0
  626. package/templates/nextjs-standalone/src/lib/gchat/store.ts +202 -0
  627. package/templates/nextjs-standalone/src/lib/github/store.ts +197 -0
  628. package/templates/nextjs-standalone/src/lib/id.ts +29 -0
  629. package/templates/nextjs-standalone/src/lib/integrations/types.ts +166 -0
  630. package/templates/nextjs-standalone/src/lib/learn/pattern-analyzer.ts +224 -0
  631. package/templates/nextjs-standalone/src/lib/learn/pattern-cache.ts +229 -0
  632. package/templates/nextjs-standalone/src/lib/learn/pattern-proposer.ts +87 -0
  633. package/templates/nextjs-standalone/src/lib/learn/suggestion-helpers.ts +34 -0
  634. package/templates/nextjs-standalone/src/lib/learn/suggestions.ts +139 -0
  635. package/templates/nextjs-standalone/src/lib/linear/store.ts +200 -0
  636. package/templates/nextjs-standalone/src/lib/logger.ts +35 -3
  637. package/templates/nextjs-standalone/src/lib/metering.ts +272 -0
  638. package/templates/nextjs-standalone/src/lib/parsers.ts +99 -0
  639. package/templates/nextjs-standalone/src/lib/plugins/hooks.ts +13 -11
  640. package/templates/nextjs-standalone/src/lib/plugins/index.ts +3 -1
  641. package/templates/nextjs-standalone/src/lib/plugins/registry.ts +58 -6
  642. package/templates/nextjs-standalone/src/lib/plugins/settings.ts +147 -0
  643. package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +6 -9
  644. package/templates/nextjs-standalone/src/lib/profiler.ts +1665 -0
  645. package/templates/nextjs-standalone/src/lib/providers.ts +188 -13
  646. package/templates/nextjs-standalone/src/lib/rls.ts +172 -60
  647. package/templates/nextjs-standalone/src/lib/sandbox/credentials.ts +206 -0
  648. package/templates/nextjs-standalone/src/lib/sandbox/validate.ts +179 -0
  649. package/templates/nextjs-standalone/src/lib/scheduled-task-types.ts +26 -94
  650. package/templates/nextjs-standalone/src/lib/scheduled-tasks.ts +174 -34
  651. package/templates/nextjs-standalone/src/lib/scheduler/delivery.ts +248 -150
  652. package/templates/nextjs-standalone/src/lib/scheduler/engine.ts +190 -154
  653. package/templates/nextjs-standalone/src/lib/scheduler/executor.ts +74 -23
  654. package/templates/nextjs-standalone/src/lib/scheduler/preview.ts +72 -0
  655. package/templates/nextjs-standalone/src/lib/security/abuse.ts +463 -0
  656. package/templates/nextjs-standalone/src/lib/semantic/diff.ts +267 -0
  657. package/templates/nextjs-standalone/src/lib/semantic/entities.ts +167 -0
  658. package/templates/nextjs-standalone/src/lib/semantic/files.ts +283 -0
  659. package/templates/nextjs-standalone/src/lib/semantic/index.ts +27 -0
  660. package/templates/nextjs-standalone/src/lib/{semantic-index.ts → semantic/search.ts} +80 -9
  661. package/templates/nextjs-standalone/src/lib/semantic/sync.ts +581 -0
  662. package/templates/nextjs-standalone/src/lib/{semantic.ts → semantic/whitelist.ts} +189 -3
  663. package/templates/nextjs-standalone/src/lib/settings.ts +817 -0
  664. package/templates/nextjs-standalone/src/lib/sidecar-types.ts +13 -0
  665. package/templates/nextjs-standalone/src/lib/slack/store.ts +134 -25
  666. package/templates/nextjs-standalone/src/lib/startup.ts +528 -362
  667. package/templates/nextjs-standalone/src/lib/teams/store.ts +216 -0
  668. package/templates/nextjs-standalone/src/lib/telegram/store.ts +202 -0
  669. package/templates/nextjs-standalone/src/lib/telemetry.ts +40 -0
  670. package/templates/nextjs-standalone/src/lib/tools/actions/audit.ts +8 -5
  671. package/templates/nextjs-standalone/src/lib/tools/actions/email.ts +3 -1
  672. package/templates/nextjs-standalone/src/lib/tools/actions/handler.ts +276 -93
  673. package/templates/nextjs-standalone/src/lib/tools/actions/jira.ts +2 -2
  674. package/templates/nextjs-standalone/src/lib/tools/backends/detect.ts +16 -0
  675. package/templates/nextjs-standalone/src/lib/tools/backends/index.ts +11 -0
  676. package/templates/nextjs-standalone/src/lib/tools/backends/nsjail.ts +213 -0
  677. package/templates/nextjs-standalone/src/lib/tools/backends/shared.ts +103 -0
  678. package/templates/nextjs-standalone/src/lib/tools/backends/types.ts +26 -0
  679. package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +7 -228
  680. package/templates/nextjs-standalone/src/lib/tools/explore-sandbox.ts +4 -29
  681. package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +18 -2
  682. package/templates/nextjs-standalone/src/lib/tools/explore.ts +246 -54
  683. package/templates/nextjs-standalone/src/lib/tools/index.ts +17 -0
  684. package/templates/nextjs-standalone/src/lib/tools/python-nsjail.ts +11 -139
  685. package/templates/nextjs-standalone/src/lib/tools/python-sandbox.ts +9 -132
  686. package/templates/nextjs-standalone/src/lib/tools/python-sidecar.ts +184 -3
  687. package/templates/nextjs-standalone/src/lib/tools/python-stream.ts +33 -0
  688. package/templates/nextjs-standalone/src/lib/tools/python-wrapper.ts +129 -0
  689. package/templates/nextjs-standalone/src/lib/tools/python.ts +115 -15
  690. package/templates/nextjs-standalone/src/lib/tools/registry.ts +14 -2
  691. package/templates/nextjs-standalone/src/lib/tools/sql.ts +778 -362
  692. package/templates/nextjs-standalone/src/lib/tracing.ts +16 -0
  693. package/templates/nextjs-standalone/src/lib/whatsapp/store.ts +198 -0
  694. package/templates/nextjs-standalone/src/lib/workspace.ts +89 -0
  695. package/templates/nextjs-standalone/src/progress.ts +121 -0
  696. package/templates/nextjs-standalone/src/types/data-table.ts +48 -0
  697. package/templates/nextjs-standalone/src/ui/atlas-chat-reexport.ts +3 -0
  698. package/templates/nextjs-standalone/src/ui/components/actions/action-approval-card.tsx +26 -19
  699. package/templates/nextjs-standalone/src/ui/components/actions/action-status-badge.tsx +3 -3
  700. package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +57 -39
  701. package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +213 -35
  702. package/templates/nextjs-standalone/src/ui/components/admin/delivery-status-badge.tsx +53 -0
  703. package/templates/nextjs-standalone/src/ui/components/admin/empty-state.tsx +27 -6
  704. package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +3 -52
  705. package/templates/nextjs-standalone/src/ui/components/admin/error-banner.tsx +2 -2
  706. package/templates/nextjs-standalone/src/ui/components/admin/feature-disabled.tsx +28 -5
  707. package/templates/nextjs-standalone/src/ui/components/admin-content-wrapper.tsx +87 -0
  708. package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +449 -166
  709. package/templates/nextjs-standalone/src/ui/components/branding-head.tsx +41 -0
  710. package/templates/nextjs-standalone/src/ui/components/chart/chart-detection.ts +62 -5
  711. package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +316 -125
  712. package/templates/nextjs-standalone/src/ui/components/chat/api-key-bar.tsx +4 -4
  713. package/templates/nextjs-standalone/src/ui/components/chat/data-table.tsx +45 -4
  714. package/templates/nextjs-standalone/src/ui/components/chat/error-banner.tsx +86 -5
  715. package/templates/nextjs-standalone/src/ui/components/chat/follow-up-chips.tsx +29 -0
  716. package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +24 -0
  717. package/templates/nextjs-standalone/src/ui/components/chat/prompt-library.tsx +206 -0
  718. package/templates/nextjs-standalone/src/ui/components/chat/python-result-card.tsx +106 -78
  719. package/templates/nextjs-standalone/src/ui/components/chat/result-card-base.tsx +101 -0
  720. package/templates/nextjs-standalone/src/ui/components/chat/share-dialog.tsx +377 -0
  721. package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +94 -73
  722. package/templates/nextjs-standalone/src/ui/components/chat/suggestion-chips.tsx +46 -0
  723. package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +16 -4
  724. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +48 -17
  725. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-list.tsx +38 -24
  726. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-sidebar.tsx +66 -7
  727. package/templates/nextjs-standalone/src/ui/components/conversations/delete-confirmation.tsx +9 -2
  728. package/templates/nextjs-standalone/src/ui/components/error-boundary.tsx +66 -0
  729. package/templates/nextjs-standalone/src/ui/components/notebook/delete-cell-dialog.tsx +48 -0
  730. package/templates/nextjs-standalone/src/ui/components/notebook/fork-branch-selector.tsx +68 -0
  731. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell-input.tsx +76 -0
  732. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell-output.tsx +58 -0
  733. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell-toolbar.tsx +91 -0
  734. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-cell.tsx +119 -0
  735. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-empty-state.tsx +19 -0
  736. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-export.ts +287 -0
  737. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-input-bar.tsx +49 -0
  738. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-shell.tsx +266 -0
  739. package/templates/nextjs-standalone/src/ui/components/notebook/notebook-text-cell.tsx +152 -0
  740. package/templates/nextjs-standalone/src/ui/components/notebook/types.ts +39 -0
  741. package/templates/nextjs-standalone/src/ui/components/notebook/use-keyboard-nav.ts +109 -0
  742. package/templates/nextjs-standalone/src/ui/components/notebook/use-notebook.ts +684 -0
  743. package/templates/nextjs-standalone/src/ui/components/org-switcher.tsx +111 -0
  744. package/templates/nextjs-standalone/src/ui/components/region-picker.tsx +103 -0
  745. package/templates/nextjs-standalone/src/ui/components/schema-explorer/schema-explorer.tsx +522 -0
  746. package/templates/nextjs-standalone/src/ui/components/social-icons.tsx +26 -0
  747. package/templates/nextjs-standalone/src/ui/components/tour/guided-tour.tsx +81 -0
  748. package/templates/nextjs-standalone/src/ui/components/tour/index.ts +5 -0
  749. package/templates/nextjs-standalone/src/ui/components/tour/nav-bar.tsx +100 -0
  750. package/templates/nextjs-standalone/src/ui/components/tour/tour-overlay.tsx +298 -0
  751. package/templates/nextjs-standalone/src/ui/components/tour/tour-steps.ts +43 -0
  752. package/templates/nextjs-standalone/src/ui/components/tour/types.ts +21 -0
  753. package/templates/nextjs-standalone/src/ui/components/tour/use-tour.ts +193 -0
  754. package/templates/nextjs-standalone/src/ui/context-reexport.ts +3 -0
  755. package/templates/nextjs-standalone/src/ui/hooks/theme-init-script.ts +17 -0
  756. package/templates/nextjs-standalone/src/ui/hooks/use-admin-fetch.ts +38 -30
  757. package/templates/nextjs-standalone/src/ui/hooks/use-admin-mutation.ts +188 -0
  758. package/templates/nextjs-standalone/src/ui/hooks/use-atlas-transport.ts +225 -0
  759. package/templates/nextjs-standalone/src/ui/hooks/use-branding.ts +68 -0
  760. package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +106 -83
  761. package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +134 -10
  762. package/templates/nextjs-standalone/src/ui/hooks/use-deploy-mode.ts +36 -0
  763. package/templates/nextjs-standalone/src/ui/hooks/use-platform-admin-guard.ts +49 -0
  764. package/templates/nextjs-standalone/src/ui/lib/action-types.ts +11 -63
  765. package/templates/nextjs-standalone/src/ui/lib/admin-schemas.ts +744 -0
  766. package/templates/nextjs-standalone/src/ui/lib/fetch-client.ts +84 -0
  767. package/templates/nextjs-standalone/src/ui/lib/fetch-error.ts +54 -0
  768. package/templates/nextjs-standalone/src/ui/lib/helpers.ts +94 -1
  769. package/templates/nextjs-standalone/src/ui/lib/types.ts +149 -140
  770. package/templates/nextjs-standalone/tsconfig.json +3 -2
  771. package/templates/docker/src/api/__tests__/actions.test.ts +0 -683
  772. package/templates/docker/src/api/__tests__/admin.test.ts +0 -820
  773. package/templates/docker/src/api/__tests__/auth.test.ts +0 -165
  774. package/templates/docker/src/api/__tests__/chat.test.ts +0 -376
  775. package/templates/docker/src/api/__tests__/conversations.test.ts +0 -555
  776. package/templates/docker/src/api/__tests__/cors.test.ts +0 -135
  777. package/templates/docker/src/api/__tests__/health-plugin.test.ts +0 -176
  778. package/templates/docker/src/api/__tests__/health.test.ts +0 -283
  779. package/templates/docker/src/api/__tests__/query.test.ts +0 -891
  780. package/templates/docker/src/api/__tests__/scheduled-tasks.test.ts +0 -601
  781. package/templates/docker/src/api/__tests__/slack.test.ts +0 -847
  782. package/templates/docker/src/lib/__tests__/agent-cache.test.ts +0 -439
  783. package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +0 -131
  784. package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +0 -166
  785. package/templates/docker/src/lib/__tests__/agent-integration.test.ts +0 -516
  786. package/templates/docker/src/lib/__tests__/config-actions.test.ts +0 -166
  787. package/templates/docker/src/lib/__tests__/config.test.ts +0 -1113
  788. package/templates/docker/src/lib/__tests__/conversations.test.ts +0 -589
  789. package/templates/docker/src/lib/__tests__/errors.test.ts +0 -256
  790. package/templates/docker/src/lib/__tests__/logger.test.ts +0 -200
  791. package/templates/docker/src/lib/__tests__/plugin-aware-validation.test.ts +0 -321
  792. package/templates/docker/src/lib/__tests__/providers.test.ts +0 -130
  793. package/templates/docker/src/lib/__tests__/rls.test.ts +0 -435
  794. package/templates/docker/src/lib/__tests__/scheduled-task-types.test.ts +0 -124
  795. package/templates/docker/src/lib/__tests__/scheduled-tasks.test.ts +0 -550
  796. package/templates/docker/src/lib/__tests__/semantic-index.test.ts +0 -547
  797. package/templates/docker/src/lib/__tests__/semantic-multisource.test.ts +0 -544
  798. package/templates/docker/src/lib/__tests__/semantic.test.ts +0 -363
  799. package/templates/docker/src/lib/__tests__/startup-actions.test.ts +0 -461
  800. package/templates/docker/src/lib/__tests__/startup-first-run.test.ts +0 -429
  801. package/templates/docker/src/lib/__tests__/startup.test.ts +0 -470
  802. package/templates/docker/src/lib/__tests__/tracing.test.ts +0 -28
  803. package/templates/docker/src/lib/auth/__tests__/audit.test.ts +0 -418
  804. package/templates/docker/src/lib/auth/__tests__/byot-integration.test.ts +0 -222
  805. package/templates/docker/src/lib/auth/__tests__/byot.test.ts +0 -366
  806. package/templates/docker/src/lib/auth/__tests__/detect.test.ts +0 -190
  807. package/templates/docker/src/lib/auth/__tests__/managed.test.ts +0 -173
  808. package/templates/docker/src/lib/auth/__tests__/middleware.test.ts +0 -456
  809. package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +0 -203
  810. package/templates/docker/src/lib/auth/__tests__/permissions.test.ts +0 -225
  811. package/templates/docker/src/lib/auth/__tests__/server.test.ts +0 -34
  812. package/templates/docker/src/lib/auth/__tests__/simple-key.test.ts +0 -176
  813. package/templates/docker/src/lib/auth/__tests__/types.test.ts +0 -44
  814. package/templates/docker/src/lib/db/__tests__/connection.test.ts +0 -144
  815. package/templates/docker/src/lib/db/__tests__/internal.test.ts +0 -387
  816. package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +0 -190
  817. package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -137
  818. package/templates/docker/src/lib/db/__tests__/registry.test.ts +0 -398
  819. package/templates/docker/src/lib/db/__tests__/source-rate-limit.test.ts +0 -130
  820. package/templates/docker/src/lib/errors.ts +0 -154
  821. package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +0 -204
  822. package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +0 -529
  823. package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +0 -875
  824. package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +0 -373
  825. package/templates/docker/src/lib/plugins/__tests__/tools.test.ts +0 -49
  826. package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +0 -799
  827. package/templates/docker/src/lib/scheduler/__tests__/delivery.test.ts +0 -192
  828. package/templates/docker/src/lib/scheduler/__tests__/engine.test.ts +0 -248
  829. package/templates/docker/src/lib/scheduler/__tests__/format-email.test.ts +0 -96
  830. package/templates/docker/src/lib/scheduler/__tests__/format-slack.test.ts +0 -78
  831. package/templates/docker/src/lib/scheduler/__tests__/format-webhook.test.ts +0 -78
  832. package/templates/docker/src/lib/scheduler/index.ts +0 -7
  833. package/templates/docker/src/lib/slack/__tests__/api.test.ts +0 -160
  834. package/templates/docker/src/lib/slack/__tests__/format.test.ts +0 -237
  835. package/templates/docker/src/lib/slack/__tests__/store.test.ts +0 -188
  836. package/templates/docker/src/lib/slack/__tests__/threads.test.ts +0 -112
  837. package/templates/docker/src/lib/slack/__tests__/verify.test.ts +0 -111
  838. package/templates/docker/src/lib/tools/__tests__/action-permissions.test.ts +0 -594
  839. package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +0 -240
  840. package/templates/docker/src/lib/tools/__tests__/explore-backend.test.ts +0 -267
  841. package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +0 -506
  842. package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +0 -374
  843. package/templates/docker/src/lib/tools/__tests__/explore-sdk-compat.test.ts +0 -82
  844. package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +0 -210
  845. package/templates/docker/src/lib/tools/__tests__/python-nsjail.test.ts +0 -515
  846. package/templates/docker/src/lib/tools/__tests__/python-sandbox.test.ts +0 -397
  847. package/templates/docker/src/lib/tools/__tests__/python-sidecar.test.ts +0 -365
  848. package/templates/docker/src/lib/tools/__tests__/python.test.ts +0 -331
  849. package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +0 -132
  850. package/templates/docker/src/lib/tools/__tests__/registry.test.ts +0 -242
  851. package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +0 -227
  852. package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +0 -100
  853. package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +0 -227
  854. package/templates/docker/src/lib/tools/__tests__/sql.test.ts +0 -709
  855. package/templates/docker/src/lib/tools/actions/__tests__/audit.test.ts +0 -211
  856. package/templates/docker/src/lib/tools/actions/__tests__/email.test.ts +0 -378
  857. package/templates/docker/src/lib/tools/actions/__tests__/handler.test.ts +0 -681
  858. package/templates/docker/src/lib/tools/actions/__tests__/jira.test.ts +0 -427
  859. package/templates/docker/src/test-setup.ts +0 -38
  860. package/templates/docker/src/types/vercel-sandbox.d.ts +0 -61
  861. package/templates/docker/src/ui/components/chat/managed-auth-card.tsx +0 -116
  862. package/templates/nextjs-standalone/src/api/__tests__/actions.test.ts +0 -683
  863. package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +0 -820
  864. package/templates/nextjs-standalone/src/api/__tests__/auth.test.ts +0 -165
  865. package/templates/nextjs-standalone/src/api/__tests__/chat.test.ts +0 -376
  866. package/templates/nextjs-standalone/src/api/__tests__/conversations.test.ts +0 -555
  867. package/templates/nextjs-standalone/src/api/__tests__/cors.test.ts +0 -135
  868. package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +0 -176
  869. package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +0 -283
  870. package/templates/nextjs-standalone/src/api/__tests__/query.test.ts +0 -891
  871. package/templates/nextjs-standalone/src/api/__tests__/scheduled-tasks.test.ts +0 -601
  872. package/templates/nextjs-standalone/src/api/__tests__/slack.test.ts +0 -847
  873. package/templates/nextjs-standalone/src/app/global-error.tsx +0 -68
  874. package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +0 -439
  875. package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +0 -131
  876. package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +0 -166
  877. package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +0 -516
  878. package/templates/nextjs-standalone/src/lib/__tests__/config-actions.test.ts +0 -166
  879. package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +0 -1113
  880. package/templates/nextjs-standalone/src/lib/__tests__/conversations.test.ts +0 -589
  881. package/templates/nextjs-standalone/src/lib/__tests__/errors.test.ts +0 -256
  882. package/templates/nextjs-standalone/src/lib/__tests__/logger.test.ts +0 -200
  883. package/templates/nextjs-standalone/src/lib/__tests__/plugin-aware-validation.test.ts +0 -321
  884. package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +0 -130
  885. package/templates/nextjs-standalone/src/lib/__tests__/rls.test.ts +0 -435
  886. package/templates/nextjs-standalone/src/lib/__tests__/scheduled-task-types.test.ts +0 -124
  887. package/templates/nextjs-standalone/src/lib/__tests__/scheduled-tasks.test.ts +0 -550
  888. package/templates/nextjs-standalone/src/lib/__tests__/semantic-index.test.ts +0 -547
  889. package/templates/nextjs-standalone/src/lib/__tests__/semantic-multisource.test.ts +0 -544
  890. package/templates/nextjs-standalone/src/lib/__tests__/semantic.test.ts +0 -363
  891. package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +0 -461
  892. package/templates/nextjs-standalone/src/lib/__tests__/startup-first-run.test.ts +0 -429
  893. package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +0 -470
  894. package/templates/nextjs-standalone/src/lib/__tests__/tracing.test.ts +0 -28
  895. package/templates/nextjs-standalone/src/lib/auth/__tests__/audit.test.ts +0 -418
  896. package/templates/nextjs-standalone/src/lib/auth/__tests__/byot-integration.test.ts +0 -222
  897. package/templates/nextjs-standalone/src/lib/auth/__tests__/byot.test.ts +0 -366
  898. package/templates/nextjs-standalone/src/lib/auth/__tests__/detect.test.ts +0 -190
  899. package/templates/nextjs-standalone/src/lib/auth/__tests__/managed.test.ts +0 -173
  900. package/templates/nextjs-standalone/src/lib/auth/__tests__/middleware.test.ts +0 -456
  901. package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +0 -203
  902. package/templates/nextjs-standalone/src/lib/auth/__tests__/permissions.test.ts +0 -225
  903. package/templates/nextjs-standalone/src/lib/auth/__tests__/server.test.ts +0 -34
  904. package/templates/nextjs-standalone/src/lib/auth/__tests__/simple-key.test.ts +0 -176
  905. package/templates/nextjs-standalone/src/lib/auth/__tests__/types.test.ts +0 -44
  906. package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +0 -144
  907. package/templates/nextjs-standalone/src/lib/db/__tests__/internal.test.ts +0 -387
  908. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +0 -190
  909. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -137
  910. package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +0 -398
  911. package/templates/nextjs-standalone/src/lib/db/__tests__/source-rate-limit.test.ts +0 -130
  912. package/templates/nextjs-standalone/src/lib/errors.ts +0 -154
  913. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +0 -204
  914. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +0 -529
  915. package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +0 -875
  916. package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +0 -373
  917. package/templates/nextjs-standalone/src/lib/plugins/__tests__/tools.test.ts +0 -49
  918. package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +0 -799
  919. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/delivery.test.ts +0 -192
  920. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/engine.test.ts +0 -248
  921. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-email.test.ts +0 -96
  922. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-slack.test.ts +0 -78
  923. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-webhook.test.ts +0 -78
  924. package/templates/nextjs-standalone/src/lib/scheduler/index.ts +0 -7
  925. package/templates/nextjs-standalone/src/lib/slack/__tests__/api.test.ts +0 -160
  926. package/templates/nextjs-standalone/src/lib/slack/__tests__/format.test.ts +0 -237
  927. package/templates/nextjs-standalone/src/lib/slack/__tests__/store.test.ts +0 -188
  928. package/templates/nextjs-standalone/src/lib/slack/__tests__/threads.test.ts +0 -112
  929. package/templates/nextjs-standalone/src/lib/slack/__tests__/verify.test.ts +0 -111
  930. package/templates/nextjs-standalone/src/lib/tools/__tests__/action-permissions.test.ts +0 -594
  931. package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +0 -240
  932. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-backend.test.ts +0 -267
  933. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +0 -506
  934. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +0 -374
  935. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sdk-compat.test.ts +0 -82
  936. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +0 -210
  937. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-nsjail.test.ts +0 -515
  938. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sandbox.test.ts +0 -397
  939. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sidecar.test.ts +0 -365
  940. package/templates/nextjs-standalone/src/lib/tools/__tests__/python.test.ts +0 -331
  941. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +0 -132
  942. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +0 -242
  943. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +0 -227
  944. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +0 -100
  945. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +0 -227
  946. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +0 -709
  947. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/audit.test.ts +0 -211
  948. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/email.test.ts +0 -378
  949. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/handler.test.ts +0 -681
  950. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/jira.test.ts +0 -427
  951. package/templates/nextjs-standalone/src/test-setup.ts +0 -38
  952. package/templates/nextjs-standalone/src/ui/components/chat/managed-auth-card.tsx +0 -116
@@ -1,17 +1,22 @@
1
1
  /**
2
- * Conversations REST routes — list, get, and delete conversations.
2
+ * Conversations REST routes — list, get, delete, star, share/unshare.
3
3
  *
4
- * Middleware stack follows the same auth rate limit → withRequestContext
5
- * pattern as chat.ts and query.ts.
4
+ * Authenticated routes use `standardAuth` + `requestContext` middleware from
5
+ * `./middleware`. The public shared-conversation route (`publicConversations`)
6
+ * has its own in-memory rate limiter and no auth.
6
7
  */
7
8
 
8
- import { Hono } from "hono";
9
+ import { OpenAPIHono, createRoute } from "@hono/zod-openapi";
10
+ import { Effect } from "effect";
11
+ import { runEffect } from "@atlas/api/lib/effect/hono";
12
+ import { RequestContext, AuthContext } from "@atlas/api/lib/effect/services";
9
13
  import { z } from "zod";
10
- import { createLogger, withRequestContext } from "@atlas/api/lib/logger";
14
+ import { HTTPException } from "hono/http-exception";
15
+ import { createLogger } from "@atlas/api/lib/logger";
16
+ import { validationHook } from "./validation-hook";
11
17
  import type { AuthResult } from "@atlas/api/lib/auth/types";
12
18
  import {
13
19
  authenticateRequest,
14
- checkRateLimit,
15
20
  getClientIP,
16
21
  } from "@atlas/api/lib/auth/middleware";
17
22
  import { hasInternalDB } from "@atlas/api/lib/db/internal";
@@ -20,8 +25,20 @@ import {
20
25
  getConversation,
21
26
  deleteConversation,
22
27
  starConversation,
28
+ updateNotebookState,
29
+ forkConversation,
30
+ shareConversation,
31
+ unshareConversation,
32
+ getShareStatus,
33
+ getSharedConversation,
34
+ cleanupExpiredShares,
23
35
  type CrudFailReason,
36
+ type SharedConversationFailReason,
24
37
  } from "@atlas/api/lib/conversations";
38
+ import type { ShareExpiryKey } from "@useatlas/types/share";
39
+ import { SHARE_MODES, SHARE_EXPIRY_OPTIONS } from "@useatlas/types/share";
40
+ import { standardAuth, requestContext, type AuthEnv } from "./middleware";
41
+ import { ErrorSchema, AuthErrorSchema, parsePagination } from "./shared-schemas";
25
42
 
26
43
  const log = createLogger("conversations");
27
44
 
@@ -29,7 +46,24 @@ const log = createLogger("conversations");
29
46
  // Zod schemas — exported for OpenAPI spec generation
30
47
  // ---------------------------------------------------------------------------
31
48
 
32
- export const ConversationSchema = z.object({
49
+ const ForkBranchWireSchema = z.object({
50
+ conversationId: z.string(),
51
+ forkPointCellId: z.string(),
52
+ label: z.string(),
53
+ createdAt: z.string(),
54
+ });
55
+
56
+ const NotebookStateWireSchema = z.object({
57
+ version: z.number().int().min(1).max(10),
58
+ cellOrder: z.array(z.string()).optional(),
59
+ cellProps: z.record(z.string(), z.object({ collapsed: z.boolean().optional() })).optional(),
60
+ textCells: z.record(z.string(), z.object({ content: z.string() })).optional(),
61
+ branches: z.array(ForkBranchWireSchema).optional(),
62
+ forkRootId: z.string().optional(),
63
+ forkPointCellId: z.string().optional(),
64
+ });
65
+
66
+ const ConversationSchema = z.object({
33
67
  id: z.string().uuid(),
34
68
  userId: z.string().nullable(),
35
69
  title: z.string().nullable(),
@@ -38,13 +72,21 @@ export const ConversationSchema = z.object({
38
72
  starred: z.boolean(),
39
73
  createdAt: z.string().datetime(),
40
74
  updatedAt: z.string().datetime(),
75
+ notebookState: NotebookStateWireSchema.nullable().optional(),
41
76
  });
42
77
 
43
78
  export const StarConversationBodySchema = z.object({
44
79
  starred: z.boolean(),
45
80
  });
46
81
 
47
- export const MessageSchema = z.object({
82
+ export const NotebookStateBodySchema = NotebookStateWireSchema;
83
+
84
+ export const ForkConversationBodySchema = z.object({
85
+ forkPointMessageId: z.string(),
86
+ label: z.string().optional(),
87
+ });
88
+
89
+ const MessageSchema = z.object({
48
90
  id: z.string().uuid(),
49
91
  conversationId: z.string().uuid(),
50
92
  role: z.enum(["user", "assistant", "system", "tool"]),
@@ -61,206 +103,1019 @@ export const ListConversationsResponseSchema = z.object({
61
103
  total: z.number().int().nonnegative(),
62
104
  });
63
105
 
106
+ const EXPIRY_KEYS = Object.keys(SHARE_EXPIRY_OPTIONS) as [ShareExpiryKey, ...ShareExpiryKey[]];
107
+
108
+ const ShareConversationBodySchema = z.object({
109
+ expiresIn: z.enum(EXPIRY_KEYS).optional(),
110
+ shareMode: z.enum(SHARE_MODES).optional(),
111
+ }).optional();
112
+
64
113
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
65
114
 
66
115
  /** Map a CrudFailReason to { body, status } for JSON responses. */
67
- function crudFailResponse(reason: CrudFailReason) {
116
+ function crudFailResponse(reason: CrudFailReason, requestId?: string) {
68
117
  switch (reason) {
69
118
  case "no_db":
70
119
  return { body: { error: "not_available", message: "Conversation history is not available (no internal database configured)." }, status: 404 as const };
71
120
  case "not_found":
72
121
  return { body: { error: "not_found", message: "Conversation not found." }, status: 404 as const };
73
122
  case "error":
74
- return { body: { error: "internal_error", message: "A database error occurred. Please try again." }, status: 500 as const };
123
+ return { body: { error: "internal_error", message: "A database error occurred. Please try again.", ...(requestId && { requestId }) }, status: 500 as const };
75
124
  default: {
76
125
  const _exhaustive: never = reason;
77
- return { body: { error: "internal_error", message: `Unexpected failure: ${_exhaustive}` }, status: 500 as const };
126
+ return { body: { error: "internal_error", message: `Unexpected failure: ${_exhaustive}`, ...(requestId && { requestId }) }, status: 500 as const };
78
127
  }
79
128
  }
80
129
  }
81
130
 
82
- const conversations = new Hono();
131
+ // ---------------------------------------------------------------------------
132
+ // Shared path param schemas
133
+ // ---------------------------------------------------------------------------
134
+
135
+ const IdParamSchema = z.object({
136
+ id: z.string().openapi({ param: { name: "id", in: "path" }, example: "550e8400-e29b-41d4-a716-446655440000" }),
137
+ });
83
138
 
84
139
  // ---------------------------------------------------------------------------
85
- // Shared auth + rate-limit preamble
140
+ // Route definitions
86
141
  // ---------------------------------------------------------------------------
87
142
 
88
- async function authPreamble(req: Request, requestId: string) {
89
- let authResult: AuthResult;
90
- try {
91
- authResult = await authenticateRequest(req);
92
- } catch (err) {
93
- log.error(
94
- { err: err instanceof Error ? err : new Error(String(err)), requestId },
95
- "Auth dispatch failed",
96
- );
97
- return { error: { error: "auth_error", message: "Authentication system error" }, status: 500 as const };
98
- }
99
- if (!authResult.authenticated) {
100
- log.warn({ requestId, status: authResult.status }, "Authentication failed");
101
- return { error: { error: "auth_error", message: authResult.error }, status: authResult.status as 401 | 403 | 500 };
102
- }
143
+ const listConversationsRoute = createRoute({
144
+ method: "get",
145
+ path: "/",
146
+ tags: ["Conversations"],
147
+ summary: "List conversations",
148
+ description:
149
+ "Returns a paginated list of conversations for the authenticated user. Requires an internal database (DATABASE_URL).",
150
+ request: {
151
+ query: z.object({
152
+ limit: z.string().optional().openapi({ param: { name: "limit", in: "query" }, example: "20" }),
153
+ offset: z.string().optional().openapi({ param: { name: "offset", in: "query" }, example: "0" }),
154
+ starred: z.string().optional().openapi({ param: { name: "starred", in: "query" }, example: "true" }),
155
+ }),
156
+ },
157
+ responses: {
158
+ 200: {
159
+ description: "Paginated list of conversations",
160
+ content: { "application/json": { schema: ListConversationsResponseSchema } },
161
+ },
162
+ 401: {
163
+ description: "Authentication required",
164
+ content: { "application/json": { schema: AuthErrorSchema } },
165
+ },
166
+ 403: {
167
+ description: "Forbidden — insufficient permissions",
168
+ content: { "application/json": { schema: AuthErrorSchema } },
169
+ },
170
+ 404: {
171
+ description: "Not available (no internal database configured)",
172
+ content: { "application/json": { schema: ErrorSchema } },
173
+ },
174
+ 429: {
175
+ description: "Rate limit exceeded",
176
+ content: { "application/json": { schema: AuthErrorSchema } },
177
+ },
178
+ 500: {
179
+ description: "Internal server error",
180
+ content: { "application/json": { schema: ErrorSchema } },
181
+ },
182
+ },
183
+ });
103
184
 
104
- const ip = getClientIP(req);
105
- const rateLimitKey = authResult.user?.id ?? (ip ? `ip:${ip}` : "anon");
106
- const rateCheck = checkRateLimit(rateLimitKey);
107
- if (!rateCheck.allowed) {
108
- const retryAfterSeconds = Math.ceil((rateCheck.retryAfterMs ?? 60000) / 1000);
109
- return {
110
- error: { error: "rate_limited", message: "Too many requests. Please wait before trying again.", retryAfterSeconds },
111
- status: 429 as const,
112
- headers: { "Retry-After": String(retryAfterSeconds) },
113
- };
114
- }
185
+ const getConversationRoute = createRoute({
186
+ method: "get",
187
+ path: "/{id}",
188
+ tags: ["Conversations"],
189
+ summary: "Get conversation with messages",
190
+ description:
191
+ "Returns a single conversation with all its messages. Enforces ownership when auth is enabled.",
192
+ request: {
193
+ params: IdParamSchema,
194
+ },
195
+ responses: {
196
+ 200: {
197
+ description: "Conversation with messages",
198
+ content: { "application/json": { schema: ConversationWithMessagesSchema } },
199
+ },
200
+ 400: {
201
+ description: "Invalid conversation ID format",
202
+ content: { "application/json": { schema: ErrorSchema } },
203
+ },
204
+ 401: {
205
+ description: "Authentication required",
206
+ content: { "application/json": { schema: AuthErrorSchema } },
207
+ },
208
+ 403: {
209
+ description: "Forbidden — insufficient permissions",
210
+ content: { "application/json": { schema: AuthErrorSchema } },
211
+ },
212
+ 404: {
213
+ description: "Conversation not found or not available",
214
+ content: { "application/json": { schema: ErrorSchema } },
215
+ },
216
+ 429: {
217
+ description: "Rate limit exceeded",
218
+ content: { "application/json": { schema: AuthErrorSchema } },
219
+ },
220
+ 500: {
221
+ description: "Internal server error",
222
+ content: { "application/json": { schema: ErrorSchema } },
223
+ },
224
+ },
225
+ });
115
226
 
116
- return { authResult };
117
- }
227
+ const starConversationRoute = createRoute({
228
+ method: "patch",
229
+ path: "/{id}/star",
230
+ tags: ["Conversations"],
231
+ summary: "Star or unstar a conversation",
232
+ description: "Sets the starred status of a conversation.",
233
+ request: {
234
+ params: IdParamSchema,
235
+ body: {
236
+ content: { "application/json": { schema: StarConversationBodySchema } },
237
+ required: true,
238
+ },
239
+ },
240
+ responses: {
241
+ 200: {
242
+ description: "Star status updated",
243
+ content: {
244
+ "application/json": {
245
+ schema: z.object({ id: z.string(), starred: z.boolean() }),
246
+ },
247
+ },
248
+ },
249
+ 400: {
250
+ description: "Invalid conversation ID or request body",
251
+ content: { "application/json": { schema: ErrorSchema } },
252
+ },
253
+ 401: {
254
+ description: "Authentication required",
255
+ content: { "application/json": { schema: AuthErrorSchema } },
256
+ },
257
+ 403: {
258
+ description: "Forbidden — insufficient permissions",
259
+ content: { "application/json": { schema: AuthErrorSchema } },
260
+ },
261
+ 404: {
262
+ description: "Conversation not found or not available",
263
+ content: { "application/json": { schema: ErrorSchema } },
264
+ },
265
+ 429: {
266
+ description: "Rate limit exceeded",
267
+ content: { "application/json": { schema: AuthErrorSchema } },
268
+ },
269
+ 500: {
270
+ description: "Internal server error",
271
+ content: { "application/json": { schema: ErrorSchema } },
272
+ },
273
+ },
274
+ });
275
+
276
+ const notebookStateRoute = createRoute({
277
+ method: "patch",
278
+ path: "/{id}/notebook-state",
279
+ tags: ["Conversations"],
280
+ summary: "Update notebook state",
281
+ description:
282
+ "Updates the notebook state of a conversation, including cell order, cell properties, and branch metadata.",
283
+ request: {
284
+ params: IdParamSchema,
285
+ body: {
286
+ content: { "application/json": { schema: NotebookStateBodySchema } },
287
+ required: true,
288
+ },
289
+ },
290
+ responses: {
291
+ 200: {
292
+ description: "Notebook state updated",
293
+ content: {
294
+ "application/json": {
295
+ schema: z.object({ id: z.string(), notebookState: z.record(z.string(), z.unknown()) }),
296
+ },
297
+ },
298
+ },
299
+ 400: {
300
+ description: "Invalid conversation ID or notebook state body",
301
+ content: { "application/json": { schema: ErrorSchema } },
302
+ },
303
+ 401: {
304
+ description: "Authentication required",
305
+ content: { "application/json": { schema: AuthErrorSchema } },
306
+ },
307
+ 403: {
308
+ description: "Forbidden — insufficient permissions",
309
+ content: { "application/json": { schema: AuthErrorSchema } },
310
+ },
311
+ 404: {
312
+ description: "Conversation not found or not available",
313
+ content: { "application/json": { schema: ErrorSchema } },
314
+ },
315
+ 429: {
316
+ description: "Rate limit exceeded",
317
+ content: { "application/json": { schema: AuthErrorSchema } },
318
+ },
319
+ 500: {
320
+ description: "Internal server error",
321
+ content: { "application/json": { schema: ErrorSchema } },
322
+ },
323
+ },
324
+ });
325
+
326
+ const forkConversationRoute = createRoute({
327
+ method: "post",
328
+ path: "/{id}/fork",
329
+ tags: ["Conversations"],
330
+ summary: "Fork a conversation at a specific message",
331
+ description:
332
+ "Creates a new conversation by forking an existing one at the specified message. " +
333
+ "Messages up to and including the fork point are copied to the new conversation. " +
334
+ "Branch metadata is saved to both the source and forked conversation's notebook state.",
335
+ request: {
336
+ params: IdParamSchema,
337
+ body: {
338
+ content: { "application/json": { schema: ForkConversationBodySchema } },
339
+ required: true,
340
+ },
341
+ },
342
+ responses: {
343
+ 200: {
344
+ description: "Fork created successfully",
345
+ content: {
346
+ "application/json": {
347
+ schema: z.record(z.string(), z.unknown()),
348
+ },
349
+ },
350
+ },
351
+ 400: {
352
+ description: "Invalid conversation ID or request body",
353
+ content: { "application/json": { schema: ErrorSchema } },
354
+ },
355
+ 401: {
356
+ description: "Authentication required",
357
+ content: { "application/json": { schema: AuthErrorSchema } },
358
+ },
359
+ 403: {
360
+ description: "Forbidden — insufficient permissions",
361
+ content: { "application/json": { schema: AuthErrorSchema } },
362
+ },
363
+ 404: {
364
+ description: "Conversation not found or not available",
365
+ content: { "application/json": { schema: ErrorSchema } },
366
+ },
367
+ 429: {
368
+ description: "Rate limit exceeded",
369
+ content: { "application/json": { schema: AuthErrorSchema } },
370
+ },
371
+ 500: {
372
+ description: "Internal server error",
373
+ content: { "application/json": { schema: ErrorSchema } },
374
+ },
375
+ },
376
+ });
377
+
378
+ const getShareStatusRoute = createRoute({
379
+ method: "get",
380
+ path: "/{id}/share",
381
+ tags: ["Conversations"],
382
+ summary: "Get conversation share status",
383
+ description:
384
+ "Returns whether a conversation is currently shared and its share link details.",
385
+ request: {
386
+ params: IdParamSchema,
387
+ },
388
+ responses: {
389
+ 200: {
390
+ description: "Share status",
391
+ content: {
392
+ "application/json": {
393
+ schema: z.record(z.string(), z.unknown()),
394
+ },
395
+ },
396
+ },
397
+ 400: {
398
+ description: "Invalid conversation ID format",
399
+ content: { "application/json": { schema: ErrorSchema } },
400
+ },
401
+ 401: {
402
+ description: "Authentication required",
403
+ content: { "application/json": { schema: AuthErrorSchema } },
404
+ },
405
+ 403: {
406
+ description: "Forbidden — insufficient permissions",
407
+ content: { "application/json": { schema: AuthErrorSchema } },
408
+ },
409
+ 404: {
410
+ description: "Conversation not found or not available",
411
+ content: { "application/json": { schema: ErrorSchema } },
412
+ },
413
+ 429: {
414
+ description: "Rate limit exceeded",
415
+ content: { "application/json": { schema: AuthErrorSchema } },
416
+ },
417
+ 500: {
418
+ description: "Internal server error",
419
+ content: { "application/json": { schema: ErrorSchema } },
420
+ },
421
+ },
422
+ });
423
+
424
+ // Body is optional and parsed manually in the handler via safeParse — not declared
425
+ // in the route schema to avoid framework-level validation on empty/missing bodies.
426
+ const shareConversationRoute = createRoute({
427
+ method: "post",
428
+ path: "/{id}/share",
429
+ tags: ["Conversations"],
430
+ summary: "Generate share link",
431
+ description:
432
+ "Creates a shareable link for a conversation. Optionally specify expiry duration and share mode (public or org-only).",
433
+ request: {
434
+ params: IdParamSchema,
435
+ },
436
+ responses: {
437
+ 200: {
438
+ description: "Share link created",
439
+ content: {
440
+ "application/json": {
441
+ schema: z.record(z.string(), z.unknown()),
442
+ },
443
+ },
444
+ },
445
+ 400: {
446
+ description: "Invalid conversation ID or share options",
447
+ content: { "application/json": { schema: ErrorSchema } },
448
+ },
449
+ 401: {
450
+ description: "Authentication required",
451
+ content: { "application/json": { schema: AuthErrorSchema } },
452
+ },
453
+ 403: {
454
+ description: "Forbidden — insufficient permissions",
455
+ content: { "application/json": { schema: AuthErrorSchema } },
456
+ },
457
+ 404: {
458
+ description: "Conversation not found or not available",
459
+ content: { "application/json": { schema: ErrorSchema } },
460
+ },
461
+ 429: {
462
+ description: "Rate limit exceeded",
463
+ content: { "application/json": { schema: AuthErrorSchema } },
464
+ },
465
+ 500: {
466
+ description: "Internal server error",
467
+ content: { "application/json": { schema: ErrorSchema } },
468
+ },
469
+ },
470
+ });
471
+
472
+ const unshareConversationRoute = createRoute({
473
+ method: "delete",
474
+ path: "/{id}/share",
475
+ tags: ["Conversations"],
476
+ summary: "Revoke share link",
477
+ description: "Revokes the share link for a conversation, making it private again.",
478
+ request: {
479
+ params: IdParamSchema,
480
+ },
481
+ responses: {
482
+ 204: {
483
+ description: "Share link revoked",
484
+ },
485
+ 400: {
486
+ description: "Invalid conversation ID format",
487
+ content: { "application/json": { schema: ErrorSchema } },
488
+ },
489
+ 401: {
490
+ description: "Authentication required",
491
+ content: { "application/json": { schema: AuthErrorSchema } },
492
+ },
493
+ 403: {
494
+ description: "Forbidden — insufficient permissions",
495
+ content: { "application/json": { schema: AuthErrorSchema } },
496
+ },
497
+ 404: {
498
+ description: "Conversation not found or not available",
499
+ content: { "application/json": { schema: ErrorSchema } },
500
+ },
501
+ 429: {
502
+ description: "Rate limit exceeded",
503
+ content: { "application/json": { schema: AuthErrorSchema } },
504
+ },
505
+ 500: {
506
+ description: "Internal server error",
507
+ content: { "application/json": { schema: ErrorSchema } },
508
+ },
509
+ },
510
+ });
511
+
512
+ const deleteConversationRoute = createRoute({
513
+ method: "delete",
514
+ path: "/{id}",
515
+ tags: ["Conversations"],
516
+ summary: "Delete a conversation",
517
+ description:
518
+ "Deletes a conversation and all its messages. Enforces ownership when auth is enabled.",
519
+ request: {
520
+ params: IdParamSchema,
521
+ },
522
+ responses: {
523
+ 204: {
524
+ description: "Conversation deleted successfully",
525
+ },
526
+ 400: {
527
+ description: "Invalid conversation ID format",
528
+ content: { "application/json": { schema: ErrorSchema } },
529
+ },
530
+ 401: {
531
+ description: "Authentication required",
532
+ content: { "application/json": { schema: AuthErrorSchema } },
533
+ },
534
+ 403: {
535
+ description: "Forbidden — insufficient permissions",
536
+ content: { "application/json": { schema: AuthErrorSchema } },
537
+ },
538
+ 404: {
539
+ description: "Conversation not found or not available",
540
+ content: { "application/json": { schema: ErrorSchema } },
541
+ },
542
+ 429: {
543
+ description: "Rate limit exceeded",
544
+ content: { "application/json": { schema: AuthErrorSchema } },
545
+ },
546
+ 500: {
547
+ description: "Internal server error",
548
+ content: { "application/json": { schema: ErrorSchema } },
549
+ },
550
+ },
551
+ });
118
552
 
119
553
  // ---------------------------------------------------------------------------
120
- // GET / — list conversations
554
+ // Router
121
555
  // ---------------------------------------------------------------------------
122
556
 
123
- conversations.get("/", async (c) => {
124
- const req = c.req.raw;
125
- const requestId = crypto.randomUUID();
557
+ const conversations = new OpenAPIHono<AuthEnv>({
558
+ defaultHook: validationHook,
559
+ });
126
560
 
127
- if (!hasInternalDB()) {
128
- return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
129
- }
561
+ conversations.use(standardAuth);
562
+ conversations.use(requestContext);
130
563
 
131
- const preamble = await authPreamble(req, requestId);
132
- if ("error" in preamble) {
133
- return c.json(preamble.error, { status: preamble.status, headers: preamble.headers });
564
+ // JSON parse error handler — only for truly malformed request bodies
565
+ // (e.g. unparseable JSON). Zod validation failures are handled by the
566
+ // defaultHook above which uses the `target` field for accurate messages.
567
+ conversations.onError((err, c) => {
568
+ if (err instanceof HTTPException) {
569
+ if (err.res) return err.res;
570
+ if (err.status === 400) return c.json({ error: "invalid_request", message: "Invalid JSON body." }, 400);
134
571
  }
135
- const { authResult } = preamble;
136
-
137
- return withRequestContext({ requestId, user: authResult.user }, async () => {
138
- const rawLimit = parseInt(c.req.query("limit") ?? "20", 10);
139
- const rawOffset = parseInt(c.req.query("offset") ?? "0", 10);
140
- const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? Math.min(rawLimit, 100) : 20;
141
- const offset = Number.isFinite(rawOffset) && rawOffset >= 0 ? rawOffset : 0;
142
- const starredParam = c.req.query("starred");
572
+ throw err;
573
+ });
574
+
575
+ // ---------------------------------------------------------------------------
576
+ // GET / list conversations
577
+ // ---------------------------------------------------------------------------
578
+
579
+ conversations.openapi(listConversationsRoute, async (c) => {
580
+ return runEffect(c, Effect.gen(function* () {
581
+ if (!hasInternalDB()) {
582
+ return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
583
+ }
584
+
585
+ const { user } = yield* AuthContext;
586
+
587
+ const { limit, offset } = parsePagination(c, { limit: 20, maxLimit: 100 });
588
+ const starredParam = c.req.valid("query").starred;
143
589
  const starred = starredParam === "true" ? true : starredParam === "false" ? false : undefined;
144
- const result = await listConversations({
145
- userId: authResult.user?.id,
590
+ const items = yield* Effect.promise(() => listConversations({
591
+ userId: user?.id,
592
+ orgId: user?.activeOrganizationId,
146
593
  starred,
147
594
  limit,
148
595
  offset,
149
- });
150
- return c.json(result);
151
- });
596
+ }));
597
+ return c.json(items, 200);
598
+ }), { label: "list conversations" });
152
599
  });
153
600
 
154
601
  // ---------------------------------------------------------------------------
155
602
  // GET /:id — get conversation with messages
156
603
  // ---------------------------------------------------------------------------
157
604
 
158
- conversations.get("/:id", async (c) => {
159
- const req = c.req.raw;
160
- const requestId = crypto.randomUUID();
161
-
162
- if (!hasInternalDB()) {
163
- return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
164
- }
605
+ conversations.openapi(getConversationRoute, async (c) => {
606
+ return runEffect(c, Effect.gen(function* () {
607
+ if (!hasInternalDB()) {
608
+ return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
609
+ }
165
610
 
166
- const preamble = await authPreamble(req, requestId);
167
- if ("error" in preamble) {
168
- return c.json(preamble.error, { status: preamble.status, headers: preamble.headers });
169
- }
170
- const { authResult } = preamble;
611
+ const { requestId } = yield* RequestContext;
612
+ const { user } = yield* AuthContext;
171
613
 
172
- const id = c.req.param("id");
173
- if (!UUID_RE.test(id)) {
174
- return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
175
- }
614
+ const { id } = c.req.valid("param");
615
+ if (!UUID_RE.test(id)) {
616
+ return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
617
+ }
176
618
 
177
- return withRequestContext({ requestId, user: authResult.user }, async () => {
178
- const result = await getConversation(id, authResult.user?.id);
179
- if (!result.ok) {
180
- const fail = crudFailResponse(result.reason);
619
+ const conv = yield* Effect.promise(() => getConversation(id, user?.id));
620
+ if (!conv.ok) {
621
+ const fail = crudFailResponse(conv.reason, requestId);
181
622
  return c.json(fail.body, fail.status);
182
623
  }
183
- return c.json(result.data);
184
- });
624
+ return c.json(conv.data, 200);
625
+ }), { label: "get conversation" });
185
626
  });
186
627
 
187
628
  // ---------------------------------------------------------------------------
188
629
  // PATCH /:id/star — star or unstar a conversation
189
630
  // ---------------------------------------------------------------------------
190
631
 
191
- conversations.patch("/:id/star", async (c) => {
192
- const req = c.req.raw;
193
- const requestId = crypto.randomUUID();
632
+ conversations.openapi(starConversationRoute, async (c) => {
633
+ return runEffect(c, Effect.gen(function* () {
634
+ if (!hasInternalDB()) {
635
+ return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
636
+ }
194
637
 
195
- if (!hasInternalDB()) {
196
- return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
197
- }
638
+ const { requestId } = yield* RequestContext;
639
+ const { user } = yield* AuthContext;
198
640
 
199
- const preamble = await authPreamble(req, requestId);
200
- if ("error" in preamble) {
201
- return c.json(preamble.error, { status: preamble.status, headers: preamble.headers });
202
- }
203
- const { authResult } = preamble;
641
+ const { id } = c.req.valid("param");
642
+ if (!UUID_RE.test(id)) {
643
+ return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
644
+ }
204
645
 
205
- const id = c.req.param("id");
206
- if (!UUID_RE.test(id)) {
207
- return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
208
- }
646
+ const parsed = c.req.valid("json");
209
647
 
210
- return withRequestContext({ requestId, user: authResult.user }, async () => {
211
- let body: unknown;
212
- try {
213
- body = await req.json();
214
- } catch (err) {
215
- log.debug({ err: err instanceof Error ? err.message : String(err) }, "Invalid JSON body in PATCH star");
648
+ const starResult = yield* Effect.promise(() => starConversation(id, parsed.starred, user?.id));
649
+ if (!starResult.ok) {
650
+ const fail = crudFailResponse(starResult.reason, requestId);
651
+ return c.json(fail.body, fail.status);
652
+ }
653
+ return c.json({ id, starred: parsed.starred }, 200);
654
+ }), { label: "star conversation" });
655
+ });
656
+
657
+ // ---------------------------------------------------------------------------
658
+ // PATCH /:id/notebook-state — update notebook state
659
+ // ---------------------------------------------------------------------------
660
+
661
+ conversations.openapi(notebookStateRoute, async (c) => {
662
+ return runEffect(c, Effect.gen(function* () {
663
+ if (!hasInternalDB()) {
664
+ return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
665
+ }
666
+
667
+ const { requestId } = yield* RequestContext;
668
+ const { user } = yield* AuthContext;
669
+
670
+ const { id } = c.req.valid("param");
671
+ if (!UUID_RE.test(id)) {
672
+ return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
673
+ }
674
+
675
+ const parsed = c.req.valid("json");
676
+
677
+ const nbResult = yield* Effect.promise(() => updateNotebookState(id, parsed, user?.id));
678
+ if (!nbResult.ok) {
679
+ const fail = crudFailResponse(nbResult.reason, requestId);
680
+ return c.json(fail.body, fail.status);
681
+ }
682
+ return c.json({ id, notebookState: parsed }, 200);
683
+ }), { label: "update notebook state" });
684
+ });
685
+
686
+ // ---------------------------------------------------------------------------
687
+ // POST /:id/fork — fork a conversation at a specific message
688
+ // ---------------------------------------------------------------------------
689
+
690
+ conversations.openapi(forkConversationRoute, async (c) => {
691
+ return runEffect(c, Effect.gen(function* () {
692
+ if (!hasInternalDB()) {
693
+ return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
694
+ }
695
+
696
+ const { requestId } = yield* RequestContext;
697
+ const { user } = yield* AuthContext;
698
+
699
+ const { id } = c.req.valid("param");
700
+ if (!UUID_RE.test(id)) {
701
+ return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
702
+ }
703
+
704
+ const parsed = c.req.valid("json");
705
+
706
+ const forkResult = yield* Effect.promise(() => forkConversation({
707
+ sourceId: id,
708
+ forkPointMessageId: parsed.forkPointMessageId,
709
+ userId: user?.id,
710
+ orgId: user?.activeOrganizationId,
711
+ }));
712
+ if (!forkResult.ok) {
713
+ const fail = crudFailResponse(forkResult.reason, requestId);
714
+ return c.json(fail.body, fail.status);
715
+ }
716
+
717
+ // Update notebook_state on source and new conversation
718
+ const label = parsed.label ?? `Fork from cell`;
719
+ const branch = {
720
+ conversationId: forkResult.data.id,
721
+ forkPointCellId: parsed.forkPointMessageId,
722
+ label,
723
+ createdAt: new Date().toISOString(),
724
+ };
725
+
726
+ // Read current notebook_state from source to preserve existing data
727
+ const sourceConv = yield* Effect.promise(() => getConversation(id, user?.id));
728
+ if (!sourceConv.ok) {
729
+ log.error({ requestId, conversationId: id, reason: sourceConv.reason }, "Failed to read source conversation for branch metadata");
730
+ return c.json({
731
+ id: forkResult.data.id,
732
+ messageCount: forkResult.data.messageCount,
733
+ branches: [branch],
734
+ warning: "Fork created but branch metadata could not be saved to source conversation.",
735
+ }, 200);
736
+ }
737
+
738
+ const existing = sourceConv.data.notebookState ?? { version: 3 };
739
+ const existingBranches = existing.branches ?? [];
740
+
741
+ const updatedSourceState = {
742
+ ...existing,
743
+ version: existing.version || 3,
744
+ branches: [...existingBranches, branch],
745
+ };
746
+
747
+ const sourceRoot = existing.forkRootId;
748
+ const forkChildState = {
749
+ version: 3,
750
+ forkRootId: sourceRoot ?? id,
751
+ forkPointCellId: parsed.forkPointMessageId,
752
+ };
753
+
754
+ // Write both notebook_state updates in parallel
755
+ const [sourceResult, forkMetaResult] = yield* Effect.promise(() => Promise.all([
756
+ updateNotebookState(id, updatedSourceState, user?.id),
757
+ updateNotebookState(forkResult.data.id, forkChildState, user?.id),
758
+ ]));
759
+
760
+ let metadataWarning: string | undefined;
761
+ if (!sourceResult.ok) {
762
+ log.error({ requestId, conversationId: id, reason: sourceResult.reason }, "Failed to update source notebook_state after fork");
763
+ metadataWarning = "Fork created but branch metadata could not be fully saved.";
764
+ }
765
+ if (!forkMetaResult.ok) {
766
+ log.error({ requestId, conversationId: forkResult.data.id, reason: forkMetaResult.reason }, "Failed to set fork metadata on new conversation");
767
+ metadataWarning = "Fork created but branch metadata could not be fully saved.";
768
+ }
769
+
770
+ return c.json({
771
+ id: forkResult.data.id,
772
+ messageCount: forkResult.data.messageCount,
773
+ branches: [...existingBranches, branch],
774
+ ...(metadataWarning ? { warning: metadataWarning } : {}),
775
+ }, 200);
776
+ }), { label: "fork conversation" });
777
+ });
778
+
779
+ // ---------------------------------------------------------------------------
780
+ // GET /:id/share — get share status
781
+ // ---------------------------------------------------------------------------
782
+
783
+ conversations.openapi(getShareStatusRoute, async (c) => {
784
+ return runEffect(c, Effect.gen(function* () {
785
+ if (!hasInternalDB()) {
786
+ return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
787
+ }
788
+
789
+ const { requestId } = yield* RequestContext;
790
+ const { user } = yield* AuthContext;
791
+
792
+ const { id } = c.req.valid("param");
793
+ if (!UUID_RE.test(id)) {
794
+ return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
795
+ }
796
+
797
+ const shareResult = yield* Effect.promise(() => getShareStatus(id, user?.id));
798
+ if (!shareResult.ok) {
799
+ if (shareResult.reason === "error") {
800
+ log.error({ requestId, conversationId: id }, "Share status fetch failed due to DB error");
801
+ }
802
+ const fail = crudFailResponse(shareResult.reason, requestId);
803
+ return c.json(fail.body, fail.status);
804
+ }
805
+ if (!shareResult.data.shared) {
806
+ return c.json({ shared: false as const }, 200);
807
+ }
808
+ const baseUrl = new URL(c.req.raw.url).origin;
809
+ return c.json({
810
+ shared: true as const,
811
+ token: shareResult.data.token,
812
+ url: `${baseUrl}/shared/${shareResult.data.token}`,
813
+ expiresAt: shareResult.data.expiresAt,
814
+ shareMode: shareResult.data.shareMode,
815
+ }, 200);
816
+ }), { label: "get share status" });
817
+ });
818
+
819
+ // ---------------------------------------------------------------------------
820
+ // POST /:id/share — generate share link
821
+ // ---------------------------------------------------------------------------
822
+
823
+ conversations.openapi(shareConversationRoute, async (c) => {
824
+ return runEffect(c, Effect.gen(function* () {
825
+ if (!hasInternalDB()) {
826
+ return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
827
+ }
828
+
829
+ const { requestId } = yield* RequestContext;
830
+ const { user } = yield* AuthContext;
831
+
832
+ const { id } = c.req.valid("param");
833
+ if (!UUID_RE.test(id)) {
834
+ return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
835
+ }
836
+
837
+ const bodyResult = yield* Effect.tryPromise({
838
+ try: async () => {
839
+ const text = await c.req.raw.text();
840
+ return text ? JSON.parse(text) as unknown : undefined;
841
+ },
842
+ catch: (err) => err instanceof Error ? err : new Error(String(err)),
843
+ }).pipe(Effect.either);
844
+ if (bodyResult._tag === "Left") {
845
+ log.debug({ err: bodyResult.left.message }, "Invalid JSON body in POST share");
216
846
  return c.json({ error: "invalid_request", message: "Invalid JSON body." }, 400);
217
847
  }
848
+ const body: unknown = bodyResult.right;
218
849
 
219
- const parsed = StarConversationBodySchema.safeParse(body);
850
+ const parsed = ShareConversationBodySchema.safeParse(body);
220
851
  if (!parsed.success) {
221
- return c.json({ error: "invalid_request", message: "Body must contain { starred: boolean }." }, 400);
852
+ return c.json({ error: "invalid_request", message: "Invalid share options." }, 400);
222
853
  }
223
854
 
224
- const result = await starConversation(id, parsed.data.starred, authResult.user?.id);
225
- if (!result.ok) {
226
- const fail = crudFailResponse(result.reason);
855
+ const opts = parsed.data;
856
+ const shareResult = yield* Effect.promise(() => shareConversation(id, user?.id, {
857
+ expiresIn: opts?.expiresIn,
858
+ shareMode: opts?.shareMode,
859
+ }));
860
+ if (!shareResult.ok) {
861
+ const fail = crudFailResponse(shareResult.reason, requestId);
227
862
  return c.json(fail.body, fail.status);
228
863
  }
229
- return c.json({ id, starred: parsed.data.starred });
230
- });
864
+ const baseUrl = new URL(c.req.raw.url).origin;
865
+ return c.json({
866
+ token: shareResult.data.token,
867
+ url: `${baseUrl}/shared/${shareResult.data.token}`,
868
+ expiresAt: shareResult.data.expiresAt,
869
+ shareMode: shareResult.data.shareMode,
870
+ }, 200);
871
+ }), { label: "share conversation" });
872
+ });
873
+
874
+ // ---------------------------------------------------------------------------
875
+ // DELETE /:id/share — revoke share link
876
+ // ---------------------------------------------------------------------------
877
+
878
+ conversations.openapi(unshareConversationRoute, async (c) => {
879
+ return runEffect(c, Effect.gen(function* () {
880
+ if (!hasInternalDB()) {
881
+ return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
882
+ }
883
+
884
+ const { requestId } = yield* RequestContext;
885
+ const { user } = yield* AuthContext;
886
+
887
+ const { id } = c.req.valid("param");
888
+ if (!UUID_RE.test(id)) {
889
+ return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
890
+ }
891
+
892
+ const unshareResult = yield* Effect.promise(() => unshareConversation(id, user?.id));
893
+ if (!unshareResult.ok) {
894
+ const fail = crudFailResponse(unshareResult.reason, requestId);
895
+ return c.json(fail.body, fail.status);
896
+ }
897
+ return c.body(null, 204);
898
+ }), { label: "unshare conversation" });
231
899
  });
232
900
 
233
901
  // ---------------------------------------------------------------------------
234
902
  // DELETE /:id — delete conversation
235
903
  // ---------------------------------------------------------------------------
236
904
 
237
- conversations.delete("/:id", async (c) => {
238
- const req = c.req.raw;
905
+ conversations.openapi(deleteConversationRoute, async (c) => {
906
+ return runEffect(c, Effect.gen(function* () {
907
+ if (!hasInternalDB()) {
908
+ return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
909
+ }
910
+
911
+ const { requestId } = yield* RequestContext;
912
+ const { user } = yield* AuthContext;
913
+
914
+ const { id } = c.req.valid("param");
915
+ if (!UUID_RE.test(id)) {
916
+ return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
917
+ }
918
+
919
+ const delResult = yield* Effect.promise(() => deleteConversation(id, user?.id));
920
+ if (!delResult.ok) {
921
+ const fail = crudFailResponse(delResult.reason, requestId);
922
+ return c.json(fail.body, fail.status);
923
+ }
924
+ return c.body(null, 204);
925
+ }), { label: "delete conversation" });
926
+ });
927
+
928
+ // ---------------------------------------------------------------------------
929
+ // Public shared conversation route (no auth required)
930
+ // ---------------------------------------------------------------------------
931
+
932
+ const SHARE_TOKEN_RE = /^[A-Za-z0-9_-]{20,64}$/;
933
+
934
+ // ---------------------------------------------------------------------------
935
+ // In-memory rate limiter for public route
936
+ // ---------------------------------------------------------------------------
937
+
938
+ const PUBLIC_RATE_WINDOW_MS = 60_000;
939
+ const PUBLIC_RATE_MAX = 60;
940
+
941
+ const publicRateMap = new Map<string, { count: number; resetAt: number }>();
942
+
943
+ /** Evict expired entries to prevent unbounded growth. Runs periodically. */
944
+ function sweepPublicRateMap() {
945
+ const now = Date.now();
946
+ for (const [key, entry] of publicRateMap) {
947
+ if (now > entry.resetAt) publicRateMap.delete(key);
948
+ }
949
+ }
950
+
951
+ // Sweep every 60 seconds
952
+ const _sweepInterval = setInterval(sweepPublicRateMap, PUBLIC_RATE_WINDOW_MS);
953
+ // Don't prevent process exit
954
+ if (typeof _sweepInterval === "object" && "unref" in _sweepInterval) _sweepInterval.unref();
955
+
956
+ // Clean up expired share tokens every 60 minutes
957
+ const SHARE_CLEANUP_INTERVAL_MS = 60 * 60 * 1000;
958
+ let shareCleanupConsecutiveFailures = 0;
959
+ const _shareCleanupInterval = setInterval(async () => {
960
+ try {
961
+ const count = await cleanupExpiredShares();
962
+ if (count >= 0) {
963
+ shareCleanupConsecutiveFailures = 0;
964
+ } else {
965
+ shareCleanupConsecutiveFailures++;
966
+ if (shareCleanupConsecutiveFailures >= 5) {
967
+ log.error({ consecutiveFailures: shareCleanupConsecutiveFailures },
968
+ "Share cleanup has failed repeatedly — expired tokens may remain accessible");
969
+ }
970
+ }
971
+ } catch (err) {
972
+ shareCleanupConsecutiveFailures++;
973
+ log.error({ err: err instanceof Error ? err.message : String(err) },
974
+ "Unexpected error in share cleanup interval");
975
+ }
976
+ }, SHARE_CLEANUP_INTERVAL_MS);
977
+ if (typeof _shareCleanupInterval === "object" && "unref" in _shareCleanupInterval) _shareCleanupInterval.unref();
978
+
979
+ function checkPublicRateLimit(ip: string): boolean {
980
+ const now = Date.now();
981
+ const entry = publicRateMap.get(ip);
982
+ if (!entry || now > entry.resetAt) {
983
+ publicRateMap.set(ip, { count: 1, resetAt: now + PUBLIC_RATE_WINDOW_MS });
984
+ return true;
985
+ }
986
+ entry.count++;
987
+ return entry.count <= PUBLIC_RATE_MAX;
988
+ }
989
+
990
+ // ---------------------------------------------------------------------------
991
+ // Public router + route definition
992
+ // ---------------------------------------------------------------------------
993
+
994
+ const getSharedConversationRoute = createRoute({
995
+ method: "get",
996
+ path: "/{token}",
997
+ tags: ["Conversations"],
998
+ summary: "View a shared conversation",
999
+ description:
1000
+ "Returns the content of a shared conversation. No authentication required for public shares. Org-scoped shares require authentication. Rate limited per IP.",
1001
+ request: {
1002
+ params: z.object({
1003
+ token: z.string().openapi({ param: { name: "token", in: "path" }, example: "abc123def456ghi789jk" }),
1004
+ }),
1005
+ },
1006
+ responses: {
1007
+ 200: {
1008
+ description: "Shared conversation content",
1009
+ content: {
1010
+ "application/json": {
1011
+ schema: z.record(z.string(), z.unknown()),
1012
+ },
1013
+ },
1014
+ },
1015
+ 403: {
1016
+ description: "Org-scoped share requires authentication",
1017
+ content: { "application/json": { schema: ErrorSchema } },
1018
+ },
1019
+ 404: {
1020
+ description: "Conversation not found",
1021
+ content: { "application/json": { schema: ErrorSchema } },
1022
+ },
1023
+ 410: {
1024
+ description: "Share link has expired",
1025
+ content: { "application/json": { schema: ErrorSchema } },
1026
+ },
1027
+ 429: {
1028
+ description: "Rate limit exceeded",
1029
+ content: { "application/json": { schema: ErrorSchema } },
1030
+ },
1031
+ 500: {
1032
+ description: "Internal server error",
1033
+ content: { "application/json": { schema: ErrorSchema } },
1034
+ },
1035
+ },
1036
+ });
1037
+
1038
+ const publicConversations = new OpenAPIHono({ defaultHook: validationHook });
1039
+
1040
+ /** Map a SharedConversationFailReason to a JSON response. */
1041
+ function sharedConversationFailResponse(reason: SharedConversationFailReason) {
1042
+ switch (reason) {
1043
+ case "expired":
1044
+ return { body: { error: "expired", message: "This share link has expired." }, status: 410 as const };
1045
+ case "no_db":
1046
+ return { body: { error: "not_available", message: "Sharing is not available." }, status: 404 as const };
1047
+ case "not_found":
1048
+ return { body: { error: "not_found", message: "Conversation not found." }, status: 404 as const };
1049
+ case "error":
1050
+ return { body: { error: "internal_error", message: "A server error occurred. Please try again." }, status: 500 as const };
1051
+ default: {
1052
+ const _exhaustive: never = reason;
1053
+ return { body: { error: "internal_error", message: `Unexpected failure: ${_exhaustive}` }, status: 500 as const };
1054
+ }
1055
+ }
1056
+ }
1057
+
1058
+ publicConversations.openapi(getSharedConversationRoute, async (c) => {
239
1059
  const requestId = crypto.randomUUID();
240
1060
 
241
1061
  if (!hasInternalDB()) {
242
- return c.json({ error: "not_available", message: "Conversation history is not available (no internal database configured)." }, 404);
1062
+ return c.json({ error: "not_available", message: "Sharing is not available." }, 404);
243
1063
  }
244
1064
 
245
- const preamble = await authPreamble(req, requestId);
246
- if ("error" in preamble) {
247
- return c.json(preamble.error, { status: preamble.status, headers: preamble.headers });
1065
+ const ip = getClientIP(c.req.raw);
1066
+ if (!ip) {
1067
+ log.warn({ requestId }, "Public conversation request with no client IP");
1068
+ }
1069
+ const rateLimitKey = ip ?? `unknown-${requestId}`;
1070
+ if (!checkPublicRateLimit(rateLimitKey)) {
1071
+ log.warn({ requestId, ip }, "Public conversation rate limited");
1072
+ return c.json({ error: "rate_limited", message: "Too many requests. Please wait before trying again.", requestId }, 429);
248
1073
  }
249
- const { authResult } = preamble;
250
1074
 
251
- const id = c.req.param("id");
252
- if (!UUID_RE.test(id)) {
253
- return c.json({ error: "invalid_request", message: "Invalid conversation ID format." }, 400);
1075
+ const { token } = c.req.valid("param");
1076
+ if (!SHARE_TOKEN_RE.test(token)) {
1077
+ return c.json({ error: "not_found", message: "Conversation not found." }, 404);
254
1078
  }
255
1079
 
256
- return withRequestContext({ requestId, user: authResult.user }, async () => {
257
- const result = await deleteConversation(id, authResult.user?.id);
258
- if (!result.ok) {
259
- const fail = crudFailResponse(result.reason);
260
- return c.json(fail.body, fail.status);
1080
+ const result = await getSharedConversation(token);
1081
+ if (!result.ok) {
1082
+ const fail = sharedConversationFailResponse(result.reason);
1083
+ if (result.reason === "error") {
1084
+ log.error({ requestId, token }, "Public conversation fetch failed due to DB error");
261
1085
  }
262
- return c.body(null, 204);
263
- });
1086
+ return c.json(fail.body, fail.status);
1087
+ }
1088
+
1089
+ // Org-scoped shares require the requester to be authenticated
1090
+ if (result.data.shareMode === "org") {
1091
+ let authResult: AuthResult;
1092
+ try {
1093
+ authResult = await authenticateRequest(c.req.raw);
1094
+ } catch (err) {
1095
+ log.error(
1096
+ { err: err instanceof Error ? err.message : String(err), requestId, token },
1097
+ "Auth check failed for org-scoped share",
1098
+ );
1099
+ return c.json({ error: "internal_error", message: "Authentication check failed. Please try again.", requestId }, 500);
1100
+ }
1101
+ if (!authResult.authenticated) {
1102
+ return c.json({ error: "auth_required", message: "This shared conversation requires authentication.", requestId }, 403);
1103
+ }
1104
+ }
1105
+
1106
+ // Strip internal IDs — only expose conversation content
1107
+ const { title, surface, createdAt, messages, shareMode } = result.data;
1108
+ return c.json({
1109
+ title,
1110
+ surface,
1111
+ createdAt,
1112
+ shareMode,
1113
+ messages: messages.map((m) => ({
1114
+ role: m.role,
1115
+ content: m.content,
1116
+ createdAt: m.createdAt,
1117
+ })),
1118
+ }, 200);
264
1119
  });
265
1120
 
266
- export { conversations };
1121
+ export { conversations, publicConversations };