@btst/stack 1.3.1 → 1.4.0

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 (229) hide show
  1. package/README.md +85 -37
  2. package/dist/node_modules/.pnpm/{@radix-ui_react-alert-dialog@1.1.15_@types_react-dom@19.2.2_@types_react@19.2.2__@types_ec789942cd38340bd7362c09e7d34384 → @radix-ui_react-alert-dialog@1.1.15_@types_react-dom@19.2.3_@types_react@19.2.6__@types_4f58c757aa677e233cf96d60fda2f1da}/node_modules/@radix-ui/react-alert-dialog/dist/index.cjs +2 -2
  3. package/dist/node_modules/.pnpm/{@radix-ui_react-alert-dialog@1.1.15_@types_react-dom@19.2.2_@types_react@19.2.2__@types_ec789942cd38340bd7362c09e7d34384 → @radix-ui_react-alert-dialog@1.1.15_@types_react-dom@19.2.3_@types_react@19.2.6__@types_4f58c757aa677e233cf96d60fda2f1da}/node_modules/@radix-ui/react-alert-dialog/dist/index.mjs +2 -2
  4. package/dist/node_modules/.pnpm/{@radix-ui_react-arrow@1.1.7_@types_react-dom@19.2.2_@types_react@19.2.2__@types_react@1_9e04309f365863673e44407648bb0cb6 → @radix-ui_react-arrow@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@1_35df44f6d87656c1401686c91d770dbb}/node_modules/@radix-ui/react-arrow/dist/index.cjs +1 -1
  5. package/dist/node_modules/.pnpm/{@radix-ui_react-arrow@1.1.7_@types_react-dom@19.2.2_@types_react@19.2.2__@types_react@1_9e04309f365863673e44407648bb0cb6 → @radix-ui_react-arrow@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@1_35df44f6d87656c1401686c91d770dbb}/node_modules/@radix-ui/react-arrow/dist/index.mjs +1 -1
  6. package/dist/node_modules/.pnpm/{@radix-ui_react-collection@1.1.7_@types_react-dom@19.2.2_@types_react@19.2.2__@types_re_6d7c277722b3619c9ee7e64e9a822c45 → @radix-ui_react-collection@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.6__@types_re_59aa5e150e70a3e7bfb1567148b021b5}/node_modules/@radix-ui/react-collection/dist/index.cjs +2 -2
  7. package/dist/node_modules/.pnpm/{@radix-ui_react-collection@1.1.7_@types_react-dom@19.2.2_@types_react@19.2.2__@types_re_6d7c277722b3619c9ee7e64e9a822c45 → @radix-ui_react-collection@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.6__@types_re_59aa5e150e70a3e7bfb1567148b021b5}/node_modules/@radix-ui/react-collection/dist/index.mjs +2 -2
  8. package/dist/node_modules/.pnpm/{@radix-ui_react-dismissable-layer@1.1.11_@types_react-dom@19.2.2_@types_react@19.2.2__@_ca5522e5d45d4722cb9eb5ce53defa61 → @radix-ui_react-dismissable-layer@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.6__@_9ee1db7daf927866cf505b31d40047ad}/node_modules/@radix-ui/react-dismissable-layer/dist/index.cjs +4 -4
  9. package/dist/node_modules/.pnpm/{@radix-ui_react-dismissable-layer@1.1.11_@types_react-dom@19.2.2_@types_react@19.2.2__@_ca5522e5d45d4722cb9eb5ce53defa61 → @radix-ui_react-dismissable-layer@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.6__@_9ee1db7daf927866cf505b31d40047ad}/node_modules/@radix-ui/react-dismissable-layer/dist/index.mjs +4 -4
  10. package/dist/node_modules/.pnpm/@radix-ui_react-dropdown-menu@2.1.16_@types_react-dom@19.2.3_@types_react@19.2.6__@type_a50051c7210b6fbd5be09388bda08578/node_modules/@radix-ui/react-dropdown-menu/dist/index.cjs +282 -0
  11. package/dist/node_modules/.pnpm/@radix-ui_react-dropdown-menu@2.1.16_@types_react-dom@19.2.3_@types_react@19.2.6__@type_a50051c7210b6fbd5be09388bda08578/node_modules/@radix-ui/react-dropdown-menu/dist/index.mjs +247 -0
  12. package/dist/node_modules/.pnpm/{@radix-ui_react-focus-scope@1.1.7_@types_react-dom@19.2.2_@types_react@19.2.2__@types_r_93de389b3f622f9f764acc8e59ec80c0 → @radix-ui_react-focus-scope@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.6__@types_r_0a31b7f987af9482d13505312e1a1be9}/node_modules/@radix-ui/react-focus-scope/dist/index.cjs +3 -3
  13. package/dist/node_modules/.pnpm/{@radix-ui_react-focus-scope@1.1.7_@types_react-dom@19.2.2_@types_react@19.2.2__@types_r_93de389b3f622f9f764acc8e59ec80c0 → @radix-ui_react-focus-scope@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.6__@types_r_0a31b7f987af9482d13505312e1a1be9}/node_modules/@radix-ui/react-focus-scope/dist/index.mjs +3 -3
  14. package/dist/node_modules/.pnpm/{@radix-ui_react-id@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-id@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-id/dist/index.cjs +1 -1
  15. package/dist/node_modules/.pnpm/{@radix-ui_react-id@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-id@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-id/dist/index.mjs +1 -1
  16. package/dist/node_modules/.pnpm/@radix-ui_react-menu@2.1.16_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@1_82ed1fcd848b6984d9291a784d477cf4/node_modules/@radix-ui/react-menu/dist/index.cjs +845 -0
  17. package/dist/node_modules/.pnpm/@radix-ui_react-menu@2.1.16_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@1_82ed1fcd848b6984d9291a784d477cf4/node_modules/@radix-ui/react-menu/dist/index.mjs +799 -0
  18. package/dist/node_modules/.pnpm/{@radix-ui_react-popper@1.2.8_@types_react-dom@19.2.2_@types_react@19.2.2__@types_react@_d6285b8269ea5d6b59b300f5be279a0c → @radix-ui_react-popper@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@_7ac2caae1e39f9ba93d5015614525161}/node_modules/@radix-ui/react-popper/dist/index.cjs +7 -7
  19. package/dist/node_modules/.pnpm/{@radix-ui_react-popper@1.2.8_@types_react-dom@19.2.2_@types_react@19.2.2__@types_react@_d6285b8269ea5d6b59b300f5be279a0c → @radix-ui_react-popper@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@_7ac2caae1e39f9ba93d5015614525161}/node_modules/@radix-ui/react-popper/dist/index.mjs +7 -7
  20. package/dist/node_modules/.pnpm/{@radix-ui_react-portal@1.1.9_@types_react-dom@19.2.2_@types_react@19.2.2__@types_react@_478b3d5dd4afab1a3dcce7ed1748cb95 → @radix-ui_react-portal@1.1.9_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@_1bb4e0f97f86496802d28a2e74e2a8b9}/node_modules/@radix-ui/react-portal/dist/index.cjs +2 -2
  21. package/dist/node_modules/.pnpm/{@radix-ui_react-portal@1.1.9_@types_react-dom@19.2.2_@types_react@19.2.2__@types_react@_478b3d5dd4afab1a3dcce7ed1748cb95 → @radix-ui_react-portal@1.1.9_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@_1bb4e0f97f86496802d28a2e74e2a8b9}/node_modules/@radix-ui/react-portal/dist/index.mjs +2 -2
  22. package/dist/node_modules/.pnpm/@radix-ui_react-presence@1.1.5_@types_react-dom@19.2.3_@types_react@19.2.6__@types_reac_90f8e5c12233caef3399d5fd66452a13/node_modules/@radix-ui/react-presence/dist/index.cjs +147 -0
  23. package/dist/node_modules/.pnpm/@radix-ui_react-presence@1.1.5_@types_react-dom@19.2.3_@types_react@19.2.6__@types_reac_90f8e5c12233caef3399d5fd66452a13/node_modules/@radix-ui/react-presence/dist/index.mjs +131 -0
  24. package/dist/node_modules/.pnpm/@radix-ui_react-roving-focus@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.6__@types_fe1151d1f393bbc1072b24a86dff3a23/node_modules/@radix-ui/react-roving-focus/dist/index.cjs +244 -0
  25. package/dist/node_modules/.pnpm/@radix-ui_react-roving-focus@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.6__@types_fe1151d1f393bbc1072b24a86dff3a23/node_modules/@radix-ui/react-roving-focus/dist/index.mjs +224 -0
  26. package/dist/node_modules/.pnpm/@radix-ui_react-scroll-area@1.2.10_@types_react-dom@19.2.3_@types_react@19.2.6__@types__e3f7735e9b444a10b3bbfd9fe97d44d0/node_modules/@radix-ui/react-scroll-area/dist/index.cjs +742 -0
  27. package/dist/node_modules/.pnpm/@radix-ui_react-scroll-area@1.2.10_@types_react-dom@19.2.3_@types_react@19.2.6__@types__e3f7735e9b444a10b3bbfd9fe97d44d0/node_modules/@radix-ui/react-scroll-area/dist/index.mjs +719 -0
  28. package/dist/node_modules/.pnpm/{@radix-ui_react-select@2.2.6_@types_react-dom@19.2.2_@types_react@19.2.2__@types_react@_802c3d414c85063bee785fcc98a39c07 → @radix-ui_react-select@2.2.6_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@_38dc681bb1f2bcfeb5249d8ca2bc01f5}/node_modules/@radix-ui/react-select/dist/index.cjs +17 -17
  29. package/dist/node_modules/.pnpm/{@radix-ui_react-select@2.2.6_@types_react-dom@19.2.2_@types_react@19.2.2__@types_react@_802c3d414c85063bee785fcc98a39c07 → @radix-ui_react-select@2.2.6_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@_38dc681bb1f2bcfeb5249d8ca2bc01f5}/node_modules/@radix-ui/react-select/dist/index.mjs +17 -17
  30. package/dist/node_modules/.pnpm/{@radix-ui_react-use-controllable-state@1.2.2_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-controllable-state@1.2.2_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-controllable-state/dist/index.cjs +1 -1
  31. package/dist/node_modules/.pnpm/{@radix-ui_react-use-controllable-state@1.2.2_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-controllable-state@1.2.2_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-controllable-state/dist/index.mjs +1 -1
  32. package/dist/node_modules/.pnpm/{@radix-ui_react-use-escape-keydown@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-escape-keydown@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-escape-keydown/dist/index.cjs +1 -1
  33. package/dist/node_modules/.pnpm/{@radix-ui_react-use-escape-keydown@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-escape-keydown@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-escape-keydown/dist/index.mjs +1 -1
  34. package/dist/node_modules/.pnpm/{@radix-ui_react-use-size@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-size@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-size/dist/index.cjs +1 -1
  35. package/dist/node_modules/.pnpm/{@radix-ui_react-use-size@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-size@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-size/dist/index.mjs +1 -1
  36. package/dist/node_modules/.pnpm/{@radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.2.2_@types_react@19.2.2__@typ_a84e98a44624c31e835a98d4b8b0c30d → @radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.2.3_@types_react@19.2.6__@typ_f453379bbd5a4932ec515167f81be42a}/node_modules/@radix-ui/react-visually-hidden/dist/index.cjs +1 -1
  37. package/dist/node_modules/.pnpm/{@radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.2.2_@types_react@19.2.2__@typ_a84e98a44624c31e835a98d4b8b0c30d → @radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.2.3_@types_react@19.2.6__@typ_f453379bbd5a4932ec515167f81be42a}/node_modules/@radix-ui/react-visually-hidden/dist/index.mjs +1 -1
  38. package/dist/node_modules/.pnpm/{react-remove-scroll-bar@2.3.8_@types_react@19.2.2_react@19.2.0 → react-remove-scroll-bar@2.3.8_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll-bar/dist/es2015/component.cjs +1 -1
  39. package/dist/node_modules/.pnpm/{react-remove-scroll-bar@2.3.8_@types_react@19.2.2_react@19.2.0 → react-remove-scroll-bar@2.3.8_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll-bar/dist/es2015/component.mjs +1 -1
  40. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/SideEffect.cjs +2 -2
  41. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/SideEffect.mjs +2 -2
  42. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/UI.cjs +2 -2
  43. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/UI.mjs +2 -2
  44. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/medium.cjs +1 -1
  45. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/medium.mjs +1 -1
  46. package/dist/node_modules/.pnpm/react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0/node_modules/react-remove-scroll/dist/es2015/sidecar.cjs +9 -0
  47. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/sidecar.mjs +1 -1
  48. package/dist/packages/better-stack/src/plugins/ai-chat/api/plugin.cjs +610 -0
  49. package/dist/packages/better-stack/src/plugins/ai-chat/api/plugin.mjs +608 -0
  50. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-input.cjs +221 -0
  51. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-input.mjs +219 -0
  52. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-interface.cjs +315 -0
  53. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-interface.mjs +313 -0
  54. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-layout.cjs +122 -0
  55. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-layout.mjs +120 -0
  56. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-message.cjs +397 -0
  57. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-message.mjs +391 -0
  58. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-sidebar.cjs +227 -0
  59. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/chat-sidebar.mjs +225 -0
  60. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/loading/chat-page-skeleton.cjs +31 -0
  61. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/loading/chat-page-skeleton.mjs +29 -0
  62. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/loading/index.cjs +11 -0
  63. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/loading/index.mjs +8 -0
  64. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/pages/404-page.cjs +18 -0
  65. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/pages/404-page.mjs +16 -0
  66. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/pages/chat-page.cjs +39 -0
  67. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/pages/chat-page.internal.cjs +22 -0
  68. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/pages/chat-page.internal.mjs +20 -0
  69. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/pages/chat-page.mjs +37 -0
  70. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/shared/default-error.cjs +18 -0
  71. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/shared/default-error.mjs +16 -0
  72. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/shared/error-placeholder.cjs +26 -0
  73. package/dist/packages/better-stack/src/plugins/ai-chat/client/components/shared/error-placeholder.mjs +24 -0
  74. package/dist/packages/better-stack/src/plugins/ai-chat/client/hooks/chat-hooks.cjs +199 -0
  75. package/dist/packages/better-stack/src/plugins/ai-chat/client/hooks/chat-hooks.mjs +191 -0
  76. package/dist/packages/better-stack/src/plugins/ai-chat/client/localization/index.cjs +63 -0
  77. package/dist/packages/better-stack/src/plugins/ai-chat/client/localization/index.mjs +61 -0
  78. package/dist/packages/better-stack/src/plugins/ai-chat/client/overrides.cjs +14 -0
  79. package/dist/packages/better-stack/src/plugins/ai-chat/client/overrides.mjs +11 -0
  80. package/dist/packages/better-stack/src/plugins/ai-chat/client/plugin.cjs +241 -0
  81. package/dist/packages/better-stack/src/plugins/ai-chat/client/plugin.mjs +239 -0
  82. package/dist/packages/better-stack/src/plugins/ai-chat/db.cjs +65 -0
  83. package/dist/packages/better-stack/src/plugins/ai-chat/db.mjs +63 -0
  84. package/dist/packages/better-stack/src/plugins/ai-chat/schemas.cjs +42 -0
  85. package/dist/packages/better-stack/src/plugins/ai-chat/schemas.mjs +38 -0
  86. package/dist/packages/better-stack/src/plugins/blog/client/components/shared/markdown-content.cjs +12 -309
  87. package/dist/packages/better-stack/src/plugins/blog/client/components/shared/markdown-content.mjs +13 -303
  88. package/dist/packages/better-stack/src/plugins/blog/client/components/shared/page-wrapper.cjs +2 -2
  89. package/dist/packages/better-stack/src/plugins/blog/client/components/shared/page-wrapper.mjs +2 -2
  90. package/dist/packages/ui/src/components/alert-dialog.cjs +1 -1
  91. package/dist/packages/ui/src/components/alert-dialog.mjs +1 -1
  92. package/dist/packages/{better-stack/src/plugins/blog/client/components/shared/better-blog-attribution.cjs → ui/src/components/better-stack-attribution.cjs} +3 -3
  93. package/dist/packages/{better-stack/src/plugins/blog/client/components/shared/better-blog-attribution.mjs → ui/src/components/better-stack-attribution.mjs} +3 -3
  94. package/dist/packages/ui/src/components/dialog.cjs +14 -0
  95. package/dist/packages/ui/src/components/dialog.mjs +14 -1
  96. package/dist/packages/ui/src/components/dropdown-menu.cjs +67 -0
  97. package/dist/packages/ui/src/components/dropdown-menu.mjs +62 -0
  98. package/dist/packages/ui/src/components/markdown-content.cjs +306 -0
  99. package/dist/packages/ui/src/components/markdown-content.mjs +297 -0
  100. package/dist/packages/ui/src/components/scroll-area.cjs +63 -0
  101. package/dist/packages/ui/src/components/scroll-area.mjs +60 -0
  102. package/dist/packages/ui/src/components/select.cjs +1 -1
  103. package/dist/packages/ui/src/components/select.mjs +1 -1
  104. package/dist/packages/ui/src/components/sheet.cjs +87 -0
  105. package/dist/packages/ui/src/components/sheet.mjs +69 -0
  106. package/dist/plugins/ai-chat/api/index.cjs +9 -0
  107. package/dist/plugins/ai-chat/api/index.d.cts +9 -0
  108. package/dist/plugins/ai-chat/api/index.d.mts +9 -0
  109. package/dist/plugins/ai-chat/api/index.d.ts +9 -0
  110. package/dist/plugins/ai-chat/api/index.mjs +2 -0
  111. package/dist/plugins/ai-chat/client/components/index.cjs +27 -0
  112. package/dist/plugins/ai-chat/client/components/index.d.cts +30 -0
  113. package/dist/plugins/ai-chat/client/components/index.d.mts +30 -0
  114. package/dist/plugins/ai-chat/client/components/index.d.ts +30 -0
  115. package/dist/plugins/ai-chat/client/components/index.mjs +11 -0
  116. package/dist/plugins/ai-chat/client/hooks/index.cjs +13 -0
  117. package/dist/plugins/ai-chat/client/hooks/index.d.cts +98 -0
  118. package/dist/plugins/ai-chat/client/hooks/index.d.mts +98 -0
  119. package/dist/plugins/ai-chat/client/hooks/index.d.ts +98 -0
  120. package/dist/plugins/ai-chat/client/hooks/index.mjs +1 -0
  121. package/dist/plugins/ai-chat/client/index.cjs +19 -0
  122. package/dist/plugins/ai-chat/client/index.d.cts +327 -0
  123. package/dist/plugins/ai-chat/client/index.d.mts +327 -0
  124. package/dist/plugins/ai-chat/client/index.d.ts +327 -0
  125. package/dist/plugins/ai-chat/client/index.mjs +7 -0
  126. package/dist/plugins/ai-chat/client.css +6 -0
  127. package/dist/plugins/ai-chat/query-keys.cjs +60 -0
  128. package/dist/plugins/ai-chat/query-keys.d.cts +478 -0
  129. package/dist/plugins/ai-chat/query-keys.d.mts +478 -0
  130. package/dist/plugins/ai-chat/query-keys.d.ts +478 -0
  131. package/dist/plugins/ai-chat/query-keys.mjs +58 -0
  132. package/dist/plugins/ai-chat/style.css +19 -0
  133. package/dist/plugins/blog/api/index.d.cts +1 -1
  134. package/dist/plugins/blog/api/index.d.mts +1 -1
  135. package/dist/plugins/blog/api/index.d.ts +1 -1
  136. package/dist/plugins/blog/client/components/shared/markdown-content-styles.css +85 -62
  137. package/dist/plugins/blog/client/hooks/index.d.cts +4 -4
  138. package/dist/plugins/blog/client/hooks/index.d.mts +4 -4
  139. package/dist/plugins/blog/client/hooks/index.d.ts +4 -4
  140. package/dist/plugins/blog/client/index.d.cts +1 -1
  141. package/dist/plugins/blog/client/index.d.mts +1 -1
  142. package/dist/plugins/blog/client/index.d.ts +1 -1
  143. package/dist/plugins/blog/query-keys.d.cts +7 -7
  144. package/dist/plugins/blog/query-keys.d.mts +7 -7
  145. package/dist/plugins/blog/query-keys.d.ts +7 -7
  146. package/dist/shared/stack.Be1QIHEn.d.cts +23 -0
  147. package/dist/shared/stack.Be1QIHEn.d.mts +23 -0
  148. package/dist/shared/stack.Be1QIHEn.d.ts +23 -0
  149. package/dist/shared/stack.DorMi9CZ.d.cts +80 -0
  150. package/dist/shared/stack.DorMi9CZ.d.mts +80 -0
  151. package/dist/shared/stack.DorMi9CZ.d.ts +80 -0
  152. package/package.json +59 -1
  153. package/src/plugins/ai-chat/api/index.ts +2 -0
  154. package/src/plugins/ai-chat/api/plugin.ts +1083 -0
  155. package/src/plugins/ai-chat/client/components/chat-input.tsx +295 -0
  156. package/src/plugins/ai-chat/client/components/chat-interface.tsx +455 -0
  157. package/src/plugins/ai-chat/client/components/chat-layout.tsx +160 -0
  158. package/src/plugins/ai-chat/client/components/chat-message.tsx +505 -0
  159. package/src/plugins/ai-chat/client/components/chat-sidebar.tsx +296 -0
  160. package/src/plugins/ai-chat/client/components/index.ts +16 -0
  161. package/src/plugins/ai-chat/client/components/loading/chat-page-skeleton.tsx +57 -0
  162. package/src/plugins/ai-chat/client/components/loading/index.tsx +11 -0
  163. package/src/plugins/ai-chat/client/components/pages/404-page.tsx +27 -0
  164. package/src/plugins/ai-chat/client/components/pages/chat-page.internal.tsx +31 -0
  165. package/src/plugins/ai-chat/client/components/pages/chat-page.tsx +46 -0
  166. package/src/plugins/ai-chat/client/components/shared/default-error.tsx +28 -0
  167. package/src/plugins/ai-chat/client/components/shared/error-placeholder.tsx +22 -0
  168. package/src/plugins/ai-chat/client/hooks/chat-hooks.tsx +349 -0
  169. package/src/plugins/ai-chat/client/hooks/index.tsx +1 -0
  170. package/src/plugins/ai-chat/client/index.ts +14 -0
  171. package/src/plugins/ai-chat/client/localization/index.ts +156 -0
  172. package/src/plugins/ai-chat/client/overrides.ts +170 -0
  173. package/src/plugins/ai-chat/client/plugin.tsx +449 -0
  174. package/src/plugins/ai-chat/client.css +6 -0
  175. package/src/plugins/ai-chat/db.ts +65 -0
  176. package/src/plugins/ai-chat/query-keys.ts +87 -0
  177. package/src/plugins/ai-chat/schemas.ts +40 -0
  178. package/src/plugins/ai-chat/style.css +19 -0
  179. package/src/plugins/ai-chat/types.ts +29 -0
  180. package/src/plugins/blog/client/components/shared/markdown-content-styles.css +85 -62
  181. package/src/plugins/blog/client/components/shared/markdown-content.tsx +19 -427
  182. package/src/plugins/blog/client/components/shared/page-wrapper.tsx +2 -2
  183. package/dist/node_modules/.pnpm/react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0/node_modules/react-remove-scroll/dist/es2015/sidecar.cjs +0 -9
  184. package/src/plugins/blog/client/components/shared/better-blog-attribution.tsx +0 -19
  185. package/dist/node_modules/.pnpm/{@radix-ui_react-compose-refs@1.1.2_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-compose-refs@1.1.2_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-compose-refs/dist/index.cjs +0 -0
  186. package/dist/node_modules/.pnpm/{@radix-ui_react-compose-refs@1.1.2_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-compose-refs@1.1.2_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-compose-refs/dist/index.mjs +0 -0
  187. package/dist/node_modules/.pnpm/{@radix-ui_react-context@1.1.2_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-context@1.1.2_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-context/dist/index.cjs +0 -0
  188. package/dist/node_modules/.pnpm/{@radix-ui_react-context@1.1.2_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-context@1.1.2_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-context/dist/index.mjs +0 -0
  189. package/dist/node_modules/.pnpm/{@radix-ui_react-direction@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-direction@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-direction/dist/index.cjs +0 -0
  190. package/dist/node_modules/.pnpm/{@radix-ui_react-direction@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-direction@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-direction/dist/index.mjs +0 -0
  191. package/dist/node_modules/.pnpm/{@radix-ui_react-focus-guards@1.1.3_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-focus-guards@1.1.3_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-focus-guards/dist/index.cjs +0 -0
  192. package/dist/node_modules/.pnpm/{@radix-ui_react-focus-guards@1.1.3_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-focus-guards@1.1.3_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-focus-guards/dist/index.mjs +0 -0
  193. package/dist/node_modules/.pnpm/{@radix-ui_react-primitive@2.1.3_@types_react-dom@19.2.2_@types_react@19.2.2__@types_rea_bdc15f10281778271ffcbe8dd3cd491e → @radix-ui_react-primitive@2.1.3_@types_react-dom@19.2.3_@types_react@19.2.6__@types_rea_a92a69cb1cb39305138539e4fa72f596}/node_modules/@radix-ui/react-primitive/dist/index.cjs +0 -0
  194. package/dist/node_modules/.pnpm/{@radix-ui_react-primitive@2.1.3_@types_react-dom@19.2.2_@types_react@19.2.2__@types_rea_bdc15f10281778271ffcbe8dd3cd491e → @radix-ui_react-primitive@2.1.3_@types_react-dom@19.2.3_@types_react@19.2.6__@types_rea_a92a69cb1cb39305138539e4fa72f596}/node_modules/@radix-ui/react-primitive/dist/index.mjs +0 -0
  195. package/dist/node_modules/.pnpm/{@radix-ui_react-use-callback-ref@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-callback-ref@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-callback-ref/dist/index.cjs +0 -0
  196. package/dist/node_modules/.pnpm/{@radix-ui_react-use-callback-ref@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-callback-ref@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-callback-ref/dist/index.mjs +0 -0
  197. package/dist/node_modules/.pnpm/{@radix-ui_react-use-layout-effect@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-layout-effect@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-layout-effect/dist/index.cjs +0 -0
  198. package/dist/node_modules/.pnpm/{@radix-ui_react-use-layout-effect@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-layout-effect@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-layout-effect/dist/index.mjs +0 -0
  199. package/dist/node_modules/.pnpm/{@radix-ui_react-use-previous@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-previous@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-previous/dist/index.cjs +0 -0
  200. package/dist/node_modules/.pnpm/{@radix-ui_react-use-previous@1.1.1_@types_react@19.2.2_react@19.2.0 → @radix-ui_react-use-previous@1.1.1_@types_react@19.2.6_react@19.2.0}/node_modules/@radix-ui/react-use-previous/dist/index.mjs +0 -0
  201. package/dist/node_modules/.pnpm/{react-remove-scroll-bar@2.3.8_@types_react@19.2.2_react@19.2.0 → react-remove-scroll-bar@2.3.8_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll-bar/dist/es2015/constants.cjs +0 -0
  202. package/dist/node_modules/.pnpm/{react-remove-scroll-bar@2.3.8_@types_react@19.2.2_react@19.2.0 → react-remove-scroll-bar@2.3.8_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll-bar/dist/es2015/constants.mjs +0 -0
  203. package/dist/node_modules/.pnpm/{react-remove-scroll-bar@2.3.8_@types_react@19.2.2_react@19.2.0 → react-remove-scroll-bar@2.3.8_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll-bar/dist/es2015/utils.cjs +0 -0
  204. package/dist/node_modules/.pnpm/{react-remove-scroll-bar@2.3.8_@types_react@19.2.2_react@19.2.0 → react-remove-scroll-bar@2.3.8_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll-bar/dist/es2015/utils.mjs +0 -0
  205. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/Combination.cjs +0 -0
  206. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/Combination.mjs +0 -0
  207. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/aggresiveCapture.cjs +0 -0
  208. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/aggresiveCapture.mjs +0 -0
  209. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/handleScroll.cjs +0 -0
  210. package/dist/node_modules/.pnpm/{react-remove-scroll@2.7.1_@types_react@19.2.2_react@19.2.0 → react-remove-scroll@2.7.1_@types_react@19.2.6_react@19.2.0}/node_modules/react-remove-scroll/dist/es2015/handleScroll.mjs +0 -0
  211. package/dist/node_modules/.pnpm/{react-style-singleton@2.2.3_@types_react@19.2.2_react@19.2.0 → react-style-singleton@2.2.3_@types_react@19.2.6_react@19.2.0}/node_modules/react-style-singleton/dist/es2015/component.cjs +0 -0
  212. package/dist/node_modules/.pnpm/{react-style-singleton@2.2.3_@types_react@19.2.2_react@19.2.0 → react-style-singleton@2.2.3_@types_react@19.2.6_react@19.2.0}/node_modules/react-style-singleton/dist/es2015/component.mjs +0 -0
  213. package/dist/node_modules/.pnpm/{react-style-singleton@2.2.3_@types_react@19.2.2_react@19.2.0 → react-style-singleton@2.2.3_@types_react@19.2.6_react@19.2.0}/node_modules/react-style-singleton/dist/es2015/hook.cjs +0 -0
  214. package/dist/node_modules/.pnpm/{react-style-singleton@2.2.3_@types_react@19.2.2_react@19.2.0 → react-style-singleton@2.2.3_@types_react@19.2.6_react@19.2.0}/node_modules/react-style-singleton/dist/es2015/hook.mjs +0 -0
  215. package/dist/node_modules/.pnpm/{react-style-singleton@2.2.3_@types_react@19.2.2_react@19.2.0 → react-style-singleton@2.2.3_@types_react@19.2.6_react@19.2.0}/node_modules/react-style-singleton/dist/es2015/singleton.cjs +0 -0
  216. package/dist/node_modules/.pnpm/{react-style-singleton@2.2.3_@types_react@19.2.2_react@19.2.0 → react-style-singleton@2.2.3_@types_react@19.2.6_react@19.2.0}/node_modules/react-style-singleton/dist/es2015/singleton.mjs +0 -0
  217. package/dist/node_modules/.pnpm/{use-callback-ref@1.3.3_@types_react@19.2.2_react@19.2.0 → use-callback-ref@1.3.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-callback-ref/dist/es2015/assignRef.cjs +0 -0
  218. package/dist/node_modules/.pnpm/{use-callback-ref@1.3.3_@types_react@19.2.2_react@19.2.0 → use-callback-ref@1.3.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-callback-ref/dist/es2015/assignRef.mjs +0 -0
  219. package/dist/node_modules/.pnpm/{use-callback-ref@1.3.3_@types_react@19.2.2_react@19.2.0 → use-callback-ref@1.3.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-callback-ref/dist/es2015/useMergeRef.cjs +0 -0
  220. package/dist/node_modules/.pnpm/{use-callback-ref@1.3.3_@types_react@19.2.2_react@19.2.0 → use-callback-ref@1.3.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-callback-ref/dist/es2015/useMergeRef.mjs +0 -0
  221. package/dist/node_modules/.pnpm/{use-callback-ref@1.3.3_@types_react@19.2.2_react@19.2.0 → use-callback-ref@1.3.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-callback-ref/dist/es2015/useRef.cjs +0 -0
  222. package/dist/node_modules/.pnpm/{use-callback-ref@1.3.3_@types_react@19.2.2_react@19.2.0 → use-callback-ref@1.3.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-callback-ref/dist/es2015/useRef.mjs +0 -0
  223. package/dist/node_modules/.pnpm/{use-sidecar@1.1.3_@types_react@19.2.2_react@19.2.0 → use-sidecar@1.1.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-sidecar/dist/es2015/exports.cjs +0 -0
  224. package/dist/node_modules/.pnpm/{use-sidecar@1.1.3_@types_react@19.2.2_react@19.2.0 → use-sidecar@1.1.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-sidecar/dist/es2015/exports.mjs +0 -0
  225. package/dist/node_modules/.pnpm/{use-sidecar@1.1.3_@types_react@19.2.2_react@19.2.0 → use-sidecar@1.1.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-sidecar/dist/es2015/medium.cjs +0 -0
  226. package/dist/node_modules/.pnpm/{use-sidecar@1.1.3_@types_react@19.2.2_react@19.2.0 → use-sidecar@1.1.3_@types_react@19.2.6_react@19.2.0}/node_modules/use-sidecar/dist/es2015/medium.mjs +0 -0
  227. package/dist/shared/{stack.CbuN2zVV.d.ts → stack.CcI4sYJP.d.cts} +3 -3
  228. package/dist/shared/{stack.CbuN2zVV.d.cts → stack.CcI4sYJP.d.mts} +3 -3
  229. package/dist/shared/{stack.CbuN2zVV.d.mts → stack.CcI4sYJP.d.ts} +3 -3
@@ -0,0 +1,610 @@
1
+ 'use strict';
2
+
3
+ const api = require('@btst/stack/plugins/api');
4
+ const ai = require('ai');
5
+ const db = require('../db.cjs');
6
+ const schemas = require('../schemas.cjs');
7
+
8
+ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
9
+ name: "ai-chat",
10
+ // Always include db schema - in public mode we just don't use it
11
+ dbPlugin: db.aiChatSchema,
12
+ routes: (adapter) => {
13
+ const mode = config.mode ?? "authenticated";
14
+ const isPublicMode = mode === "public";
15
+ const getMessageTextContent = (msg) => {
16
+ if (msg.parts && Array.isArray(msg.parts)) {
17
+ return msg.parts.filter((part) => part.type === "text").map((part) => part.text).join("");
18
+ }
19
+ return "";
20
+ };
21
+ const serializeMessageParts = (msg) => {
22
+ if (msg.parts && Array.isArray(msg.parts)) {
23
+ const serializableParts = msg.parts.filter(
24
+ (part) => part.type === "text" || part.type === "file"
25
+ );
26
+ return JSON.stringify(serializableParts);
27
+ }
28
+ return JSON.stringify([]);
29
+ };
30
+ const resolveUserId = async (context, throwOnMissing) => {
31
+ if (isPublicMode) {
32
+ return null;
33
+ }
34
+ if (!config.getUserId) {
35
+ return null;
36
+ }
37
+ const userId = await config.getUserId(context);
38
+ if (!userId) {
39
+ throwOnMissing();
40
+ }
41
+ return userId;
42
+ };
43
+ const chat = api.createEndpoint(
44
+ "/chat",
45
+ {
46
+ method: "POST",
47
+ body: schemas.chatRequestSchema
48
+ },
49
+ async (ctx) => {
50
+ const { messages: rawMessages, conversationId } = ctx.body;
51
+ const uiMessages = rawMessages;
52
+ const context = {
53
+ body: ctx.body,
54
+ headers: ctx.headers,
55
+ request: ctx.request
56
+ };
57
+ try {
58
+ if (config.hooks?.onBeforeChat) {
59
+ const messagesForHook = uiMessages.map((msg) => ({
60
+ role: msg.role,
61
+ content: getMessageTextContent(msg)
62
+ }));
63
+ const canChat = await config.hooks.onBeforeChat(
64
+ messagesForHook,
65
+ context
66
+ );
67
+ if (!canChat) {
68
+ throw ctx.error(403, {
69
+ message: "Unauthorized: Cannot start chat"
70
+ });
71
+ }
72
+ }
73
+ const firstMessage = uiMessages[0];
74
+ if (!firstMessage) {
75
+ throw ctx.error(400, {
76
+ message: "At least one message is required"
77
+ });
78
+ }
79
+ const firstMessageContent = getMessageTextContent(firstMessage);
80
+ const modelMessages = ai.convertToModelMessages(uiMessages);
81
+ const messagesWithSystem = config.systemPrompt ? [
82
+ { role: "system", content: config.systemPrompt },
83
+ ...modelMessages
84
+ ] : modelMessages;
85
+ if (isPublicMode) {
86
+ const result2 = ai.streamText({
87
+ model: config.model,
88
+ messages: messagesWithSystem,
89
+ tools: config.tools,
90
+ // Enable multi-step tool calls if tools are configured
91
+ ...config.tools ? { stopWhen: ai.stepCountIs(5) } : {}
92
+ });
93
+ return result2.toUIMessageStreamResponse({
94
+ originalMessages: uiMessages
95
+ });
96
+ }
97
+ let userId = null;
98
+ if (config.getUserId) {
99
+ const resolvedUserId = await config.getUserId(context);
100
+ if (!resolvedUserId) {
101
+ throw ctx.error(403, {
102
+ message: "Unauthorized: User authentication required"
103
+ });
104
+ }
105
+ userId = resolvedUserId;
106
+ }
107
+ let convId = conversationId;
108
+ if (!convId) {
109
+ const newConv = await adapter.create({
110
+ model: "conversation",
111
+ data: {
112
+ ...userId ? { userId } : {},
113
+ title: firstMessageContent.slice(0, 50) || "New Conversation",
114
+ createdAt: /* @__PURE__ */ new Date(),
115
+ updatedAt: /* @__PURE__ */ new Date()
116
+ }
117
+ });
118
+ convId = newConv.id;
119
+ } else {
120
+ const existing = await adapter.findMany({
121
+ model: "conversation",
122
+ where: [{ field: "id", value: convId, operator: "eq" }],
123
+ limit: 1
124
+ });
125
+ if (!existing.length) {
126
+ const newConv = await adapter.create({
127
+ model: "conversation",
128
+ data: {
129
+ id: convId,
130
+ ...userId ? { userId } : {},
131
+ title: firstMessageContent.slice(0, 50) || "New Conversation",
132
+ createdAt: /* @__PURE__ */ new Date(),
133
+ updatedAt: /* @__PURE__ */ new Date()
134
+ }
135
+ });
136
+ convId = newConv.id;
137
+ } else {
138
+ const conv = existing[0];
139
+ if (userId && conv.userId && conv.userId !== userId) {
140
+ throw ctx.error(403, {
141
+ message: "Unauthorized: Cannot access this conversation"
142
+ });
143
+ }
144
+ }
145
+ }
146
+ const existingMessages = await adapter.findMany({
147
+ model: "message",
148
+ where: [
149
+ {
150
+ field: "conversationId",
151
+ value: convId,
152
+ operator: "eq"
153
+ }
154
+ ],
155
+ sortBy: { field: "createdAt", direction: "asc" }
156
+ });
157
+ const lastIncomingMessage = uiMessages[uiMessages.length - 1];
158
+ const isNewUserMessage = lastIncomingMessage?.role === "user";
159
+ let expectedDbCount;
160
+ let shouldAddUserMessage = false;
161
+ if (isNewUserMessage) {
162
+ const lastDbUserMessage = [...existingMessages].reverse().find((m) => m.role === "user");
163
+ const incomingUserContent = serializeMessageParts(lastIncomingMessage);
164
+ if (lastDbUserMessage && lastDbUserMessage.content === incomingUserContent) {
165
+ expectedDbCount = uiMessages.length;
166
+ shouldAddUserMessage = false;
167
+ } else {
168
+ expectedDbCount = uiMessages.length - 1;
169
+ shouldAddUserMessage = true;
170
+ }
171
+ } else {
172
+ expectedDbCount = uiMessages.length;
173
+ shouldAddUserMessage = false;
174
+ }
175
+ const actualDbCount = existingMessages.length;
176
+ const messagesToDelete = actualDbCount > expectedDbCount ? existingMessages.slice(expectedDbCount) : [];
177
+ await adapter.transaction(async (tx) => {
178
+ for (const msg of messagesToDelete) {
179
+ await tx.delete({
180
+ model: "message",
181
+ where: [{ field: "id", value: msg.id }]
182
+ });
183
+ }
184
+ if (shouldAddUserMessage && lastIncomingMessage) {
185
+ await tx.create({
186
+ model: "message",
187
+ data: {
188
+ conversationId: convId,
189
+ role: "user",
190
+ content: serializeMessageParts(lastIncomingMessage),
191
+ createdAt: /* @__PURE__ */ new Date()
192
+ }
193
+ });
194
+ }
195
+ });
196
+ const result = ai.streamText({
197
+ model: config.model,
198
+ messages: messagesWithSystem,
199
+ tools: config.tools,
200
+ // Enable multi-step tool calls if tools are configured
201
+ ...config.tools ? { stopWhen: ai.stepCountIs(5) } : {},
202
+ onFinish: async (completion) => {
203
+ try {
204
+ const assistantParts = completion.text ? [{ type: "text", text: completion.text }] : [];
205
+ await adapter.create({
206
+ model: "message",
207
+ data: {
208
+ conversationId: convId,
209
+ role: "assistant",
210
+ content: JSON.stringify(assistantParts),
211
+ createdAt: /* @__PURE__ */ new Date()
212
+ }
213
+ });
214
+ await adapter.update({
215
+ model: "conversation",
216
+ where: [{ field: "id", value: convId }],
217
+ update: { updatedAt: /* @__PURE__ */ new Date() }
218
+ });
219
+ if (config.hooks?.onAfterChat) {
220
+ const messages = await adapter.findMany({
221
+ model: "message",
222
+ where: [
223
+ {
224
+ field: "conversationId",
225
+ value: convId,
226
+ operator: "eq"
227
+ }
228
+ ],
229
+ sortBy: { field: "createdAt", direction: "asc" }
230
+ });
231
+ await config.hooks.onAfterChat(
232
+ convId,
233
+ messages,
234
+ context
235
+ );
236
+ }
237
+ } catch (error) {
238
+ console.error("[ai-chat] Error in onFinish callback:", error);
239
+ if (config.hooks?.onChatError) {
240
+ try {
241
+ await config.hooks.onChatError(error, context);
242
+ } catch (hookError) {
243
+ console.error(
244
+ "[ai-chat] Error in onChatError hook:",
245
+ hookError
246
+ );
247
+ }
248
+ }
249
+ }
250
+ }
251
+ });
252
+ const response = result.toUIMessageStreamResponse({
253
+ originalMessages: uiMessages
254
+ });
255
+ const headers = new Headers(response.headers);
256
+ headers.set("X-Conversation-Id", convId);
257
+ return new Response(response.body, {
258
+ status: response.status,
259
+ statusText: response.statusText,
260
+ headers
261
+ });
262
+ } catch (error) {
263
+ if (config.hooks?.onChatError) {
264
+ await config.hooks.onChatError(error, context);
265
+ }
266
+ throw error;
267
+ }
268
+ }
269
+ );
270
+ const createConversation = api.createEndpoint(
271
+ "/chat/conversations",
272
+ {
273
+ method: "POST",
274
+ body: schemas.createConversationSchema
275
+ },
276
+ async (ctx) => {
277
+ if (isPublicMode) {
278
+ throw ctx.error(404, {
279
+ message: "Conversations not available in public mode"
280
+ });
281
+ }
282
+ const { id, title } = ctx.body;
283
+ const context = {
284
+ body: ctx.body,
285
+ headers: ctx.headers
286
+ };
287
+ try {
288
+ const userId = await resolveUserId(context, () => {
289
+ throw ctx.error(403, {
290
+ message: "Unauthorized: User authentication required"
291
+ });
292
+ });
293
+ if (config.hooks?.onBeforeCreateConversation) {
294
+ const canCreate = await config.hooks.onBeforeCreateConversation(
295
+ { id, title },
296
+ context
297
+ );
298
+ if (!canCreate) {
299
+ throw ctx.error(403, {
300
+ message: "Unauthorized: Cannot create conversation"
301
+ });
302
+ }
303
+ }
304
+ const newConv = await adapter.create({
305
+ model: "conversation",
306
+ data: {
307
+ ...id ? { id } : {},
308
+ ...userId ? { userId } : {},
309
+ title: title || "New Conversation",
310
+ createdAt: /* @__PURE__ */ new Date(),
311
+ updatedAt: /* @__PURE__ */ new Date()
312
+ }
313
+ });
314
+ if (config.hooks?.onConversationCreated) {
315
+ await config.hooks.onConversationCreated(newConv, context);
316
+ }
317
+ return newConv;
318
+ } catch (error) {
319
+ if (config.hooks?.onCreateConversationError) {
320
+ await config.hooks.onCreateConversationError(
321
+ error,
322
+ context
323
+ );
324
+ }
325
+ throw error;
326
+ }
327
+ }
328
+ );
329
+ const listConversations = api.createEndpoint(
330
+ "/chat/conversations",
331
+ {
332
+ method: "GET"
333
+ },
334
+ async (ctx) => {
335
+ if (isPublicMode) {
336
+ return [];
337
+ }
338
+ const context = {
339
+ headers: ctx.headers
340
+ };
341
+ try {
342
+ const userId = await resolveUserId(context, () => {
343
+ throw ctx.error(403, {
344
+ message: "Unauthorized: User authentication required"
345
+ });
346
+ });
347
+ if (config.hooks?.onBeforeListConversations) {
348
+ const canList = await config.hooks.onBeforeListConversations(context);
349
+ if (!canList) {
350
+ throw ctx.error(403, {
351
+ message: "Unauthorized: Cannot list conversations"
352
+ });
353
+ }
354
+ }
355
+ const whereConditions = [];
356
+ if (userId) {
357
+ whereConditions.push({
358
+ field: "userId",
359
+ value: userId,
360
+ operator: "eq"
361
+ });
362
+ }
363
+ const conversations = await adapter.findMany({
364
+ model: "conversation",
365
+ where: whereConditions.length > 0 ? whereConditions : void 0,
366
+ sortBy: { field: "updatedAt", direction: "desc" }
367
+ });
368
+ if (config.hooks?.onConversationsRead) {
369
+ await config.hooks.onConversationsRead(conversations, context);
370
+ }
371
+ return conversations;
372
+ } catch (error) {
373
+ if (config.hooks?.onListConversationsError) {
374
+ await config.hooks.onListConversationsError(
375
+ error,
376
+ context
377
+ );
378
+ }
379
+ throw error;
380
+ }
381
+ }
382
+ );
383
+ const getConversation = api.createEndpoint(
384
+ "/chat/conversations/:id",
385
+ {
386
+ method: "GET"
387
+ },
388
+ async (ctx) => {
389
+ if (isPublicMode) {
390
+ throw ctx.error(404, {
391
+ message: "Conversations not available in public mode"
392
+ });
393
+ }
394
+ const { id } = ctx.params;
395
+ const context = {
396
+ params: ctx.params,
397
+ headers: ctx.headers
398
+ };
399
+ try {
400
+ const userId = await resolveUserId(context, () => {
401
+ throw ctx.error(403, {
402
+ message: "Unauthorized: User authentication required"
403
+ });
404
+ });
405
+ if (config.hooks?.onBeforeGetConversation) {
406
+ const canGet = await config.hooks.onBeforeGetConversation(
407
+ id,
408
+ context
409
+ );
410
+ if (!canGet) {
411
+ throw ctx.error(403, {
412
+ message: "Unauthorized: Cannot get conversation"
413
+ });
414
+ }
415
+ }
416
+ const conversations = await adapter.findMany({
417
+ model: "conversation",
418
+ where: [{ field: "id", value: id, operator: "eq" }],
419
+ limit: 1,
420
+ join: {
421
+ message: true
422
+ }
423
+ });
424
+ if (!conversations.length) {
425
+ throw ctx.error(404, { message: "Conversation not found" });
426
+ }
427
+ const conversation = conversations[0];
428
+ if (userId && conversation.userId && conversation.userId !== userId) {
429
+ throw ctx.error(403, {
430
+ message: "Unauthorized: Cannot access this conversation"
431
+ });
432
+ }
433
+ const messages = (conversation.message || []).sort(
434
+ (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
435
+ );
436
+ const { message: _, ...conversationWithoutJoin } = conversation;
437
+ const result = {
438
+ ...conversationWithoutJoin,
439
+ messages
440
+ };
441
+ if (config.hooks?.onConversationRead) {
442
+ await config.hooks.onConversationRead(result, context);
443
+ }
444
+ return result;
445
+ } catch (error) {
446
+ if (config.hooks?.onGetConversationError) {
447
+ await config.hooks.onGetConversationError(
448
+ error,
449
+ context
450
+ );
451
+ }
452
+ throw error;
453
+ }
454
+ }
455
+ );
456
+ const updateConversation = api.createEndpoint(
457
+ "/chat/conversations/:id",
458
+ {
459
+ method: "PUT",
460
+ body: schemas.updateConversationSchema
461
+ },
462
+ async (ctx) => {
463
+ if (isPublicMode) {
464
+ throw ctx.error(404, {
465
+ message: "Conversations not available in public mode"
466
+ });
467
+ }
468
+ const { id } = ctx.params;
469
+ const { title } = ctx.body;
470
+ const context = {
471
+ params: ctx.params,
472
+ body: ctx.body,
473
+ headers: ctx.headers
474
+ };
475
+ try {
476
+ const userId = await resolveUserId(context, () => {
477
+ throw ctx.error(403, {
478
+ message: "Unauthorized: User authentication required"
479
+ });
480
+ });
481
+ const existing = await adapter.findMany({
482
+ model: "conversation",
483
+ where: [{ field: "id", value: id, operator: "eq" }],
484
+ limit: 1
485
+ });
486
+ if (!existing.length) {
487
+ throw ctx.error(404, { message: "Conversation not found" });
488
+ }
489
+ const conversation = existing[0];
490
+ if (userId && conversation.userId && conversation.userId !== userId) {
491
+ throw ctx.error(403, {
492
+ message: "Unauthorized: Cannot update this conversation"
493
+ });
494
+ }
495
+ if (config.hooks?.onBeforeUpdateConversation) {
496
+ const canUpdate = await config.hooks.onBeforeUpdateConversation(
497
+ id,
498
+ { title },
499
+ context
500
+ );
501
+ if (!canUpdate) {
502
+ throw ctx.error(403, {
503
+ message: "Unauthorized: Cannot update conversation"
504
+ });
505
+ }
506
+ }
507
+ const updated = await adapter.update({
508
+ model: "conversation",
509
+ where: [{ field: "id", value: id }],
510
+ update: {
511
+ ...title !== void 0 ? { title } : {},
512
+ updatedAt: /* @__PURE__ */ new Date()
513
+ }
514
+ });
515
+ if (!updated) {
516
+ throw ctx.error(404, { message: "Conversation not found" });
517
+ }
518
+ if (config.hooks?.onConversationUpdated) {
519
+ await config.hooks.onConversationUpdated(updated, context);
520
+ }
521
+ return updated;
522
+ } catch (error) {
523
+ if (config.hooks?.onUpdateConversationError) {
524
+ await config.hooks.onUpdateConversationError(
525
+ error,
526
+ context
527
+ );
528
+ }
529
+ throw error;
530
+ }
531
+ }
532
+ );
533
+ const deleteConversation = api.createEndpoint(
534
+ "/chat/conversations/:id",
535
+ {
536
+ method: "DELETE"
537
+ },
538
+ async (ctx) => {
539
+ if (isPublicMode) {
540
+ throw ctx.error(404, {
541
+ message: "Conversations not available in public mode"
542
+ });
543
+ }
544
+ const { id } = ctx.params;
545
+ const context = {
546
+ params: ctx.params,
547
+ headers: ctx.headers
548
+ };
549
+ try {
550
+ const userId = await resolveUserId(context, () => {
551
+ throw ctx.error(403, {
552
+ message: "Unauthorized: User authentication required"
553
+ });
554
+ });
555
+ const existing = await adapter.findMany({
556
+ model: "conversation",
557
+ where: [{ field: "id", value: id, operator: "eq" }],
558
+ limit: 1
559
+ });
560
+ if (!existing.length) {
561
+ throw ctx.error(404, { message: "Conversation not found" });
562
+ }
563
+ const conversation = existing[0];
564
+ if (userId && conversation.userId && conversation.userId !== userId) {
565
+ throw ctx.error(403, {
566
+ message: "Unauthorized: Cannot delete this conversation"
567
+ });
568
+ }
569
+ if (config.hooks?.onBeforeDeleteConversation) {
570
+ const canDelete = await config.hooks.onBeforeDeleteConversation(
571
+ id,
572
+ context
573
+ );
574
+ if (!canDelete) {
575
+ throw ctx.error(403, {
576
+ message: "Unauthorized: Cannot delete conversation"
577
+ });
578
+ }
579
+ }
580
+ await adapter.delete({
581
+ model: "conversation",
582
+ where: [{ field: "id", value: id }]
583
+ });
584
+ if (config.hooks?.onConversationDeleted) {
585
+ await config.hooks.onConversationDeleted(id, context);
586
+ }
587
+ return { success: true };
588
+ } catch (error) {
589
+ if (config.hooks?.onDeleteConversationError) {
590
+ await config.hooks.onDeleteConversationError(
591
+ error,
592
+ context
593
+ );
594
+ }
595
+ throw error;
596
+ }
597
+ }
598
+ );
599
+ return {
600
+ chat,
601
+ createConversation,
602
+ listConversations,
603
+ getConversation,
604
+ updateConversation,
605
+ deleteConversation
606
+ };
607
+ }
608
+ });
609
+
610
+ exports.aiChatBackendPlugin = aiChatBackendPlugin;