@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,1873 @@
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 type { StackIdentity } from "@btst/stack/context";
5
+ import {
6
+ type DeepReadonly,
7
+ defineOperation,
8
+ type Operation,
9
+ OperationHttpError,
10
+ type OperationContext,
11
+ type OperationData,
12
+ } from "@btst/stack/plugins/api";
13
+ import { z } from "zod";
14
+ import { mediaPermissions } from "../permissions";
15
+ import {
16
+ AssetListQuerySchema,
17
+ createAssetSchema,
18
+ createFolderSchema,
19
+ updateAssetSchema,
20
+ uploadTokenRequestSchema,
21
+ } from "../schemas";
22
+ import type {
23
+ Asset,
24
+ Folder,
25
+ SerializedAsset,
26
+ SerializedFolder,
27
+ } from "../types";
28
+ import {
29
+ getAssetById,
30
+ getFolderById,
31
+ listAssets,
32
+ listFolders,
33
+ } from "./getters";
34
+ import { createAsset } from "./mutations";
35
+ import { serializeAsset, serializeFolder } from "./serializers";
36
+ import {
37
+ isDirectAdapter,
38
+ isS3Adapter,
39
+ isVercelBlobAdapter,
40
+ type S3UploadToken,
41
+ type StorageAdapter,
42
+ type VercelBlobHandleUploadBody,
43
+ type VercelBlobUploadCompletedBody,
44
+ } from "./storage-adapter";
45
+
46
+ /** Runtime input for one asset operation. */
47
+ export const AssetIdOperationInputSchema = z.object({ id: z.string() });
48
+ /** Runtime input for an asset update operation. */
49
+ export const UpdateAssetOperationInputSchema = z.object({
50
+ id: z.string(),
51
+ data: updateAssetSchema,
52
+ });
53
+ /** Runtime input for one folder operation. */
54
+ export const FolderIdOperationInputSchema = z.object({ id: z.string() });
55
+ /** Runtime input for a folder collection operation. */
56
+ export const FolderListOperationInputSchema = z.object({
57
+ parentId: z.string().nullable().optional(),
58
+ });
59
+ /** Runtime input for a direct file upload operation. */
60
+ export const DirectUploadOperationInputSchema = z.object({
61
+ filename: z.string().min(1),
62
+ mimeType: z.string(),
63
+ size: z.number().int().min(0),
64
+ contentBase64: z.string(),
65
+ folderId: z.string().optional(),
66
+ });
67
+
68
+ const VercelGenerateBodySchema = z.object({
69
+ type: z.literal("blob.generate-client-token"),
70
+ payload: z.object({
71
+ pathname: z.string(),
72
+ multipart: z.boolean(),
73
+ clientPayload: z.string().nullable(),
74
+ callbackUrl: z.string().optional(),
75
+ }),
76
+ });
77
+ const VercelCallbackBodyShape = z.object({
78
+ type: z.literal("blob.upload-completed"),
79
+ payload: z.object({
80
+ blob: z.object({ url: z.string(), pathname: z.string() }),
81
+ tokenPayload: z.string().nullable().optional(),
82
+ }),
83
+ });
84
+ // Provider signatures cover JSON.stringify() of the exact parsed request body.
85
+ // Validate the required shape without stripping or reordering provider fields.
86
+ const VercelCallbackBodySchema = z.custom<
87
+ z.output<typeof VercelCallbackBodyShape>
88
+ >(
89
+ (value) => VercelCallbackBodyShape.safeParse(value).success,
90
+ "Invalid Vercel Blob callback body",
91
+ );
92
+ const LegacyVercelGenerateBodySchema = z.object({
93
+ pathname: z.string(),
94
+ clientPayload: z.string().nullable().optional(),
95
+ });
96
+ const VercelClientPayloadSchema = z.object({
97
+ mimeType: z.string().min(1).optional(),
98
+ size: z.number().int().min(0).optional(),
99
+ folderId: z.string().min(1).optional(),
100
+ });
101
+ /** Runtime input for the Vercel Blob token and callback operation. */
102
+ export const VercelBlobOperationInputSchema = z.object({
103
+ body: z.union([
104
+ VercelGenerateBodySchema,
105
+ VercelCallbackBodySchema,
106
+ LegacyVercelGenerateBodySchema,
107
+ ]),
108
+ });
109
+
110
+ type LibraryReadFacts = PermissionFactsFor<
111
+ typeof mediaPermissions.library.read
112
+ >;
113
+ type AssetReadFacts = PermissionFactsFor<typeof mediaPermissions.asset.read>;
114
+ type AssetUpdateFacts = PermissionFactsFor<
115
+ typeof mediaPermissions.asset.update
116
+ >;
117
+ type AssetDeleteFacts = PermissionFactsFor<
118
+ typeof mediaPermissions.asset.delete
119
+ >;
120
+ type AssetUploadFacts = PermissionFactsFor<
121
+ typeof mediaPermissions.asset.upload
122
+ >;
123
+ type FolderCreateFacts = PermissionFactsFor<
124
+ typeof mediaPermissions.folder.create
125
+ >;
126
+ type FolderDeleteFacts = PermissionFactsFor<
127
+ typeof mediaPermissions.folder.delete
128
+ >;
129
+
130
+ /** An authorized, row-filtered page of Media assets. */
131
+ export interface MediaAssetListResult {
132
+ readonly items: readonly SerializedAsset[];
133
+ readonly total: number;
134
+ readonly limit?: number;
135
+ readonly offset?: number;
136
+ }
137
+
138
+ /** Complete Media operation inventory shared by every server transport. */
139
+ export type MediaOperations = {
140
+ readonly listAssets: Operation<
141
+ typeof AssetListQuerySchema,
142
+ typeof mediaPermissions.library.read,
143
+ MediaAssetListResult
144
+ >;
145
+ readonly createAsset: Operation<
146
+ typeof createAssetSchema,
147
+ typeof mediaPermissions.asset.upload,
148
+ SerializedAsset
149
+ >;
150
+ readonly updateAsset: Operation<
151
+ typeof UpdateAssetOperationInputSchema,
152
+ typeof mediaPermissions.asset.update,
153
+ SerializedAsset
154
+ >;
155
+ readonly deleteAsset: Operation<
156
+ typeof AssetIdOperationInputSchema,
157
+ typeof mediaPermissions.asset.delete,
158
+ { readonly success: true }
159
+ >;
160
+ readonly listFolders: Operation<
161
+ typeof FolderListOperationInputSchema,
162
+ typeof mediaPermissions.library.read,
163
+ readonly SerializedFolder[]
164
+ >;
165
+ readonly createFolder: Operation<
166
+ typeof createFolderSchema,
167
+ typeof mediaPermissions.folder.create,
168
+ SerializedFolder
169
+ >;
170
+ readonly deleteFolder: Operation<
171
+ typeof FolderIdOperationInputSchema,
172
+ typeof mediaPermissions.folder.delete,
173
+ { readonly success: true }
174
+ >;
175
+ readonly uploadDirect: Operation<
176
+ typeof DirectUploadOperationInputSchema,
177
+ typeof mediaPermissions.asset.upload,
178
+ SerializedAsset
179
+ >;
180
+ readonly uploadToken: Operation<
181
+ typeof uploadTokenRequestSchema,
182
+ typeof mediaPermissions.asset.upload,
183
+ S3UploadToken
184
+ >;
185
+ readonly uploadVercelBlob: Operation<
186
+ typeof VercelBlobOperationInputSchema,
187
+ typeof mediaPermissions.asset.upload,
188
+ OperationData
189
+ >;
190
+ };
191
+
192
+ /** A domain/HTTP failure raised after Media authorization succeeds. */
193
+ export class MediaOperationError extends OperationHttpError {
194
+ constructor(statusCode: number, message: string, code: string) {
195
+ super(statusCode, message, code);
196
+ this.name = "MediaOperationError";
197
+ }
198
+ }
199
+
200
+ /** Typed context passed to Media lifecycle hooks after authorization succeeds. */
201
+ export interface MediaApiContext<TInput = unknown, TFacts = unknown> {
202
+ readonly input: DeepReadonly<TInput>;
203
+ readonly facts: DeepReadonly<TFacts>;
204
+ readonly identity: DeepReadonly<StackIdentity> | null;
205
+ readonly request?: Request;
206
+ readonly headers?: Headers;
207
+ readonly body?: unknown;
208
+ readonly params?: unknown;
209
+ readonly query?: unknown;
210
+ }
211
+
212
+ /** Typed post-operation context passed to Media result lifecycle hooks. */
213
+ export interface MediaApiResultContext<
214
+ TInput = unknown,
215
+ TFacts = unknown,
216
+ TResult = unknown,
217
+ > extends MediaApiContext<TInput, TFacts> {
218
+ readonly result: DeepReadonly<TResult>;
219
+ }
220
+
221
+ /** Validated input passed to upload lifecycle hooks. */
222
+ export type MediaUploadOperationInput =
223
+ | z.output<typeof createAssetSchema>
224
+ | z.output<typeof DirectUploadOperationInputSchema>
225
+ | z.output<typeof uploadTokenRequestSchema>
226
+ | z.output<typeof VercelBlobOperationInputSchema>;
227
+
228
+ /** Validated input for upload operations that create an asset result. */
229
+ export type MediaUploadResultOperationInput =
230
+ | z.output<typeof createAssetSchema>
231
+ | z.output<typeof DirectUploadOperationInputSchema>;
232
+
233
+ /** Every typed Media lifecycle error context. */
234
+ export type MediaOperationHookContext =
235
+ | MediaApiContext<z.output<typeof AssetListQuerySchema>, LibraryReadFacts>
236
+ | MediaApiContext<z.output<typeof createAssetSchema>, AssetUploadFacts>
237
+ | MediaApiContext<
238
+ z.output<typeof UpdateAssetOperationInputSchema>,
239
+ AssetUpdateFacts
240
+ >
241
+ | MediaApiContext<
242
+ z.output<typeof AssetIdOperationInputSchema>,
243
+ AssetDeleteFacts
244
+ >
245
+ | MediaApiContext<
246
+ z.output<typeof FolderListOperationInputSchema>,
247
+ LibraryReadFacts
248
+ >
249
+ | MediaApiContext<z.output<typeof createFolderSchema>, FolderCreateFacts>
250
+ | MediaApiContext<
251
+ z.output<typeof FolderIdOperationInputSchema>,
252
+ FolderDeleteFacts
253
+ >
254
+ | MediaApiContext<
255
+ z.output<typeof DirectUploadOperationInputSchema>,
256
+ AssetUploadFacts
257
+ >
258
+ | MediaApiContext<z.output<typeof uploadTokenRequestSchema>, AssetUploadFacts>
259
+ | MediaApiContext<
260
+ z.output<typeof VercelBlobOperationInputSchema>,
261
+ AssetUploadFacts
262
+ >;
263
+
264
+ /** Configuration hooks for the Media operation lifecycle. */
265
+ export interface MediaBackendHooks {
266
+ onBeforeUpload?: (
267
+ meta: { filename: string; mimeType: string; size?: number },
268
+ context: MediaApiContext<MediaUploadOperationInput, AssetUploadFacts>,
269
+ ) => Promise<void> | void;
270
+ onAfterUpload?: (
271
+ asset: DeepReadonly<SerializedAsset>,
272
+ context: MediaApiResultContext<
273
+ MediaUploadResultOperationInput,
274
+ AssetUploadFacts,
275
+ SerializedAsset
276
+ >,
277
+ ) => Promise<void> | void;
278
+ onBeforeDeleteAsset?: (
279
+ asset: DeepReadonly<SerializedAsset>,
280
+ context: MediaApiContext<
281
+ z.output<typeof AssetIdOperationInputSchema>,
282
+ AssetDeleteFacts
283
+ >,
284
+ ) => Promise<void> | void;
285
+ onAfterDeleteAsset?: (
286
+ assetId: string,
287
+ context: MediaApiResultContext<
288
+ z.output<typeof AssetIdOperationInputSchema>,
289
+ AssetDeleteFacts,
290
+ { readonly success: true }
291
+ >,
292
+ ) => Promise<void> | void;
293
+ onBeforeListAssets?: (
294
+ filter: z.output<typeof AssetListQuerySchema>,
295
+ context: MediaApiContext<
296
+ z.output<typeof AssetListQuerySchema>,
297
+ LibraryReadFacts
298
+ >,
299
+ ) => Promise<void> | void;
300
+ onBeforeUpdateAsset?: (
301
+ asset: DeepReadonly<SerializedAsset>,
302
+ updates: z.output<typeof updateAssetSchema>,
303
+ context: MediaApiContext<
304
+ z.output<typeof UpdateAssetOperationInputSchema>,
305
+ AssetUpdateFacts
306
+ >,
307
+ ) => Promise<void> | void;
308
+ onBeforeListFolders?: (
309
+ filter: { parentId?: string | null },
310
+ context: MediaApiContext<
311
+ z.output<typeof FolderListOperationInputSchema>,
312
+ LibraryReadFacts
313
+ >,
314
+ ) => Promise<void> | void;
315
+ onBeforeCreateFolder?: (
316
+ input: z.output<typeof createFolderSchema>,
317
+ context: MediaApiContext<
318
+ z.output<typeof createFolderSchema>,
319
+ FolderCreateFacts
320
+ >,
321
+ ) => Promise<void> | void;
322
+ onBeforeDeleteFolder?: (
323
+ folder: DeepReadonly<SerializedFolder>,
324
+ context: MediaApiContext<
325
+ z.output<typeof FolderIdOperationInputSchema>,
326
+ FolderDeleteFacts
327
+ >,
328
+ ) => Promise<void> | void;
329
+ /** Observes failures after authorization without replacing the original error. */
330
+ onError?: (
331
+ error: Error,
332
+ context: MediaOperationHookContext,
333
+ ) => Promise<void> | void;
334
+ }
335
+
336
+ interface MediaResolverContext {
337
+ readonly input: unknown;
338
+ readonly request?: Request;
339
+ readonly headers?: Headers;
340
+ readonly body?: unknown;
341
+ readonly params?: unknown;
342
+ readonly query?: unknown;
343
+ }
344
+
345
+ /** Server-only dependencies and lifecycle configuration for Media operations. */
346
+ export interface MediaOperationsConfig {
347
+ /** Storage provider used for upload initialization, storage effects, and cleanup. */
348
+ storageAdapter: StorageAdapter;
349
+ /** Maximum accepted upload size in bytes. */
350
+ maxFileSizeBytes?: number;
351
+ /** Optional exact or wildcard MIME allowlist. */
352
+ allowedMimeTypes?: string[];
353
+ /** Trusted public URL prefixes accepted during asset finalization. */
354
+ allowedUrlPrefixes?: string[];
355
+ /** Post-authorization Media domain lifecycle hooks. */
356
+ hooks?: MediaBackendHooks;
357
+ /** Resolve server-only collection scope from validated input/request context. */
358
+ resolveTenantId?: (
359
+ context: MediaResolverContext,
360
+ ) => Promise<string | null | undefined> | string | null | undefined;
361
+ }
362
+
363
+ interface AssetSnapshot {
364
+ readonly id: string;
365
+ readonly filename: string;
366
+ readonly originalName: string;
367
+ readonly mimeType: string;
368
+ readonly size: number;
369
+ readonly url: string;
370
+ readonly folderId?: string;
371
+ readonly alt?: string;
372
+ readonly tenantId?: string;
373
+ readonly createdAt: Date;
374
+ readonly updatedAt?: Date;
375
+ }
376
+
377
+ interface FolderSnapshot {
378
+ readonly id: string;
379
+ readonly name: string;
380
+ readonly parentId?: string;
381
+ readonly tenantId?: string;
382
+ readonly createdAt: Date;
383
+ readonly updatedAt?: Date;
384
+ }
385
+
386
+ function assetSnapshot(asset: Asset): AssetSnapshot {
387
+ return {
388
+ id: asset.id,
389
+ filename: asset.filename,
390
+ originalName: asset.originalName,
391
+ mimeType: asset.mimeType,
392
+ size: asset.size,
393
+ url: asset.url,
394
+ ...(asset.folderId ? { folderId: asset.folderId } : {}),
395
+ ...(asset.alt ? { alt: asset.alt } : {}),
396
+ ...(asset.tenantId ? { tenantId: asset.tenantId } : {}),
397
+ createdAt: asset.createdAt,
398
+ ...(asset.updatedAt ? { updatedAt: asset.updatedAt } : {}),
399
+ };
400
+ }
401
+
402
+ function folderSnapshot(folder: Folder): FolderSnapshot {
403
+ return {
404
+ id: folder.id,
405
+ name: folder.name,
406
+ ...(folder.parentId ? { parentId: folder.parentId } : {}),
407
+ ...(folder.tenantId ? { tenantId: folder.tenantId } : {}),
408
+ createdAt: folder.createdAt,
409
+ ...(folder.updatedAt ? { updatedAt: folder.updatedAt } : {}),
410
+ };
411
+ }
412
+
413
+ function sameDate(left: Date | undefined, right: Date | undefined) {
414
+ return left?.getTime() === right?.getTime();
415
+ }
416
+
417
+ function sameAsset(asset: Asset | null, expected: AssetSnapshot) {
418
+ return (
419
+ asset !== null &&
420
+ asset.id === expected.id &&
421
+ asset.filename === expected.filename &&
422
+ asset.originalName === expected.originalName &&
423
+ asset.mimeType === expected.mimeType &&
424
+ asset.size === expected.size &&
425
+ asset.url === expected.url &&
426
+ (asset.folderId || undefined) === expected.folderId &&
427
+ (asset.alt || undefined) === expected.alt &&
428
+ (asset.tenantId || undefined) === expected.tenantId &&
429
+ sameDate(asset.createdAt, expected.createdAt) &&
430
+ sameDate(asset.updatedAt, expected.updatedAt)
431
+ );
432
+ }
433
+
434
+ function sameFolder(folder: Folder | null, expected: FolderSnapshot) {
435
+ return (
436
+ folder !== null &&
437
+ folder.id === expected.id &&
438
+ folder.name === expected.name &&
439
+ (folder.parentId || undefined) === expected.parentId &&
440
+ (folder.tenantId || undefined) === expected.tenantId &&
441
+ sameDate(folder.createdAt, expected.createdAt) &&
442
+ sameDate(folder.updatedAt, expected.updatedAt)
443
+ );
444
+ }
445
+
446
+ function nextVersion(previous: Date) {
447
+ return new Date(Math.max(Date.now(), previous.getTime() + 1));
448
+ }
449
+
450
+ const AFFECTED_ROW_KEYS = [
451
+ "rowCount",
452
+ "affectedRows",
453
+ "rowsAffected",
454
+ "changes",
455
+ "numUpdatedRows",
456
+ ] as const;
457
+
458
+ function positive(value: unknown) {
459
+ return (
460
+ (typeof value === "number" && Number.isFinite(value) && value > 0) ||
461
+ (typeof value === "bigint" && value > 0n)
462
+ );
463
+ }
464
+
465
+ function didAffectRow(result: unknown, id: string): boolean {
466
+ if (typeof result === "number" || typeof result === "bigint")
467
+ return positive(result);
468
+ if (!result || typeof result !== "object") return false;
469
+ const record = result as Record<string, unknown>;
470
+ if ("count" in record) return positive(record.count);
471
+ if (Array.isArray(result))
472
+ return result.length > 0 && didAffectRow(result[0], id);
473
+ for (const key of AFFECTED_ROW_KEYS) {
474
+ if (key in record) return positive(record[key]);
475
+ }
476
+ if ("meta" in record) {
477
+ const meta = record.meta;
478
+ return Boolean(
479
+ meta &&
480
+ typeof meta === "object" &&
481
+ "changes" in meta &&
482
+ positive((meta as Record<string, unknown>).changes),
483
+ );
484
+ }
485
+ return record.id === id;
486
+ }
487
+
488
+ function assetWhere(snapshot: AssetSnapshot) {
489
+ return [
490
+ { field: "id", value: snapshot.id, operator: "eq" as const },
491
+ { field: "filename", value: snapshot.filename, operator: "eq" as const },
492
+ {
493
+ field: "originalName",
494
+ value: snapshot.originalName,
495
+ operator: "eq" as const,
496
+ },
497
+ { field: "mimeType", value: snapshot.mimeType, operator: "eq" as const },
498
+ { field: "size", value: snapshot.size, operator: "eq" as const },
499
+ { field: "url", value: snapshot.url, operator: "eq" as const },
500
+ {
501
+ field: "folderId",
502
+ value: snapshot.folderId ?? null,
503
+ operator: "eq" as const,
504
+ },
505
+ { field: "alt", value: snapshot.alt ?? null, operator: "eq" as const },
506
+ {
507
+ field: "tenantId",
508
+ value: snapshot.tenantId ?? null,
509
+ operator: "eq" as const,
510
+ },
511
+ { field: "createdAt", value: snapshot.createdAt, operator: "eq" as const },
512
+ ...(snapshot.updatedAt
513
+ ? [
514
+ {
515
+ field: "updatedAt",
516
+ value: snapshot.updatedAt,
517
+ operator: "eq" as const,
518
+ },
519
+ ]
520
+ : []),
521
+ ];
522
+ }
523
+
524
+ function folderWhere(snapshot: FolderSnapshot) {
525
+ return [
526
+ { field: "id", value: snapshot.id, operator: "eq" as const },
527
+ { field: "name", value: snapshot.name, operator: "eq" as const },
528
+ {
529
+ field: "parentId",
530
+ value: snapshot.parentId ?? null,
531
+ operator: "eq" as const,
532
+ },
533
+ {
534
+ field: "tenantId",
535
+ value: snapshot.tenantId ?? null,
536
+ operator: "eq" as const,
537
+ },
538
+ { field: "createdAt", value: snapshot.createdAt, operator: "eq" as const },
539
+ ...(snapshot.updatedAt
540
+ ? [
541
+ {
542
+ field: "updatedAt",
543
+ value: snapshot.updatedAt,
544
+ operator: "eq" as const,
545
+ },
546
+ ]
547
+ : []),
548
+ ];
549
+ }
550
+
551
+ function staleStateError() {
552
+ return new MediaOperationError(
553
+ 409,
554
+ "Media state changed while authorization was being evaluated. Retry the operation.",
555
+ "MEDIA_STATE_CHANGED",
556
+ );
557
+ }
558
+
559
+ function notFound(entity: "Asset" | "Folder") {
560
+ return new MediaOperationError(
561
+ 404,
562
+ `${entity} not found`,
563
+ `${entity.toUpperCase()}_NOT_FOUND`,
564
+ );
565
+ }
566
+
567
+ function normalizeError(error: unknown, fallback: string) {
568
+ return error instanceof Error
569
+ ? error
570
+ : new Error(typeof error === "string" ? error : fallback, { cause: error });
571
+ }
572
+
573
+ async function runDomainHook<T>(
574
+ run: () => Promise<T> | T,
575
+ code: string,
576
+ ): Promise<T> {
577
+ try {
578
+ return await run();
579
+ } catch (error) {
580
+ throw new MediaOperationError(
581
+ 403,
582
+ normalizeError(error, "Media operation rejected").message,
583
+ code,
584
+ );
585
+ }
586
+ }
587
+
588
+ function hookContext<TInput, TFacts, TResult>(
589
+ context: OperationContext<TInput, TFacts> & {
590
+ readonly result: DeepReadonly<TResult>;
591
+ },
592
+ legacy?: { body?: unknown; params?: unknown; query?: unknown },
593
+ ): MediaApiResultContext<TInput, TFacts, TResult>;
594
+ function hookContext<TInput, TFacts>(
595
+ context: OperationContext<TInput, TFacts>,
596
+ legacy?: { body?: unknown; params?: unknown; query?: unknown },
597
+ ): MediaApiContext<TInput, TFacts>;
598
+ function hookContext<TInput, TFacts, TResult>(
599
+ context:
600
+ | OperationContext<TInput, TFacts>
601
+ | (OperationContext<TInput, TFacts> & {
602
+ readonly result: DeepReadonly<TResult>;
603
+ }),
604
+ legacy: { body?: unknown; params?: unknown; query?: unknown } = {},
605
+ ):
606
+ | MediaApiContext<TInput, TFacts>
607
+ | MediaApiResultContext<TInput, TFacts, TResult> {
608
+ return Object.freeze({
609
+ ...context,
610
+ ...(context.request
611
+ ? { request: context.request, headers: context.request.headers }
612
+ : {}),
613
+ ...legacy,
614
+ });
615
+ }
616
+
617
+ async function notifyError(
618
+ hook: MediaBackendHooks["onError"],
619
+ error: unknown,
620
+ context: OperationContext<any, any>,
621
+ legacy: { body?: unknown; params?: unknown; query?: unknown } = {},
622
+ ) {
623
+ try {
624
+ await hook?.(
625
+ normalizeError(error, "Media operation failed"),
626
+ hookContext(context, legacy) as MediaOperationHookContext,
627
+ );
628
+ } catch {
629
+ // Error hooks are observational and never replace the operation failure.
630
+ }
631
+ }
632
+
633
+ function matchesUrlPrefix(url: string, prefix: string): boolean {
634
+ const trimmed = prefix.trim();
635
+ if (!trimmed) return false;
636
+ if (/^[a-z][a-z\d+.-]*:\/\//i.test(trimmed)) {
637
+ if (trimmed.endsWith("://")) return url.startsWith(trimmed);
638
+ const normalized = trimmed.replace(/\/+$/, "");
639
+ return url === normalized || url.startsWith(`${normalized}/`);
640
+ }
641
+ return url.startsWith(`${trimmed.replace(/\/+$/, "")}/`);
642
+ }
643
+
644
+ function sanitizeS3KeySegment(value: string): string {
645
+ return value.replace(/[/\\]/g, "-").replace(/\.\./g, "_").trim() || "unknown";
646
+ }
647
+
648
+ function validateMimeType(mimeType: string, allowed?: readonly string[]) {
649
+ if (!allowed?.length) return;
650
+ const accepted = allowed.some((pattern) =>
651
+ pattern.endsWith("/*")
652
+ ? mimeType.startsWith(pattern.slice(0, -1))
653
+ : mimeType === pattern,
654
+ );
655
+ if (!accepted) {
656
+ throw new MediaOperationError(
657
+ 415,
658
+ `MIME type '${mimeType}' is not allowed. Allowed: ${allowed.join(", ")}`,
659
+ "MIME_TYPE_NOT_ALLOWED",
660
+ );
661
+ }
662
+ }
663
+
664
+ function validateSize(size: number, maximum: number) {
665
+ if (size > maximum) {
666
+ throw new MediaOperationError(
667
+ 413,
668
+ `File size ${size} bytes exceeds the limit of ${maximum} bytes`,
669
+ "FILE_TOO_LARGE",
670
+ );
671
+ }
672
+ }
673
+
674
+ function validateAssetUrl(
675
+ url: string,
676
+ storageAdapter: StorageAdapter,
677
+ allowedUrlPrefixes?: readonly string[],
678
+ ) {
679
+ let allowed = true;
680
+ let message = "";
681
+ if (allowedUrlPrefixes?.length) {
682
+ allowed = allowedUrlPrefixes.some((prefix) =>
683
+ matchesUrlPrefix(url, prefix),
684
+ );
685
+ message = `URL must start with one of: ${allowedUrlPrefixes.join(", ")}`;
686
+ } else if (isDirectAdapter(storageAdapter)) {
687
+ allowed = false;
688
+ message =
689
+ "Client-supplied asset URLs are not allowed with localAdapter. Use POST /media/upload instead, or configure allowedUrlPrefixes to explicitly allow trusted URL prefixes.";
690
+ } else if (isS3Adapter(storageAdapter)) {
691
+ allowed = matchesUrlPrefix(url, storageAdapter.urlPrefix);
692
+ message = `URL must start with the configured S3 publicBaseUrl: ${storageAdapter.urlPrefix}`;
693
+ } else if (isVercelBlobAdapter(storageAdapter)) {
694
+ try {
695
+ allowed = new URL(url).hostname.endsWith(
696
+ storageAdapter.urlHostnameSuffix,
697
+ );
698
+ } catch {
699
+ allowed = false;
700
+ }
701
+ message = `URL hostname must end with ${storageAdapter.urlHostnameSuffix}`;
702
+ }
703
+ if (!allowed)
704
+ throw new MediaOperationError(400, message, "ASSET_URL_NOT_ALLOWED");
705
+ }
706
+
707
+ function assetFacts(snapshot: AssetSnapshot) {
708
+ return {
709
+ assetId: snapshot.id,
710
+ ...(snapshot.folderId ? { folderId: snapshot.folderId } : {}),
711
+ mimeType: snapshot.mimeType,
712
+ ...(snapshot.tenantId ? { tenantId: snapshot.tenantId } : {}),
713
+ };
714
+ }
715
+
716
+ function folderFacts(snapshot: FolderSnapshot) {
717
+ return {
718
+ folderId: snapshot.id,
719
+ ...(snapshot.parentId ? { parentId: snapshot.parentId } : {}),
720
+ ...(snapshot.tenantId ? { tenantId: snapshot.tenantId } : {}),
721
+ };
722
+ }
723
+
724
+ function withoutTenant<T extends { tenantId?: string | null }>(
725
+ value: T,
726
+ ): Omit<T, "tenantId"> {
727
+ const { tenantId: _tenantId, ...safe } = value;
728
+ return safe;
729
+ }
730
+
731
+ function plainStorageResult(value: unknown): OperationData {
732
+ if (value === undefined) return null;
733
+ let serialized: string;
734
+ try {
735
+ serialized = JSON.stringify(value);
736
+ } catch (error) {
737
+ throw new TypeError(
738
+ "Storage adapter returned a non-serializable response.",
739
+ { cause: error },
740
+ );
741
+ }
742
+ if (serialized === undefined) return null;
743
+ return JSON.parse(serialized) as OperationData;
744
+ }
745
+
746
+ type OperationAsset = SerializedAsset & {
747
+ readonly [key: string]: OperationData;
748
+ };
749
+ type OperationFolder = SerializedFolder & {
750
+ readonly [key: string]: OperationData;
751
+ };
752
+
753
+ function operationAsset(asset: Asset): OperationAsset {
754
+ return serializeAsset(asset) as OperationAsset;
755
+ }
756
+
757
+ function operationFolder(folder: Folder): OperationFolder {
758
+ return serializeFolder(folder) as OperationFolder;
759
+ }
760
+
761
+ function operationUploadToken(token: S3UploadToken) {
762
+ return token as S3UploadToken & { readonly [key: string]: OperationData };
763
+ }
764
+
765
+ const memoryRollbackMarkers = new WeakMap<Adapter, (error: unknown) => void>();
766
+
767
+ function markMemoryRollback(adapter: Adapter, error: unknown) {
768
+ memoryRollbackMarkers.get(adapter)?.(error);
769
+ }
770
+
771
+ /**
772
+ * The published memory adapter rolls transactions back from a whole-database
773
+ * clone, so overlapping callbacks can otherwise overwrite a later winner.
774
+ * Serialize every access to the shared adapter, including raw helper
775
+ * calls, while preserving the adapter's real transaction behavior.
776
+ */
777
+ function serializeMemoryOperations(adapter: Adapter): Adapter {
778
+ if (adapter.id !== "memory" || memoryRollbackMarkers.has(adapter)) {
779
+ return adapter;
780
+ }
781
+ const source: Adapter = { ...adapter };
782
+ type TransactionAdapter = Parameters<
783
+ Parameters<Adapter["transaction"]>[0]
784
+ >[0];
785
+ type ActiveAdapter = Omit<Adapter, "transaction"> &
786
+ Partial<Pick<Adapter, "transaction">>;
787
+ type LockContext = {
788
+ owner: object;
789
+ adapter: ActiveAdapter;
790
+ inTransaction?: boolean;
791
+ rollbackError?: unknown;
792
+ rollbackOnly?: boolean;
793
+ };
794
+ const lockContext = new AsyncLocalStorage<LockContext>();
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) throw new TypeError("Missing memory lock context.");
842
+ if (context.inTransaction) {
843
+ return callback(active as TransactionAdapter).catch((error) => {
844
+ context.rollbackOnly = true;
845
+ context.rollbackError = error;
846
+ throw error;
847
+ });
848
+ }
849
+ if (!active.transaction) {
850
+ throw new TypeError("Missing memory transaction adapter.");
851
+ }
852
+ return active.transaction((tx) =>
853
+ lockContext.run(
854
+ { owner: context.owner, adapter: tx, inTransaction: true },
855
+ async () => {
856
+ const transactionContext = lockContext.getStore();
857
+ const result = await callback(tx);
858
+ if (transactionContext?.rollbackOnly) {
859
+ throw transactionContext.rollbackError;
860
+ }
861
+ return result;
862
+ },
863
+ ),
864
+ );
865
+ })) as Adapter["transaction"],
866
+ };
867
+ Object.assign(adapter, serialized);
868
+ memoryRollbackMarkers.set(adapter, (error) => {
869
+ const context = lockContext.getStore();
870
+ if (!context || context.owner !== activeOwner || !context.inTransaction) {
871
+ return;
872
+ }
873
+ context.rollbackOnly = true;
874
+ context.rollbackError = error;
875
+ });
876
+ return adapter;
877
+ }
878
+
879
+ function requireAtomicTransactions(adapter: Adapter) {
880
+ if (
881
+ adapter.id !== "memory" &&
882
+ typeof adapter.options?.adapterConfig.transaction !== "function"
883
+ ) {
884
+ throw new MediaOperationError(
885
+ 500,
886
+ "Media writes require an adapter with isolated transaction support.",
887
+ "ATOMIC_TRANSACTION_REQUIRED",
888
+ );
889
+ }
890
+ }
891
+
892
+ async function claimAsset(
893
+ adapter: Pick<Adapter, "updateMany">,
894
+ snapshot: AssetSnapshot,
895
+ ) {
896
+ const claimedAt = nextVersion(snapshot.updatedAt ?? snapshot.createdAt);
897
+ const result = await adapter.updateMany({
898
+ model: "mediaAsset",
899
+ where: assetWhere(snapshot),
900
+ update: { updatedAt: claimedAt },
901
+ });
902
+ if (!didAffectRow(result, snapshot.id)) throw staleStateError();
903
+ return claimedAt;
904
+ }
905
+
906
+ async function claimFolder(
907
+ adapter: Pick<Adapter, "updateMany">,
908
+ snapshot: FolderSnapshot,
909
+ ) {
910
+ const claimedAt = nextVersion(snapshot.updatedAt ?? snapshot.createdAt);
911
+ const result = await adapter.updateMany({
912
+ model: "mediaFolder",
913
+ where: folderWhere(snapshot),
914
+ update: { updatedAt: claimedAt },
915
+ });
916
+ if (!didAffectRow(result, snapshot.id)) throw staleStateError();
917
+ return claimedAt;
918
+ }
919
+
920
+ async function restoreFolder(
921
+ adapter: Pick<Adapter, "updateMany">,
922
+ snapshot: FolderSnapshot,
923
+ claimedAt: Date,
924
+ ) {
925
+ const result = await adapter.updateMany({
926
+ model: "mediaFolder",
927
+ where: folderWhere({ ...snapshot, updatedAt: claimedAt }),
928
+ update: { updatedAt: snapshot.updatedAt ?? snapshot.createdAt },
929
+ });
930
+ if (!didAffectRow(result, snapshot.id)) throw staleStateError();
931
+ }
932
+
933
+ async function collectFolderSubtree(
934
+ adapter: Pick<Adapter, "findMany">,
935
+ root: FolderSnapshot,
936
+ ): Promise<FolderSnapshot[]> {
937
+ const subtree = [root];
938
+ const seen = new Set([root.id]);
939
+ for (let index = 0; index < subtree.length; index++) {
940
+ const children = await adapter.findMany<Folder>({
941
+ model: "mediaFolder",
942
+ where: [{ field: "parentId", value: subtree[index]!.id }],
943
+ });
944
+ for (const child of children) {
945
+ if (seen.has(child.id)) throw staleStateError();
946
+ if ((child.tenantId || undefined) !== root.tenantId) {
947
+ throw staleStateError();
948
+ }
949
+ seen.add(child.id);
950
+ subtree.push(folderSnapshot(child));
951
+ }
952
+ }
953
+ return subtree;
954
+ }
955
+
956
+ async function verifyClaimedFolderSubtree(
957
+ adapter: Pick<Adapter, "findMany" | "count">,
958
+ subtree: readonly FolderSnapshot[],
959
+ claims: ReadonlyMap<string, Date>,
960
+ ) {
961
+ const root = subtree[0];
962
+ if (!root) throw staleStateError();
963
+ const currentSubtree = await collectFolderSubtree(adapter, {
964
+ ...root,
965
+ updatedAt: claims.get(root.id)!,
966
+ });
967
+ if (currentSubtree.length !== subtree.length) throw staleStateError();
968
+ const expectedById = new Map(
969
+ subtree.map((folder) => [folder.id, folder] as const),
970
+ );
971
+ for (const current of currentSubtree) {
972
+ const expected = expectedById.get(current.id);
973
+ if (
974
+ !expected ||
975
+ !sameFolder(current, {
976
+ ...expected,
977
+ updatedAt: claims.get(expected.id)!,
978
+ })
979
+ ) {
980
+ throw staleStateError();
981
+ }
982
+ }
983
+ let totalAssets = 0;
984
+ for (const folder of subtree) {
985
+ totalAssets += await adapter.count({
986
+ model: "mediaAsset",
987
+ where: [{ field: "folderId", value: folder.id }],
988
+ });
989
+ }
990
+ if (totalAssets > 0) {
991
+ throw new MediaOperationError(
992
+ 409,
993
+ `Cannot delete folder: it or one of its subfolders contains ${totalAssets} asset(s). Move or delete them first.`,
994
+ "FOLDER_NOT_EMPTY",
995
+ );
996
+ }
997
+ }
998
+
999
+ function parseVercelInitialize(
1000
+ body: z.output<typeof VercelBlobOperationInputSchema>["body"],
1001
+ ) {
1002
+ const record = body as unknown as Record<string, OperationData>;
1003
+ const payload =
1004
+ record.payload &&
1005
+ typeof record.payload === "object" &&
1006
+ !Array.isArray(record.payload)
1007
+ ? (record.payload as Record<string, OperationData>)
1008
+ : record;
1009
+ const pathname =
1010
+ typeof payload.pathname === "string" ? payload.pathname : "asset";
1011
+ const clientPayload =
1012
+ typeof payload.clientPayload === "string" ? payload.clientPayload : null;
1013
+ let parsed: z.output<typeof VercelClientPayloadSchema> = {};
1014
+ try {
1015
+ parsed = VercelClientPayloadSchema.parse(
1016
+ clientPayload ? JSON.parse(clientPayload) : {},
1017
+ );
1018
+ } catch {
1019
+ throw new MediaOperationError(
1020
+ 400,
1021
+ "Invalid Vercel Blob client upload metadata.",
1022
+ "INVALID_UPLOAD_BODY",
1023
+ );
1024
+ }
1025
+ return {
1026
+ pathname,
1027
+ filename: pathname.split("/").pop() ?? pathname,
1028
+ mimeType: parsed.mimeType ?? "application/octet-stream",
1029
+ size: parsed.size,
1030
+ folderId: parsed.folderId,
1031
+ };
1032
+ }
1033
+
1034
+ /** Create the complete Media operation inventory used by every server transport. */
1035
+ export function createMediaOperations(
1036
+ sourceAdapter: Adapter,
1037
+ config: MediaOperationsConfig,
1038
+ ): MediaOperations {
1039
+ const adapter = serializeMemoryOperations(sourceAdapter);
1040
+ const {
1041
+ storageAdapter,
1042
+ maxFileSizeBytes = 10 * 1024 * 1024,
1043
+ allowedMimeTypes,
1044
+ allowedUrlPrefixes,
1045
+ hooks,
1046
+ resolveTenantId,
1047
+ } = config;
1048
+ const tenants = new WeakMap<object, string | undefined>();
1049
+ const assetLists = new WeakMap<
1050
+ object,
1051
+ Awaited<ReturnType<typeof listAssets>>
1052
+ >();
1053
+ const assets = new WeakMap<object, AssetSnapshot>();
1054
+ const folders = new WeakMap<object, FolderSnapshot | undefined>();
1055
+ const targetFolders = new WeakMap<object, FolderSnapshot | undefined>();
1056
+ const folderSubtrees = new WeakMap<object, readonly FolderSnapshot[]>();
1057
+ const vercelContexts = new WeakMap<
1058
+ object,
1059
+ {
1060
+ phase: "initialize" | "callback";
1061
+ pathname: string;
1062
+ filename: string;
1063
+ mimeType: string;
1064
+ size?: number;
1065
+ folderId?: string;
1066
+ tenantId?: string;
1067
+ }
1068
+ >();
1069
+
1070
+ const resolveTenant = async (
1071
+ input: object,
1072
+ request: Request | undefined,
1073
+ legacy: { body?: unknown; params?: unknown; query?: unknown },
1074
+ ) => {
1075
+ const tenantId =
1076
+ request && resolveTenantId
1077
+ ? ((await resolveTenantId({
1078
+ input,
1079
+ request,
1080
+ headers: request.headers,
1081
+ ...legacy,
1082
+ })) ?? undefined)
1083
+ : undefined;
1084
+ tenants.set(input, tenantId);
1085
+ return tenantId;
1086
+ };
1087
+
1088
+ const loadFolder = async (
1089
+ id: string | undefined,
1090
+ tenantId: string | undefined,
1091
+ ) => {
1092
+ if (!id) return undefined;
1093
+ const folder = await getFolderById(adapter, id);
1094
+ if (!folder || (tenantId !== undefined && folder.tenantId !== tenantId)) {
1095
+ throw notFound("Folder");
1096
+ }
1097
+ return folderSnapshot(folder);
1098
+ };
1099
+
1100
+ const bindFolderTenant = (
1101
+ input: object,
1102
+ resolvedTenantId: string | undefined,
1103
+ folder: FolderSnapshot | undefined,
1104
+ ) => {
1105
+ const tenantId = resolvedTenantId ?? folder?.tenantId;
1106
+ tenants.set(input, tenantId);
1107
+ return tenantId;
1108
+ };
1109
+
1110
+ const verifyFolder = async (
1111
+ reader: Pick<Adapter, "findOne">,
1112
+ snapshot: FolderSnapshot | undefined,
1113
+ ) => {
1114
+ if (!snapshot) return;
1115
+ const current =
1116
+ (await reader.findOne<Folder>({
1117
+ model: "mediaFolder",
1118
+ where: [{ field: "id", value: snapshot.id }],
1119
+ })) ?? null;
1120
+ if (!sameFolder(current, snapshot)) throw staleStateError();
1121
+ };
1122
+
1123
+ const listAssetsOperation = defineOperation({
1124
+ input: AssetListQuerySchema,
1125
+ permission: mediaPermissions.library.read,
1126
+ facts: async ({ input, request }) => {
1127
+ await resolveTenant(input as object, request, { query: input });
1128
+ return undefined;
1129
+ },
1130
+ additionalPermissions: async ({ input }) => {
1131
+ const result = await listAssets(adapter, {
1132
+ ...input,
1133
+ tenantId: tenants.get(input as object),
1134
+ });
1135
+ assetLists.set(input as object, result);
1136
+ return result.items.map((asset) =>
1137
+ mediaPermissions.asset.read(assetFacts(assetSnapshot(asset))),
1138
+ );
1139
+ },
1140
+ execute: async (context) => {
1141
+ await runDomainHook(
1142
+ () =>
1143
+ hooks?.onBeforeListAssets?.(
1144
+ { ...context.input },
1145
+ hookContext(context, { query: context.input }),
1146
+ ),
1147
+ "LIST_ASSETS_REJECTED",
1148
+ );
1149
+ const result = assetLists.get(context.input as object);
1150
+ assetLists.delete(context.input as object);
1151
+ if (!result) {
1152
+ throw new MediaOperationError(
1153
+ 500,
1154
+ "Asset-list authorization snapshot is unavailable.",
1155
+ "AUTHORIZATION_SNAPSHOT_MISSING",
1156
+ );
1157
+ }
1158
+ return {
1159
+ items: result.items.map((asset) =>
1160
+ withoutTenant(serializeAsset(asset)),
1161
+ ),
1162
+ total: result.total,
1163
+ ...(result.limit !== undefined ? { limit: result.limit } : {}),
1164
+ ...(result.offset !== undefined ? { offset: result.offset } : {}),
1165
+ };
1166
+ },
1167
+ onError: ({ error, ...context }) =>
1168
+ notifyError(hooks?.onError, error, context, {
1169
+ query: context.input,
1170
+ }),
1171
+ });
1172
+
1173
+ const createAssetOperation = defineOperation({
1174
+ input: createAssetSchema,
1175
+ permission: mediaPermissions.asset.upload,
1176
+ facts: async ({ input, request }) => {
1177
+ const tenantId = await resolveTenant(input as object, request, {
1178
+ body: input,
1179
+ });
1180
+ const folder = await loadFolder(input.folderId, tenantId);
1181
+ const effectiveTenantId = bindFolderTenant(
1182
+ input as object,
1183
+ tenantId,
1184
+ folder,
1185
+ );
1186
+ folders.set(input as object, folder);
1187
+ return {
1188
+ phase: "finalize" as const,
1189
+ ...(folder ? { folderId: folder.id } : {}),
1190
+ mimeType: input.mimeType,
1191
+ ...(effectiveTenantId ? { tenantId: effectiveTenantId } : {}),
1192
+ } satisfies AssetUploadFacts;
1193
+ },
1194
+ execute: (context) => {
1195
+ requireAtomicTransactions(adapter);
1196
+ return adapter.transaction(async (tx) => {
1197
+ const folder = folders.get(context.input as object);
1198
+ await verifyFolder(tx, folder);
1199
+ const folderClaim = folder ? await claimFolder(tx, folder) : undefined;
1200
+ await runDomainHook(
1201
+ () =>
1202
+ hooks?.onBeforeUpload?.(
1203
+ {
1204
+ filename: context.input.filename,
1205
+ mimeType: context.input.mimeType,
1206
+ size: context.input.size,
1207
+ },
1208
+ hookContext(context, { body: context.input }),
1209
+ ),
1210
+ "UPLOAD_REJECTED",
1211
+ );
1212
+ validateMimeType(context.input.mimeType, allowedMimeTypes);
1213
+ validateSize(context.input.size, maxFileSizeBytes);
1214
+ validateAssetUrl(context.input.url, storageAdapter, allowedUrlPrefixes);
1215
+ const asset = await createAsset(tx, {
1216
+ ...context.input,
1217
+ tenantId: tenants.get(context.input as object),
1218
+ });
1219
+ if (folder && folderClaim) await restoreFolder(tx, folder, folderClaim);
1220
+ return operationAsset(asset);
1221
+ });
1222
+ },
1223
+ after: ((context: any) =>
1224
+ hooks?.onAfterUpload?.(
1225
+ context.result,
1226
+ hookContext(context, { body: context.input }) as MediaApiResultContext<
1227
+ z.output<typeof createAssetSchema>,
1228
+ AssetUploadFacts,
1229
+ SerializedAsset
1230
+ >,
1231
+ )) as any,
1232
+ onError: ({ error, ...context }) => {
1233
+ markMemoryRollback(adapter, error);
1234
+ return notifyError(hooks?.onError, error, context, {
1235
+ body: context.input,
1236
+ });
1237
+ },
1238
+ });
1239
+
1240
+ const updateAssetOperation = defineOperation({
1241
+ input: UpdateAssetOperationInputSchema,
1242
+ permission: mediaPermissions.asset.update,
1243
+ facts: async ({ input, request }) => {
1244
+ const tenantId = await resolveTenant(input as object, request, {
1245
+ body: input.data,
1246
+ params: { id: input.id },
1247
+ });
1248
+ const asset = await getAssetById(adapter, input.id);
1249
+ if (!asset || (tenantId !== undefined && asset.tenantId !== tenantId)) {
1250
+ throw notFound("Asset");
1251
+ }
1252
+ const snapshot = assetSnapshot(asset);
1253
+ assets.set(input as object, snapshot);
1254
+ const changesFolder = Object.hasOwn(input.data, "folderId");
1255
+ const target =
1256
+ typeof input.data.folderId === "string"
1257
+ ? await loadFolder(input.data.folderId, tenantId)
1258
+ : undefined;
1259
+ if (target && target.tenantId !== snapshot.tenantId) {
1260
+ throw notFound("Folder");
1261
+ }
1262
+ targetFolders.set(input as object, target);
1263
+ return {
1264
+ ...assetFacts(snapshot),
1265
+ ...(changesFolder ? { targetFolderId: target?.id ?? null } : {}),
1266
+ } satisfies AssetUpdateFacts;
1267
+ },
1268
+ execute: (context) => {
1269
+ requireAtomicTransactions(adapter);
1270
+ return adapter.transaction(async (tx) => {
1271
+ const snapshot = assets.get(context.input as object);
1272
+ if (!snapshot) throw staleStateError();
1273
+ const current =
1274
+ (await tx.findOne<Asset>({
1275
+ model: "mediaAsset",
1276
+ where: [{ field: "id", value: snapshot.id }],
1277
+ })) ?? null;
1278
+ if (!sameAsset(current, snapshot)) throw staleStateError();
1279
+ const target = targetFolders.get(context.input as object);
1280
+ await verifyFolder(tx, target);
1281
+ const targetClaim = target ? await claimFolder(tx, target) : undefined;
1282
+ const claimedAt = await claimAsset(tx, snapshot);
1283
+ await runDomainHook(
1284
+ () =>
1285
+ hooks?.onBeforeUpdateAsset?.(
1286
+ operationAsset(current as Asset),
1287
+ { ...context.input.data },
1288
+ hookContext(context, {
1289
+ body: context.input.data,
1290
+ params: { id: context.input.id },
1291
+ }),
1292
+ ),
1293
+ "UPDATE_ASSET_REJECTED",
1294
+ );
1295
+ const update = {
1296
+ ...(context.input.data.alt !== undefined
1297
+ ? { alt: context.input.data.alt }
1298
+ : {}),
1299
+ ...(Object.hasOwn(context.input.data, "folderId")
1300
+ ? { folderId: context.input.data.folderId }
1301
+ : {}),
1302
+ updatedAt: nextVersion(claimedAt),
1303
+ };
1304
+ const matched = await tx.updateMany({
1305
+ model: "mediaAsset",
1306
+ where: assetWhere({ ...snapshot, updatedAt: claimedAt }),
1307
+ update,
1308
+ });
1309
+ if (!didAffectRow(matched, snapshot.id)) throw staleStateError();
1310
+ if (target && targetClaim) await restoreFolder(tx, target, targetClaim);
1311
+ const updated = await getAssetById(tx, snapshot.id);
1312
+ if (!updated) throw notFound("Asset");
1313
+ return operationAsset(updated);
1314
+ });
1315
+ },
1316
+ onError: ({ error, ...context }) => {
1317
+ markMemoryRollback(adapter, error);
1318
+ return notifyError(hooks?.onError, error, context, {
1319
+ body: context.input.data,
1320
+ params: { id: context.input.id },
1321
+ });
1322
+ },
1323
+ });
1324
+
1325
+ const deleteAssetOperation = defineOperation({
1326
+ input: AssetIdOperationInputSchema,
1327
+ permission: mediaPermissions.asset.delete,
1328
+ facts: async ({ input, request }) => {
1329
+ const tenantId = await resolveTenant(input as object, request, {
1330
+ params: { id: input.id },
1331
+ });
1332
+ const asset = await getAssetById(adapter, input.id);
1333
+ if (!asset || (tenantId !== undefined && asset.tenantId !== tenantId)) {
1334
+ throw notFound("Asset");
1335
+ }
1336
+ const snapshot = assetSnapshot(asset);
1337
+ assets.set(input as object, snapshot);
1338
+ return assetFacts(snapshot) satisfies AssetDeleteFacts;
1339
+ },
1340
+ execute: (context) => {
1341
+ requireAtomicTransactions(adapter);
1342
+ return adapter.transaction(async (tx) => {
1343
+ const snapshot = assets.get(context.input as object);
1344
+ if (!snapshot) throw staleStateError();
1345
+ const current = await getAssetById(tx, snapshot.id);
1346
+ if (!sameAsset(current, snapshot)) throw staleStateError();
1347
+ const claimedAt = await claimAsset(tx, snapshot);
1348
+ await runDomainHook(
1349
+ () =>
1350
+ hooks?.onBeforeDeleteAsset?.(
1351
+ operationAsset(current as Asset),
1352
+ hookContext(context, { params: { id: context.input.id } }),
1353
+ ),
1354
+ "DELETE_ASSET_REJECTED",
1355
+ );
1356
+ try {
1357
+ await storageAdapter.delete(snapshot.url);
1358
+ } catch (error) {
1359
+ throw new MediaOperationError(
1360
+ 500,
1361
+ "Failed to delete file from storage",
1362
+ "STORAGE_DELETE_FAILED",
1363
+ );
1364
+ }
1365
+ const deleted = await tx.deleteMany({
1366
+ model: "mediaAsset",
1367
+ where: assetWhere({ ...snapshot, updatedAt: claimedAt }),
1368
+ });
1369
+ if (!didAffectRow(deleted, snapshot.id)) throw staleStateError();
1370
+ return { success: true } as const;
1371
+ });
1372
+ },
1373
+ after: (context) =>
1374
+ hooks?.onAfterDeleteAsset?.(
1375
+ context.input.id,
1376
+ hookContext(context, { params: { id: context.input.id } }),
1377
+ ),
1378
+ onError: ({ error, ...context }) => {
1379
+ markMemoryRollback(adapter, error);
1380
+ return notifyError(hooks?.onError, error, context, {
1381
+ params: { id: context.input.id },
1382
+ });
1383
+ },
1384
+ });
1385
+
1386
+ const listFoldersOperation = defineOperation({
1387
+ input: FolderListOperationInputSchema,
1388
+ permission: mediaPermissions.library.read,
1389
+ facts: async ({ input, request }) => {
1390
+ await resolveTenant(input as object, request, { query: input });
1391
+ return undefined;
1392
+ },
1393
+ execute: async (context) => {
1394
+ const filter = { parentId: context.input.parentId };
1395
+ await runDomainHook(
1396
+ () =>
1397
+ hooks?.onBeforeListFolders?.(
1398
+ filter,
1399
+ hookContext(context, { query: context.input }),
1400
+ ),
1401
+ "LIST_FOLDERS_REJECTED",
1402
+ );
1403
+ const result = await listFolders(adapter, {
1404
+ ...filter,
1405
+ tenantId: tenants.get(context.input as object),
1406
+ });
1407
+ return result.map((folder) => withoutTenant(serializeFolder(folder)));
1408
+ },
1409
+ onError: ({ error, ...context }) =>
1410
+ notifyError(hooks?.onError, error, context, {
1411
+ query: context.input,
1412
+ }),
1413
+ });
1414
+
1415
+ const createFolderOperation = defineOperation({
1416
+ input: createFolderSchema,
1417
+ permission: mediaPermissions.folder.create,
1418
+ facts: async ({ input, request }) => {
1419
+ const tenantId = await resolveTenant(input as object, request, {
1420
+ body: input,
1421
+ });
1422
+ const parent = await loadFolder(input.parentId, tenantId);
1423
+ const effectiveTenantId = bindFolderTenant(
1424
+ input as object,
1425
+ tenantId,
1426
+ parent,
1427
+ );
1428
+ folders.set(input as object, parent);
1429
+ return {
1430
+ ...(parent ? { parentId: parent.id } : {}),
1431
+ ...(effectiveTenantId ? { tenantId: effectiveTenantId } : {}),
1432
+ } satisfies FolderCreateFacts;
1433
+ },
1434
+ execute: (context) => {
1435
+ requireAtomicTransactions(adapter);
1436
+ return adapter.transaction(async (tx) => {
1437
+ const parent = folders.get(context.input as object);
1438
+ await verifyFolder(tx, parent);
1439
+ const parentClaim = parent ? await claimFolder(tx, parent) : undefined;
1440
+ await runDomainHook(
1441
+ () =>
1442
+ hooks?.onBeforeCreateFolder?.(
1443
+ { ...context.input },
1444
+ hookContext(context, { body: context.input }),
1445
+ ),
1446
+ "CREATE_FOLDER_REJECTED",
1447
+ );
1448
+ const now = new Date();
1449
+ const folder = await tx.create<Folder>({
1450
+ model: "mediaFolder",
1451
+ data: {
1452
+ ...context.input,
1453
+ tenantId: tenants.get(context.input as object),
1454
+ createdAt: now,
1455
+ updatedAt: now,
1456
+ },
1457
+ });
1458
+ if (parent && parentClaim) await restoreFolder(tx, parent, parentClaim);
1459
+ return operationFolder(folder);
1460
+ });
1461
+ },
1462
+ onError: ({ error, ...context }) => {
1463
+ markMemoryRollback(adapter, error);
1464
+ return notifyError(hooks?.onError, error, context, {
1465
+ body: context.input,
1466
+ });
1467
+ },
1468
+ });
1469
+
1470
+ const deleteFolderOperation = defineOperation({
1471
+ input: FolderIdOperationInputSchema,
1472
+ permission: mediaPermissions.folder.delete,
1473
+ facts: async ({ input, request }) => {
1474
+ const tenantId = await resolveTenant(input as object, request, {
1475
+ params: { id: input.id },
1476
+ });
1477
+ const folder = await loadFolder(input.id, tenantId);
1478
+ if (!folder) throw notFound("Folder");
1479
+ folders.set(input as object, folder);
1480
+ return folderFacts(folder) satisfies FolderDeleteFacts;
1481
+ },
1482
+ additionalPermissions: async ({ input }) => {
1483
+ const root = folders.get(input as object);
1484
+ if (!root) throw staleStateError();
1485
+ const subtree = await collectFolderSubtree(adapter, root);
1486
+ folderSubtrees.set(input as object, subtree);
1487
+ return subtree
1488
+ .slice(1)
1489
+ .map((folder) => mediaPermissions.folder.delete(folderFacts(folder)));
1490
+ },
1491
+ execute: (context) => {
1492
+ requireAtomicTransactions(adapter);
1493
+ return adapter.transaction(async (tx) => {
1494
+ const subtree = folderSubtrees.get(context.input as object);
1495
+ folderSubtrees.delete(context.input as object);
1496
+ if (!subtree?.length) throw staleStateError();
1497
+ const snapshot = subtree[0]!;
1498
+ const claims = new Map<string, Date>();
1499
+ for (const folder of subtree) {
1500
+ claims.set(folder.id, await claimFolder(tx, folder));
1501
+ }
1502
+ await verifyClaimedFolderSubtree(tx, subtree, claims);
1503
+ await runDomainHook(
1504
+ () =>
1505
+ hooks?.onBeforeDeleteFolder?.(
1506
+ operationFolder({
1507
+ ...snapshot,
1508
+ updatedAt: snapshot.updatedAt,
1509
+ }),
1510
+ hookContext(context, { params: { id: context.input.id } }),
1511
+ ),
1512
+ "DELETE_FOLDER_REJECTED",
1513
+ );
1514
+ await verifyClaimedFolderSubtree(tx, subtree, claims);
1515
+ for (const folder of [...subtree].reverse()) {
1516
+ const deleted = await tx.deleteMany({
1517
+ model: "mediaFolder",
1518
+ where: folderWhere({
1519
+ ...folder,
1520
+ updatedAt: claims.get(folder.id)!,
1521
+ }),
1522
+ });
1523
+ if (!didAffectRow(deleted, folder.id)) throw staleStateError();
1524
+ }
1525
+ return { success: true } as const;
1526
+ });
1527
+ },
1528
+ onError: ({ error, ...context }) => {
1529
+ markMemoryRollback(adapter, error);
1530
+ return notifyError(hooks?.onError, error, context, {
1531
+ params: { id: context.input.id },
1532
+ });
1533
+ },
1534
+ });
1535
+
1536
+ const uploadDirectOperation = defineOperation({
1537
+ input: DirectUploadOperationInputSchema,
1538
+ permission: mediaPermissions.asset.upload,
1539
+ facts: async ({ input, request }) => {
1540
+ const tenantId = await resolveTenant(input as object, request, {
1541
+ body: input,
1542
+ });
1543
+ const folder = await loadFolder(input.folderId, tenantId);
1544
+ const effectiveTenantId = bindFolderTenant(
1545
+ input as object,
1546
+ tenantId,
1547
+ folder,
1548
+ );
1549
+ folders.set(input as object, folder);
1550
+ return {
1551
+ phase: "direct" as const,
1552
+ ...(folder ? { folderId: folder.id } : {}),
1553
+ mimeType: input.mimeType,
1554
+ ...(effectiveTenantId ? { tenantId: effectiveTenantId } : {}),
1555
+ } satisfies AssetUploadFacts;
1556
+ },
1557
+ execute: async (context) => {
1558
+ requireAtomicTransactions(adapter);
1559
+ if (!isDirectAdapter(storageAdapter)) {
1560
+ throw new MediaOperationError(
1561
+ 400,
1562
+ "Direct upload is only supported with the local storage adapter",
1563
+ "DIRECT_UPLOAD_UNSUPPORTED",
1564
+ );
1565
+ }
1566
+ let uploadedUrl: string | undefined;
1567
+ try {
1568
+ return await adapter.transaction(async (tx) => {
1569
+ const folder = folders.get(context.input as object);
1570
+ await verifyFolder(tx, folder);
1571
+ const folderClaim = folder
1572
+ ? await claimFolder(tx, folder)
1573
+ : undefined;
1574
+ await runDomainHook(
1575
+ () =>
1576
+ hooks?.onBeforeUpload?.(
1577
+ {
1578
+ filename: context.input.filename,
1579
+ mimeType: context.input.mimeType,
1580
+ size: context.input.size,
1581
+ },
1582
+ hookContext(context, { body: context.input }),
1583
+ ),
1584
+ "UPLOAD_REJECTED",
1585
+ );
1586
+ validateMimeType(context.input.mimeType, allowedMimeTypes);
1587
+ validateSize(context.input.size, maxFileSizeBytes);
1588
+ const buffer = Buffer.from(context.input.contentBase64, "base64");
1589
+ if (buffer.byteLength !== context.input.size) {
1590
+ throw new MediaOperationError(
1591
+ 400,
1592
+ "Uploaded file size does not match its bytes",
1593
+ "INVALID_UPLOAD_SIZE",
1594
+ );
1595
+ }
1596
+ const { url } = await storageAdapter.upload(buffer, {
1597
+ filename: context.input.filename,
1598
+ mimeType: context.input.mimeType,
1599
+ size: context.input.size,
1600
+ ...(folder ? { folderId: folder.id } : {}),
1601
+ });
1602
+ uploadedUrl = url;
1603
+ const asset = await createAsset(tx, {
1604
+ filename: url.split("/").pop() ?? context.input.filename,
1605
+ originalName: context.input.filename,
1606
+ mimeType: context.input.mimeType,
1607
+ size: context.input.size,
1608
+ url,
1609
+ ...(folder ? { folderId: folder.id } : {}),
1610
+ tenantId: tenants.get(context.input as object),
1611
+ });
1612
+ if (folder && folderClaim)
1613
+ await restoreFolder(tx, folder, folderClaim);
1614
+ return operationAsset(asset);
1615
+ });
1616
+ } catch (error) {
1617
+ if (uploadedUrl) {
1618
+ try {
1619
+ await storageAdapter.delete(uploadedUrl);
1620
+ } catch (cleanupError) {
1621
+ console.error(
1622
+ `[btst/media] Failed to clean up orphaned storage file after operation failure: ${uploadedUrl}`,
1623
+ cleanupError,
1624
+ );
1625
+ }
1626
+ }
1627
+ throw error;
1628
+ }
1629
+ },
1630
+ after: ((context: any) =>
1631
+ hooks?.onAfterUpload?.(
1632
+ context.result,
1633
+ hookContext(context, { body: context.input }) as MediaApiResultContext<
1634
+ z.output<typeof DirectUploadOperationInputSchema>,
1635
+ AssetUploadFacts,
1636
+ SerializedAsset
1637
+ >,
1638
+ )) as any,
1639
+ onError: ({ error, ...context }) => {
1640
+ markMemoryRollback(adapter, error);
1641
+ return notifyError(hooks?.onError, error, context, {
1642
+ body: context.input,
1643
+ });
1644
+ },
1645
+ });
1646
+
1647
+ const uploadTokenOperation = defineOperation({
1648
+ input: uploadTokenRequestSchema,
1649
+ permission: mediaPermissions.asset.upload,
1650
+ facts: async ({ input, request }) => {
1651
+ const tenantId = await resolveTenant(input as object, request, {
1652
+ body: input,
1653
+ });
1654
+ const folder = await loadFolder(input.folderId, tenantId);
1655
+ const effectiveTenantId = bindFolderTenant(
1656
+ input as object,
1657
+ tenantId,
1658
+ folder,
1659
+ );
1660
+ folders.set(input as object, folder);
1661
+ return {
1662
+ phase: "initialize" as const,
1663
+ ...(folder ? { folderId: folder.id } : {}),
1664
+ mimeType: input.mimeType,
1665
+ ...(effectiveTenantId ? { tenantId: effectiveTenantId } : {}),
1666
+ } satisfies AssetUploadFacts;
1667
+ },
1668
+ execute: async (context) => {
1669
+ if (!isS3Adapter(storageAdapter)) {
1670
+ throw new MediaOperationError(
1671
+ 400,
1672
+ "Upload token endpoint is only supported with the S3 storage adapter",
1673
+ "UPLOAD_TOKEN_UNSUPPORTED",
1674
+ );
1675
+ }
1676
+ const folder = folders.get(context.input as object);
1677
+ const issueToken = async () => {
1678
+ await runDomainHook(
1679
+ () =>
1680
+ hooks?.onBeforeUpload?.(
1681
+ {
1682
+ filename: context.input.filename,
1683
+ mimeType: context.input.mimeType,
1684
+ size: context.input.size,
1685
+ },
1686
+ hookContext(context, { body: context.input }),
1687
+ ),
1688
+ "UPLOAD_REJECTED",
1689
+ );
1690
+ validateMimeType(context.input.mimeType, allowedMimeTypes);
1691
+ validateSize(context.input.size, maxFileSizeBytes);
1692
+ return operationUploadToken(
1693
+ await storageAdapter.generateUploadToken({
1694
+ filename: sanitizeS3KeySegment(context.input.filename),
1695
+ mimeType: context.input.mimeType,
1696
+ size: context.input.size,
1697
+ ...(folder ? { folderId: folder.id } : {}),
1698
+ }),
1699
+ );
1700
+ };
1701
+ if (!folder) return issueToken();
1702
+ requireAtomicTransactions(adapter);
1703
+ return adapter.transaction(async (tx) => {
1704
+ await verifyFolder(tx, folder);
1705
+ const claimedAt = await claimFolder(tx, folder);
1706
+ const token = await issueToken();
1707
+ await restoreFolder(tx, folder, claimedAt);
1708
+ return token;
1709
+ });
1710
+ },
1711
+ onError: ({ error, ...context }) =>
1712
+ notifyError(hooks?.onError, error, context, {
1713
+ body: context.input,
1714
+ }),
1715
+ });
1716
+
1717
+ const uploadVercelBlobOperation = defineOperation({
1718
+ input: VercelBlobOperationInputSchema,
1719
+ permission: mediaPermissions.asset.upload,
1720
+ facts: async ({ input, request }) => {
1721
+ if (!isVercelBlobAdapter(storageAdapter)) {
1722
+ throw new MediaOperationError(
1723
+ 400,
1724
+ "Vercel Blob endpoint is only supported with the vercelBlobAdapter",
1725
+ "VERCEL_BLOB_UNSUPPORTED",
1726
+ );
1727
+ }
1728
+ if ("type" in input.body && input.body.type === "blob.upload-completed") {
1729
+ if (!request)
1730
+ throw new TypeError("Vercel Blob callbacks require a request.");
1731
+ let verified: Awaited<ReturnType<typeof storageAdapter.verifyCallback>>;
1732
+ try {
1733
+ verified = await storageAdapter.verifyCallback(
1734
+ request,
1735
+ input.body as unknown as VercelBlobUploadCompletedBody,
1736
+ );
1737
+ } catch {
1738
+ throw new MediaOperationError(
1739
+ 401,
1740
+ "Invalid Vercel Blob provider callback.",
1741
+ "INVALID_PROVIDER_CALLBACK",
1742
+ );
1743
+ }
1744
+ const context = {
1745
+ phase: "callback" as const,
1746
+ filename: verified.pathname.split("/").pop() ?? verified.pathname,
1747
+ ...verified,
1748
+ };
1749
+ vercelContexts.set(input as object, context);
1750
+ return {
1751
+ phase: "callback" as const,
1752
+ ...(verified.folderId ? { folderId: verified.folderId } : {}),
1753
+ mimeType: verified.mimeType,
1754
+ ...(verified.tenantId ? { tenantId: verified.tenantId } : {}),
1755
+ } satisfies AssetUploadFacts;
1756
+ }
1757
+ const normalized = parseVercelInitialize(input.body);
1758
+ const tenantId = await resolveTenant(input as object, request, {
1759
+ body: input.body,
1760
+ });
1761
+ const folder = await loadFolder(normalized.folderId, tenantId);
1762
+ const effectiveTenantId = bindFolderTenant(
1763
+ input as object,
1764
+ tenantId,
1765
+ folder,
1766
+ );
1767
+ folders.set(input as object, folder);
1768
+ const context = {
1769
+ phase: "initialize" as const,
1770
+ ...normalized,
1771
+ ...(folder ? { folderId: folder.id } : {}),
1772
+ ...(effectiveTenantId ? { tenantId: effectiveTenantId } : {}),
1773
+ };
1774
+ vercelContexts.set(input as object, context);
1775
+ return {
1776
+ phase: "initialize" as const,
1777
+ ...(folder ? { folderId: folder.id } : {}),
1778
+ mimeType: normalized.mimeType,
1779
+ ...(effectiveTenantId ? { tenantId: effectiveTenantId } : {}),
1780
+ } satisfies AssetUploadFacts;
1781
+ },
1782
+ execute: async (context) => {
1783
+ if (!isVercelBlobAdapter(storageAdapter) || !context.request) {
1784
+ throw new TypeError(
1785
+ "Vercel Blob execution requires its configured adapter and request.",
1786
+ );
1787
+ }
1788
+ const request = context.request;
1789
+ const upload = vercelContexts.get(context.input as object);
1790
+ if (!upload) throw staleStateError();
1791
+ const handleProviderRequest = async () => {
1792
+ if (upload.phase === "initialize") {
1793
+ await runDomainHook(
1794
+ () =>
1795
+ hooks?.onBeforeUpload?.(
1796
+ {
1797
+ filename: upload.filename,
1798
+ mimeType: upload.mimeType,
1799
+ size: upload.size,
1800
+ },
1801
+ hookContext(context, { body: context.input.body }),
1802
+ ),
1803
+ "UPLOAD_REJECTED",
1804
+ );
1805
+ validateMimeType(upload.mimeType, allowedMimeTypes);
1806
+ if (upload.size !== undefined)
1807
+ validateSize(upload.size, maxFileSizeBytes);
1808
+ }
1809
+ const response = await storageAdapter.handleRequest(
1810
+ request,
1811
+ context.input.body as unknown as VercelBlobHandleUploadBody,
1812
+ {
1813
+ onBeforeGenerateToken: async (pathname) => {
1814
+ if (
1815
+ upload.phase !== "initialize" ||
1816
+ pathname !== upload.pathname
1817
+ ) {
1818
+ throw staleStateError();
1819
+ }
1820
+ return {
1821
+ addRandomSuffix: true,
1822
+ allowedContentTypes: allowedMimeTypes?.length
1823
+ ? allowedMimeTypes
1824
+ : undefined,
1825
+ maximumSizeInBytes: maxFileSizeBytes,
1826
+ tokenPayload: JSON.stringify({
1827
+ version: 1,
1828
+ pathname: upload.pathname,
1829
+ mimeType: upload.mimeType,
1830
+ ...(upload.size !== undefined ? { size: upload.size } : {}),
1831
+ ...(upload.folderId ? { folderId: upload.folderId } : {}),
1832
+ ...(upload.tenantId ? { tenantId: upload.tenantId } : {}),
1833
+ }),
1834
+ };
1835
+ },
1836
+ },
1837
+ );
1838
+ return plainStorageResult(response);
1839
+ };
1840
+ if (upload.phase === "initialize") {
1841
+ const folder = folders.get(context.input as object);
1842
+ if (folder) {
1843
+ requireAtomicTransactions(adapter);
1844
+ return adapter.transaction(async (tx) => {
1845
+ await verifyFolder(tx, folder);
1846
+ const claimedAt = await claimFolder(tx, folder);
1847
+ const response = await handleProviderRequest();
1848
+ await restoreFolder(tx, folder, claimedAt);
1849
+ return response;
1850
+ });
1851
+ }
1852
+ }
1853
+ return handleProviderRequest();
1854
+ },
1855
+ onError: ({ error, ...context }) =>
1856
+ notifyError(hooks?.onError, error, context, {
1857
+ body: context.input.body,
1858
+ }),
1859
+ });
1860
+
1861
+ return {
1862
+ listAssets: listAssetsOperation,
1863
+ createAsset: createAssetOperation,
1864
+ updateAsset: updateAssetOperation,
1865
+ deleteAsset: deleteAssetOperation,
1866
+ listFolders: listFoldersOperation,
1867
+ createFolder: createFolderOperation,
1868
+ deleteFolder: deleteFolderOperation,
1869
+ uploadDirect: uploadDirectOperation,
1870
+ uploadToken: uploadTokenOperation,
1871
+ uploadVercelBlob: uploadVercelBlobOperation,
1872
+ };
1873
+ }