@btst/stack 3.0.0-rc.2 → 3.0.0-rc.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1168) hide show
  1. package/README.md +118 -38
  2. package/dist/api/index.cjs +133 -29
  3. package/dist/api/index.d.cts +14 -32
  4. package/dist/api/index.d.mts +14 -32
  5. package/dist/api/index.d.ts +14 -32
  6. package/dist/api/index.mjs +133 -28
  7. package/dist/authorization/client.cjs +154 -0
  8. package/dist/authorization/client.d.cts +70 -0
  9. package/dist/authorization/client.d.mts +70 -0
  10. package/dist/authorization/client.d.ts +70 -0
  11. package/dist/authorization/client.mjs +152 -0
  12. package/dist/authorization/index.cjs +371 -0
  13. package/dist/authorization/index.d.cts +201 -0
  14. package/dist/authorization/index.d.mts +201 -0
  15. package/dist/authorization/index.d.ts +201 -0
  16. package/dist/authorization/index.mjs +365 -0
  17. package/dist/authorization/remote.cjs +117 -0
  18. package/dist/authorization/remote.d.cts +79 -0
  19. package/dist/authorization/remote.d.mts +79 -0
  20. package/dist/authorization/remote.d.ts +79 -0
  21. package/dist/authorization/remote.mjs +111 -0
  22. package/dist/authorization/server.cjs +77 -0
  23. package/dist/authorization/server.d.cts +51 -0
  24. package/dist/authorization/server.d.mts +51 -0
  25. package/dist/authorization/server.d.ts +51 -0
  26. package/dist/authorization/server.mjs +73 -0
  27. package/dist/client/components/index.cjs +1 -0
  28. package/dist/client/components/index.d.cts +23 -6
  29. package/dist/client/components/index.d.mts +23 -6
  30. package/dist/client/components/index.d.ts +23 -6
  31. package/dist/client/components/index.mjs +1 -1
  32. package/dist/client/hooks/index.cjs +8 -0
  33. package/dist/client/hooks/index.d.cts +25 -0
  34. package/dist/client/hooks/index.d.mts +25 -0
  35. package/dist/client/hooks/index.d.ts +25 -0
  36. package/dist/client/hooks/index.mjs +2 -0
  37. package/dist/client/index.cjs +38 -7
  38. package/dist/client/index.d.cts +30 -100
  39. package/dist/client/index.d.mts +30 -100
  40. package/dist/client/index.d.ts +30 -100
  41. package/dist/client/index.mjs +38 -7
  42. package/dist/client/server.cjs +96 -0
  43. package/dist/client/server.d.cts +57 -0
  44. package/dist/client/server.d.mts +57 -0
  45. package/dist/client/server.d.ts +57 -0
  46. package/dist/client/server.mjs +92 -0
  47. package/dist/components/auto-form/index.d.cts +2 -2
  48. package/dist/components/auto-form/index.d.mts +2 -2
  49. package/dist/components/auto-form/index.d.ts +2 -2
  50. package/dist/components/form-builder/index.d.cts +1 -1
  51. package/dist/components/form-builder/index.d.mts +1 -1
  52. package/dist/components/form-builder/index.d.ts +1 -1
  53. package/dist/components/stepped-auto-form/index.d.cts +1 -1
  54. package/dist/components/stepped-auto-form/index.d.mts +1 -1
  55. package/dist/components/stepped-auto-form/index.d.ts +1 -1
  56. package/dist/context/index.cjs +8 -2
  57. package/dist/context/index.d.cts +111 -89
  58. package/dist/context/index.d.mts +111 -89
  59. package/dist/context/index.d.ts +111 -89
  60. package/dist/context/index.mjs +3 -1
  61. package/dist/index.cjs +1 -2
  62. package/dist/index.d.cts +8 -3
  63. package/dist/index.d.mts +8 -3
  64. package/dist/index.d.ts +8 -3
  65. package/dist/index.mjs +1 -1
  66. package/dist/next/index.d.cts +19 -7
  67. package/dist/next/index.d.mts +19 -7
  68. package/dist/next/index.d.ts +19 -7
  69. package/dist/next/server.cjs +7 -0
  70. package/dist/next/server.d.cts +56 -0
  71. package/dist/next/server.d.mts +56 -0
  72. package/dist/next/server.d.ts +56 -0
  73. package/dist/next/server.mjs +1 -0
  74. package/dist/packages/stack/src/authorization/json.cjs +57 -0
  75. package/dist/packages/stack/src/authorization/json.mjs +55 -0
  76. package/dist/packages/stack/src/client/components/compose.cjs +91 -9
  77. package/dist/packages/stack/src/client/components/compose.mjs +92 -11
  78. package/dist/packages/stack/src/client/runtime.cjs +295 -0
  79. package/dist/packages/stack/src/client/runtime.mjs +293 -0
  80. package/dist/packages/stack/src/context/auth.cjs +141 -73
  81. package/dist/packages/stack/src/context/auth.mjs +139 -73
  82. package/dist/packages/stack/src/context/provider.cjs +11 -5
  83. package/dist/packages/stack/src/context/provider.mjs +11 -5
  84. package/dist/packages/stack/src/context/router.cjs +9 -0
  85. package/dist/packages/stack/src/context/router.mjs +7 -0
  86. package/dist/packages/stack/src/context/site-navigation.cjs +40 -0
  87. package/dist/packages/stack/src/context/site-navigation.mjs +38 -0
  88. package/dist/packages/stack/src/next/layout.cjs +27 -0
  89. package/dist/packages/stack/src/next/layout.mjs +25 -0
  90. package/dist/packages/stack/src/plugin-registration.cjs +59 -0
  91. package/dist/packages/stack/src/plugin-registration.mjs +57 -0
  92. package/dist/packages/stack/src/plugins/ai-chat/api/lifecycle-migrations.cjs +18 -0
  93. package/dist/packages/stack/src/plugins/ai-chat/api/lifecycle-migrations.mjs +16 -0
  94. package/dist/packages/stack/src/plugins/ai-chat/api/operations.cjs +1341 -0
  95. package/dist/packages/stack/src/plugins/ai-chat/api/operations.mjs +1333 -0
  96. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.cjs +82 -640
  97. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +78 -641
  98. package/dist/packages/stack/src/plugins/ai-chat/api/serializers.cjs +23 -0
  99. package/dist/packages/stack/src/plugins/ai-chat/api/serializers.mjs +20 -0
  100. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.cjs +183 -111
  101. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.mjs +187 -115
  102. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.cjs +562 -116
  103. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.mjs +567 -121
  104. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.cjs +6 -6
  105. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.mjs +6 -6
  106. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-message.cjs +1 -1
  107. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-message.mjs +1 -1
  108. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.cjs +45 -29
  109. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.mjs +46 -30
  110. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/404-page.cjs +1 -1
  111. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/404-page.mjs +1 -1
  112. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/chat-page.cjs +46 -7
  113. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/chat-page.internal.cjs +5 -3
  114. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/chat-page.internal.mjs +5 -3
  115. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/chat-page.mjs +48 -9
  116. package/dist/packages/stack/src/plugins/ai-chat/client/components/shared/default-error.cjs +1 -1
  117. package/dist/packages/stack/src/plugins/ai-chat/client/components/shared/default-error.mjs +1 -1
  118. package/dist/packages/stack/src/plugins/ai-chat/client/components/tool-call-display.cjs +1 -1
  119. package/dist/packages/stack/src/plugins/ai-chat/client/components/tool-call-display.mjs +1 -1
  120. package/dist/packages/stack/src/plugins/ai-chat/client/hooks/ai-chat-resource.cjs +1 -1
  121. package/dist/packages/stack/src/plugins/ai-chat/client/hooks/ai-chat-resource.mjs +1 -1
  122. package/dist/packages/stack/src/plugins/ai-chat/client/hooks/chat-hooks.cjs +179 -19
  123. package/dist/packages/stack/src/plugins/ai-chat/client/hooks/chat-hooks.mjs +180 -21
  124. package/dist/packages/stack/src/plugins/ai-chat/client/navigation.cjs +11 -0
  125. package/dist/packages/stack/src/plugins/ai-chat/client/navigation.mjs +9 -0
  126. package/dist/packages/stack/src/plugins/ai-chat/client/overrides.cjs +24 -0
  127. package/dist/packages/stack/src/plugins/ai-chat/client/overrides.mjs +21 -1
  128. package/dist/packages/stack/src/plugins/ai-chat/client/plugin.cjs +152 -82
  129. package/dist/packages/stack/src/plugins/ai-chat/client/plugin.mjs +152 -82
  130. package/dist/packages/stack/src/plugins/api/create-endpoint.cjs +27 -9
  131. package/dist/packages/stack/src/plugins/api/create-endpoint.mjs +27 -10
  132. package/dist/packages/stack/src/plugins/api/endpoint-inventory.cjs +125 -0
  133. package/dist/packages/stack/src/plugins/api/endpoint-inventory.mjs +123 -0
  134. package/dist/packages/stack/src/plugins/api/operation.cjs +208 -0
  135. package/dist/packages/stack/src/plugins/api/operation.mjs +198 -0
  136. package/dist/packages/stack/src/plugins/blog/api/lifecycle-migrations.cjs +17 -0
  137. package/dist/packages/stack/src/plugins/blog/api/lifecycle-migrations.mjs +15 -0
  138. package/dist/packages/stack/src/plugins/blog/api/mutations.cjs +10 -2
  139. package/dist/packages/stack/src/plugins/blog/api/mutations.mjs +10 -2
  140. package/dist/packages/stack/src/plugins/blog/api/operations.cjs +455 -0
  141. package/dist/packages/stack/src/plugins/blog/api/operations.mjs +448 -0
  142. package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +51 -298
  143. package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +55 -304
  144. package/dist/packages/stack/src/plugins/blog/client/components/forms/image-field.cjs +2 -1
  145. package/dist/packages/stack/src/plugins/blog/client/components/forms/image-field.mjs +2 -1
  146. package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.cjs +2 -1
  147. package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.mjs +2 -1
  148. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.cjs +82 -67
  149. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.mjs +84 -69
  150. package/dist/packages/stack/src/plugins/blog/client/components/pages/404-page.cjs +2 -1
  151. package/dist/packages/stack/src/plugins/blog/client/components/pages/404-page.mjs +2 -1
  152. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.cjs +22 -4
  153. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.cjs +2 -1
  154. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.mjs +2 -1
  155. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.mjs +23 -5
  156. package/dist/packages/stack/src/plugins/blog/client/components/pages/home-page.cjs +6 -2
  157. package/dist/packages/stack/src/plugins/blog/client/components/pages/home-page.internal.cjs +2 -1
  158. package/dist/packages/stack/src/plugins/blog/client/components/pages/home-page.internal.mjs +2 -1
  159. package/dist/packages/stack/src/plugins/blog/client/components/pages/home-page.mjs +6 -2
  160. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.cjs +4 -2
  161. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.cjs +2 -1
  162. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.mjs +2 -1
  163. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.mjs +4 -2
  164. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.cjs +30 -3
  165. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +2 -1
  166. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +2 -1
  167. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.mjs +31 -4
  168. package/dist/packages/stack/src/plugins/blog/client/components/pages/tag-page.cjs +4 -1
  169. package/dist/packages/stack/src/plugins/blog/client/components/pages/tag-page.internal.cjs +2 -1
  170. package/dist/packages/stack/src/plugins/blog/client/components/pages/tag-page.internal.mjs +2 -1
  171. package/dist/packages/stack/src/plugins/blog/client/components/pages/tag-page.mjs +4 -1
  172. package/dist/packages/stack/src/plugins/blog/client/components/shared/collapsible-tag-list.cjs +2 -1
  173. package/dist/packages/stack/src/plugins/blog/client/components/shared/collapsible-tag-list.mjs +2 -1
  174. package/dist/packages/stack/src/plugins/blog/client/components/shared/default-error.cjs +2 -1
  175. package/dist/packages/stack/src/plugins/blog/client/components/shared/default-error.mjs +2 -1
  176. package/dist/packages/stack/src/plugins/blog/client/components/shared/on-this-page.cjs +3 -2
  177. package/dist/packages/stack/src/plugins/blog/client/components/shared/on-this-page.mjs +3 -2
  178. package/dist/packages/stack/src/plugins/blog/client/components/shared/page-wrapper.cjs +2 -1
  179. package/dist/packages/stack/src/plugins/blog/client/components/shared/page-wrapper.mjs +2 -1
  180. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-card.cjs +2 -1
  181. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-card.mjs +2 -1
  182. package/dist/packages/stack/src/plugins/blog/client/components/shared/posts-list.cjs +2 -1
  183. package/dist/packages/stack/src/plugins/blog/client/components/shared/posts-list.mjs +2 -1
  184. package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.cjs +2 -1
  185. package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.mjs +2 -1
  186. package/dist/packages/stack/src/plugins/blog/client/components/shared/search-input.cjs +2 -2
  187. package/dist/packages/stack/src/plugins/blog/client/components/shared/search-input.mjs +1 -1
  188. package/dist/packages/stack/src/plugins/blog/client/constants.cjs +5 -0
  189. package/dist/packages/stack/src/plugins/blog/client/constants.mjs +3 -0
  190. package/dist/packages/stack/src/plugins/blog/client/hooks/blog-resource.cjs +2 -1
  191. package/dist/packages/stack/src/plugins/blog/client/hooks/blog-resource.mjs +2 -1
  192. package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +169 -163
  193. package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +169 -163
  194. package/dist/packages/stack/src/plugins/client/resource/hooks.cjs +31 -16
  195. package/dist/packages/stack/src/plugins/client/resource/hooks.mjs +31 -16
  196. package/dist/packages/stack/src/plugins/client/resource/internal.cjs +66 -52
  197. package/dist/packages/stack/src/plugins/client/resource/internal.mjs +66 -52
  198. package/dist/packages/stack/src/plugins/client/resource/use-form.cjs +20 -17
  199. package/dist/packages/stack/src/plugins/client/resource/use-form.mjs +20 -17
  200. package/dist/packages/stack/src/plugins/client/resource/use-select.cjs +39 -33
  201. package/dist/packages/stack/src/plugins/client/resource/use-select.mjs +39 -33
  202. package/dist/packages/stack/src/plugins/cms/api/lifecycle-migrations.cjs +13 -0
  203. package/dist/packages/stack/src/plugins/cms/api/lifecycle-migrations.mjs +11 -0
  204. package/dist/packages/stack/src/plugins/cms/api/operations.cjs +1763 -0
  205. package/dist/packages/stack/src/plugins/cms/api/operations.mjs +1756 -0
  206. package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +165 -752
  207. package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +164 -755
  208. package/dist/packages/stack/src/plugins/cms/client/components/forms/content-form.cjs +2 -1
  209. package/dist/packages/stack/src/plugins/cms/client/components/forms/content-form.mjs +2 -1
  210. package/dist/packages/stack/src/plugins/cms/client/components/forms/file-upload.cjs +2 -1
  211. package/dist/packages/stack/src/plugins/cms/client/components/forms/file-upload.mjs +2 -1
  212. package/dist/packages/stack/src/plugins/cms/client/components/forms/relation-field.cjs +2 -1
  213. package/dist/packages/stack/src/plugins/cms/client/components/forms/relation-field.mjs +2 -1
  214. package/dist/packages/stack/src/plugins/cms/client/components/inverse-relations-panel.cjs +23 -13
  215. package/dist/packages/stack/src/plugins/cms/client/components/inverse-relations-panel.mjs +24 -14
  216. package/dist/packages/stack/src/plugins/cms/client/components/pages/404-page.cjs +5 -4
  217. package/dist/packages/stack/src/plugins/cms/client/components/pages/404-page.mjs +6 -5
  218. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.cjs +40 -7
  219. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.cjs +15 -9
  220. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.mjs +14 -8
  221. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.mjs +41 -8
  222. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.cjs +7 -1
  223. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.internal.cjs +42 -29
  224. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.internal.mjs +40 -27
  225. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.mjs +7 -1
  226. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.cjs +4 -1
  227. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.internal.cjs +13 -7
  228. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.internal.mjs +12 -6
  229. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.mjs +4 -1
  230. package/dist/packages/stack/src/plugins/cms/client/components/shared/page-wrapper.cjs +2 -1
  231. package/dist/packages/stack/src/plugins/cms/client/components/shared/page-wrapper.mjs +2 -1
  232. package/dist/packages/stack/src/plugins/cms/client/constants.cjs +5 -0
  233. package/dist/packages/stack/src/plugins/cms/client/constants.mjs +3 -0
  234. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-resource.cjs +2 -1
  235. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-resource.mjs +2 -1
  236. package/dist/packages/stack/src/plugins/cms/client/overrides.cjs +26 -0
  237. package/dist/packages/stack/src/plugins/cms/client/overrides.mjs +24 -0
  238. package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +102 -81
  239. package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +103 -82
  240. package/dist/packages/stack/src/plugins/comments/api/getters.cjs +6 -2
  241. package/dist/packages/stack/src/plugins/comments/api/getters.mjs +6 -3
  242. package/dist/packages/stack/src/plugins/comments/api/lifecycle-migrations.cjs +18 -0
  243. package/dist/packages/stack/src/plugins/comments/api/lifecycle-migrations.mjs +16 -0
  244. package/dist/packages/stack/src/plugins/comments/api/mutations.cjs +179 -68
  245. package/dist/packages/stack/src/plugins/comments/api/mutations.mjs +179 -68
  246. package/dist/packages/stack/src/plugins/comments/api/operations.cjs +453 -0
  247. package/dist/packages/stack/src/plugins/comments/api/operations.mjs +445 -0
  248. package/dist/packages/stack/src/plugins/comments/api/plugin.cjs +51 -276
  249. package/dist/packages/stack/src/plugins/comments/api/plugin.mjs +48 -277
  250. package/dist/packages/stack/src/plugins/comments/client/components/comment-count.cjs +32 -5
  251. package/dist/packages/stack/src/plugins/comments/client/components/comment-count.mjs +34 -7
  252. package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.cjs +160 -104
  253. package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.mjs +161 -105
  254. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.cjs +14 -2
  255. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.cjs +141 -71
  256. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.mjs +142 -72
  257. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.mjs +14 -2
  258. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-state.cjs +12 -0
  259. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-state.mjs +9 -0
  260. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.cjs +2 -1
  261. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.cjs +40 -26
  262. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.mjs +40 -26
  263. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.mjs +2 -1
  264. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.cjs +9 -1
  265. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.cjs +25 -20
  266. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.mjs +26 -21
  267. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.mjs +9 -1
  268. package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.cjs +2 -1
  269. package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.mjs +2 -1
  270. package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.cjs +2 -1
  271. package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.mjs +2 -1
  272. package/dist/packages/stack/src/plugins/comments/client/constants.cjs +5 -0
  273. package/dist/packages/stack/src/plugins/comments/client/constants.mjs +3 -0
  274. package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.cjs +323 -290
  275. package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.mjs +325 -292
  276. package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.cjs +1 -0
  277. package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.mjs +1 -0
  278. package/dist/packages/stack/src/plugins/comments/client/plugin.cjs +78 -46
  279. package/dist/packages/stack/src/plugins/comments/client/plugin.mjs +80 -48
  280. package/dist/packages/stack/src/plugins/form-builder/api/getters.cjs +9 -0
  281. package/dist/packages/stack/src/plugins/form-builder/api/getters.mjs +9 -1
  282. package/dist/packages/stack/src/plugins/form-builder/api/lifecycle-migrations.cjs +15 -0
  283. package/dist/packages/stack/src/plugins/form-builder/api/lifecycle-migrations.mjs +13 -0
  284. package/dist/packages/stack/src/plugins/form-builder/api/operations.cjs +1093 -0
  285. package/dist/packages/stack/src/plugins/form-builder/api/operations.mjs +1082 -0
  286. package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +97 -466
  287. package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +92 -468
  288. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.cjs +5 -0
  289. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.mjs +5 -0
  290. package/dist/packages/stack/src/plugins/form-builder/client/components/forms/form-renderer.cjs +41 -11
  291. package/dist/packages/stack/src/plugins/form-builder/client/components/forms/form-renderer.mjs +42 -12
  292. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/404-page.cjs +8 -5
  293. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/404-page.mjs +9 -6
  294. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-builder-page.cjs +36 -3
  295. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-builder-page.internal.cjs +32 -11
  296. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-builder-page.internal.mjs +35 -14
  297. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-builder-page.mjs +37 -4
  298. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.cjs +6 -1
  299. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.internal.cjs +34 -26
  300. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.internal.mjs +34 -26
  301. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.mjs +6 -1
  302. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.cjs +24 -7
  303. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.cjs +72 -40
  304. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.mjs +76 -44
  305. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.mjs +25 -8
  306. package/dist/packages/stack/src/plugins/form-builder/client/components/shared/page-wrapper.cjs +2 -1
  307. package/dist/packages/stack/src/plugins/form-builder/client/components/shared/page-wrapper.mjs +2 -1
  308. package/dist/packages/stack/src/plugins/form-builder/client/constants.cjs +5 -0
  309. package/dist/packages/stack/src/plugins/form-builder/client/constants.mjs +3 -0
  310. package/dist/packages/stack/src/plugins/form-builder/client/hooks/form-builder-hooks.cjs +29 -0
  311. package/dist/packages/stack/src/plugins/form-builder/client/hooks/form-builder-hooks.mjs +28 -1
  312. package/dist/packages/stack/src/plugins/form-builder/client/hooks/form-builder-resource.cjs +2 -1
  313. package/dist/packages/stack/src/plugins/form-builder/client/hooks/form-builder-resource.mjs +2 -1
  314. package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +113 -86
  315. package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +114 -87
  316. package/dist/packages/stack/src/plugins/form-builder/schemas.cjs +9 -3
  317. package/dist/packages/stack/src/plugins/form-builder/schemas.mjs +9 -3
  318. package/dist/packages/stack/src/plugins/kanban/api/getters.cjs +47 -36
  319. package/dist/packages/stack/src/plugins/kanban/api/getters.mjs +47 -37
  320. package/dist/packages/stack/src/plugins/kanban/api/lifecycle-migrations.cjs +23 -0
  321. package/dist/packages/stack/src/plugins/kanban/api/lifecycle-migrations.mjs +21 -0
  322. package/dist/packages/stack/src/plugins/kanban/api/operations.cjs +1552 -0
  323. package/dist/packages/stack/src/plugins/kanban/api/operations.mjs +1543 -0
  324. package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +64 -631
  325. package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +62 -634
  326. package/dist/packages/stack/src/plugins/kanban/api/serializers.cjs +21 -0
  327. package/dist/packages/stack/src/plugins/kanban/api/serializers.mjs +21 -1
  328. package/dist/packages/stack/src/plugins/kanban/client/components/forms/board-form.cjs +2 -1
  329. package/dist/packages/stack/src/plugins/kanban/client/components/forms/board-form.mjs +2 -1
  330. package/dist/packages/stack/src/plugins/kanban/client/components/forms/column-form.cjs +2 -1
  331. package/dist/packages/stack/src/plugins/kanban/client/components/forms/column-form.mjs +2 -1
  332. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.cjs +72 -54
  333. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.mjs +74 -56
  334. package/dist/packages/stack/src/plugins/kanban/client/components/pages/404-page.cjs +4 -6
  335. package/dist/packages/stack/src/plugins/kanban/client/components/pages/404-page.mjs +5 -7
  336. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.cjs +22 -6
  337. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.cjs +82 -77
  338. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.mjs +83 -78
  339. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.mjs +23 -7
  340. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.cjs +2 -1
  341. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.internal.cjs +34 -24
  342. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.internal.mjs +35 -25
  343. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.mjs +2 -1
  344. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.cjs +2 -1
  345. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.internal.cjs +6 -9
  346. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.internal.mjs +7 -10
  347. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.mjs +2 -1
  348. package/dist/packages/stack/src/plugins/kanban/client/components/shared/column-content.cjs +72 -45
  349. package/dist/packages/stack/src/plugins/kanban/client/components/shared/column-content.mjs +73 -46
  350. package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.cjs +2 -1
  351. package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.mjs +2 -1
  352. package/dist/packages/stack/src/plugins/kanban/client/components/shared/kanban-board.cjs +4 -4
  353. package/dist/packages/stack/src/plugins/kanban/client/components/shared/kanban-board.mjs +4 -4
  354. package/dist/packages/stack/src/plugins/kanban/client/components/shared/permission-access-any.cjs +23 -0
  355. package/dist/packages/stack/src/plugins/kanban/client/components/shared/permission-access-any.mjs +21 -0
  356. package/dist/packages/stack/src/plugins/kanban/client/components/shared/task-card.cjs +54 -17
  357. package/dist/packages/stack/src/plugins/kanban/client/components/shared/task-card.mjs +55 -18
  358. package/dist/packages/stack/src/plugins/kanban/client/components/shared/user-avatar.cjs +2 -1
  359. package/dist/packages/stack/src/plugins/kanban/client/components/shared/user-avatar.mjs +2 -1
  360. package/dist/packages/stack/src/plugins/kanban/client/constants.cjs +5 -0
  361. package/dist/packages/stack/src/plugins/kanban/client/constants.mjs +3 -0
  362. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.cjs +38 -9
  363. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.mjs +39 -10
  364. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-resource.cjs +2 -1
  365. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-resource.mjs +2 -1
  366. package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +177 -104
  367. package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +178 -105
  368. package/dist/packages/stack/src/plugins/kanban/schemas.cjs +32 -23
  369. package/dist/packages/stack/src/plugins/kanban/schemas.mjs +33 -21
  370. package/dist/packages/stack/src/plugins/media/api/lifecycle-migrations.cjs +9 -0
  371. package/dist/packages/stack/src/plugins/media/api/lifecycle-migrations.mjs +7 -0
  372. package/dist/packages/stack/src/plugins/media/api/mutations.cjs +7 -2
  373. package/dist/packages/stack/src/plugins/media/api/mutations.mjs +7 -2
  374. package/dist/packages/stack/src/plugins/media/api/operations.cjs +1299 -0
  375. package/dist/packages/stack/src/plugins/media/api/operations.mjs +1290 -0
  376. package/dist/packages/stack/src/plugins/media/api/plugin.cjs +131 -508
  377. package/dist/packages/stack/src/plugins/media/api/plugin.mjs +127 -510
  378. package/dist/packages/stack/src/plugins/media/api/query-key-defs.cjs +26 -2
  379. package/dist/packages/stack/src/plugins/media/api/query-key-defs.mjs +25 -3
  380. package/dist/packages/stack/src/plugins/media/api/serializers.cjs +4 -2
  381. package/dist/packages/stack/src/plugins/media/api/serializers.mjs +4 -2
  382. package/dist/packages/stack/src/plugins/media/asset-url.cjs +13 -0
  383. package/dist/packages/stack/src/plugins/media/asset-url.mjs +11 -0
  384. package/dist/packages/stack/src/plugins/media/client/components/media-picker/asset-card.cjs +10 -10
  385. package/dist/packages/stack/src/plugins/media/client/components/media-picker/asset-card.mjs +12 -12
  386. package/dist/packages/stack/src/plugins/media/client/components/media-picker/folder-tree.cjs +47 -27
  387. package/dist/packages/stack/src/plugins/media/client/components/media-picker/folder-tree.mjs +49 -29
  388. package/dist/packages/stack/src/plugins/media/client/components/media-picker/index.cjs +225 -180
  389. package/dist/packages/stack/src/plugins/media/client/components/media-picker/index.mjs +228 -183
  390. package/dist/packages/stack/src/plugins/media/client/components/media-picker/upload-tab.cjs +1 -8
  391. package/dist/packages/stack/src/plugins/media/client/components/media-picker/upload-tab.mjs +2 -9
  392. package/dist/packages/stack/src/plugins/media/client/components/media-picker/url-tab.cjs +0 -6
  393. package/dist/packages/stack/src/plugins/media/client/components/media-picker/url-tab.mjs +1 -7
  394. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.cjs +4 -2
  395. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.internal.cjs +92 -75
  396. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.internal.mjs +93 -76
  397. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.mjs +4 -2
  398. package/dist/packages/stack/src/plugins/media/client/components/upload-permission-check.cjs +52 -0
  399. package/dist/packages/stack/src/plugins/media/client/components/upload-permission-check.mjs +49 -0
  400. package/dist/packages/stack/src/plugins/media/client/constants.cjs +5 -0
  401. package/dist/packages/stack/src/plugins/media/client/constants.mjs +3 -0
  402. package/dist/packages/stack/src/plugins/media/client/hooks/media-resource.cjs +2 -1
  403. package/dist/packages/stack/src/plugins/media/client/hooks/media-resource.mjs +2 -1
  404. package/dist/packages/stack/src/plugins/media/client/hooks/use-media.cjs +214 -43
  405. package/dist/packages/stack/src/plugins/media/client/hooks/use-media.mjs +217 -46
  406. package/dist/packages/stack/src/plugins/media/client/plugin.cjs +122 -62
  407. package/dist/packages/stack/src/plugins/media/client/plugin.mjs +123 -63
  408. package/dist/packages/stack/src/plugins/media/client/upload.cjs +121 -52
  409. package/dist/packages/stack/src/plugins/media/client/upload.mjs +121 -53
  410. package/dist/packages/stack/src/plugins/media/db.cjs +8 -0
  411. package/dist/packages/stack/src/plugins/media/db.mjs +8 -0
  412. package/dist/packages/stack/src/plugins/open-api/api/generator.cjs +36 -5
  413. package/dist/packages/stack/src/plugins/open-api/api/generator.mjs +36 -5
  414. package/dist/packages/stack/src/plugins/open-api/api/plugin.cjs +22 -11
  415. package/dist/packages/stack/src/plugins/open-api/api/plugin.mjs +22 -11
  416. package/dist/packages/stack/src/plugins/route-docs/client/components/pages/docs-page.cjs +65 -34
  417. package/dist/packages/stack/src/plugins/route-docs/client/components/pages/docs-page.mjs +56 -25
  418. package/dist/packages/stack/src/plugins/route-docs/client/constants.cjs +5 -0
  419. package/dist/packages/stack/src/plugins/route-docs/client/constants.mjs +3 -0
  420. package/dist/packages/stack/src/plugins/route-docs/client/hooks.cjs +9 -8
  421. package/dist/packages/stack/src/plugins/route-docs/client/hooks.mjs +10 -9
  422. package/dist/packages/stack/src/plugins/route-docs/client/plugin.cjs +143 -75
  423. package/dist/packages/stack/src/plugins/route-docs/client/plugin.mjs +144 -74
  424. package/dist/packages/stack/src/plugins/route-docs/client/schema.cjs +26 -0
  425. package/dist/packages/stack/src/plugins/route-docs/client/schema.mjs +23 -0
  426. package/dist/packages/stack/src/plugins/route-docs/generator.cjs +7 -4
  427. package/dist/packages/stack/src/plugins/route-docs/generator.mjs +7 -4
  428. package/dist/packages/stack/src/plugins/ui-builder/client/components/page-renderer.cjs +41 -12
  429. package/dist/packages/stack/src/plugins/ui-builder/client/components/page-renderer.mjs +42 -13
  430. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.cjs +37 -3
  431. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.cjs +32 -20
  432. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.mjs +34 -22
  433. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.mjs +38 -4
  434. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-list-page.cjs +8 -2
  435. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-list-page.internal.cjs +37 -19
  436. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-list-page.internal.mjs +38 -20
  437. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-list-page.mjs +8 -2
  438. package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/default-error.cjs +2 -1
  439. package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/default-error.mjs +2 -1
  440. package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/page-wrapper.cjs +2 -1
  441. package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/page-wrapper.mjs +2 -1
  442. package/dist/packages/stack/src/plugins/ui-builder/client/constants.cjs +5 -0
  443. package/dist/packages/stack/src/plugins/ui-builder/client/constants.mjs +3 -0
  444. package/dist/packages/stack/src/plugins/ui-builder/client/hooks/ui-builder-resource.cjs +2 -1
  445. package/dist/packages/stack/src/plugins/ui-builder/client/hooks/ui-builder-resource.mjs +2 -1
  446. package/dist/packages/stack/src/plugins/ui-builder/client/overrides.cjs +8 -0
  447. package/dist/packages/stack/src/plugins/ui-builder/client/overrides.mjs +6 -0
  448. package/dist/packages/stack/src/plugins/ui-builder/client/plugin.cjs +93 -53
  449. package/dist/packages/stack/src/plugins/ui-builder/client/plugin.mjs +94 -54
  450. package/dist/packages/stack/src/plugins/utils.cjs +4 -12
  451. package/dist/packages/stack/src/plugins/utils.mjs +5 -12
  452. package/dist/packages/stack/src/react-router/layout.cjs +14 -0
  453. package/dist/packages/stack/src/react-router/layout.mjs +12 -0
  454. package/dist/packages/stack/src/react-router/page.cjs +10 -5
  455. package/dist/packages/stack/src/react-router/page.mjs +11 -6
  456. package/dist/packages/stack/src/shared/initial-identity.cjs +27 -0
  457. package/dist/packages/stack/src/shared/initial-identity.mjs +23 -0
  458. package/dist/packages/stack/src/tanstack/layout.cjs +10 -0
  459. package/dist/packages/stack/src/tanstack/layout.mjs +8 -0
  460. package/dist/packages/stack/src/tanstack/page.cjs +6 -2
  461. package/dist/packages/stack/src/tanstack/page.mjs +6 -2
  462. package/dist/plugins/ai-chat/api/index.cjs +10 -0
  463. package/dist/plugins/ai-chat/api/index.d.cts +31 -5
  464. package/dist/plugins/ai-chat/api/index.d.mts +31 -5
  465. package/dist/plugins/ai-chat/api/index.d.ts +31 -5
  466. package/dist/plugins/ai-chat/api/index.mjs +3 -1
  467. package/dist/plugins/ai-chat/client/components/index.d.cts +1 -1
  468. package/dist/plugins/ai-chat/client/components/index.d.mts +1 -1
  469. package/dist/plugins/ai-chat/client/components/index.d.ts +1 -1
  470. package/dist/plugins/ai-chat/client/hooks/index.cjs +1 -0
  471. package/dist/plugins/ai-chat/client/hooks/index.d.cts +14 -8
  472. package/dist/plugins/ai-chat/client/hooks/index.d.mts +14 -8
  473. package/dist/plugins/ai-chat/client/hooks/index.d.ts +14 -8
  474. package/dist/plugins/ai-chat/client/hooks/index.mjs +1 -1
  475. package/dist/plugins/ai-chat/client/index.d.cts +21 -25
  476. package/dist/plugins/ai-chat/client/index.d.mts +21 -25
  477. package/dist/plugins/ai-chat/client/index.d.ts +21 -25
  478. package/dist/plugins/ai-chat/permissions.cjs +90 -0
  479. package/dist/plugins/ai-chat/permissions.d.cts +84 -0
  480. package/dist/plugins/ai-chat/permissions.d.mts +84 -0
  481. package/dist/plugins/ai-chat/permissions.d.ts +84 -0
  482. package/dist/plugins/ai-chat/permissions.mjs +88 -0
  483. package/dist/plugins/ai-chat/query-keys.cjs +116 -18
  484. package/dist/plugins/ai-chat/query-keys.d.cts +6 -2
  485. package/dist/plugins/ai-chat/query-keys.d.mts +6 -2
  486. package/dist/plugins/ai-chat/query-keys.d.ts +6 -2
  487. package/dist/plugins/ai-chat/query-keys.mjs +116 -19
  488. package/dist/plugins/api/index.cjs +4 -0
  489. package/dist/plugins/api/index.d.cts +13 -18
  490. package/dist/plugins/api/index.d.mts +13 -18
  491. package/dist/plugins/api/index.d.ts +13 -18
  492. package/dist/plugins/api/index.mjs +1 -0
  493. package/dist/plugins/blog/api/index.cjs +9 -2
  494. package/dist/plugins/blog/api/index.d.cts +118 -4
  495. package/dist/plugins/blog/api/index.d.mts +118 -4
  496. package/dist/plugins/blog/api/index.d.ts +118 -4
  497. package/dist/plugins/blog/api/index.mjs +4 -1
  498. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  499. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  500. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  501. package/dist/plugins/blog/client/index.d.cts +210 -226
  502. package/dist/plugins/blog/client/index.d.mts +210 -226
  503. package/dist/plugins/blog/client/index.d.ts +210 -226
  504. package/dist/plugins/blog/permissions.cjs +47 -0
  505. package/dist/plugins/blog/permissions.d.cts +49 -0
  506. package/dist/plugins/blog/permissions.d.mts +49 -0
  507. package/dist/plugins/blog/permissions.d.ts +49 -0
  508. package/dist/plugins/blog/permissions.mjs +45 -0
  509. package/dist/plugins/blog/query-keys.d.cts +7 -3
  510. package/dist/plugins/blog/query-keys.d.mts +7 -3
  511. package/dist/plugins/blog/query-keys.d.ts +7 -3
  512. package/dist/plugins/client/hooks/index.d.cts +2 -2
  513. package/dist/plugins/client/hooks/index.d.mts +2 -2
  514. package/dist/plugins/client/hooks/index.d.ts +2 -2
  515. package/dist/plugins/client/index.cjs +3 -0
  516. package/dist/plugins/client/index.d.cts +30 -10
  517. package/dist/plugins/client/index.d.mts +30 -10
  518. package/dist/plugins/client/index.d.ts +30 -10
  519. package/dist/plugins/client/index.mjs +3 -0
  520. package/dist/plugins/cms/api/index.cjs +7 -0
  521. package/dist/plugins/cms/api/index.d.cts +173 -4
  522. package/dist/plugins/cms/api/index.d.mts +173 -4
  523. package/dist/plugins/cms/api/index.d.ts +173 -4
  524. package/dist/plugins/cms/api/index.mjs +2 -0
  525. package/dist/plugins/cms/client/hooks/index.d.cts +1 -1
  526. package/dist/plugins/cms/client/hooks/index.d.mts +1 -1
  527. package/dist/plugins/cms/client/hooks/index.d.ts +1 -1
  528. package/dist/plugins/cms/client/index.d.cts +188 -184
  529. package/dist/plugins/cms/client/index.d.mts +188 -184
  530. package/dist/plugins/cms/client/index.d.ts +188 -184
  531. package/dist/plugins/cms/permissions.cjs +46 -0
  532. package/dist/plugins/cms/permissions.d.cts +42 -0
  533. package/dist/plugins/cms/permissions.d.mts +42 -0
  534. package/dist/plugins/cms/permissions.d.ts +42 -0
  535. package/dist/plugins/cms/permissions.mjs +44 -0
  536. package/dist/plugins/cms/query-keys.d.cts +4 -4
  537. package/dist/plugins/cms/query-keys.d.mts +4 -4
  538. package/dist/plugins/cms/query-keys.d.ts +4 -4
  539. package/dist/plugins/comments/api/index.cjs +10 -0
  540. package/dist/plugins/comments/api/index.d.cts +54 -18
  541. package/dist/plugins/comments/api/index.d.mts +54 -18
  542. package/dist/plugins/comments/api/index.d.ts +54 -18
  543. package/dist/plugins/comments/api/index.mjs +3 -0
  544. package/dist/plugins/comments/client/components/index.d.cts +2 -2
  545. package/dist/plugins/comments/client/components/index.d.mts +2 -2
  546. package/dist/plugins/comments/client/components/index.d.ts +2 -2
  547. package/dist/plugins/comments/client/hooks/index.d.cts +12 -18
  548. package/dist/plugins/comments/client/hooks/index.d.mts +12 -18
  549. package/dist/plugins/comments/client/hooks/index.d.ts +12 -18
  550. package/dist/plugins/comments/client/index.d.cts +96 -114
  551. package/dist/plugins/comments/client/index.d.mts +96 -114
  552. package/dist/plugins/comments/client/index.d.ts +96 -114
  553. package/dist/plugins/comments/permissions.cjs +70 -0
  554. package/dist/plugins/comments/permissions.d.cts +76 -0
  555. package/dist/plugins/comments/permissions.d.mts +76 -0
  556. package/dist/plugins/comments/permissions.d.ts +76 -0
  557. package/dist/plugins/comments/permissions.mjs +68 -0
  558. package/dist/plugins/comments/query-keys.cjs +1 -1
  559. package/dist/plugins/comments/query-keys.d.cts +16 -19
  560. package/dist/plugins/comments/query-keys.d.mts +16 -19
  561. package/dist/plugins/comments/query-keys.d.ts +16 -19
  562. package/dist/plugins/comments/query-keys.mjs +1 -1
  563. package/dist/plugins/form-builder/api/index.cjs +8 -0
  564. package/dist/plugins/form-builder/api/index.d.cts +115 -4
  565. package/dist/plugins/form-builder/api/index.d.mts +115 -4
  566. package/dist/plugins/form-builder/api/index.d.ts +115 -4
  567. package/dist/plugins/form-builder/api/index.mjs +4 -1
  568. package/dist/plugins/form-builder/client/components/index.d.cts +6 -2
  569. package/dist/plugins/form-builder/client/components/index.d.mts +6 -2
  570. package/dist/plugins/form-builder/client/components/index.d.ts +6 -2
  571. package/dist/plugins/form-builder/client/hooks/index.cjs +2 -0
  572. package/dist/plugins/form-builder/client/hooks/index.d.cts +34 -8
  573. package/dist/plugins/form-builder/client/hooks/index.d.mts +34 -8
  574. package/dist/plugins/form-builder/client/hooks/index.d.ts +34 -8
  575. package/dist/plugins/form-builder/client/hooks/index.mjs +1 -1
  576. package/dist/plugins/form-builder/client/index.d.cts +153 -174
  577. package/dist/plugins/form-builder/client/index.d.mts +153 -174
  578. package/dist/plugins/form-builder/client/index.d.ts +153 -174
  579. package/dist/plugins/form-builder/permissions.cjs +95 -0
  580. package/dist/plugins/form-builder/permissions.d.cts +94 -0
  581. package/dist/plugins/form-builder/permissions.d.mts +94 -0
  582. package/dist/plugins/form-builder/permissions.d.ts +94 -0
  583. package/dist/plugins/form-builder/permissions.mjs +93 -0
  584. package/dist/plugins/form-builder/query-keys.cjs +11 -4
  585. package/dist/plugins/form-builder/query-keys.d.cts +38 -12
  586. package/dist/plugins/form-builder/query-keys.d.mts +38 -12
  587. package/dist/plugins/form-builder/query-keys.d.ts +38 -12
  588. package/dist/plugins/form-builder/query-keys.mjs +11 -4
  589. package/dist/plugins/kanban/api/index.cjs +9 -0
  590. package/dist/plugins/kanban/api/index.d.cts +137 -5
  591. package/dist/plugins/kanban/api/index.d.mts +137 -5
  592. package/dist/plugins/kanban/api/index.d.ts +137 -5
  593. package/dist/plugins/kanban/api/index.mjs +5 -2
  594. package/dist/plugins/kanban/client/components/index.d.cts +18 -10
  595. package/dist/plugins/kanban/client/components/index.d.mts +18 -10
  596. package/dist/plugins/kanban/client/components/index.d.ts +18 -10
  597. package/dist/plugins/kanban/client/hooks/index.d.cts +15 -7
  598. package/dist/plugins/kanban/client/hooks/index.d.mts +15 -7
  599. package/dist/plugins/kanban/client/hooks/index.d.ts +15 -7
  600. package/dist/plugins/kanban/client/index.d.cts +32 -28
  601. package/dist/plugins/kanban/client/index.d.mts +32 -28
  602. package/dist/plugins/kanban/client/index.d.ts +32 -28
  603. package/dist/plugins/kanban/permissions.cjs +101 -0
  604. package/dist/plugins/kanban/permissions.d.cts +109 -0
  605. package/dist/plugins/kanban/permissions.d.mts +109 -0
  606. package/dist/plugins/kanban/permissions.d.ts +109 -0
  607. package/dist/plugins/kanban/permissions.mjs +99 -0
  608. package/dist/plugins/kanban/query-keys.cjs +14 -15
  609. package/dist/plugins/kanban/query-keys.d.cts +63 -42
  610. package/dist/plugins/kanban/query-keys.d.mts +63 -42
  611. package/dist/plugins/kanban/query-keys.d.ts +63 -42
  612. package/dist/plugins/kanban/query-keys.mjs +14 -15
  613. package/dist/plugins/media/api/adapters/local.d.cts +1 -1
  614. package/dist/plugins/media/api/adapters/local.d.mts +1 -1
  615. package/dist/plugins/media/api/adapters/local.d.ts +1 -1
  616. package/dist/plugins/media/api/adapters/s3.d.cts +1 -1
  617. package/dist/plugins/media/api/adapters/s3.d.mts +1 -1
  618. package/dist/plugins/media/api/adapters/s3.d.ts +1 -1
  619. package/dist/plugins/media/api/adapters/vercel-blob.cjs +46 -0
  620. package/dist/plugins/media/api/adapters/vercel-blob.d.cts +6 -9
  621. package/dist/plugins/media/api/adapters/vercel-blob.d.mts +6 -9
  622. package/dist/plugins/media/api/adapters/vercel-blob.d.ts +6 -9
  623. package/dist/plugins/media/api/adapters/vercel-blob.mjs +46 -0
  624. package/dist/plugins/media/api/index.cjs +10 -0
  625. package/dist/plugins/media/api/index.d.cts +93 -6
  626. package/dist/plugins/media/api/index.d.mts +93 -6
  627. package/dist/plugins/media/api/index.d.ts +93 -6
  628. package/dist/plugins/media/api/index.mjs +2 -0
  629. package/dist/plugins/media/client/components/index.d.cts +1 -1
  630. package/dist/plugins/media/client/components/index.d.mts +1 -1
  631. package/dist/plugins/media/client/components/index.d.ts +1 -1
  632. package/dist/plugins/media/client/hooks/index.d.cts +20 -10
  633. package/dist/plugins/media/client/hooks/index.d.mts +20 -10
  634. package/dist/plugins/media/client/hooks/index.d.ts +20 -10
  635. package/dist/plugins/media/client/index.cjs +1 -0
  636. package/dist/plugins/media/client/index.d.cts +112 -100
  637. package/dist/plugins/media/client/index.d.mts +112 -100
  638. package/dist/plugins/media/client/index.d.ts +112 -100
  639. package/dist/plugins/media/client/index.mjs +1 -1
  640. package/dist/plugins/media/permissions.cjs +63 -0
  641. package/dist/plugins/media/permissions.d.cts +64 -0
  642. package/dist/plugins/media/permissions.d.mts +64 -0
  643. package/dist/plugins/media/permissions.d.ts +64 -0
  644. package/dist/plugins/media/permissions.mjs +61 -0
  645. package/dist/plugins/media/query-keys.cjs +29 -17
  646. package/dist/plugins/media/query-keys.d.cts +24 -31
  647. package/dist/plugins/media/query-keys.d.mts +24 -31
  648. package/dist/plugins/media/query-keys.d.ts +24 -31
  649. package/dist/plugins/media/query-keys.mjs +30 -18
  650. package/dist/plugins/open-api/api/index.d.cts +9 -4
  651. package/dist/plugins/open-api/api/index.d.mts +9 -4
  652. package/dist/plugins/open-api/api/index.d.ts +9 -4
  653. package/dist/plugins/route-docs/client/index.cjs +2 -2
  654. package/dist/plugins/route-docs/client/index.d.cts +54 -53
  655. package/dist/plugins/route-docs/client/index.d.mts +54 -53
  656. package/dist/plugins/route-docs/client/index.d.ts +54 -53
  657. package/dist/plugins/route-docs/client/index.mjs +2 -1
  658. package/dist/plugins/ui-builder/client/components/index.d.cts +8 -5
  659. package/dist/plugins/ui-builder/client/components/index.d.mts +8 -5
  660. package/dist/plugins/ui-builder/client/components/index.d.ts +8 -5
  661. package/dist/plugins/ui-builder/client/hooks/index.d.cts +5 -5
  662. package/dist/plugins/ui-builder/client/hooks/index.d.mts +5 -5
  663. package/dist/plugins/ui-builder/client/hooks/index.d.ts +5 -5
  664. package/dist/plugins/ui-builder/client/index.d.cts +151 -199
  665. package/dist/plugins/ui-builder/client/index.d.mts +151 -199
  666. package/dist/plugins/ui-builder/client/index.d.ts +151 -199
  667. package/dist/plugins/ui-builder/index.d.cts +11 -8
  668. package/dist/plugins/ui-builder/index.d.mts +11 -8
  669. package/dist/plugins/ui-builder/index.d.ts +11 -8
  670. package/dist/plugins/ui-builder/query-keys.d.cts +6 -6
  671. package/dist/plugins/ui-builder/query-keys.d.mts +6 -6
  672. package/dist/plugins/ui-builder/query-keys.d.ts +6 -6
  673. package/dist/react-router/index.cjs +2 -0
  674. package/dist/react-router/index.d.cts +29 -5
  675. package/dist/react-router/index.d.mts +29 -5
  676. package/dist/react-router/index.d.ts +29 -5
  677. package/dist/react-router/index.mjs +1 -0
  678. package/dist/shared/stack.0O62uXqP.d.ts +613 -0
  679. package/dist/shared/stack.0y6iTP03.d.ts +533 -0
  680. package/dist/shared/{stack.CbZenbej.d.cts → stack.1ukVJym7.d.cts} +3 -4
  681. package/dist/shared/{stack.CbZenbej.d.mts → stack.1ukVJym7.d.mts} +3 -4
  682. package/dist/shared/{stack.CbZenbej.d.ts → stack.1ukVJym7.d.ts} +3 -4
  683. package/dist/shared/stack.3Sr6qRtT.d.ts +507 -0
  684. package/dist/shared/{stack.9BAOaSqE.d.cts → stack.5_zzCejP.d.cts} +16 -14
  685. package/dist/shared/{stack.9BAOaSqE.d.mts → stack.5_zzCejP.d.mts} +16 -14
  686. package/dist/shared/{stack.9BAOaSqE.d.ts → stack.5_zzCejP.d.ts} +16 -14
  687. package/dist/shared/{stack.oVIdV7XS.d.mts → stack.94kN3pEK.d.mts} +4 -4
  688. package/dist/shared/stack.B1UrNoVl.d.mts +533 -0
  689. package/dist/shared/{stack.B2xi4jj7.d.cts → stack.B1srlBud.d.mts} +2 -2
  690. package/dist/shared/stack.B3_aDcYL.d.cts +281 -0
  691. package/dist/shared/stack.B3_aDcYL.d.mts +281 -0
  692. package/dist/shared/stack.B3_aDcYL.d.ts +281 -0
  693. package/dist/shared/stack.B5yPgHsp.d.mts +507 -0
  694. package/dist/shared/stack.BFP_9pRX.d.cts +707 -0
  695. package/dist/shared/stack.BJx1ZXrN.d.cts +118 -0
  696. package/dist/shared/{stack.7b3vsM8_.d.ts → stack.BK9Z2dcL.d.ts} +2 -2
  697. package/dist/shared/stack.BMHoxAn7.d.mts +707 -0
  698. package/dist/shared/stack.BMlTZnZp.d.ts +764 -0
  699. package/dist/shared/stack.BMmvEBH_.d.ts +118 -0
  700. package/dist/shared/stack.BPLykw4s.d.ts +436 -0
  701. package/dist/shared/{stack.aqVZ6PEW.d.mts → stack.BRvqQWGt.d.cts} +40 -1
  702. package/dist/shared/{stack.aqVZ6PEW.d.cts → stack.BRvqQWGt.d.mts} +40 -1
  703. package/dist/shared/{stack.aqVZ6PEW.d.ts → stack.BRvqQWGt.d.ts} +40 -1
  704. package/dist/shared/stack.BSACE667.d.cts +23 -0
  705. package/dist/shared/{stack.DzwZw-Ck.d.cts → stack.BTStHVTy.d.cts} +4 -4
  706. package/dist/shared/stack.BV0uNV4f.d.cts +764 -0
  707. package/dist/shared/stack.BYMentwB.d.cts +47 -0
  708. package/dist/shared/stack.BYMentwB.d.mts +47 -0
  709. package/dist/shared/stack.BYMentwB.d.ts +47 -0
  710. package/dist/shared/stack.BggTHKlo.d.mts +1184 -0
  711. package/dist/shared/stack.Bt8hfw9o.d.ts +707 -0
  712. package/dist/shared/{stack.D7bewlgt.d.mts → stack.Bu2IPOLi.d.cts} +1 -0
  713. package/dist/shared/{stack.D7bewlgt.d.ts → stack.Bu2IPOLi.d.mts} +1 -0
  714. package/dist/shared/{stack.D7bewlgt.d.cts → stack.Bu2IPOLi.d.ts} +1 -0
  715. package/dist/shared/stack.BzWGB5MG.d.cts +436 -0
  716. package/dist/shared/stack.C3bU9w6L.d.ts +351 -0
  717. package/dist/shared/stack.C4oVW2qK.d.cts +507 -0
  718. package/dist/shared/stack.CGmh-Lpe.d.ts +408 -0
  719. package/dist/shared/stack.CKXzdGiJ.d.cts +3 -0
  720. package/dist/shared/stack.CKXzdGiJ.d.mts +3 -0
  721. package/dist/shared/stack.CKXzdGiJ.d.ts +3 -0
  722. package/dist/shared/{stack.C3GBG8in.d.ts → stack.COrJrztD.d.cts} +1 -1
  723. package/dist/shared/{stack.C3GBG8in.d.cts → stack.COrJrztD.d.mts} +1 -1
  724. package/dist/shared/{stack.C3GBG8in.d.mts → stack.COrJrztD.d.ts} +1 -1
  725. package/dist/shared/stack.Cbd7sD5M.d.mts +118 -0
  726. package/dist/shared/{stack.B9NtGpAR.d.ts → stack.CcjENrr4.d.cts} +1 -5
  727. package/dist/shared/stack.CfK5NKlK.d.mts +613 -0
  728. package/dist/shared/stack.Cmg7lzzy.d.cts +44 -0
  729. package/dist/shared/stack.Cmg7lzzy.d.mts +44 -0
  730. package/dist/shared/stack.Cmg7lzzy.d.ts +44 -0
  731. package/dist/shared/stack.CpE1mS3p.d.ts +331 -0
  732. package/dist/shared/stack.CskhFw3z.d.mts +23 -0
  733. package/dist/shared/stack.CtrnoQgH.d.cts +1184 -0
  734. package/dist/shared/stack.CvlC5kqe.d.cts +331 -0
  735. package/dist/shared/stack.CxKc9evq.d.ts +23 -0
  736. package/dist/shared/{stack.lkebw2nj.d.mts → stack.DVEjWKCT.d.cts} +19 -5
  737. package/dist/shared/{stack.lkebw2nj.d.ts → stack.DVEjWKCT.d.mts} +19 -5
  738. package/dist/shared/{stack.lkebw2nj.d.cts → stack.DVEjWKCT.d.ts} +19 -5
  739. package/dist/shared/{stack.Cp_6mO5s.d.mts → stack.DbbvHbhn.d.mts} +1 -5
  740. package/dist/shared/{stack.DseBJmGF.d.ts → stack.DfrRYOIl.d.ts} +4 -4
  741. package/dist/shared/stack.DiuRuzIs.d.cts +613 -0
  742. package/dist/shared/{stack.BMlLOMED.d.cts → stack.DjGixVx3.d.cts} +6 -2
  743. package/dist/shared/{stack.BMlLOMED.d.mts → stack.DjGixVx3.d.mts} +6 -2
  744. package/dist/shared/{stack.BMlLOMED.d.ts → stack.DjGixVx3.d.ts} +6 -2
  745. package/dist/shared/stack.DlCycSM-.d.mts +331 -0
  746. package/dist/shared/{stack.DycBcTeg.d.mts → stack.DmpPDPxA.d.cts} +2 -2
  747. package/dist/shared/stack.Doy2_wgl.d.mts +408 -0
  748. package/dist/shared/stack.DxHPKr2R.d.mts +436 -0
  749. package/dist/shared/stack.Mak7pzIV.d.cts +533 -0
  750. package/dist/shared/stack.OYT8WU4n.d.mts +351 -0
  751. package/dist/shared/{stack.CPsYC2-Z.d.cts → stack.fdi94T4S.d.cts} +7 -7
  752. package/dist/shared/{stack.CPsYC2-Z.d.mts → stack.fdi94T4S.d.mts} +7 -7
  753. package/dist/shared/{stack.CPsYC2-Z.d.ts → stack.fdi94T4S.d.ts} +7 -7
  754. package/dist/shared/{stack.Dlgtumru.d.cts → stack.kaCV7vEL.d.ts} +1 -5
  755. package/dist/shared/stack.lPKwd_v0.d.ts +1184 -0
  756. package/dist/shared/stack.lsbdKRj7.d.mts +764 -0
  757. package/dist/shared/stack.v2O65JqF.d.cts +351 -0
  758. package/dist/shared/stack.zch70Loj.d.cts +408 -0
  759. package/dist/tanstack/index.cjs +2 -0
  760. package/dist/tanstack/index.d.cts +27 -5
  761. package/dist/tanstack/index.d.mts +27 -5
  762. package/dist/tanstack/index.d.ts +27 -5
  763. package/dist/tanstack/index.mjs +1 -0
  764. package/dist/tanstack/server.cjs +9 -0
  765. package/dist/tanstack/server.d.cts +15 -0
  766. package/dist/tanstack/server.d.mts +15 -0
  767. package/dist/tanstack/server.d.ts +15 -0
  768. package/dist/tanstack/server.mjs +7 -0
  769. package/package.json +198 -3
  770. package/src/__tests__/ai-chat-client-runtime.test.ts +481 -0
  771. package/src/__tests__/ai-chat-client-runtime.typecheck.tsx +130 -0
  772. package/src/__tests__/ai-chat-lifecycle-migrations.typecheck.ts +61 -0
  773. package/src/__tests__/ai-chat-query-keys.test.ts +125 -22
  774. package/src/__tests__/auth-provider.test.tsx +41 -314
  775. package/src/__tests__/auth-test-utils.ts +24 -0
  776. package/src/__tests__/authorization-client.test.tsx +767 -0
  777. package/src/__tests__/authorization-contraction.test.ts +182 -0
  778. package/src/__tests__/authorization-remote.test.ts +222 -0
  779. package/src/__tests__/authorization-server.test.ts +90 -0
  780. package/src/__tests__/authorization.test.ts +652 -0
  781. package/src/__tests__/authorization.typecheck.ts +671 -0
  782. package/src/__tests__/backend-plugin-factories.test.ts +54 -0
  783. package/src/__tests__/backend-plugin-factories.typecheck.ts +133 -0
  784. package/src/__tests__/client-plugin-ssr-loaders.test.ts +304 -138
  785. package/src/__tests__/client-runtime.test.ts +1021 -0
  786. package/src/__tests__/client-runtime.typecheck.ts +107 -0
  787. package/src/__tests__/client-stack-test-utils.ts +36 -0
  788. package/src/__tests__/content-lifecycle-migrations.typecheck.ts +122 -0
  789. package/src/__tests__/endpoint-inventory.test.ts +768 -0
  790. package/src/__tests__/form-builder-query-keys.test.ts +32 -0
  791. package/src/__tests__/i18n-provider.test.tsx +4 -3
  792. package/src/__tests__/initial-identity-hydration.test.tsx +156 -0
  793. package/src/__tests__/initial-identity-layouts.test.tsx +204 -0
  794. package/src/__tests__/kanban-query-keys.test.ts +189 -2
  795. package/src/__tests__/managed-origin-hydration.browser.test.tsx +163 -0
  796. package/src/__tests__/media-query-keys.test.ts +91 -17
  797. package/src/__tests__/notify-provider.test.tsx +3 -2
  798. package/src/__tests__/package-metadata.test.ts +294 -0
  799. package/src/__tests__/page-component-overrides.test.tsx +3 -4
  800. package/src/__tests__/plugin-registration.test.tsx +183 -0
  801. package/src/__tests__/plugin-registration.typecheck.tsx +139 -0
  802. package/src/__tests__/plugins.test.tsx +72 -42
  803. package/src/__tests__/resource-factory.test.tsx +79 -2
  804. package/src/__tests__/resource-use-form.test.tsx +2 -2
  805. package/src/__tests__/resource-use-select.test.tsx +2 -4
  806. package/src/__tests__/router-overrides.test.tsx +20 -8
  807. package/src/__tests__/sitemap.test.ts +38 -22
  808. package/src/__tests__/stack-api.test.ts +39 -34
  809. package/src/__tests__/stack-auth.test.ts +44 -140
  810. package/src/__tests__/stack-constructors.test.ts +96 -0
  811. package/src/__tests__/stack-constructors.typecheck.ts +115 -0
  812. package/src/__tests__/use-list-state.test.tsx +7 -6
  813. package/src/__tests__/workflow-lifecycle-migrations.typecheck.ts +150 -0
  814. package/src/api/index.ts +204 -99
  815. package/src/authorization/client.tsx +310 -0
  816. package/src/authorization/index.ts +873 -0
  817. package/src/authorization/json.ts +70 -0
  818. package/src/authorization/remote.ts +234 -0
  819. package/src/authorization/server.ts +171 -0
  820. package/src/client/__tests__/server-origin.test.ts +119 -0
  821. package/src/client/components/compose.tsx +126 -18
  822. package/src/client/hooks/index.ts +12 -0
  823. package/src/client/hooks/use-list-state.ts +7 -13
  824. package/src/client/index.ts +105 -50
  825. package/src/client/runtime.ts +414 -0
  826. package/src/client/server.ts +174 -0
  827. package/src/context/auth.tsx +205 -154
  828. package/src/context/index.ts +10 -4
  829. package/src/context/provider.tsx +96 -57
  830. package/src/context/router.tsx +7 -0
  831. package/src/context/site-navigation.ts +52 -0
  832. package/src/next/layout.tsx +81 -0
  833. package/src/next/page.tsx +16 -3
  834. package/src/next/router.tsx +1 -1
  835. package/src/next/server.ts +5 -0
  836. package/src/plugin-registration.ts +70 -0
  837. package/src/plugins/ai-chat/__tests__/authorization.test.ts +2051 -0
  838. package/src/plugins/ai-chat/__tests__/chat-hooks.test.tsx +147 -0
  839. package/src/plugins/ai-chat/__tests__/chat-input-authorization.test.tsx +188 -0
  840. package/src/plugins/ai-chat/__tests__/client-sweep.test.tsx +1506 -34
  841. package/src/plugins/ai-chat/__tests__/hooks.test.tsx +131 -23
  842. package/src/plugins/ai-chat/api/getters.ts +2 -2
  843. package/src/plugins/ai-chat/api/index.ts +6 -1
  844. package/src/plugins/ai-chat/api/lifecycle-migrations.ts +20 -0
  845. package/src/plugins/ai-chat/api/operations.ts +1865 -0
  846. package/src/plugins/ai-chat/api/plugin.ts +78 -1168
  847. package/src/plugins/ai-chat/api/serializers.ts +30 -0
  848. package/src/plugins/ai-chat/client/components/chat-input.tsx +228 -129
  849. package/src/plugins/ai-chat/client/components/chat-interface.tsx +776 -183
  850. package/src/plugins/ai-chat/client/components/chat-layout.tsx +6 -7
  851. package/src/plugins/ai-chat/client/components/chat-message.tsx +1 -1
  852. package/src/plugins/ai-chat/client/components/chat-sidebar.tsx +57 -37
  853. package/src/plugins/ai-chat/client/components/pages/404-page.tsx +1 -1
  854. package/src/plugins/ai-chat/client/components/pages/chat-page.internal.tsx +5 -3
  855. package/src/plugins/ai-chat/client/components/pages/chat-page.tsx +56 -15
  856. package/src/plugins/ai-chat/client/components/shared/default-error.tsx +1 -1
  857. package/src/plugins/ai-chat/client/components/tool-call-display.tsx +1 -1
  858. package/src/plugins/ai-chat/client/hooks/ai-chat-resource.ts +1 -1
  859. package/src/plugins/ai-chat/client/hooks/chat-hooks.tsx +253 -20
  860. package/src/plugins/ai-chat/client/index.ts +1 -0
  861. package/src/plugins/ai-chat/client/navigation.ts +11 -0
  862. package/src/plugins/ai-chat/client/overrides.ts +47 -11
  863. package/src/plugins/ai-chat/client/plugin.tsx +208 -111
  864. package/src/plugins/ai-chat/permissions.ts +89 -0
  865. package/src/plugins/ai-chat/query-keys.ts +183 -25
  866. package/src/plugins/ai-chat/types.ts +7 -5
  867. package/src/plugins/api/create-endpoint.ts +40 -22
  868. package/src/plugins/api/endpoint-inventory.ts +206 -0
  869. package/src/plugins/api/index.ts +38 -4
  870. package/src/plugins/api/operation.ts +600 -0
  871. package/src/plugins/blog/__tests__/authorization.test.ts +1366 -0
  872. package/src/plugins/blog/__tests__/client-runtime.browser.test.tsx +257 -0
  873. package/src/plugins/blog/__tests__/client-runtime.test.ts +283 -0
  874. package/src/plugins/blog/__tests__/client-runtime.typecheck.tsx +98 -0
  875. package/src/plugins/blog/__tests__/client-sweep.test.tsx +212 -37
  876. package/src/plugins/blog/api/getters.ts +3 -3
  877. package/src/plugins/blog/api/index.ts +2 -0
  878. package/src/plugins/blog/api/lifecycle-migrations.ts +19 -0
  879. package/src/plugins/blog/api/mutations.ts +26 -5
  880. package/src/plugins/blog/api/operations.ts +727 -0
  881. package/src/plugins/blog/api/plugin.ts +99 -504
  882. package/src/plugins/blog/client/components/forms/image-field.tsx +2 -1
  883. package/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.tsx +2 -1
  884. package/src/plugins/blog/client/components/forms/post-forms.tsx +61 -33
  885. package/src/plugins/blog/client/components/pages/404-page.tsx +3 -1
  886. package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +2 -1
  887. package/src/plugins/blog/client/components/pages/edit-post-page.tsx +28 -5
  888. package/src/plugins/blog/client/components/pages/home-page.internal.tsx +2 -1
  889. package/src/plugins/blog/client/components/pages/home-page.tsx +7 -4
  890. package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +2 -1
  891. package/src/plugins/blog/client/components/pages/new-post-page.tsx +5 -2
  892. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +2 -1
  893. package/src/plugins/blog/client/components/pages/post-page.tsx +38 -4
  894. package/src/plugins/blog/client/components/pages/tag-page.internal.tsx +2 -1
  895. package/src/plugins/blog/client/components/pages/tag-page.tsx +5 -1
  896. package/src/plugins/blog/client/components/shared/collapsible-tag-list.tsx +2 -1
  897. package/src/plugins/blog/client/components/shared/default-error.tsx +3 -1
  898. package/src/plugins/blog/client/components/shared/on-this-page.tsx +5 -2
  899. package/src/plugins/blog/client/components/shared/page-wrapper.tsx +2 -1
  900. package/src/plugins/blog/client/components/shared/post-card.tsx +2 -1
  901. package/src/plugins/blog/client/components/shared/posts-list.tsx +2 -1
  902. package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +2 -1
  903. package/src/plugins/blog/client/components/shared/search-input.tsx +1 -1
  904. package/src/plugins/blog/client/constants.ts +2 -0
  905. package/src/plugins/blog/client/hooks/blog-resource.ts +2 -1
  906. package/src/plugins/blog/client/overrides.ts +1 -6
  907. package/src/plugins/blog/client/plugin.tsx +145 -129
  908. package/src/plugins/blog/permissions.ts +44 -0
  909. package/src/plugins/client/index.ts +108 -7
  910. package/src/plugins/client/resource/hooks.tsx +41 -18
  911. package/src/plugins/client/resource/internal.ts +77 -61
  912. package/src/plugins/client/resource/queries.ts +3 -4
  913. package/src/plugins/client/resource/use-form.ts +23 -20
  914. package/src/plugins/client/resource/use-select.ts +40 -34
  915. package/src/plugins/cms/__tests__/authorization.test.ts +2188 -0
  916. package/src/plugins/cms/__tests__/client-runtime.browser.test.tsx +245 -0
  917. package/src/plugins/cms/__tests__/client-runtime.test.ts +320 -0
  918. package/src/plugins/cms/__tests__/client-runtime.typecheck.tsx +208 -0
  919. package/src/plugins/cms/__tests__/client-sweep.test.tsx +202 -50
  920. package/src/plugins/cms/api/getters.ts +4 -4
  921. package/src/plugins/cms/api/index.ts +20 -0
  922. package/src/plugins/cms/api/lifecycle-migrations.ts +15 -0
  923. package/src/plugins/cms/api/mutations.ts +2 -2
  924. package/src/plugins/cms/api/operations.ts +2218 -0
  925. package/src/plugins/cms/api/plugin.ts +169 -1047
  926. package/src/plugins/cms/api/relations.ts +3 -1
  927. package/src/plugins/cms/client/components/forms/content-form.tsx +2 -1
  928. package/src/plugins/cms/client/components/forms/file-upload.tsx +3 -1
  929. package/src/plugins/cms/client/components/forms/relation-field.tsx +3 -1
  930. package/src/plugins/cms/client/components/inverse-relations-panel.tsx +29 -17
  931. package/src/plugins/cms/client/components/pages/404-page.tsx +7 -5
  932. package/src/plugins/cms/client/components/pages/content-editor-page.internal.tsx +19 -10
  933. package/src/plugins/cms/client/components/pages/content-editor-page.tsx +50 -12
  934. package/src/plugins/cms/client/components/pages/content-list-page.internal.tsx +48 -34
  935. package/src/plugins/cms/client/components/pages/content-list-page.tsx +8 -1
  936. package/src/plugins/cms/client/components/pages/dashboard-page.internal.tsx +15 -8
  937. package/src/plugins/cms/client/components/pages/dashboard-page.tsx +5 -1
  938. package/src/plugins/cms/client/components/shared/page-wrapper.tsx +2 -1
  939. package/src/plugins/cms/client/constants.ts +2 -0
  940. package/src/plugins/cms/client/hooks/cms-resource.ts +2 -1
  941. package/src/plugins/cms/client/index.ts +6 -1
  942. package/src/plugins/cms/client/overrides.ts +46 -6
  943. package/src/plugins/cms/client/plugin.tsx +135 -80
  944. package/src/plugins/cms/permissions.ts +43 -0
  945. package/src/plugins/cms/types.ts +174 -46
  946. package/src/plugins/comments/__tests__/authorization.test.ts +1570 -0
  947. package/src/plugins/comments/__tests__/client-runtime.browser.test.tsx +207 -0
  948. package/src/plugins/comments/__tests__/client-runtime.test.ts +224 -0
  949. package/src/plugins/comments/__tests__/client-runtime.typecheck.tsx +85 -0
  950. package/src/plugins/comments/__tests__/client-sweep.test.tsx +445 -82
  951. package/src/plugins/comments/api/getters.ts +19 -3
  952. package/src/plugins/comments/api/index.ts +2 -6
  953. package/src/plugins/comments/api/lifecycle-migrations.ts +20 -0
  954. package/src/plugins/comments/api/mutations.ts +261 -88
  955. package/src/plugins/comments/api/operations.ts +742 -0
  956. package/src/plugins/comments/api/plugin.ts +76 -548
  957. package/src/plugins/comments/client/components/comment-count.tsx +38 -5
  958. package/src/plugins/comments/client/components/comment-thread.tsx +148 -110
  959. package/src/plugins/comments/client/components/pages/moderation-page.internal.tsx +144 -78
  960. package/src/plugins/comments/client/components/pages/moderation-page.tsx +18 -2
  961. package/src/plugins/comments/client/components/pages/moderation-state.ts +13 -0
  962. package/src/plugins/comments/client/components/pages/my-comments-page.internal.tsx +38 -30
  963. package/src/plugins/comments/client/components/pages/my-comments-page.tsx +3 -1
  964. package/src/plugins/comments/client/components/pages/resource-comments-page.internal.tsx +29 -30
  965. package/src/plugins/comments/client/components/pages/resource-comments-page.tsx +10 -1
  966. package/src/plugins/comments/client/components/shared/page-wrapper.tsx +2 -1
  967. package/src/plugins/comments/client/components/shared/pagination.tsx +2 -1
  968. package/src/plugins/comments/client/constants.ts +2 -0
  969. package/src/plugins/comments/client/hooks/use-comments.tsx +430 -421
  970. package/src/plugins/comments/client/localization/comments-thread.ts +1 -0
  971. package/src/plugins/comments/client/plugin.tsx +113 -72
  972. package/src/plugins/comments/permissions.ts +68 -0
  973. package/src/plugins/comments/query-keys.ts +9 -10
  974. package/src/plugins/comments/schemas.ts +7 -8
  975. package/src/plugins/form-builder/__tests__/authorization.test.ts +1600 -0
  976. package/src/plugins/form-builder/__tests__/client-runtime.browser.test.tsx +255 -0
  977. package/src/plugins/form-builder/__tests__/client-runtime.test.ts +132 -0
  978. package/src/plugins/form-builder/__tests__/client-runtime.typecheck.tsx +77 -0
  979. package/src/plugins/form-builder/__tests__/client-sweep.test.tsx +350 -54
  980. package/src/plugins/form-builder/__tests__/form-renderer-authorization.test.tsx +162 -0
  981. package/src/plugins/form-builder/api/getters.ts +21 -5
  982. package/src/plugins/form-builder/api/index.ts +31 -0
  983. package/src/plugins/form-builder/api/lifecycle-migrations.ts +17 -0
  984. package/src/plugins/form-builder/api/operations.ts +1493 -0
  985. package/src/plugins/form-builder/api/plugin.ts +125 -632
  986. package/src/plugins/form-builder/api/query-key-defs.ts +7 -0
  987. package/src/plugins/form-builder/api/serializers.ts +1 -0
  988. package/src/plugins/form-builder/client/components/forms/form-renderer.tsx +49 -19
  989. package/src/plugins/form-builder/client/components/pages/404-page.tsx +9 -9
  990. package/src/plugins/form-builder/client/components/pages/form-builder-page.internal.tsx +54 -30
  991. package/src/plugins/form-builder/client/components/pages/form-builder-page.tsx +42 -9
  992. package/src/plugins/form-builder/client/components/pages/form-list-page.internal.tsx +46 -34
  993. package/src/plugins/form-builder/client/components/pages/form-list-page.tsx +6 -2
  994. package/src/plugins/form-builder/client/components/pages/submissions-page.internal.tsx +98 -64
  995. package/src/plugins/form-builder/client/components/pages/submissions-page.tsx +29 -9
  996. package/src/plugins/form-builder/client/components/shared/page-wrapper.tsx +2 -1
  997. package/src/plugins/form-builder/client/constants.ts +2 -0
  998. package/src/plugins/form-builder/client/hooks/form-builder-hooks.tsx +68 -4
  999. package/src/plugins/form-builder/client/hooks/form-builder-resource.ts +2 -1
  1000. package/src/plugins/form-builder/client/hooks/index.tsx +1 -0
  1001. package/src/plugins/form-builder/client/overrides.ts +1 -6
  1002. package/src/plugins/form-builder/client/plugin.tsx +128 -96
  1003. package/src/plugins/form-builder/permissions.ts +94 -0
  1004. package/src/plugins/form-builder/query-keys.ts +28 -3
  1005. package/src/plugins/form-builder/schemas.ts +9 -1
  1006. package/src/plugins/form-builder/types.ts +173 -41
  1007. package/src/plugins/kanban/__tests__/authorization.test.ts +1382 -0
  1008. package/src/plugins/kanban/__tests__/client-runtime.browser.test.tsx +302 -0
  1009. package/src/plugins/kanban/__tests__/client-runtime.test.ts +130 -0
  1010. package/src/plugins/kanban/__tests__/client-runtime.typecheck.tsx +81 -0
  1011. package/src/plugins/kanban/__tests__/client-sweep.test.tsx +418 -33
  1012. package/src/plugins/kanban/__tests__/identity-partition.test.tsx +306 -0
  1013. package/src/plugins/kanban/api/getters.ts +65 -50
  1014. package/src/plugins/kanban/api/index.ts +55 -4
  1015. package/src/plugins/kanban/api/lifecycle-migrations.ts +25 -0
  1016. package/src/plugins/kanban/api/mutations.ts +3 -3
  1017. package/src/plugins/kanban/api/operations.ts +2065 -0
  1018. package/src/plugins/kanban/api/plugin.ts +83 -1013
  1019. package/src/plugins/kanban/api/serializers.ts +26 -0
  1020. package/src/plugins/kanban/client/components/forms/board-form.tsx +3 -1
  1021. package/src/plugins/kanban/client/components/forms/column-form.tsx +3 -1
  1022. package/src/plugins/kanban/client/components/forms/task-form.tsx +92 -74
  1023. package/src/plugins/kanban/client/components/pages/404-page.tsx +6 -9
  1024. package/src/plugins/kanban/client/components/pages/board-page.internal.tsx +57 -74
  1025. package/src/plugins/kanban/client/components/pages/board-page.tsx +31 -7
  1026. package/src/plugins/kanban/client/components/pages/boards-list-page.internal.tsx +54 -45
  1027. package/src/plugins/kanban/client/components/pages/boards-list-page.tsx +2 -1
  1028. package/src/plugins/kanban/client/components/pages/new-board-page.internal.tsx +8 -12
  1029. package/src/plugins/kanban/client/components/pages/new-board-page.tsx +2 -1
  1030. package/src/plugins/kanban/client/components/shared/column-content.tsx +61 -48
  1031. package/src/plugins/kanban/client/components/shared/default-error.tsx +3 -1
  1032. package/src/plugins/kanban/client/components/shared/kanban-board.tsx +6 -6
  1033. package/src/plugins/kanban/client/components/shared/permission-access-any.tsx +32 -0
  1034. package/src/plugins/kanban/client/components/shared/task-card.tsx +64 -20
  1035. package/src/plugins/kanban/client/components/shared/user-avatar.tsx +3 -1
  1036. package/src/plugins/kanban/client/constants.ts +2 -0
  1037. package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +55 -10
  1038. package/src/plugins/kanban/client/hooks/kanban-resource.ts +2 -1
  1039. package/src/plugins/kanban/client/overrides.ts +0 -5
  1040. package/src/plugins/kanban/client/plugin.tsx +201 -113
  1041. package/src/plugins/kanban/permissions.ts +100 -0
  1042. package/src/plugins/kanban/query-keys.ts +61 -21
  1043. package/src/plugins/kanban/schemas.ts +44 -18
  1044. package/src/plugins/kanban/types.ts +381 -1
  1045. package/src/plugins/media/__tests__/authorization.test.ts +1769 -0
  1046. package/src/plugins/media/__tests__/client-runtime.browser.test.tsx +975 -0
  1047. package/src/plugins/media/__tests__/client-runtime.test.ts +539 -0
  1048. package/src/plugins/media/__tests__/client-runtime.typecheck.tsx +135 -0
  1049. package/src/plugins/media/__tests__/client-sweep.test.tsx +292 -24
  1050. package/src/plugins/media/__tests__/identity-partition.test.tsx +741 -0
  1051. package/src/plugins/media/__tests__/plugin.test.ts +68 -28
  1052. package/src/plugins/media/__tests__/query-key-defs.test.ts +32 -2
  1053. package/src/plugins/media/api/adapters/vercel-blob.ts +84 -8
  1054. package/src/plugins/media/api/getters.ts +6 -6
  1055. package/src/plugins/media/api/index.ts +3 -0
  1056. package/src/plugins/media/api/lifecycle-migrations.ts +11 -0
  1057. package/src/plugins/media/api/mutations.ts +19 -13
  1058. package/src/plugins/media/api/operations.ts +1873 -0
  1059. package/src/plugins/media/api/plugin.ts +211 -899
  1060. package/src/plugins/media/api/query-key-defs.ts +66 -4
  1061. package/src/plugins/media/api/serializers.ts +4 -2
  1062. package/src/plugins/media/api/storage-adapter.ts +22 -4
  1063. package/src/plugins/media/asset-url.ts +14 -0
  1064. package/src/plugins/media/client/components/media-picker/asset-card.tsx +105 -98
  1065. package/src/plugins/media/client/components/media-picker/folder-tree.tsx +82 -60
  1066. package/src/plugins/media/client/components/media-picker/index.tsx +235 -171
  1067. package/src/plugins/media/client/components/media-picker/upload-tab.tsx +2 -10
  1068. package/src/plugins/media/client/components/media-picker/url-tab.tsx +1 -8
  1069. package/src/plugins/media/client/components/pages/library-page.internal.tsx +103 -82
  1070. package/src/plugins/media/client/components/pages/library-page.tsx +4 -2
  1071. package/src/plugins/media/client/components/upload-permission-check.tsx +75 -0
  1072. package/src/plugins/media/client/constants.ts +2 -0
  1073. package/src/plugins/media/client/hooks/media-resource.ts +2 -1
  1074. package/src/plugins/media/client/hooks/use-media.tsx +292 -49
  1075. package/src/plugins/media/client/index.ts +16 -3
  1076. package/src/plugins/media/client/overrides.ts +6 -17
  1077. package/src/plugins/media/client/plugin.tsx +188 -123
  1078. package/src/plugins/media/client/upload.ts +170 -53
  1079. package/src/plugins/media/db.ts +8 -0
  1080. package/src/plugins/media/permissions.ts +61 -0
  1081. package/src/plugins/media/query-keys.ts +63 -19
  1082. package/src/plugins/media/types.ts +8 -2
  1083. package/src/plugins/open-api/__tests__/route-introspection.test.ts +277 -0
  1084. package/src/plugins/open-api/api/generator.ts +49 -8
  1085. package/src/plugins/open-api/api/plugin.ts +36 -14
  1086. package/src/plugins/route-docs/client/components/pages/docs-page.tsx +63 -23
  1087. package/src/plugins/route-docs/client/constants.ts +2 -0
  1088. package/src/plugins/route-docs/client/hooks.ts +23 -13
  1089. package/src/plugins/route-docs/client/index.ts +7 -1
  1090. package/src/plugins/route-docs/client/plugin.tsx +222 -145
  1091. package/src/plugins/route-docs/client/schema.ts +31 -0
  1092. package/src/plugins/route-docs/generator.ts +9 -5
  1093. package/src/plugins/ui-builder/__tests__/client-sweep.test.tsx +427 -48
  1094. package/src/plugins/ui-builder/client/components/page-renderer.tsx +58 -16
  1095. package/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.tsx +47 -26
  1096. package/src/plugins/ui-builder/client/components/pages/page-builder-page.tsx +43 -8
  1097. package/src/plugins/ui-builder/client/components/pages/page-list-page.internal.tsx +38 -19
  1098. package/src/plugins/ui-builder/client/components/pages/page-list-page.tsx +8 -2
  1099. package/src/plugins/ui-builder/client/components/shared/default-error.tsx +2 -1
  1100. package/src/plugins/ui-builder/client/components/shared/page-wrapper.tsx +2 -1
  1101. package/src/plugins/ui-builder/client/constants.ts +2 -0
  1102. package/src/plugins/ui-builder/client/hooks/ui-builder-resource.ts +2 -1
  1103. package/src/plugins/ui-builder/client/index.ts +4 -1
  1104. package/src/plugins/ui-builder/client/overrides.ts +16 -21
  1105. package/src/plugins/ui-builder/client/plugin.tsx +119 -66
  1106. package/src/plugins/ui-builder/client/registry.ts +3 -5
  1107. package/src/plugins/ui-builder/types.ts +7 -4
  1108. package/src/plugins/utils.ts +5 -1
  1109. package/src/react-router/index.tsx +5 -0
  1110. package/src/react-router/layout.ts +43 -0
  1111. package/src/react-router/page.tsx +12 -5
  1112. package/src/react-router/router.tsx +1 -1
  1113. package/src/shared/auth-types.ts +19 -70
  1114. package/src/shared/entry-factories.ts +3 -3
  1115. package/src/shared/initial-identity.ts +73 -0
  1116. package/src/shared/list-state.ts +12 -0
  1117. package/src/shared/types.ts +1 -0
  1118. package/src/tanstack/index.tsx +5 -0
  1119. package/src/tanstack/layout.ts +36 -0
  1120. package/src/tanstack/page.tsx +7 -2
  1121. package/src/tanstack/router.tsx +1 -1
  1122. package/src/tanstack/server.ts +18 -0
  1123. package/src/types.ts +557 -65
  1124. package/dist/shared/stack.B8vdOMnQ.d.cts +0 -329
  1125. package/dist/shared/stack.BISAZ5LX.d.mts +0 -492
  1126. package/dist/shared/stack.BL5PvShn.d.mts +0 -193
  1127. package/dist/shared/stack.Be1QIHEn.d.cts +0 -23
  1128. package/dist/shared/stack.Be1QIHEn.d.mts +0 -23
  1129. package/dist/shared/stack.Be1QIHEn.d.ts +0 -23
  1130. package/dist/shared/stack.BjvOk_Bs.d.cts +0 -492
  1131. package/dist/shared/stack.BozPgbrZ.d.cts +0 -201
  1132. package/dist/shared/stack.BozPgbrZ.d.mts +0 -201
  1133. package/dist/shared/stack.BozPgbrZ.d.ts +0 -201
  1134. package/dist/shared/stack.BqTR6qi2.d.ts +0 -193
  1135. package/dist/shared/stack.BsmDN8r9.d.cts +0 -406
  1136. package/dist/shared/stack.C1ATQ3pd.d.ts +0 -416
  1137. package/dist/shared/stack.C4_gEENS.d.cts +0 -97
  1138. package/dist/shared/stack.C4_gEENS.d.mts +0 -97
  1139. package/dist/shared/stack.C4_gEENS.d.ts +0 -97
  1140. package/dist/shared/stack.C5Y5lViI.d.cts +0 -461
  1141. package/dist/shared/stack.C8SwdUz8.d.ts +0 -461
  1142. package/dist/shared/stack.CBsp9rDM.d.cts +0 -193
  1143. package/dist/shared/stack.CKGjOI3Z.d.cts +0 -840
  1144. package/dist/shared/stack.Cf-DbL1A.d.ts +0 -329
  1145. package/dist/shared/stack.CuI_-z-_.d.cts +0 -560
  1146. package/dist/shared/stack.D2RVkQD8.d.mts +0 -560
  1147. package/dist/shared/stack.DHTvwoNG.d.mts +0 -329
  1148. package/dist/shared/stack.DJaKVY7v.d.cts +0 -76
  1149. package/dist/shared/stack.DJaKVY7v.d.mts +0 -76
  1150. package/dist/shared/stack.DJaKVY7v.d.ts +0 -76
  1151. package/dist/shared/stack.DKZMaVr6.d.cts +0 -416
  1152. package/dist/shared/stack.DOzsgzkY.d.ts +0 -406
  1153. package/dist/shared/stack.DQq8DEIv.d.mts +0 -461
  1154. package/dist/shared/stack.DXrOtuek.d.ts +0 -560
  1155. package/dist/shared/stack.DZHEHd-S.d.mts +0 -840
  1156. package/dist/shared/stack.Dd-8shBE.d.ts +0 -492
  1157. package/dist/shared/stack.EOPVnJrF.d.cts +0 -39
  1158. package/dist/shared/stack.EOPVnJrF.d.mts +0 -39
  1159. package/dist/shared/stack.EOPVnJrF.d.ts +0 -39
  1160. package/dist/shared/stack.NGKtwA6S.d.mts +0 -406
  1161. package/dist/shared/stack.WELCDuMs.d.ts +0 -840
  1162. package/dist/shared/stack.aXdBOJAR.d.cts +0 -173
  1163. package/dist/shared/stack.aXdBOJAR.d.mts +0 -173
  1164. package/dist/shared/stack.aXdBOJAR.d.ts +0 -173
  1165. package/dist/shared/stack.oBokjN_J.d.mts +0 -416
  1166. package/dist/shared/{stack.D18Dq3ve.d.mts → stack.CKc_Bais.d.cts} +8 -8
  1167. package/dist/shared/{stack.D18Dq3ve.d.ts → stack.CKc_Bais.d.mts} +8 -8
  1168. package/dist/shared/{stack.D18Dq3ve.d.cts → stack.CKc_Bais.d.ts} +8 -8
@@ -0,0 +1,1865 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import type { DBAdapter as Adapter } from "@btst/db";
3
+ import type { PermissionFactsFor } from "@btst/stack/authorization";
4
+ import {
5
+ defineOperation,
6
+ definePassthroughOperation,
7
+ type DeepReadonly,
8
+ type Operation,
9
+ OperationHttpError,
10
+ type OperationContext,
11
+ } from "@btst/stack/plugins/api";
12
+ import {
13
+ convertToModelMessages,
14
+ stepCountIs,
15
+ streamText,
16
+ type LanguageModel,
17
+ type Tool,
18
+ type UIMessage,
19
+ } from "ai";
20
+ import { z } from "zod";
21
+ import { aiChatPermissions } from "../permissions";
22
+ import {
23
+ chatRequestSchema,
24
+ createConversationSchema,
25
+ updateConversationSchema,
26
+ } from "../schemas";
27
+ import type {
28
+ Conversation,
29
+ Message,
30
+ SerializedConversation,
31
+ SerializedMessage,
32
+ } from "../types";
33
+ import { getAllConversations, getConversationById } from "./getters";
34
+ import {
35
+ BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST,
36
+ BUILT_IN_PAGE_TOOL_SCHEMAS,
37
+ } from "./page-tools";
38
+ import { serializeConversation, serializeMessage } from "./serializers";
39
+
40
+ type TransactionAdapter = Parameters<Parameters<Adapter["transaction"]>[0]>[0];
41
+ type ActiveAdapter = Omit<Adapter, "transaction"> &
42
+ Partial<Pick<Adapter, "transaction">>;
43
+ type MemoryHistoryLockContext = {
44
+ owner: object;
45
+ adapter: ActiveAdapter;
46
+ inTransaction?: boolean;
47
+ rollbackError?: unknown;
48
+ rollbackOnly?: boolean;
49
+ };
50
+
51
+ export type AiChatAccess = "authorized" | "public";
52
+
53
+ /** Runtime input for one conversation operation. */
54
+ export const ConversationOperationInputSchema = z.object({ id: z.string() });
55
+ /** Runtime input for one conversation rename operation. */
56
+ export const UpdateConversationOperationInputSchema = z.object({
57
+ id: z.string(),
58
+ data: updateConversationSchema,
59
+ });
60
+ /** Runtime input accepted only from trusted stream callers. */
61
+ export const ChatOperationInputSchema = chatRequestSchema.extend({
62
+ trustedUserId: z.string().optional(),
63
+ }) as unknown as z.ZodType<ChatOperationInput>;
64
+ /** JSON-safe AI SDK message shape accepted at the operation boundary. */
65
+ export type ChatOperationInput = {
66
+ readonly messages: readonly (
67
+ | {
68
+ readonly role: "system" | "user" | "assistant" | "data";
69
+ readonly content: string;
70
+ readonly id?: string;
71
+ }
72
+ | {
73
+ readonly role: "system" | "user" | "assistant" | "data";
74
+ readonly parts: readonly ({
75
+ readonly type: string;
76
+ readonly text?: string;
77
+ } & Record<string, any>)[];
78
+ readonly id?: string;
79
+ readonly metadata?: any;
80
+ }
81
+ )[];
82
+ readonly conversationId?: string;
83
+ readonly model?: string;
84
+ readonly pageContext?: string;
85
+ readonly availableTools?: readonly string[];
86
+ readonly routeName?: string;
87
+ readonly trustedUserId?: string;
88
+ };
89
+ const EmptyInputSchema = z.object({});
90
+
91
+ type ConversationReadFacts = PermissionFactsFor<
92
+ typeof aiChatPermissions.conversation.read
93
+ >;
94
+ type ConversationRecordFacts = PermissionFactsFor<
95
+ typeof aiChatPermissions.conversation.update
96
+ >;
97
+ type StreamStartFacts = PermissionFactsFor<
98
+ typeof aiChatPermissions.stream.start
99
+ >;
100
+
101
+ /** One conversation and its serialized message history. */
102
+ export type AiChatConversationResult = SerializedConversation & {
103
+ readonly messages: readonly SerializedMessage[];
104
+ };
105
+
106
+ /** Complete AI Chat operation inventory shared by every server transport. */
107
+ export type AiChatOperations = {
108
+ readonly startStream: Operation<
109
+ typeof ChatOperationInputSchema,
110
+ typeof aiChatPermissions.stream.start,
111
+ Response,
112
+ true
113
+ >;
114
+ readonly listConversations: Operation<
115
+ typeof EmptyInputSchema,
116
+ typeof aiChatPermissions.conversation.read,
117
+ readonly SerializedConversation[]
118
+ >;
119
+ readonly getConversation: Operation<
120
+ typeof ConversationOperationInputSchema,
121
+ typeof aiChatPermissions.conversation.read,
122
+ AiChatConversationResult
123
+ >;
124
+ readonly createConversation: Operation<
125
+ typeof createConversationSchema,
126
+ typeof aiChatPermissions.conversation.create,
127
+ SerializedConversation
128
+ >;
129
+ readonly updateConversation: Operation<
130
+ typeof UpdateConversationOperationInputSchema,
131
+ typeof aiChatPermissions.conversation.update,
132
+ SerializedConversation
133
+ >;
134
+ readonly deleteConversation: Operation<
135
+ typeof ConversationOperationInputSchema,
136
+ typeof aiChatPermissions.conversation.delete,
137
+ { readonly success: true }
138
+ >;
139
+ };
140
+
141
+ /** Executable inventory used by tests, docs, and future transport audits. */
142
+ export const AI_CHAT_OPERATION_INVENTORY = Object.freeze({
143
+ startStream: Object.freeze({
144
+ http: "POST /chat",
145
+ request: "forRequest(request).operations.aiChat.startStream",
146
+ trusted: "trusted.aiChat.startStream",
147
+ ui: Object.freeze([
148
+ "composer",
149
+ "edit",
150
+ "retry",
151
+ "attachment",
152
+ "tool-result",
153
+ ]),
154
+ semantics: Object.freeze([
155
+ "stream.start",
156
+ "conversation.create",
157
+ "message.send",
158
+ "message.edit",
159
+ "message.retry",
160
+ "attachment.send",
161
+ "tool.activate",
162
+ ]),
163
+ publicSemantics: Object.freeze([
164
+ "stream.start",
165
+ "message.send",
166
+ "message.edit",
167
+ "message.retry",
168
+ "attachment.send",
169
+ "tool.activate",
170
+ ]),
171
+ publicWhenConfigured: true,
172
+ }),
173
+ listConversations: Object.freeze({
174
+ http: "GET /chat/conversations",
175
+ request: "forRequest(request).operations.aiChat.listConversations",
176
+ trusted: "trusted.aiChat.listConversations",
177
+ ui: Object.freeze(["conversation sidebar"]),
178
+ semantics: Object.freeze(["conversation.read"]),
179
+ publicWhenConfigured: false,
180
+ }),
181
+ getConversation: Object.freeze({
182
+ http: "GET /chat/conversations/:id",
183
+ request: "forRequest(request).operations.aiChat.getConversation",
184
+ trusted: "trusted.aiChat.getConversation",
185
+ ui: Object.freeze(["conversation route"]),
186
+ semantics: Object.freeze(["conversation.read"]),
187
+ publicWhenConfigured: false,
188
+ }),
189
+ createConversation: Object.freeze({
190
+ http: "POST /chat/conversations",
191
+ request: "forRequest(request).operations.aiChat.createConversation",
192
+ trusted: "trusted.aiChat.createConversation",
193
+ ui: Object.freeze(["new chat"]),
194
+ semantics: Object.freeze(["conversation.create"]),
195
+ publicWhenConfigured: false,
196
+ }),
197
+ updateConversation: Object.freeze({
198
+ http: "PUT /chat/conversations/:id",
199
+ request: "forRequest(request).operations.aiChat.updateConversation",
200
+ trusted: "trusted.aiChat.updateConversation",
201
+ ui: Object.freeze(["rename conversation"]),
202
+ semantics: Object.freeze(["conversation.update"]),
203
+ publicWhenConfigured: false,
204
+ }),
205
+ deleteConversation: Object.freeze({
206
+ http: "DELETE /chat/conversations/:id",
207
+ request: "forRequest(request).operations.aiChat.deleteConversation",
208
+ trusted: "trusted.aiChat.deleteConversation",
209
+ ui: Object.freeze(["delete conversation"]),
210
+ semantics: Object.freeze(["conversation.delete"]),
211
+ publicWhenConfigured: false,
212
+ }),
213
+ });
214
+
215
+ /** Standalone raw getters that bypass authorization and operation lifecycle hooks. */
216
+ export const AI_CHAT_RAW_ESCAPE_HATCH_INVENTORY = Object.freeze([
217
+ "@btst/stack/plugins/ai-chat/api#getAllConversations",
218
+ "@btst/stack/plugins/ai-chat/api#getConversationById",
219
+ ]);
220
+
221
+ /** A domain/HTTP failure raised after AI Chat authorization succeeds. */
222
+ export class AiChatOperationError extends OperationHttpError {
223
+ constructor(statusCode: number, message: string, code: string) {
224
+ super(statusCode, message, code);
225
+ this.name = "AiChatOperationError";
226
+ }
227
+ }
228
+
229
+ async function runBeforeHook<T>(
230
+ hook: () => T | Promise<T>,
231
+ defaultMessage: string,
232
+ ): Promise<Awaited<T>> {
233
+ try {
234
+ return await hook();
235
+ } catch (cause) {
236
+ if (cause instanceof AiChatOperationError) throw cause;
237
+ throw new AiChatOperationError(
238
+ 403,
239
+ cause instanceof Error ? cause.message : defaultMessage,
240
+ "HOOK_DENIED",
241
+ );
242
+ }
243
+ }
244
+
245
+ /** Typed operation context supplied to AI Chat lifecycle hooks. */
246
+ export interface ChatApiContext<TInput = unknown, TFacts = unknown>
247
+ extends OperationContext<TInput, TFacts> {
248
+ readonly headers?: Headers;
249
+ readonly body?: DeepReadonly<TInput>;
250
+ readonly params?: Readonly<Record<string, string>>;
251
+ readonly query?: DeepReadonly<TInput>;
252
+ }
253
+
254
+ /** Post-authorization AI Chat domain lifecycle hooks. */
255
+ export interface AiChatBackendHooks {
256
+ onBeforeChat?: (
257
+ messages: readonly { readonly role: string; readonly content: string }[],
258
+ context: ChatApiContext<
259
+ z.output<typeof ChatOperationInputSchema>,
260
+ StreamStartFacts
261
+ >,
262
+ ) => Promise<void> | void;
263
+ onBeforeListConversations?: (
264
+ context: ChatApiContext<
265
+ z.output<typeof EmptyInputSchema>,
266
+ ConversationReadFacts
267
+ >,
268
+ ) => Promise<void> | void;
269
+ onBeforeGetConversation?: (
270
+ conversationId: string,
271
+ context: ChatApiContext<
272
+ z.output<typeof ConversationOperationInputSchema>,
273
+ ConversationReadFacts
274
+ >,
275
+ ) => Promise<void> | void;
276
+ onBeforeCreateConversation?: (
277
+ data: DeepReadonly<z.output<typeof createConversationSchema>>,
278
+ context: ChatApiContext<
279
+ z.output<typeof createConversationSchema>,
280
+ undefined
281
+ >,
282
+ ) => Promise<void> | void;
283
+ onBeforeUpdateConversation?: (
284
+ conversationId: string,
285
+ data: DeepReadonly<z.output<typeof updateConversationSchema>>,
286
+ context: ChatApiContext<
287
+ z.output<typeof UpdateConversationOperationInputSchema>,
288
+ ConversationRecordFacts
289
+ >,
290
+ ) => Promise<void> | void;
291
+ onBeforeDeleteConversation?: (
292
+ conversationId: string,
293
+ context: ChatApiContext<
294
+ z.output<typeof ConversationOperationInputSchema>,
295
+ ConversationRecordFacts
296
+ >,
297
+ ) => Promise<void> | void;
298
+ /**
299
+ * Post-authorization tool safety/filter hook. Structural route validation and
300
+ * exact `tool.activate` authorization have already succeeded.
301
+ */
302
+ onBeforeActivateTools?: (
303
+ toolNames: readonly string[],
304
+ routeName: string | undefined,
305
+ context: ChatApiContext<
306
+ z.output<typeof ChatOperationInputSchema>,
307
+ StreamStartFacts
308
+ >,
309
+ ) => Promise<readonly string[]> | readonly string[];
310
+ onAfterChat?: (
311
+ conversationId: string,
312
+ messages: readonly SerializedMessage[],
313
+ context: ChatApiContext<
314
+ z.output<typeof ChatOperationInputSchema>,
315
+ StreamStartFacts
316
+ >,
317
+ ) => Promise<void> | void;
318
+ onAfterListConversations?: (
319
+ conversations: readonly SerializedConversation[],
320
+ context: ChatApiContext<
321
+ z.output<typeof EmptyInputSchema>,
322
+ ConversationReadFacts
323
+ >,
324
+ ) => Promise<void> | void;
325
+ onAfterGetConversation?: (
326
+ conversation: DeepReadonly<AiChatConversationResult>,
327
+ context: ChatApiContext<
328
+ z.output<typeof ConversationOperationInputSchema>,
329
+ ConversationReadFacts
330
+ >,
331
+ ) => Promise<void> | void;
332
+ onAfterCreateConversation?: (
333
+ conversation: DeepReadonly<SerializedConversation>,
334
+ context: ChatApiContext<
335
+ z.output<typeof createConversationSchema>,
336
+ undefined
337
+ >,
338
+ ) => Promise<void> | void;
339
+ onAfterUpdateConversation?: (
340
+ conversation: DeepReadonly<SerializedConversation>,
341
+ context: ChatApiContext<
342
+ z.output<typeof UpdateConversationOperationInputSchema>,
343
+ ConversationRecordFacts
344
+ >,
345
+ ) => Promise<void> | void;
346
+ onAfterDeleteConversation?: (
347
+ conversationId: string,
348
+ context: ChatApiContext<
349
+ z.output<typeof ConversationOperationInputSchema>,
350
+ ConversationRecordFacts
351
+ >,
352
+ ) => Promise<void> | void;
353
+ onErrorChat?: (
354
+ error: Error,
355
+ context: ChatApiContext<
356
+ z.output<typeof ChatOperationInputSchema>,
357
+ StreamStartFacts
358
+ >,
359
+ ) => Promise<void> | void;
360
+ onErrorListConversations?: (
361
+ error: Error,
362
+ context: ChatApiContext<
363
+ z.output<typeof EmptyInputSchema>,
364
+ ConversationReadFacts
365
+ >,
366
+ ) => Promise<void> | void;
367
+ onErrorGetConversation?: (
368
+ error: Error,
369
+ context: ChatApiContext<
370
+ z.output<typeof ConversationOperationInputSchema>,
371
+ ConversationReadFacts
372
+ >,
373
+ ) => Promise<void> | void;
374
+ onErrorCreateConversation?: (
375
+ error: Error,
376
+ context: ChatApiContext<
377
+ z.output<typeof createConversationSchema>,
378
+ undefined
379
+ >,
380
+ ) => Promise<void> | void;
381
+ onErrorUpdateConversation?: (
382
+ error: Error,
383
+ context: ChatApiContext<
384
+ z.output<typeof UpdateConversationOperationInputSchema>,
385
+ ConversationRecordFacts
386
+ >,
387
+ ) => Promise<void> | void;
388
+ onErrorDeleteConversation?: (
389
+ error: Error,
390
+ context: ChatApiContext<
391
+ z.output<typeof ConversationOperationInputSchema>,
392
+ ConversationRecordFacts
393
+ >,
394
+ ) => Promise<void> | void;
395
+ }
396
+
397
+ export interface AiChatOperationsConfig {
398
+ access: AiChatAccess;
399
+ model: LanguageModel;
400
+ systemPrompt?: string;
401
+ tools?: Record<string, Tool>;
402
+ enablePageTools?: boolean;
403
+ clientToolSchemas?: Record<string, Tool>;
404
+ hooks?: AiChatBackendHooks;
405
+ }
406
+
407
+ interface ConversationSnapshot {
408
+ readonly id: string;
409
+ readonly userId?: string;
410
+ readonly title: string;
411
+ readonly createdAt: number;
412
+ readonly updatedAt: number;
413
+ readonly messages: readonly MessageSnapshot[];
414
+ }
415
+
416
+ interface MessageSnapshot {
417
+ readonly id: string;
418
+ readonly conversationId: string;
419
+ readonly role: Message["role"];
420
+ readonly content: string;
421
+ readonly createdAt: number;
422
+ }
423
+
424
+ interface StreamPreparation {
425
+ readonly snapshot: ConversationSnapshot | null;
426
+ readonly intent: StreamStartFacts["intent"];
427
+ readonly messageId?: string;
428
+ readonly mediaTypes: readonly string[];
429
+ readonly authorizationToolNames: readonly string[];
430
+ readonly toolNames: readonly string[];
431
+ }
432
+
433
+ function normalizeError(error: unknown, fallback: string): Error {
434
+ if (error instanceof Error) return error;
435
+ return new Error(typeof error === "string" ? error : fallback, {
436
+ cause: error,
437
+ });
438
+ }
439
+
440
+ function requestFields(request: Request | undefined) {
441
+ return request ? { request, headers: request.headers } : {};
442
+ }
443
+
444
+ function hookContext<TInput, TFacts>(
445
+ context: OperationContext<TInput, TFacts>,
446
+ fields: {
447
+ body?: DeepReadonly<TInput>;
448
+ params?: Readonly<Record<string, string>>;
449
+ query?: DeepReadonly<TInput>;
450
+ } = {},
451
+ ): ChatApiContext<TInput, TFacts> {
452
+ return Object.freeze({
453
+ ...context,
454
+ ...requestFields(context.request),
455
+ ...fields,
456
+ });
457
+ }
458
+
459
+ async function notifyError<TInput, TFacts>(
460
+ hook:
461
+ | ((
462
+ error: Error,
463
+ context: ChatApiContext<TInput, TFacts>,
464
+ ) => Promise<void> | void)
465
+ | undefined,
466
+ error: unknown,
467
+ context: OperationContext<TInput, TFacts>,
468
+ fields?: {
469
+ body?: DeepReadonly<TInput>;
470
+ params?: Readonly<Record<string, string>>;
471
+ query?: DeepReadonly<TInput>;
472
+ },
473
+ ) {
474
+ await hook?.(
475
+ normalizeError(error, "AI Chat operation failed"),
476
+ hookContext(context, fields),
477
+ );
478
+ }
479
+
480
+ function publicConversation(
481
+ conversation: Conversation,
482
+ ): SerializedConversation {
483
+ // `userId` is the minimum rendered owner hint needed by browser permission
484
+ // gates. The server always reloads the authoritative owner before enforcement.
485
+ return serializeConversation(conversation);
486
+ }
487
+
488
+ function conversationResult(
489
+ conversation: Conversation & { messages: Message[] },
490
+ ): AiChatConversationResult {
491
+ return {
492
+ ...publicConversation(conversation),
493
+ messages: conversation.messages.map(serializeMessage),
494
+ };
495
+ }
496
+
497
+ function snapshotConversation(
498
+ conversation: Conversation & { messages?: Message[] },
499
+ ): ConversationSnapshot {
500
+ return {
501
+ id: conversation.id,
502
+ ...(conversation.userId ? { userId: conversation.userId } : {}),
503
+ title: conversation.title,
504
+ createdAt: conversation.createdAt.getTime(),
505
+ updatedAt: conversation.updatedAt.getTime(),
506
+ messages: (conversation.messages ?? []).map((message) => ({
507
+ id: message.id,
508
+ conversationId: message.conversationId,
509
+ role: message.role,
510
+ content: message.content,
511
+ createdAt: message.createdAt.getTime(),
512
+ })),
513
+ };
514
+ }
515
+
516
+ function sameSnapshot(
517
+ conversation: (Conversation & { messages: Message[] }) | null,
518
+ expected: ConversationSnapshot | null,
519
+ ) {
520
+ if (!conversation || !expected)
521
+ return conversation === null && expected === null;
522
+ return (
523
+ JSON.stringify(snapshotConversation(conversation)) ===
524
+ JSON.stringify(expected)
525
+ );
526
+ }
527
+
528
+ function recordFacts(
529
+ id: string,
530
+ snapshot: ConversationSnapshot | null,
531
+ ): ConversationRecordFacts {
532
+ return {
533
+ conversationId: id,
534
+ exists: snapshot !== null,
535
+ ...(snapshot?.userId ? { ownerId: snapshot.userId } : {}),
536
+ };
537
+ }
538
+
539
+ function textContent(message: UIMessage): string {
540
+ return (message.parts ?? [])
541
+ .filter(
542
+ (part): part is Extract<UIMessage["parts"][number], { type: "text" }> =>
543
+ part.type === "text",
544
+ )
545
+ .map((part) => part.text)
546
+ .join("");
547
+ }
548
+
549
+ function serializedParts(message: UIMessage): string {
550
+ return JSON.stringify(
551
+ (message.parts ?? []).filter(
552
+ (part) => part.type === "text" || part.type === "file",
553
+ ),
554
+ );
555
+ }
556
+
557
+ function matchesPersistedUserMessage(
558
+ message: UIMessage,
559
+ persisted: MessageSnapshot,
560
+ ) {
561
+ if (persisted.content === serializedParts(message)) return true;
562
+ const parts = message.parts ?? [];
563
+ return (
564
+ parts.length === 1 &&
565
+ parts[0]?.type === "text" &&
566
+ persisted.content === parts[0].text
567
+ );
568
+ }
569
+
570
+ function fileParts(messages: readonly UIMessage[]) {
571
+ return messages.flatMap((message) =>
572
+ (message.parts ?? []).filter(
573
+ (part): part is Extract<UIMessage["parts"][number], { type: "file" }> =>
574
+ part.type === "file",
575
+ ),
576
+ );
577
+ }
578
+
579
+ function completedToolNames(message: UIMessage | undefined) {
580
+ if (!message) return [];
581
+ return [
582
+ ...new Set(
583
+ (message.parts ?? []).flatMap((part) => {
584
+ if (
585
+ !("state" in part) ||
586
+ (part.state !== "output-available" && part.state !== "output-error")
587
+ ) {
588
+ return [];
589
+ }
590
+ if (part.type === "dynamic-tool" && "toolName" in part) {
591
+ return typeof part.toolName === "string" ? [part.toolName] : [];
592
+ }
593
+ return part.type.startsWith("tool-") ? [part.type.slice(5)] : [];
594
+ }),
595
+ ),
596
+ ];
597
+ }
598
+
599
+ function validateAttachments(messages: readonly UIMessage[]) {
600
+ const files = fileParts(messages);
601
+ if (files.length > 10) {
602
+ throw new AiChatOperationError(
603
+ 400,
604
+ "A chat request may include at most 10 attachments.",
605
+ "TOO_MANY_ATTACHMENTS",
606
+ );
607
+ }
608
+ for (const file of files) {
609
+ if (
610
+ typeof file.url !== "string" ||
611
+ (!file.url.startsWith("https://") &&
612
+ !file.url.startsWith("http://") &&
613
+ !file.url.startsWith("data:"))
614
+ ) {
615
+ throw new AiChatOperationError(
616
+ 400,
617
+ "Attachment URLs must use http, https, or data URLs.",
618
+ "INVALID_ATTACHMENT_URL",
619
+ );
620
+ }
621
+ if (file.url.startsWith("data:") && file.url.length > 14_000_000) {
622
+ throw new AiChatOperationError(
623
+ 413,
624
+ "Inline attachments must not exceed 10 MB.",
625
+ "ATTACHMENT_TOO_LARGE",
626
+ );
627
+ }
628
+ }
629
+ }
630
+
631
+ function structuralToolNames(
632
+ input: DeepReadonly<z.output<typeof ChatOperationInputSchema>>,
633
+ config: AiChatOperationsConfig,
634
+ ) {
635
+ if (!config.enablePageTools || !input.availableTools?.length) return [];
636
+ const consumerSchemas = config.clientToolSchemas ?? {};
637
+ return [...new Set(input.availableTools)].filter((name) => {
638
+ if (name in BUILT_IN_PAGE_TOOL_SCHEMAS) {
639
+ const allowlist = BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST[name];
640
+ return Boolean(
641
+ allowlist && input.routeName && allowlist.includes(input.routeName),
642
+ );
643
+ }
644
+ return name in consumerSchemas;
645
+ });
646
+ }
647
+
648
+ function buildTools(names: readonly string[], config: AiChatOperationsConfig) {
649
+ const pageTools = Object.fromEntries(
650
+ names.map((name) => [
651
+ name,
652
+ BUILT_IN_PAGE_TOOL_SCHEMAS[name] ?? config.clientToolSchemas?.[name],
653
+ ]),
654
+ ) as Record<string, Tool>;
655
+ return Object.keys(pageTools).length > 0
656
+ ? { ...pageTools, ...config.tools }
657
+ : config.tools;
658
+ }
659
+
660
+ function determineIntent(
661
+ messages: readonly UIMessage[],
662
+ snapshot: ConversationSnapshot | null,
663
+ ): { intent: StreamStartFacts["intent"]; messageId?: string } {
664
+ const last = messages[messages.length - 1];
665
+ if (!last) return { intent: "send" };
666
+ if (last.role !== "user" && last.role !== "assistant") {
667
+ throw new AiChatOperationError(
668
+ 400,
669
+ "A chat request must end with a user or assistant message.",
670
+ "INVALID_MESSAGE_SEQUENCE",
671
+ );
672
+ }
673
+ if (!snapshot) return { intent: "send" };
674
+ const incomingUsers = messages.filter((message) => message.role === "user");
675
+ const persistedUsers = snapshot.messages.filter(
676
+ (message) => message.role === "user",
677
+ );
678
+ const sharedUserCount = Math.min(incomingUsers.length, persistedUsers.length);
679
+ for (let index = 0; index < sharedUserCount; index++) {
680
+ const incoming = incomingUsers[index];
681
+ const persisted = persistedUsers[index];
682
+ if (!incoming || !persisted) continue;
683
+ const matches = matchesPersistedUserMessage(incoming, persisted);
684
+ if (matches) continue;
685
+ if (
686
+ last.role === "user" &&
687
+ incoming === last &&
688
+ index === incomingUsers.length - 1
689
+ ) {
690
+ return { intent: "edit", messageId: persisted.id };
691
+ }
692
+ throw new AiChatOperationError(
693
+ 409,
694
+ "The conversation transcript changed before authorization.",
695
+ "STALE_MESSAGE",
696
+ );
697
+ }
698
+ if (incomingUsers.length > persistedUsers.length) {
699
+ if (
700
+ incomingUsers.length === persistedUsers.length + 1 &&
701
+ incomingUsers[incomingUsers.length - 1] === last
702
+ ) {
703
+ return { intent: "send" };
704
+ }
705
+ throw new AiChatOperationError(
706
+ 409,
707
+ "The conversation transcript changed before authorization.",
708
+ "STALE_MESSAGE",
709
+ );
710
+ }
711
+ const isToolResult =
712
+ last.role === "assistant" && completedToolNames(last).length > 0;
713
+ if (isToolResult && incomingUsers.length !== persistedUsers.length) {
714
+ throw new AiChatOperationError(
715
+ 409,
716
+ "The tool continuation no longer follows the latest user message.",
717
+ "STALE_MESSAGE",
718
+ );
719
+ }
720
+ const target = persistedUsers[incomingUsers.length - 1];
721
+ if (!target) {
722
+ throw new AiChatOperationError(
723
+ 400,
724
+ "Retry requires a persisted message.",
725
+ "MESSAGE_NOT_FOUND",
726
+ );
727
+ }
728
+ return {
729
+ intent: isToolResult ? "tool-result" : "retry",
730
+ messageId: target.id,
731
+ };
732
+ }
733
+
734
+ function nextVersion(date: Date) {
735
+ return new Date(Math.max(Date.now(), date.getTime() + 1));
736
+ }
737
+
738
+ const AFFECTED_ROW_KEYS = [
739
+ "rowCount",
740
+ "affectedRows",
741
+ "rowsAffected",
742
+ "changes",
743
+ "numUpdatedRows",
744
+ ] as const;
745
+
746
+ function hasPositiveCount(value: unknown): boolean {
747
+ if (typeof value === "number") return Number.isFinite(value) && value > 0;
748
+ if (typeof value === "bigint") return value > 0n;
749
+ return false;
750
+ }
751
+
752
+ /** Normalize conditional-update results across the supported adapters. */
753
+ function didAffectRow(result: unknown, expectedId: string): boolean {
754
+ if (typeof result === "number" || typeof result === "bigint") {
755
+ return hasPositiveCount(result);
756
+ }
757
+ if (!result || typeof result !== "object") return false;
758
+ const record = result as Record<string, unknown>;
759
+ if ("count" in record) return hasPositiveCount(record.count);
760
+ if (Array.isArray(result)) {
761
+ return result.length > 0 && didAffectRow(result[0], expectedId);
762
+ }
763
+ for (const key of AFFECTED_ROW_KEYS) {
764
+ if (key in record) return hasPositiveCount(record[key]);
765
+ }
766
+ if ("meta" in record) {
767
+ const meta = record.meta;
768
+ return Boolean(
769
+ meta &&
770
+ typeof meta === "object" &&
771
+ "changes" in meta &&
772
+ hasPositiveCount((meta as Record<string, unknown>).changes),
773
+ );
774
+ }
775
+ return record.id === expectedId;
776
+ }
777
+
778
+ const memoryRollbackMarkers = new WeakMap<Adapter, (error: unknown) => void>();
779
+
780
+ function markMemoryRollback(adapter: Adapter, error: unknown) {
781
+ memoryRollbackMarkers.get(adapter)?.(error);
782
+ }
783
+
784
+ /**
785
+ * The published memory adapter rolls transactions back from a whole-database
786
+ * clone. Serialize every access to the shared adapter so a rejected AI Chat
787
+ * transaction cannot erase a concurrent operation from this or another plugin.
788
+ */
789
+ function serializeMemoryOperations(adapter: Adapter): Adapter {
790
+ if (adapter.id !== "memory" || memoryRollbackMarkers.has(adapter)) {
791
+ return adapter;
792
+ }
793
+ const source: Adapter = { ...adapter };
794
+ const lockContext = new AsyncLocalStorage<MemoryHistoryLockContext>();
795
+ let tail = Promise.resolve();
796
+ let activeOwner: object | undefined;
797
+ const withLock = async <T>(
798
+ run: (activeAdapter: ActiveAdapter) => Promise<T>,
799
+ ): Promise<T> => {
800
+ const inherited = lockContext.getStore();
801
+ if (inherited && inherited.owner === activeOwner) {
802
+ return run(inherited.adapter);
803
+ }
804
+ let release = () => {};
805
+ const previous = tail;
806
+ tail = new Promise<void>((resolve) => {
807
+ release = resolve;
808
+ });
809
+ await previous;
810
+ const owner = {};
811
+ activeOwner = owner;
812
+ try {
813
+ return await lockContext.run({ owner, adapter: source }, () =>
814
+ run(source),
815
+ );
816
+ } finally {
817
+ if (activeOwner === owner) activeOwner = undefined;
818
+ release();
819
+ }
820
+ };
821
+ const serialized: Adapter = {
822
+ ...source,
823
+ create: ((input) =>
824
+ withLock((active) => active.create(input))) as Adapter["create"],
825
+ findOne: ((input) =>
826
+ withLock((active) => active.findOne(input))) as Adapter["findOne"],
827
+ findMany: ((input) =>
828
+ withLock((active) => active.findMany(input))) as Adapter["findMany"],
829
+ count: (input) => withLock((active) => active.count(input)),
830
+ update: ((input) =>
831
+ withLock((active) => active.update(input))) as Adapter["update"],
832
+ updateMany: (input) => withLock((active) => active.updateMany(input)),
833
+ delete: ((input) =>
834
+ withLock((active) => active.delete(input))) as Adapter["delete"],
835
+ deleteMany: (input) => withLock((active) => active.deleteMany(input)),
836
+ consumeOne: ((input) =>
837
+ withLock((active) => active.consumeOne(input))) as Adapter["consumeOne"],
838
+ transaction: ((callback) =>
839
+ withLock((active) => {
840
+ const context = lockContext.getStore();
841
+ if (!context)
842
+ throw new TypeError("Missing AI Chat memory lock context.");
843
+ if (context.inTransaction) {
844
+ return callback(active as TransactionAdapter).catch((error) => {
845
+ context.rollbackOnly = true;
846
+ context.rollbackError = error;
847
+ throw error;
848
+ });
849
+ }
850
+ if (!active.transaction) {
851
+ throw new TypeError("Missing AI Chat memory transaction adapter.");
852
+ }
853
+ return active.transaction((transaction) =>
854
+ lockContext.run(
855
+ {
856
+ owner: context.owner,
857
+ adapter: transaction,
858
+ inTransaction: true,
859
+ },
860
+ async () => {
861
+ const transactionContext = lockContext.getStore();
862
+ const result = await callback(transaction);
863
+ if (transactionContext?.rollbackOnly) {
864
+ throw transactionContext.rollbackError;
865
+ }
866
+ return result;
867
+ },
868
+ ),
869
+ );
870
+ })) as Adapter["transaction"],
871
+ };
872
+ Object.assign(adapter, serialized);
873
+ memoryRollbackMarkers.set(adapter, (error) => {
874
+ const context = lockContext.getStore();
875
+ if (!context || context.owner !== activeOwner || !context.inTransaction) {
876
+ return;
877
+ }
878
+ context.rollbackOnly = true;
879
+ context.rollbackError = error;
880
+ });
881
+ return adapter;
882
+ }
883
+
884
+ function requireAtomicConversationTransactions(adapter: Adapter) {
885
+ if (
886
+ adapter.id !== "memory" &&
887
+ typeof adapter.options?.adapterConfig.transaction !== "function"
888
+ ) {
889
+ throw new AiChatOperationError(
890
+ 500,
891
+ "AI Chat conversation writes require an adapter with isolated transaction support.",
892
+ "ATOMIC_TRANSACTION_REQUIRED",
893
+ );
894
+ }
895
+ }
896
+
897
+ async function scopedUserId(
898
+ context: OperationContext<any, any>,
899
+ input: object,
900
+ ) {
901
+ if (context.identity) return context.identity.id;
902
+ const trustedUserId = (input as { trustedUserId?: string }).trustedUserId;
903
+ if (!context.request && trustedUserId) return trustedUserId;
904
+ return undefined;
905
+ }
906
+
907
+ function assertConversationScope(
908
+ snapshot: ConversationSnapshot | null,
909
+ userId: string | undefined,
910
+ message: string,
911
+ ) {
912
+ if (userId && snapshot?.userId && snapshot.userId !== userId) {
913
+ throw new AiChatOperationError(403, message, "FORBIDDEN");
914
+ }
915
+ }
916
+
917
+ /** Build all AI Chat operations once for HTTP, request, and trusted execution. */
918
+ export function createAiChatOperations(
919
+ sourceAdapter: Adapter,
920
+ config: AiChatOperationsConfig,
921
+ ): AiChatOperations {
922
+ const adapter = serializeMemoryOperations(sourceAdapter);
923
+ const hooks = config.hooks;
924
+ const conversationSnapshots = new WeakMap<
925
+ object,
926
+ ConversationSnapshot | null
927
+ >();
928
+ const streamPreparations = new WeakMap<object, StreamPreparation>();
929
+ const scopedUserIds = new WeakMap<object, string | undefined>();
930
+ const pendingRequestedConversationClaims = new Set<string>();
931
+ const pendingConversationMutationClaims = new Set<string>();
932
+ const claimConversationMutation = (conversationId: string) => {
933
+ requireAtomicConversationTransactions(adapter);
934
+ if (pendingConversationMutationClaims.has(conversationId)) {
935
+ throw new AiChatOperationError(
936
+ 409,
937
+ "Conversation changed during authorization.",
938
+ "STALE_CONVERSATION",
939
+ );
940
+ }
941
+ pendingConversationMutationClaims.add(conversationId);
942
+ return () => pendingConversationMutationClaims.delete(conversationId);
943
+ };
944
+ const assertHistoryAvailable = () => {
945
+ if (config.access === "public") {
946
+ throw new AiChatOperationError(
947
+ 404,
948
+ "Conversations are not available in public mode.",
949
+ "HISTORY_UNAVAILABLE",
950
+ );
951
+ }
952
+ };
953
+
954
+ const listConversations = defineOperation({
955
+ input: EmptyInputSchema,
956
+ permission: aiChatPermissions.conversation.read,
957
+ facts: () => {
958
+ assertHistoryAvailable();
959
+ return { scope: "collection" as const };
960
+ },
961
+ before: async (context) => {
962
+ const userId = await scopedUserId(context, context.input);
963
+ scopedUserIds.set(context.input as object, userId);
964
+ await runBeforeHook(
965
+ () =>
966
+ hooks?.onBeforeListConversations?.(
967
+ hookContext(context, { query: context.input }),
968
+ ),
969
+ "Unauthorized: Cannot list conversations",
970
+ );
971
+ },
972
+ execute: async (context) => {
973
+ const userId = scopedUserIds.get(context.input as object);
974
+ const allConversations = await getAllConversations(adapter, userId);
975
+ const conversations = (
976
+ context.request && !userId
977
+ ? allConversations.filter((conversation) => !conversation.userId)
978
+ : allConversations
979
+ ).map(publicConversation);
980
+ await hooks?.onAfterListConversations?.(
981
+ conversations,
982
+ hookContext(context, { query: context.input }),
983
+ );
984
+ return conversations;
985
+ },
986
+ onError: ({ error, ...context }) =>
987
+ notifyError(hooks?.onErrorListConversations, error, context, {
988
+ query: context.input,
989
+ }),
990
+ });
991
+
992
+ const getConversation = defineOperation({
993
+ input: ConversationOperationInputSchema,
994
+ permission: aiChatPermissions.conversation.read,
995
+ facts: async ({ input }) => {
996
+ assertHistoryAvailable();
997
+ const conversation = await getConversationById(adapter, input.id);
998
+ const snapshot = conversation ? snapshotConversation(conversation) : null;
999
+ conversationSnapshots.set(input as object, snapshot);
1000
+ return {
1001
+ scope: "record" as const,
1002
+ ...recordFacts(input.id, snapshot),
1003
+ };
1004
+ },
1005
+ before: async (context) => {
1006
+ const userId = await scopedUserId(context, context.input);
1007
+ assertConversationScope(
1008
+ conversationSnapshots.get(context.input as object) ?? null,
1009
+ context.identity ? undefined : userId,
1010
+ "Unauthorized: Cannot access this conversation",
1011
+ );
1012
+ const current = await getConversationById(adapter, context.input.id);
1013
+ if (
1014
+ !sameSnapshot(
1015
+ current,
1016
+ conversationSnapshots.get(context.input as object) ?? null,
1017
+ )
1018
+ ) {
1019
+ throw new AiChatOperationError(
1020
+ 409,
1021
+ "Conversation changed during authorization.",
1022
+ "STALE_CONVERSATION",
1023
+ );
1024
+ }
1025
+ await runBeforeHook(
1026
+ () =>
1027
+ hooks?.onBeforeGetConversation?.(
1028
+ context.input.id,
1029
+ hookContext(context, { params: { id: context.input.id } }),
1030
+ ),
1031
+ "Unauthorized: Cannot get conversation",
1032
+ );
1033
+ },
1034
+ execute: async (context) => {
1035
+ const conversation = await getConversationById(adapter, context.input.id);
1036
+ if (!conversation) {
1037
+ throw new AiChatOperationError(
1038
+ 404,
1039
+ "Conversation not found.",
1040
+ "CONVERSATION_NOT_FOUND",
1041
+ );
1042
+ }
1043
+ if (
1044
+ !sameSnapshot(
1045
+ conversation,
1046
+ conversationSnapshots.get(context.input as object) ?? null,
1047
+ )
1048
+ ) {
1049
+ throw new AiChatOperationError(
1050
+ 409,
1051
+ "Conversation changed during authorization.",
1052
+ "STALE_CONVERSATION",
1053
+ );
1054
+ }
1055
+ const result = conversationResult(conversation);
1056
+ await hooks?.onAfterGetConversation?.(
1057
+ result,
1058
+ hookContext(context, { params: { id: context.input.id } }),
1059
+ );
1060
+ return result;
1061
+ },
1062
+ onError: ({ error, ...context }) =>
1063
+ notifyError(hooks?.onErrorGetConversation, error, context, {
1064
+ params: { id: context.input.id },
1065
+ }),
1066
+ });
1067
+
1068
+ const createConversation = defineOperation({
1069
+ input: createConversationSchema,
1070
+ permission: aiChatPermissions.conversation.create,
1071
+ facts: () => {
1072
+ assertHistoryAvailable();
1073
+ return undefined;
1074
+ },
1075
+ before: async (context) => {
1076
+ const userId = await scopedUserId(context, context.input);
1077
+ scopedUserIds.set(context.input as object, userId);
1078
+ await runBeforeHook(
1079
+ () =>
1080
+ hooks?.onBeforeCreateConversation?.(
1081
+ context.input,
1082
+ hookContext(context, { body: context.input }),
1083
+ ),
1084
+ "Unauthorized: Cannot create conversation",
1085
+ );
1086
+ },
1087
+ execute: async (context) => {
1088
+ const userId = scopedUserIds.get(context.input as object);
1089
+ const now = new Date();
1090
+ const conversation = await adapter.create<Conversation>({
1091
+ model: "conversation",
1092
+ forceAllowId: Boolean(context.input.id),
1093
+ data: {
1094
+ ...(context.input.id ? { id: context.input.id } : {}),
1095
+ ...(userId ? { userId } : {}),
1096
+ title: context.input.title || "New Conversation",
1097
+ createdAt: now,
1098
+ updatedAt: now,
1099
+ } as Conversation,
1100
+ });
1101
+ const result = publicConversation(conversation);
1102
+ await hooks?.onAfterCreateConversation?.(
1103
+ result,
1104
+ hookContext(context, { body: context.input }),
1105
+ );
1106
+ return result;
1107
+ },
1108
+ onError: ({ error, ...context }) => {
1109
+ markMemoryRollback(adapter, error);
1110
+ return notifyError(hooks?.onErrorCreateConversation, error, context, {
1111
+ body: context.input,
1112
+ });
1113
+ },
1114
+ });
1115
+
1116
+ const updateConversation = defineOperation({
1117
+ input: UpdateConversationOperationInputSchema,
1118
+ permission: aiChatPermissions.conversation.update,
1119
+ facts: async ({ input }) => {
1120
+ assertHistoryAvailable();
1121
+ const conversation = await getConversationById(adapter, input.id);
1122
+ const snapshot = conversation ? snapshotConversation(conversation) : null;
1123
+ conversationSnapshots.set(input as object, snapshot);
1124
+ return recordFacts(input.id, snapshot);
1125
+ },
1126
+ execute: async (context) => {
1127
+ const expected =
1128
+ conversationSnapshots.get(context.input as object) ?? null;
1129
+ if (!expected) {
1130
+ throw new AiChatOperationError(
1131
+ 404,
1132
+ "Conversation not found.",
1133
+ "CONVERSATION_NOT_FOUND",
1134
+ );
1135
+ }
1136
+ const userId = await scopedUserId(context, context.input);
1137
+ assertConversationScope(
1138
+ expected,
1139
+ context.identity ? undefined : userId,
1140
+ "Unauthorized: Cannot update this conversation",
1141
+ );
1142
+ const releaseMutation = claimConversationMutation(expected.id);
1143
+ try {
1144
+ return await adapter.transaction(async (tx) => {
1145
+ const current = await getConversationById(tx, context.input.id);
1146
+ if (!sameSnapshot(current, expected)) {
1147
+ throw new AiChatOperationError(
1148
+ 409,
1149
+ "Conversation changed during authorization.",
1150
+ "STALE_CONVERSATION",
1151
+ );
1152
+ }
1153
+ await runBeforeHook(
1154
+ () =>
1155
+ hooks?.onBeforeUpdateConversation?.(
1156
+ context.input.id,
1157
+ context.input.data,
1158
+ hookContext(context, {
1159
+ body: context.input,
1160
+ params: { id: context.input.id },
1161
+ }),
1162
+ ),
1163
+ "Unauthorized: Cannot update conversation",
1164
+ );
1165
+ const updatedAt = nextVersion(new Date(expected.updatedAt));
1166
+ const matched = await tx.updateMany({
1167
+ model: "conversation",
1168
+ where: [
1169
+ {
1170
+ field: "id",
1171
+ value: expected.id,
1172
+ operator: "eq" as const,
1173
+ },
1174
+ {
1175
+ field: "updatedAt",
1176
+ value: new Date(expected.updatedAt),
1177
+ operator: "gte" as const,
1178
+ },
1179
+ {
1180
+ field: "updatedAt",
1181
+ value: new Date(expected.updatedAt),
1182
+ operator: "lte" as const,
1183
+ },
1184
+ ],
1185
+ update: { title: context.input.data.title, updatedAt },
1186
+ });
1187
+ if (!didAffectRow(matched, expected.id)) {
1188
+ throw new AiChatOperationError(
1189
+ 409,
1190
+ "Conversation changed during authorization.",
1191
+ "STALE_CONVERSATION",
1192
+ );
1193
+ }
1194
+ const updated = await tx.findOne<Conversation>({
1195
+ model: "conversation",
1196
+ where: [{ field: "id", value: expected.id }],
1197
+ });
1198
+ if (!updated) {
1199
+ throw new AiChatOperationError(
1200
+ 404,
1201
+ "Conversation not found.",
1202
+ "CONVERSATION_NOT_FOUND",
1203
+ );
1204
+ }
1205
+ return publicConversation(updated);
1206
+ });
1207
+ } finally {
1208
+ releaseMutation();
1209
+ }
1210
+ },
1211
+ after: (context) =>
1212
+ hooks?.onAfterUpdateConversation?.(
1213
+ context.result,
1214
+ hookContext(context, {
1215
+ body: context.input,
1216
+ params: { id: context.input.id },
1217
+ }),
1218
+ ),
1219
+ onError: ({ error, ...context }) => {
1220
+ markMemoryRollback(adapter, error);
1221
+ return notifyError(hooks?.onErrorUpdateConversation, error, context, {
1222
+ body: context.input,
1223
+ params: { id: context.input.id },
1224
+ });
1225
+ },
1226
+ });
1227
+
1228
+ const deleteConversation = defineOperation({
1229
+ input: ConversationOperationInputSchema,
1230
+ permission: aiChatPermissions.conversation.delete,
1231
+ facts: async ({ input }) => {
1232
+ assertHistoryAvailable();
1233
+ const conversation = await getConversationById(adapter, input.id);
1234
+ const snapshot = conversation ? snapshotConversation(conversation) : null;
1235
+ conversationSnapshots.set(input as object, snapshot);
1236
+ return recordFacts(input.id, snapshot);
1237
+ },
1238
+ execute: async (context) => {
1239
+ const expected =
1240
+ conversationSnapshots.get(context.input as object) ?? null;
1241
+ if (!expected) {
1242
+ throw new AiChatOperationError(
1243
+ 404,
1244
+ "Conversation not found.",
1245
+ "CONVERSATION_NOT_FOUND",
1246
+ );
1247
+ }
1248
+ const userId = await scopedUserId(context, context.input);
1249
+ assertConversationScope(
1250
+ expected,
1251
+ context.identity ? undefined : userId,
1252
+ "Unauthorized: Cannot delete this conversation",
1253
+ );
1254
+ const releaseMutation = claimConversationMutation(expected.id);
1255
+ try {
1256
+ return await adapter.transaction(async (tx) => {
1257
+ const current = await getConversationById(tx, context.input.id);
1258
+ if (!sameSnapshot(current, expected)) {
1259
+ throw new AiChatOperationError(
1260
+ 409,
1261
+ "Conversation changed during authorization.",
1262
+ "STALE_CONVERSATION",
1263
+ );
1264
+ }
1265
+ await runBeforeHook(
1266
+ () =>
1267
+ hooks?.onBeforeDeleteConversation?.(
1268
+ context.input.id,
1269
+ hookContext(context, {
1270
+ params: { id: context.input.id },
1271
+ }),
1272
+ ),
1273
+ "Unauthorized: Cannot delete conversation",
1274
+ );
1275
+ const deleted = await tx.deleteMany({
1276
+ model: "conversation",
1277
+ where: [
1278
+ {
1279
+ field: "id",
1280
+ value: expected.id,
1281
+ operator: "eq" as const,
1282
+ },
1283
+ {
1284
+ field: "updatedAt",
1285
+ value: new Date(expected.updatedAt),
1286
+ operator: "gte" as const,
1287
+ },
1288
+ {
1289
+ field: "updatedAt",
1290
+ value: new Date(expected.updatedAt),
1291
+ operator: "lte" as const,
1292
+ },
1293
+ ],
1294
+ });
1295
+ if (!didAffectRow(deleted, expected.id)) {
1296
+ throw new AiChatOperationError(
1297
+ 409,
1298
+ "Conversation changed during authorization.",
1299
+ "STALE_CONVERSATION",
1300
+ );
1301
+ }
1302
+ return { success: true as const };
1303
+ });
1304
+ } finally {
1305
+ releaseMutation();
1306
+ }
1307
+ },
1308
+ after: (context) =>
1309
+ hooks?.onAfterDeleteConversation?.(
1310
+ context.input.id,
1311
+ hookContext(context, { params: { id: context.input.id } }),
1312
+ ),
1313
+ onError: ({ error, ...context }) => {
1314
+ markMemoryRollback(adapter, error);
1315
+ return notifyError(hooks?.onErrorDeleteConversation, error, context, {
1316
+ params: { id: context.input.id },
1317
+ });
1318
+ },
1319
+ });
1320
+
1321
+ const startStream = definePassthroughOperation({
1322
+ input: ChatOperationInputSchema,
1323
+ permission: aiChatPermissions.stream.start,
1324
+ access: config.access,
1325
+ facts: async ({ input }) => {
1326
+ const uiMessages = input.messages as UIMessage[];
1327
+ if (!uiMessages[0]) {
1328
+ throw new AiChatOperationError(
1329
+ 400,
1330
+ "At least one message is required.",
1331
+ "EMPTY_CHAT",
1332
+ );
1333
+ }
1334
+ validateAttachments(uiMessages);
1335
+ const conversation =
1336
+ config.access === "authorized" && input.conversationId
1337
+ ? await getConversationById(adapter, input.conversationId)
1338
+ : null;
1339
+ const snapshot = conversation ? snapshotConversation(conversation) : null;
1340
+ const intent = determineIntent(uiMessages, snapshot);
1341
+ const mediaTypes = fileParts(uiMessages).map((file) => file.mediaType);
1342
+ const toolNames = structuralToolNames(input, config);
1343
+ const toolResultNames = completedToolNames(
1344
+ uiMessages[uiMessages.length - 1],
1345
+ );
1346
+ const availableToolNames = new Set([
1347
+ ...toolNames,
1348
+ ...Object.keys(config.tools ?? {}),
1349
+ ]);
1350
+ if (toolResultNames.some((name) => !availableToolNames.has(name))) {
1351
+ throw new AiChatOperationError(
1352
+ 400,
1353
+ "Tool results must match a server-enabled tool.",
1354
+ "INVALID_TOOL_RESULT",
1355
+ );
1356
+ }
1357
+ streamPreparations.set(input as object, {
1358
+ snapshot,
1359
+ ...intent,
1360
+ mediaTypes,
1361
+ authorizationToolNames: [...availableToolNames],
1362
+ toolNames,
1363
+ });
1364
+ return {
1365
+ ...(input.conversationId
1366
+ ? { conversationId: input.conversationId }
1367
+ : {}),
1368
+ ...(snapshot?.userId ? { ownerId: snapshot.userId } : {}),
1369
+ createsConversation: snapshot === null,
1370
+ intent: intent.intent,
1371
+ };
1372
+ },
1373
+ additionalPermissions: ({ input, facts }) => {
1374
+ const prepared = streamPreparations.get(input as object);
1375
+ if (!prepared) {
1376
+ throw new AiChatOperationError(
1377
+ 500,
1378
+ "Stream authorization context is unavailable.",
1379
+ "AUTHORIZATION_SNAPSHOT_MISSING",
1380
+ );
1381
+ }
1382
+ const requests = [];
1383
+ if (config.access === "authorized" && !prepared.snapshot) {
1384
+ requests.push(aiChatPermissions.conversation.create());
1385
+ }
1386
+ const base = {
1387
+ ...(facts.conversationId
1388
+ ? { conversationId: facts.conversationId }
1389
+ : {}),
1390
+ ...(facts.ownerId ? { ownerId: facts.ownerId } : {}),
1391
+ };
1392
+ if (prepared.intent === "send") {
1393
+ requests.push(
1394
+ aiChatPermissions.message.send({
1395
+ ...base,
1396
+ createsConversation: !prepared.snapshot,
1397
+ }),
1398
+ );
1399
+ } else if (prepared.intent === "edit" && facts.conversationId) {
1400
+ if (!prepared.messageId) {
1401
+ throw new AiChatOperationError(
1402
+ 500,
1403
+ "Edit authorization message is unavailable.",
1404
+ "AUTHORIZATION_SNAPSHOT_MISSING",
1405
+ );
1406
+ }
1407
+ requests.push(
1408
+ aiChatPermissions.message.edit({
1409
+ conversationId: facts.conversationId,
1410
+ messageId: prepared.messageId,
1411
+ ...(facts.ownerId ? { ownerId: facts.ownerId } : {}),
1412
+ }),
1413
+ );
1414
+ } else if (prepared.intent === "retry" && facts.conversationId) {
1415
+ if (!prepared.messageId) {
1416
+ throw new AiChatOperationError(
1417
+ 500,
1418
+ "Retry authorization message is unavailable.",
1419
+ "AUTHORIZATION_SNAPSHOT_MISSING",
1420
+ );
1421
+ }
1422
+ requests.push(
1423
+ aiChatPermissions.message.retry({
1424
+ conversationId: facts.conversationId,
1425
+ messageId: prepared.messageId,
1426
+ ...(facts.ownerId ? { ownerId: facts.ownerId } : {}),
1427
+ }),
1428
+ );
1429
+ } else if (prepared.intent === "tool-result") {
1430
+ requests.push(
1431
+ aiChatPermissions.message.send({
1432
+ ...base,
1433
+ createsConversation: false,
1434
+ }),
1435
+ );
1436
+ if (!facts.conversationId || !prepared.messageId) {
1437
+ throw new AiChatOperationError(
1438
+ 500,
1439
+ "Tool continuation authorization message is unavailable.",
1440
+ "AUTHORIZATION_SNAPSHOT_MISSING",
1441
+ );
1442
+ }
1443
+ // A completed tool result starts another generation for the same
1444
+ // persisted user message. Requiring retry as well as send prevents an
1445
+ // assistant-ended browser transcript from bypassing a denied retry rule.
1446
+ requests.push(
1447
+ aiChatPermissions.message.retry({
1448
+ conversationId: facts.conversationId,
1449
+ messageId: prepared.messageId,
1450
+ ...(facts.ownerId ? { ownerId: facts.ownerId } : {}),
1451
+ }),
1452
+ );
1453
+ }
1454
+ if (prepared.mediaTypes.length > 0) {
1455
+ requests.push(
1456
+ aiChatPermissions.attachment.send({
1457
+ ...base,
1458
+ mediaTypes: [...prepared.mediaTypes],
1459
+ }),
1460
+ );
1461
+ }
1462
+ if (prepared.authorizationToolNames.length > 0) {
1463
+ requests.push(
1464
+ aiChatPermissions.tool.activate({
1465
+ ...base,
1466
+ ...(input.routeName ? { routeName: input.routeName } : {}),
1467
+ toolNames: [...prepared.authorizationToolNames],
1468
+ }),
1469
+ );
1470
+ }
1471
+ return requests;
1472
+ },
1473
+ execute: async (context) => {
1474
+ const prepared = streamPreparations.get(context.input as object);
1475
+ if (!prepared) {
1476
+ throw new AiChatOperationError(
1477
+ 500,
1478
+ "Stream authorization context is unavailable.",
1479
+ "AUTHORIZATION_SNAPSHOT_MISSING",
1480
+ );
1481
+ }
1482
+ const uiMessages = context.input.messages as UIMessage[];
1483
+ const firstMessage = uiMessages[0] as UIMessage;
1484
+ const userId =
1485
+ config.access === "authorized"
1486
+ ? await scopedUserId(context, context.input)
1487
+ : undefined;
1488
+ if (config.access === "authorized") {
1489
+ assertConversationScope(
1490
+ prepared.snapshot,
1491
+ context.identity ? undefined : userId,
1492
+ "Unauthorized: Cannot access this conversation",
1493
+ );
1494
+ }
1495
+
1496
+ if (config.access === "authorized" && context.input.conversationId) {
1497
+ const current = await getConversationById(
1498
+ adapter,
1499
+ context.input.conversationId,
1500
+ );
1501
+ if (!sameSnapshot(current, prepared.snapshot)) {
1502
+ throw new AiChatOperationError(
1503
+ 409,
1504
+ "Conversation changed during authorization.",
1505
+ "STALE_CONVERSATION",
1506
+ );
1507
+ }
1508
+ }
1509
+
1510
+ const modelMessages = await convertToModelMessages(uiMessages);
1511
+ const pageContext = context.input.pageContext?.trim();
1512
+ const pageSuffix = pageContext
1513
+ ? `\n\nCurrent page context:\n${pageContext}`
1514
+ : "";
1515
+ const systemContent = config.systemPrompt
1516
+ ? `${config.systemPrompt}${pageSuffix}`
1517
+ : pageSuffix || undefined;
1518
+ const messages = systemContent
1519
+ ? [
1520
+ { role: "system" as const, content: systemContent },
1521
+ ...modelMessages,
1522
+ ]
1523
+ : modelMessages;
1524
+ const contextForHooks = hookContext(context, { body: context.input });
1525
+ const enterChatLifecycle = async () => {
1526
+ await runBeforeHook(
1527
+ () =>
1528
+ hooks?.onBeforeChat?.(
1529
+ uiMessages.map((message) => ({
1530
+ role: message.role,
1531
+ content: textContent(message),
1532
+ })),
1533
+ contextForHooks,
1534
+ ),
1535
+ "Unauthorized: Cannot start chat",
1536
+ );
1537
+
1538
+ let allowedToolNames = [...prepared.toolNames];
1539
+ if (allowedToolNames.length > 0 && hooks?.onBeforeActivateTools) {
1540
+ const onBeforeActivateTools = hooks.onBeforeActivateTools;
1541
+ const filtered = await runBeforeHook(
1542
+ () =>
1543
+ onBeforeActivateTools(
1544
+ allowedToolNames,
1545
+ context.input.routeName,
1546
+ contextForHooks,
1547
+ ),
1548
+ "Unauthorized: Tool activation denied",
1549
+ );
1550
+ const structurallyAllowed = new Set(allowedToolNames);
1551
+ allowedToolNames = [
1552
+ ...new Set(
1553
+ filtered.filter((name) => structurallyAllowed.has(name)),
1554
+ ),
1555
+ ];
1556
+ }
1557
+ return buildTools(allowedToolNames, config);
1558
+ };
1559
+
1560
+ const reportStreamError = async (error: unknown) => {
1561
+ try {
1562
+ await hooks?.onErrorChat?.(
1563
+ normalizeError(error, "Chat provider stream failed"),
1564
+ contextForHooks,
1565
+ );
1566
+ } catch (hookError) {
1567
+ console.error("[ai-chat] Error in onErrorChat hook:", hookError);
1568
+ }
1569
+ };
1570
+
1571
+ const startModelStream = (
1572
+ mergedTools: Record<string, Tool> | undefined,
1573
+ onFinish?: (completion: { text: string }) => Promise<void>,
1574
+ ) => {
1575
+ const result = streamText({
1576
+ model: config.model,
1577
+ messages,
1578
+ tools: mergedTools,
1579
+ ...(mergedTools ? { stopWhen: stepCountIs(5) } : {}),
1580
+ ...(onFinish ? { onFinish } : {}),
1581
+ onError: ({ error }) => reportStreamError(error),
1582
+ });
1583
+ return result.toUIMessageStreamResponse({
1584
+ originalMessages: uiMessages,
1585
+ });
1586
+ };
1587
+
1588
+ if (config.access === "public") {
1589
+ const mergedTools = await enterChatLifecycle();
1590
+ return startModelStream(mergedTools);
1591
+ }
1592
+ requireAtomicConversationTransactions(adapter);
1593
+ const releaseExistingConversationClaim = prepared.snapshot
1594
+ ? claimConversationMutation(prepared.snapshot.id)
1595
+ : undefined;
1596
+
1597
+ const requestedMissingConversationId =
1598
+ !prepared.snapshot && context.input.conversationId
1599
+ ? context.input.conversationId
1600
+ : undefined;
1601
+ if (
1602
+ requestedMissingConversationId &&
1603
+ pendingRequestedConversationClaims.has(requestedMissingConversationId)
1604
+ ) {
1605
+ throw new AiChatOperationError(
1606
+ 409,
1607
+ "Conversation changed during authorization.",
1608
+ "STALE_CONVERSATION",
1609
+ );
1610
+ }
1611
+ if (requestedMissingConversationId) {
1612
+ pendingRequestedConversationClaims.add(requestedMissingConversationId);
1613
+ }
1614
+ try {
1615
+ return await adapter.transaction(async (tx) => {
1616
+ let conversationId = context.input.conversationId;
1617
+ let streamClaimVersion: Date | undefined;
1618
+ const createConversation = () => {
1619
+ const now = new Date();
1620
+ return tx.create<Conversation>({
1621
+ model: "conversation",
1622
+ forceAllowId: Boolean(conversationId),
1623
+ data: {
1624
+ ...(conversationId ? { id: conversationId } : {}),
1625
+ ...(userId ? { userId } : {}),
1626
+ title:
1627
+ textContent(firstMessage).slice(0, 50) || "New Conversation",
1628
+ createdAt: now,
1629
+ updatedAt: now,
1630
+ } as Conversation,
1631
+ });
1632
+ };
1633
+ if (prepared.snapshot) {
1634
+ const claimedAt = nextVersion(
1635
+ new Date(prepared.snapshot.updatedAt),
1636
+ );
1637
+ const claimed = await tx.updateMany({
1638
+ model: "conversation",
1639
+ where: [
1640
+ {
1641
+ field: "id",
1642
+ value: prepared.snapshot.id,
1643
+ operator: "eq" as const,
1644
+ },
1645
+ {
1646
+ field: "updatedAt",
1647
+ value: new Date(prepared.snapshot.updatedAt),
1648
+ operator: "gte" as const,
1649
+ },
1650
+ {
1651
+ field: "updatedAt",
1652
+ value: new Date(prepared.snapshot.updatedAt),
1653
+ operator: "lte" as const,
1654
+ },
1655
+ ],
1656
+ update: { updatedAt: claimedAt },
1657
+ });
1658
+ if (!didAffectRow(claimed, prepared.snapshot.id)) {
1659
+ throw new AiChatOperationError(
1660
+ 409,
1661
+ "Conversation changed during authorization.",
1662
+ "STALE_CONVERSATION",
1663
+ );
1664
+ }
1665
+ conversationId = prepared.snapshot.id;
1666
+ streamClaimVersion = claimedAt;
1667
+ } else if (conversationId) {
1668
+ // A caller-selected id is also the atomic absence claim. Creating it
1669
+ // inside the transaction ensures a concurrent loser fails before any
1670
+ // ordinary lifecycle hook runs; hook failures roll the claim back.
1671
+ const current = await getConversationById(tx, conversationId);
1672
+ if (current) {
1673
+ throw new AiChatOperationError(
1674
+ 409,
1675
+ "Conversation changed during authorization.",
1676
+ "STALE_CONVERSATION",
1677
+ );
1678
+ }
1679
+ const created = await createConversation();
1680
+ conversationId = created.id;
1681
+ streamClaimVersion = created.updatedAt;
1682
+ }
1683
+ const mergedTools = await enterChatLifecycle();
1684
+ if (!prepared.snapshot && !conversationId) {
1685
+ const created = await createConversation();
1686
+ conversationId = created.id;
1687
+ streamClaimVersion = created.updatedAt;
1688
+ }
1689
+ if (!conversationId || !streamClaimVersion) {
1690
+ throw new AiChatOperationError(
1691
+ 500,
1692
+ "Conversation id was not created.",
1693
+ "CONVERSATION_CREATE_FAILED",
1694
+ );
1695
+ }
1696
+ const existingMessages = await tx.findMany<Message>({
1697
+ model: "message",
1698
+ where: [
1699
+ {
1700
+ field: "conversationId",
1701
+ value: conversationId,
1702
+ operator: "eq",
1703
+ },
1704
+ ],
1705
+ sortBy: { field: "createdAt", direction: "asc" },
1706
+ });
1707
+ const lastIncoming = uiMessages[uiMessages.length - 1];
1708
+ const targetIndex = prepared.messageId
1709
+ ? existingMessages.findIndex(
1710
+ (message) => message.id === prepared.messageId,
1711
+ )
1712
+ : -1;
1713
+ if (
1714
+ (prepared.intent === "retry" || prepared.intent === "edit") &&
1715
+ targetIndex === -1
1716
+ ) {
1717
+ throw new AiChatOperationError(
1718
+ 409,
1719
+ "The authorized message changed before persistence.",
1720
+ "STALE_MESSAGE",
1721
+ );
1722
+ }
1723
+ const deleteFrom =
1724
+ prepared.intent === "edit"
1725
+ ? targetIndex
1726
+ : prepared.intent === "retry"
1727
+ ? targetIndex + 1
1728
+ : existingMessages.length;
1729
+ for (const message of existingMessages.slice(deleteFrom)) {
1730
+ await tx.delete({
1731
+ model: "message",
1732
+ where: [{ field: "id", value: message.id }],
1733
+ });
1734
+ }
1735
+ if (
1736
+ (prepared.intent === "send" || prepared.intent === "edit") &&
1737
+ lastIncoming?.role === "user"
1738
+ ) {
1739
+ await tx.create<Message>({
1740
+ model: "message",
1741
+ data: {
1742
+ conversationId,
1743
+ role: "user",
1744
+ content: serializedParts(lastIncoming),
1745
+ createdAt: new Date(),
1746
+ },
1747
+ });
1748
+ }
1749
+
1750
+ const completionConversationId = conversationId;
1751
+ const completionClaimVersion = streamClaimVersion;
1752
+ const response = startModelStream(mergedTools, async ({ text }) => {
1753
+ try {
1754
+ requireAtomicConversationTransactions(adapter);
1755
+ const persisted = await adapter.transaction(
1756
+ async (completionTx) => {
1757
+ const completedAt = nextVersion(completionClaimVersion);
1758
+ const claimed = await completionTx.updateMany({
1759
+ model: "conversation",
1760
+ where: [
1761
+ {
1762
+ field: "id",
1763
+ value: completionConversationId,
1764
+ operator: "eq" as const,
1765
+ },
1766
+ {
1767
+ field: "updatedAt",
1768
+ value: completionClaimVersion,
1769
+ operator: "gte" as const,
1770
+ },
1771
+ {
1772
+ field: "updatedAt",
1773
+ value: completionClaimVersion,
1774
+ operator: "lte" as const,
1775
+ },
1776
+ ],
1777
+ update: { updatedAt: completedAt },
1778
+ });
1779
+ if (!didAffectRow(claimed, completionConversationId)) {
1780
+ throw new AiChatOperationError(
1781
+ 409,
1782
+ "A newer stream owns this conversation.",
1783
+ "STALE_STREAM",
1784
+ );
1785
+ }
1786
+ await completionTx.create<Message>({
1787
+ model: "message",
1788
+ data: {
1789
+ conversationId: completionConversationId,
1790
+ role: "assistant",
1791
+ content: JSON.stringify(
1792
+ text ? [{ type: "text", text }] : [],
1793
+ ),
1794
+ createdAt: new Date(),
1795
+ },
1796
+ });
1797
+ return completionTx.findMany<Message>({
1798
+ model: "message",
1799
+ where: [
1800
+ {
1801
+ field: "conversationId",
1802
+ value: completionConversationId,
1803
+ operator: "eq",
1804
+ },
1805
+ ],
1806
+ sortBy: { field: "createdAt", direction: "asc" },
1807
+ });
1808
+ },
1809
+ );
1810
+ if (hooks?.onAfterChat) {
1811
+ await hooks.onAfterChat(
1812
+ completionConversationId,
1813
+ persisted.map(serializeMessage),
1814
+ contextForHooks,
1815
+ );
1816
+ }
1817
+ } catch (error) {
1818
+ console.error("[ai-chat] Error in stream completion:", error);
1819
+ try {
1820
+ await hooks?.onErrorChat?.(
1821
+ normalizeError(error, "Chat completion persistence failed"),
1822
+ contextForHooks,
1823
+ );
1824
+ } catch (hookError) {
1825
+ console.error(
1826
+ "[ai-chat] Error in onErrorChat hook:",
1827
+ hookError,
1828
+ );
1829
+ }
1830
+ }
1831
+ });
1832
+ const headers = new Headers(response.headers);
1833
+ headers.set("X-Conversation-Id", completionConversationId);
1834
+ return new Response(response.body, {
1835
+ status: response.status,
1836
+ statusText: response.statusText,
1837
+ headers,
1838
+ });
1839
+ });
1840
+ } finally {
1841
+ releaseExistingConversationClaim?.();
1842
+ if (requestedMissingConversationId) {
1843
+ pendingRequestedConversationClaims.delete(
1844
+ requestedMissingConversationId,
1845
+ );
1846
+ }
1847
+ }
1848
+ },
1849
+ onError: ({ error, ...context }) => {
1850
+ markMemoryRollback(adapter, error);
1851
+ return notifyError(hooks?.onErrorChat, error, context, {
1852
+ body: context.input,
1853
+ });
1854
+ },
1855
+ });
1856
+
1857
+ return {
1858
+ startStream,
1859
+ listConversations,
1860
+ getConversation,
1861
+ createConversation,
1862
+ updateConversation,
1863
+ deleteConversation,
1864
+ };
1865
+ }