@btst/stack 3.0.0-rc.1 → 3.0.0-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1172) hide show
  1. package/README.md +122 -46
  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 +30 -12
  67. package/dist/next/index.d.mts +30 -12
  68. package/dist/next/index.d.ts +30 -12
  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/next/page.cjs +8 -6
  91. package/dist/packages/stack/src/next/page.mjs +8 -6
  92. package/dist/packages/stack/src/plugin-registration.cjs +59 -0
  93. package/dist/packages/stack/src/plugin-registration.mjs +57 -0
  94. package/dist/packages/stack/src/plugins/ai-chat/api/lifecycle-migrations.cjs +18 -0
  95. package/dist/packages/stack/src/plugins/ai-chat/api/lifecycle-migrations.mjs +16 -0
  96. package/dist/packages/stack/src/plugins/ai-chat/api/operations.cjs +1341 -0
  97. package/dist/packages/stack/src/plugins/ai-chat/api/operations.mjs +1333 -0
  98. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.cjs +82 -640
  99. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +78 -641
  100. package/dist/packages/stack/src/plugins/ai-chat/api/serializers.cjs +23 -0
  101. package/dist/packages/stack/src/plugins/ai-chat/api/serializers.mjs +20 -0
  102. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.cjs +183 -111
  103. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.mjs +187 -115
  104. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.cjs +562 -116
  105. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.mjs +567 -121
  106. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.cjs +6 -6
  107. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.mjs +6 -6
  108. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-message.cjs +1 -1
  109. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-message.mjs +1 -1
  110. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.cjs +45 -29
  111. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.mjs +46 -30
  112. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/404-page.cjs +1 -1
  113. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/404-page.mjs +1 -1
  114. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/chat-page.cjs +46 -7
  115. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/chat-page.internal.cjs +5 -3
  116. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/chat-page.internal.mjs +5 -3
  117. package/dist/packages/stack/src/plugins/ai-chat/client/components/pages/chat-page.mjs +48 -9
  118. package/dist/packages/stack/src/plugins/ai-chat/client/components/shared/default-error.cjs +1 -1
  119. package/dist/packages/stack/src/plugins/ai-chat/client/components/shared/default-error.mjs +1 -1
  120. package/dist/packages/stack/src/plugins/ai-chat/client/components/tool-call-display.cjs +1 -1
  121. package/dist/packages/stack/src/plugins/ai-chat/client/components/tool-call-display.mjs +1 -1
  122. package/dist/packages/stack/src/plugins/ai-chat/client/hooks/ai-chat-resource.cjs +1 -1
  123. package/dist/packages/stack/src/plugins/ai-chat/client/hooks/ai-chat-resource.mjs +1 -1
  124. package/dist/packages/stack/src/plugins/ai-chat/client/hooks/chat-hooks.cjs +179 -19
  125. package/dist/packages/stack/src/plugins/ai-chat/client/hooks/chat-hooks.mjs +180 -21
  126. package/dist/packages/stack/src/plugins/ai-chat/client/navigation.cjs +11 -0
  127. package/dist/packages/stack/src/plugins/ai-chat/client/navigation.mjs +9 -0
  128. package/dist/packages/stack/src/plugins/ai-chat/client/overrides.cjs +24 -0
  129. package/dist/packages/stack/src/plugins/ai-chat/client/overrides.mjs +21 -1
  130. package/dist/packages/stack/src/plugins/ai-chat/client/plugin.cjs +152 -82
  131. package/dist/packages/stack/src/plugins/ai-chat/client/plugin.mjs +152 -82
  132. package/dist/packages/stack/src/plugins/api/create-endpoint.cjs +27 -9
  133. package/dist/packages/stack/src/plugins/api/create-endpoint.mjs +27 -10
  134. package/dist/packages/stack/src/plugins/api/endpoint-inventory.cjs +125 -0
  135. package/dist/packages/stack/src/plugins/api/endpoint-inventory.mjs +123 -0
  136. package/dist/packages/stack/src/plugins/api/operation.cjs +208 -0
  137. package/dist/packages/stack/src/plugins/api/operation.mjs +198 -0
  138. package/dist/packages/stack/src/plugins/blog/api/lifecycle-migrations.cjs +17 -0
  139. package/dist/packages/stack/src/plugins/blog/api/lifecycle-migrations.mjs +15 -0
  140. package/dist/packages/stack/src/plugins/blog/api/mutations.cjs +10 -2
  141. package/dist/packages/stack/src/plugins/blog/api/mutations.mjs +10 -2
  142. package/dist/packages/stack/src/plugins/blog/api/operations.cjs +455 -0
  143. package/dist/packages/stack/src/plugins/blog/api/operations.mjs +448 -0
  144. package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +51 -298
  145. package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +55 -304
  146. package/dist/packages/stack/src/plugins/blog/client/components/forms/image-field.cjs +2 -1
  147. package/dist/packages/stack/src/plugins/blog/client/components/forms/image-field.mjs +2 -1
  148. package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.cjs +2 -1
  149. package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.mjs +2 -1
  150. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.cjs +82 -67
  151. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.mjs +84 -69
  152. package/dist/packages/stack/src/plugins/blog/client/components/pages/404-page.cjs +2 -1
  153. package/dist/packages/stack/src/plugins/blog/client/components/pages/404-page.mjs +2 -1
  154. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.cjs +22 -4
  155. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.cjs +2 -1
  156. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.mjs +2 -1
  157. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.mjs +23 -5
  158. package/dist/packages/stack/src/plugins/blog/client/components/pages/home-page.cjs +6 -2
  159. package/dist/packages/stack/src/plugins/blog/client/components/pages/home-page.internal.cjs +2 -1
  160. package/dist/packages/stack/src/plugins/blog/client/components/pages/home-page.internal.mjs +2 -1
  161. package/dist/packages/stack/src/plugins/blog/client/components/pages/home-page.mjs +6 -2
  162. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.cjs +4 -2
  163. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.cjs +2 -1
  164. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.mjs +2 -1
  165. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.mjs +4 -2
  166. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.cjs +30 -3
  167. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +2 -1
  168. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +2 -1
  169. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.mjs +31 -4
  170. package/dist/packages/stack/src/plugins/blog/client/components/pages/tag-page.cjs +4 -1
  171. package/dist/packages/stack/src/plugins/blog/client/components/pages/tag-page.internal.cjs +2 -1
  172. package/dist/packages/stack/src/plugins/blog/client/components/pages/tag-page.internal.mjs +2 -1
  173. package/dist/packages/stack/src/plugins/blog/client/components/pages/tag-page.mjs +4 -1
  174. package/dist/packages/stack/src/plugins/blog/client/components/shared/collapsible-tag-list.cjs +2 -1
  175. package/dist/packages/stack/src/plugins/blog/client/components/shared/collapsible-tag-list.mjs +2 -1
  176. package/dist/packages/stack/src/plugins/blog/client/components/shared/default-error.cjs +2 -1
  177. package/dist/packages/stack/src/plugins/blog/client/components/shared/default-error.mjs +2 -1
  178. package/dist/packages/stack/src/plugins/blog/client/components/shared/on-this-page.cjs +3 -2
  179. package/dist/packages/stack/src/plugins/blog/client/components/shared/on-this-page.mjs +3 -2
  180. package/dist/packages/stack/src/plugins/blog/client/components/shared/page-wrapper.cjs +2 -1
  181. package/dist/packages/stack/src/plugins/blog/client/components/shared/page-wrapper.mjs +2 -1
  182. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-card.cjs +2 -1
  183. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-card.mjs +2 -1
  184. package/dist/packages/stack/src/plugins/blog/client/components/shared/posts-list.cjs +2 -1
  185. package/dist/packages/stack/src/plugins/blog/client/components/shared/posts-list.mjs +2 -1
  186. package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.cjs +2 -1
  187. package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.mjs +2 -1
  188. package/dist/packages/stack/src/plugins/blog/client/components/shared/search-input.cjs +2 -2
  189. package/dist/packages/stack/src/plugins/blog/client/components/shared/search-input.mjs +1 -1
  190. package/dist/packages/stack/src/plugins/blog/client/constants.cjs +5 -0
  191. package/dist/packages/stack/src/plugins/blog/client/constants.mjs +3 -0
  192. package/dist/packages/stack/src/plugins/blog/client/hooks/blog-resource.cjs +2 -1
  193. package/dist/packages/stack/src/plugins/blog/client/hooks/blog-resource.mjs +2 -1
  194. package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +169 -163
  195. package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +169 -163
  196. package/dist/packages/stack/src/plugins/client/resource/hooks.cjs +31 -16
  197. package/dist/packages/stack/src/plugins/client/resource/hooks.mjs +31 -16
  198. package/dist/packages/stack/src/plugins/client/resource/internal.cjs +66 -52
  199. package/dist/packages/stack/src/plugins/client/resource/internal.mjs +66 -52
  200. package/dist/packages/stack/src/plugins/client/resource/use-form.cjs +20 -17
  201. package/dist/packages/stack/src/plugins/client/resource/use-form.mjs +20 -17
  202. package/dist/packages/stack/src/plugins/client/resource/use-select.cjs +39 -33
  203. package/dist/packages/stack/src/plugins/client/resource/use-select.mjs +39 -33
  204. package/dist/packages/stack/src/plugins/cms/api/lifecycle-migrations.cjs +13 -0
  205. package/dist/packages/stack/src/plugins/cms/api/lifecycle-migrations.mjs +11 -0
  206. package/dist/packages/stack/src/plugins/cms/api/operations.cjs +1763 -0
  207. package/dist/packages/stack/src/plugins/cms/api/operations.mjs +1756 -0
  208. package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +165 -752
  209. package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +164 -755
  210. package/dist/packages/stack/src/plugins/cms/client/components/forms/content-form.cjs +2 -1
  211. package/dist/packages/stack/src/plugins/cms/client/components/forms/content-form.mjs +2 -1
  212. package/dist/packages/stack/src/plugins/cms/client/components/forms/file-upload.cjs +2 -1
  213. package/dist/packages/stack/src/plugins/cms/client/components/forms/file-upload.mjs +2 -1
  214. package/dist/packages/stack/src/plugins/cms/client/components/forms/relation-field.cjs +2 -1
  215. package/dist/packages/stack/src/plugins/cms/client/components/forms/relation-field.mjs +2 -1
  216. package/dist/packages/stack/src/plugins/cms/client/components/inverse-relations-panel.cjs +23 -13
  217. package/dist/packages/stack/src/plugins/cms/client/components/inverse-relations-panel.mjs +24 -14
  218. package/dist/packages/stack/src/plugins/cms/client/components/pages/404-page.cjs +5 -4
  219. package/dist/packages/stack/src/plugins/cms/client/components/pages/404-page.mjs +6 -5
  220. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.cjs +40 -7
  221. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.cjs +15 -9
  222. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.mjs +14 -8
  223. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.mjs +41 -8
  224. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.cjs +7 -1
  225. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.internal.cjs +42 -29
  226. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.internal.mjs +40 -27
  227. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.mjs +7 -1
  228. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.cjs +4 -1
  229. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.internal.cjs +13 -7
  230. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.internal.mjs +12 -6
  231. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.mjs +4 -1
  232. package/dist/packages/stack/src/plugins/cms/client/components/shared/page-wrapper.cjs +2 -1
  233. package/dist/packages/stack/src/plugins/cms/client/components/shared/page-wrapper.mjs +2 -1
  234. package/dist/packages/stack/src/plugins/cms/client/constants.cjs +5 -0
  235. package/dist/packages/stack/src/plugins/cms/client/constants.mjs +3 -0
  236. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-resource.cjs +2 -1
  237. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-resource.mjs +2 -1
  238. package/dist/packages/stack/src/plugins/cms/client/overrides.cjs +26 -0
  239. package/dist/packages/stack/src/plugins/cms/client/overrides.mjs +24 -0
  240. package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +102 -81
  241. package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +103 -82
  242. package/dist/packages/stack/src/plugins/comments/api/getters.cjs +6 -2
  243. package/dist/packages/stack/src/plugins/comments/api/getters.mjs +6 -3
  244. package/dist/packages/stack/src/plugins/comments/api/lifecycle-migrations.cjs +18 -0
  245. package/dist/packages/stack/src/plugins/comments/api/lifecycle-migrations.mjs +16 -0
  246. package/dist/packages/stack/src/plugins/comments/api/mutations.cjs +179 -68
  247. package/dist/packages/stack/src/plugins/comments/api/mutations.mjs +179 -68
  248. package/dist/packages/stack/src/plugins/comments/api/operations.cjs +453 -0
  249. package/dist/packages/stack/src/plugins/comments/api/operations.mjs +445 -0
  250. package/dist/packages/stack/src/plugins/comments/api/plugin.cjs +51 -276
  251. package/dist/packages/stack/src/plugins/comments/api/plugin.mjs +48 -277
  252. package/dist/packages/stack/src/plugins/comments/client/components/comment-count.cjs +32 -5
  253. package/dist/packages/stack/src/plugins/comments/client/components/comment-count.mjs +34 -7
  254. package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.cjs +161 -105
  255. package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.mjs +162 -106
  256. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.cjs +14 -2
  257. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.cjs +141 -71
  258. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.mjs +142 -72
  259. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.mjs +14 -2
  260. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-state.cjs +12 -0
  261. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-state.mjs +9 -0
  262. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.cjs +2 -1
  263. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.cjs +40 -26
  264. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.mjs +40 -26
  265. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.mjs +2 -1
  266. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.cjs +9 -1
  267. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.cjs +25 -20
  268. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.mjs +26 -21
  269. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.mjs +9 -1
  270. package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.cjs +2 -1
  271. package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.mjs +2 -1
  272. package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.cjs +2 -1
  273. package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.mjs +2 -1
  274. package/dist/packages/stack/src/plugins/comments/client/constants.cjs +5 -0
  275. package/dist/packages/stack/src/plugins/comments/client/constants.mjs +3 -0
  276. package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.cjs +323 -290
  277. package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.mjs +325 -292
  278. package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.cjs +1 -0
  279. package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.mjs +1 -0
  280. package/dist/packages/stack/src/plugins/comments/client/plugin.cjs +78 -46
  281. package/dist/packages/stack/src/plugins/comments/client/plugin.mjs +80 -48
  282. package/dist/packages/stack/src/plugins/form-builder/api/getters.cjs +9 -0
  283. package/dist/packages/stack/src/plugins/form-builder/api/getters.mjs +9 -1
  284. package/dist/packages/stack/src/plugins/form-builder/api/lifecycle-migrations.cjs +15 -0
  285. package/dist/packages/stack/src/plugins/form-builder/api/lifecycle-migrations.mjs +13 -0
  286. package/dist/packages/stack/src/plugins/form-builder/api/operations.cjs +1093 -0
  287. package/dist/packages/stack/src/plugins/form-builder/api/operations.mjs +1082 -0
  288. package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +97 -466
  289. package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +92 -468
  290. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.cjs +5 -0
  291. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.mjs +5 -0
  292. package/dist/packages/stack/src/plugins/form-builder/client/components/forms/form-renderer.cjs +41 -11
  293. package/dist/packages/stack/src/plugins/form-builder/client/components/forms/form-renderer.mjs +42 -12
  294. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/404-page.cjs +8 -5
  295. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/404-page.mjs +9 -6
  296. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-builder-page.cjs +36 -3
  297. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-builder-page.internal.cjs +32 -11
  298. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-builder-page.internal.mjs +35 -14
  299. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-builder-page.mjs +37 -4
  300. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.cjs +6 -1
  301. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.internal.cjs +34 -26
  302. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.internal.mjs +34 -26
  303. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.mjs +6 -1
  304. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.cjs +24 -7
  305. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.cjs +72 -40
  306. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.mjs +76 -44
  307. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.mjs +25 -8
  308. package/dist/packages/stack/src/plugins/form-builder/client/components/shared/page-wrapper.cjs +2 -1
  309. package/dist/packages/stack/src/plugins/form-builder/client/components/shared/page-wrapper.mjs +2 -1
  310. package/dist/packages/stack/src/plugins/form-builder/client/constants.cjs +5 -0
  311. package/dist/packages/stack/src/plugins/form-builder/client/constants.mjs +3 -0
  312. package/dist/packages/stack/src/plugins/form-builder/client/hooks/form-builder-hooks.cjs +29 -0
  313. package/dist/packages/stack/src/plugins/form-builder/client/hooks/form-builder-hooks.mjs +28 -1
  314. package/dist/packages/stack/src/plugins/form-builder/client/hooks/form-builder-resource.cjs +2 -1
  315. package/dist/packages/stack/src/plugins/form-builder/client/hooks/form-builder-resource.mjs +2 -1
  316. package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +113 -86
  317. package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +114 -87
  318. package/dist/packages/stack/src/plugins/form-builder/schemas.cjs +9 -3
  319. package/dist/packages/stack/src/plugins/form-builder/schemas.mjs +9 -3
  320. package/dist/packages/stack/src/plugins/kanban/api/getters.cjs +47 -36
  321. package/dist/packages/stack/src/plugins/kanban/api/getters.mjs +47 -37
  322. package/dist/packages/stack/src/plugins/kanban/api/lifecycle-migrations.cjs +23 -0
  323. package/dist/packages/stack/src/plugins/kanban/api/lifecycle-migrations.mjs +21 -0
  324. package/dist/packages/stack/src/plugins/kanban/api/operations.cjs +1552 -0
  325. package/dist/packages/stack/src/plugins/kanban/api/operations.mjs +1543 -0
  326. package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +64 -631
  327. package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +62 -634
  328. package/dist/packages/stack/src/plugins/kanban/api/serializers.cjs +21 -0
  329. package/dist/packages/stack/src/plugins/kanban/api/serializers.mjs +21 -1
  330. package/dist/packages/stack/src/plugins/kanban/client/components/forms/board-form.cjs +2 -1
  331. package/dist/packages/stack/src/plugins/kanban/client/components/forms/board-form.mjs +2 -1
  332. package/dist/packages/stack/src/plugins/kanban/client/components/forms/column-form.cjs +2 -1
  333. package/dist/packages/stack/src/plugins/kanban/client/components/forms/column-form.mjs +2 -1
  334. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.cjs +72 -54
  335. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.mjs +74 -56
  336. package/dist/packages/stack/src/plugins/kanban/client/components/pages/404-page.cjs +4 -6
  337. package/dist/packages/stack/src/plugins/kanban/client/components/pages/404-page.mjs +5 -7
  338. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.cjs +22 -6
  339. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.cjs +82 -77
  340. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.mjs +83 -78
  341. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.mjs +23 -7
  342. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.cjs +2 -1
  343. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.internal.cjs +34 -24
  344. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.internal.mjs +35 -25
  345. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.mjs +2 -1
  346. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.cjs +2 -1
  347. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.internal.cjs +6 -9
  348. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.internal.mjs +7 -10
  349. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.mjs +2 -1
  350. package/dist/packages/stack/src/plugins/kanban/client/components/shared/column-content.cjs +72 -45
  351. package/dist/packages/stack/src/plugins/kanban/client/components/shared/column-content.mjs +73 -46
  352. package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.cjs +2 -1
  353. package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.mjs +2 -1
  354. package/dist/packages/stack/src/plugins/kanban/client/components/shared/kanban-board.cjs +4 -4
  355. package/dist/packages/stack/src/plugins/kanban/client/components/shared/kanban-board.mjs +4 -4
  356. package/dist/packages/stack/src/plugins/kanban/client/components/shared/permission-access-any.cjs +23 -0
  357. package/dist/packages/stack/src/plugins/kanban/client/components/shared/permission-access-any.mjs +21 -0
  358. package/dist/packages/stack/src/plugins/kanban/client/components/shared/task-card.cjs +54 -17
  359. package/dist/packages/stack/src/plugins/kanban/client/components/shared/task-card.mjs +55 -18
  360. package/dist/packages/stack/src/plugins/kanban/client/components/shared/user-avatar.cjs +2 -1
  361. package/dist/packages/stack/src/plugins/kanban/client/components/shared/user-avatar.mjs +2 -1
  362. package/dist/packages/stack/src/plugins/kanban/client/constants.cjs +5 -0
  363. package/dist/packages/stack/src/plugins/kanban/client/constants.mjs +3 -0
  364. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.cjs +38 -9
  365. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.mjs +39 -10
  366. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-resource.cjs +2 -1
  367. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-resource.mjs +2 -1
  368. package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +177 -104
  369. package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +178 -105
  370. package/dist/packages/stack/src/plugins/kanban/schemas.cjs +32 -23
  371. package/dist/packages/stack/src/plugins/kanban/schemas.mjs +33 -21
  372. package/dist/packages/stack/src/plugins/media/api/lifecycle-migrations.cjs +9 -0
  373. package/dist/packages/stack/src/plugins/media/api/lifecycle-migrations.mjs +7 -0
  374. package/dist/packages/stack/src/plugins/media/api/mutations.cjs +7 -2
  375. package/dist/packages/stack/src/plugins/media/api/mutations.mjs +7 -2
  376. package/dist/packages/stack/src/plugins/media/api/operations.cjs +1299 -0
  377. package/dist/packages/stack/src/plugins/media/api/operations.mjs +1290 -0
  378. package/dist/packages/stack/src/plugins/media/api/plugin.cjs +131 -508
  379. package/dist/packages/stack/src/plugins/media/api/plugin.mjs +127 -510
  380. package/dist/packages/stack/src/plugins/media/api/query-key-defs.cjs +26 -2
  381. package/dist/packages/stack/src/plugins/media/api/query-key-defs.mjs +25 -3
  382. package/dist/packages/stack/src/plugins/media/api/serializers.cjs +4 -2
  383. package/dist/packages/stack/src/plugins/media/api/serializers.mjs +4 -2
  384. package/dist/packages/stack/src/plugins/media/asset-url.cjs +13 -0
  385. package/dist/packages/stack/src/plugins/media/asset-url.mjs +11 -0
  386. package/dist/packages/stack/src/plugins/media/client/components/media-picker/asset-card.cjs +10 -10
  387. package/dist/packages/stack/src/plugins/media/client/components/media-picker/asset-card.mjs +12 -12
  388. package/dist/packages/stack/src/plugins/media/client/components/media-picker/folder-tree.cjs +47 -27
  389. package/dist/packages/stack/src/plugins/media/client/components/media-picker/folder-tree.mjs +49 -29
  390. package/dist/packages/stack/src/plugins/media/client/components/media-picker/index.cjs +225 -180
  391. package/dist/packages/stack/src/plugins/media/client/components/media-picker/index.mjs +228 -183
  392. package/dist/packages/stack/src/plugins/media/client/components/media-picker/upload-tab.cjs +1 -8
  393. package/dist/packages/stack/src/plugins/media/client/components/media-picker/upload-tab.mjs +2 -9
  394. package/dist/packages/stack/src/plugins/media/client/components/media-picker/url-tab.cjs +0 -6
  395. package/dist/packages/stack/src/plugins/media/client/components/media-picker/url-tab.mjs +1 -7
  396. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.cjs +4 -2
  397. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.internal.cjs +92 -75
  398. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.internal.mjs +93 -76
  399. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.mjs +4 -2
  400. package/dist/packages/stack/src/plugins/media/client/components/upload-permission-check.cjs +52 -0
  401. package/dist/packages/stack/src/plugins/media/client/components/upload-permission-check.mjs +49 -0
  402. package/dist/packages/stack/src/plugins/media/client/constants.cjs +5 -0
  403. package/dist/packages/stack/src/plugins/media/client/constants.mjs +3 -0
  404. package/dist/packages/stack/src/plugins/media/client/hooks/media-resource.cjs +2 -1
  405. package/dist/packages/stack/src/plugins/media/client/hooks/media-resource.mjs +2 -1
  406. package/dist/packages/stack/src/plugins/media/client/hooks/use-media.cjs +214 -43
  407. package/dist/packages/stack/src/plugins/media/client/hooks/use-media.mjs +217 -46
  408. package/dist/packages/stack/src/plugins/media/client/plugin.cjs +122 -62
  409. package/dist/packages/stack/src/plugins/media/client/plugin.mjs +123 -63
  410. package/dist/packages/stack/src/plugins/media/client/upload.cjs +121 -52
  411. package/dist/packages/stack/src/plugins/media/client/upload.mjs +121 -53
  412. package/dist/packages/stack/src/plugins/media/db.cjs +8 -0
  413. package/dist/packages/stack/src/plugins/media/db.mjs +8 -0
  414. package/dist/packages/stack/src/plugins/open-api/api/generator.cjs +36 -5
  415. package/dist/packages/stack/src/plugins/open-api/api/generator.mjs +36 -5
  416. package/dist/packages/stack/src/plugins/open-api/api/plugin.cjs +22 -11
  417. package/dist/packages/stack/src/plugins/open-api/api/plugin.mjs +22 -11
  418. package/dist/packages/stack/src/plugins/route-docs/client/components/pages/docs-page.cjs +65 -34
  419. package/dist/packages/stack/src/plugins/route-docs/client/components/pages/docs-page.mjs +56 -25
  420. package/dist/packages/stack/src/plugins/route-docs/client/constants.cjs +5 -0
  421. package/dist/packages/stack/src/plugins/route-docs/client/constants.mjs +3 -0
  422. package/dist/packages/stack/src/plugins/route-docs/client/hooks.cjs +9 -8
  423. package/dist/packages/stack/src/plugins/route-docs/client/hooks.mjs +10 -9
  424. package/dist/packages/stack/src/plugins/route-docs/client/plugin.cjs +143 -75
  425. package/dist/packages/stack/src/plugins/route-docs/client/plugin.mjs +144 -74
  426. package/dist/packages/stack/src/plugins/route-docs/client/schema.cjs +26 -0
  427. package/dist/packages/stack/src/plugins/route-docs/client/schema.mjs +23 -0
  428. package/dist/packages/stack/src/plugins/route-docs/generator.cjs +7 -4
  429. package/dist/packages/stack/src/plugins/route-docs/generator.mjs +7 -4
  430. package/dist/packages/stack/src/plugins/ui-builder/client/components/page-renderer.cjs +41 -12
  431. package/dist/packages/stack/src/plugins/ui-builder/client/components/page-renderer.mjs +42 -13
  432. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.cjs +37 -3
  433. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.cjs +32 -20
  434. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.mjs +34 -22
  435. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.mjs +38 -4
  436. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-list-page.cjs +8 -2
  437. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-list-page.internal.cjs +37 -19
  438. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-list-page.internal.mjs +38 -20
  439. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-list-page.mjs +8 -2
  440. package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/default-error.cjs +2 -1
  441. package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/default-error.mjs +2 -1
  442. package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/page-wrapper.cjs +2 -1
  443. package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/page-wrapper.mjs +2 -1
  444. package/dist/packages/stack/src/plugins/ui-builder/client/constants.cjs +5 -0
  445. package/dist/packages/stack/src/plugins/ui-builder/client/constants.mjs +3 -0
  446. package/dist/packages/stack/src/plugins/ui-builder/client/hooks/ui-builder-resource.cjs +2 -1
  447. package/dist/packages/stack/src/plugins/ui-builder/client/hooks/ui-builder-resource.mjs +2 -1
  448. package/dist/packages/stack/src/plugins/ui-builder/client/overrides.cjs +8 -0
  449. package/dist/packages/stack/src/plugins/ui-builder/client/overrides.mjs +6 -0
  450. package/dist/packages/stack/src/plugins/ui-builder/client/plugin.cjs +93 -53
  451. package/dist/packages/stack/src/plugins/ui-builder/client/plugin.mjs +94 -54
  452. package/dist/packages/stack/src/plugins/utils.cjs +4 -12
  453. package/dist/packages/stack/src/plugins/utils.mjs +5 -12
  454. package/dist/packages/stack/src/react-router/layout.cjs +14 -0
  455. package/dist/packages/stack/src/react-router/layout.mjs +12 -0
  456. package/dist/packages/stack/src/react-router/page.cjs +27 -16
  457. package/dist/packages/stack/src/react-router/page.mjs +28 -17
  458. package/dist/packages/stack/src/shared/initial-identity.cjs +27 -0
  459. package/dist/packages/stack/src/shared/initial-identity.mjs +23 -0
  460. package/dist/packages/stack/src/tanstack/layout.cjs +10 -0
  461. package/dist/packages/stack/src/tanstack/layout.mjs +8 -0
  462. package/dist/packages/stack/src/tanstack/page.cjs +11 -5
  463. package/dist/packages/stack/src/tanstack/page.mjs +11 -5
  464. package/dist/plugins/ai-chat/api/index.cjs +10 -0
  465. package/dist/plugins/ai-chat/api/index.d.cts +31 -5
  466. package/dist/plugins/ai-chat/api/index.d.mts +31 -5
  467. package/dist/plugins/ai-chat/api/index.d.ts +31 -5
  468. package/dist/plugins/ai-chat/api/index.mjs +3 -1
  469. package/dist/plugins/ai-chat/client/components/index.d.cts +1 -1
  470. package/dist/plugins/ai-chat/client/components/index.d.mts +1 -1
  471. package/dist/plugins/ai-chat/client/components/index.d.ts +1 -1
  472. package/dist/plugins/ai-chat/client/hooks/index.cjs +1 -0
  473. package/dist/plugins/ai-chat/client/hooks/index.d.cts +14 -8
  474. package/dist/plugins/ai-chat/client/hooks/index.d.mts +14 -8
  475. package/dist/plugins/ai-chat/client/hooks/index.d.ts +14 -8
  476. package/dist/plugins/ai-chat/client/hooks/index.mjs +1 -1
  477. package/dist/plugins/ai-chat/client/index.d.cts +21 -25
  478. package/dist/plugins/ai-chat/client/index.d.mts +21 -25
  479. package/dist/plugins/ai-chat/client/index.d.ts +21 -25
  480. package/dist/plugins/ai-chat/permissions.cjs +90 -0
  481. package/dist/plugins/ai-chat/permissions.d.cts +84 -0
  482. package/dist/plugins/ai-chat/permissions.d.mts +84 -0
  483. package/dist/plugins/ai-chat/permissions.d.ts +84 -0
  484. package/dist/plugins/ai-chat/permissions.mjs +88 -0
  485. package/dist/plugins/ai-chat/query-keys.cjs +116 -18
  486. package/dist/plugins/ai-chat/query-keys.d.cts +6 -2
  487. package/dist/plugins/ai-chat/query-keys.d.mts +6 -2
  488. package/dist/plugins/ai-chat/query-keys.d.ts +6 -2
  489. package/dist/plugins/ai-chat/query-keys.mjs +116 -19
  490. package/dist/plugins/api/index.cjs +4 -0
  491. package/dist/plugins/api/index.d.cts +13 -18
  492. package/dist/plugins/api/index.d.mts +13 -18
  493. package/dist/plugins/api/index.d.ts +13 -18
  494. package/dist/plugins/api/index.mjs +1 -0
  495. package/dist/plugins/blog/api/index.cjs +9 -2
  496. package/dist/plugins/blog/api/index.d.cts +118 -4
  497. package/dist/plugins/blog/api/index.d.mts +118 -4
  498. package/dist/plugins/blog/api/index.d.ts +118 -4
  499. package/dist/plugins/blog/api/index.mjs +4 -1
  500. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  501. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  502. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  503. package/dist/plugins/blog/client/index.d.cts +210 -226
  504. package/dist/plugins/blog/client/index.d.mts +210 -226
  505. package/dist/plugins/blog/client/index.d.ts +210 -226
  506. package/dist/plugins/blog/permissions.cjs +47 -0
  507. package/dist/plugins/blog/permissions.d.cts +49 -0
  508. package/dist/plugins/blog/permissions.d.mts +49 -0
  509. package/dist/plugins/blog/permissions.d.ts +49 -0
  510. package/dist/plugins/blog/permissions.mjs +45 -0
  511. package/dist/plugins/blog/query-keys.d.cts +7 -3
  512. package/dist/plugins/blog/query-keys.d.mts +7 -3
  513. package/dist/plugins/blog/query-keys.d.ts +7 -3
  514. package/dist/plugins/client/hooks/index.d.cts +2 -2
  515. package/dist/plugins/client/hooks/index.d.mts +2 -2
  516. package/dist/plugins/client/hooks/index.d.ts +2 -2
  517. package/dist/plugins/client/index.cjs +3 -0
  518. package/dist/plugins/client/index.d.cts +30 -10
  519. package/dist/plugins/client/index.d.mts +30 -10
  520. package/dist/plugins/client/index.d.ts +30 -10
  521. package/dist/plugins/client/index.mjs +3 -0
  522. package/dist/plugins/cms/api/index.cjs +7 -0
  523. package/dist/plugins/cms/api/index.d.cts +173 -4
  524. package/dist/plugins/cms/api/index.d.mts +173 -4
  525. package/dist/plugins/cms/api/index.d.ts +173 -4
  526. package/dist/plugins/cms/api/index.mjs +2 -0
  527. package/dist/plugins/cms/client/hooks/index.d.cts +1 -1
  528. package/dist/plugins/cms/client/hooks/index.d.mts +1 -1
  529. package/dist/plugins/cms/client/hooks/index.d.ts +1 -1
  530. package/dist/plugins/cms/client/index.d.cts +188 -184
  531. package/dist/plugins/cms/client/index.d.mts +188 -184
  532. package/dist/plugins/cms/client/index.d.ts +188 -184
  533. package/dist/plugins/cms/permissions.cjs +46 -0
  534. package/dist/plugins/cms/permissions.d.cts +42 -0
  535. package/dist/plugins/cms/permissions.d.mts +42 -0
  536. package/dist/plugins/cms/permissions.d.ts +42 -0
  537. package/dist/plugins/cms/permissions.mjs +44 -0
  538. package/dist/plugins/cms/query-keys.d.cts +4 -4
  539. package/dist/plugins/cms/query-keys.d.mts +4 -4
  540. package/dist/plugins/cms/query-keys.d.ts +4 -4
  541. package/dist/plugins/comments/api/index.cjs +10 -0
  542. package/dist/plugins/comments/api/index.d.cts +54 -18
  543. package/dist/plugins/comments/api/index.d.mts +54 -18
  544. package/dist/plugins/comments/api/index.d.ts +54 -18
  545. package/dist/plugins/comments/api/index.mjs +3 -0
  546. package/dist/plugins/comments/client/components/index.d.cts +7 -2
  547. package/dist/plugins/comments/client/components/index.d.mts +7 -2
  548. package/dist/plugins/comments/client/components/index.d.ts +7 -2
  549. package/dist/plugins/comments/client/hooks/index.d.cts +12 -18
  550. package/dist/plugins/comments/client/hooks/index.d.mts +12 -18
  551. package/dist/plugins/comments/client/hooks/index.d.ts +12 -18
  552. package/dist/plugins/comments/client/index.d.cts +96 -114
  553. package/dist/plugins/comments/client/index.d.mts +96 -114
  554. package/dist/plugins/comments/client/index.d.ts +96 -114
  555. package/dist/plugins/comments/permissions.cjs +70 -0
  556. package/dist/plugins/comments/permissions.d.cts +76 -0
  557. package/dist/plugins/comments/permissions.d.mts +76 -0
  558. package/dist/plugins/comments/permissions.d.ts +76 -0
  559. package/dist/plugins/comments/permissions.mjs +68 -0
  560. package/dist/plugins/comments/query-keys.cjs +1 -1
  561. package/dist/plugins/comments/query-keys.d.cts +16 -19
  562. package/dist/plugins/comments/query-keys.d.mts +16 -19
  563. package/dist/plugins/comments/query-keys.d.ts +16 -19
  564. package/dist/plugins/comments/query-keys.mjs +1 -1
  565. package/dist/plugins/form-builder/api/index.cjs +8 -0
  566. package/dist/plugins/form-builder/api/index.d.cts +115 -4
  567. package/dist/plugins/form-builder/api/index.d.mts +115 -4
  568. package/dist/plugins/form-builder/api/index.d.ts +115 -4
  569. package/dist/plugins/form-builder/api/index.mjs +4 -1
  570. package/dist/plugins/form-builder/client/components/index.d.cts +6 -2
  571. package/dist/plugins/form-builder/client/components/index.d.mts +6 -2
  572. package/dist/plugins/form-builder/client/components/index.d.ts +6 -2
  573. package/dist/plugins/form-builder/client/hooks/index.cjs +2 -0
  574. package/dist/plugins/form-builder/client/hooks/index.d.cts +34 -8
  575. package/dist/plugins/form-builder/client/hooks/index.d.mts +34 -8
  576. package/dist/plugins/form-builder/client/hooks/index.d.ts +34 -8
  577. package/dist/plugins/form-builder/client/hooks/index.mjs +1 -1
  578. package/dist/plugins/form-builder/client/index.d.cts +153 -174
  579. package/dist/plugins/form-builder/client/index.d.mts +153 -174
  580. package/dist/plugins/form-builder/client/index.d.ts +153 -174
  581. package/dist/plugins/form-builder/permissions.cjs +95 -0
  582. package/dist/plugins/form-builder/permissions.d.cts +94 -0
  583. package/dist/plugins/form-builder/permissions.d.mts +94 -0
  584. package/dist/plugins/form-builder/permissions.d.ts +94 -0
  585. package/dist/plugins/form-builder/permissions.mjs +93 -0
  586. package/dist/plugins/form-builder/query-keys.cjs +11 -4
  587. package/dist/plugins/form-builder/query-keys.d.cts +38 -12
  588. package/dist/plugins/form-builder/query-keys.d.mts +38 -12
  589. package/dist/plugins/form-builder/query-keys.d.ts +38 -12
  590. package/dist/plugins/form-builder/query-keys.mjs +11 -4
  591. package/dist/plugins/kanban/api/index.cjs +9 -0
  592. package/dist/plugins/kanban/api/index.d.cts +137 -5
  593. package/dist/plugins/kanban/api/index.d.mts +137 -5
  594. package/dist/plugins/kanban/api/index.d.ts +137 -5
  595. package/dist/plugins/kanban/api/index.mjs +5 -2
  596. package/dist/plugins/kanban/client/components/index.d.cts +18 -10
  597. package/dist/plugins/kanban/client/components/index.d.mts +18 -10
  598. package/dist/plugins/kanban/client/components/index.d.ts +18 -10
  599. package/dist/plugins/kanban/client/hooks/index.d.cts +15 -7
  600. package/dist/plugins/kanban/client/hooks/index.d.mts +15 -7
  601. package/dist/plugins/kanban/client/hooks/index.d.ts +15 -7
  602. package/dist/plugins/kanban/client/index.d.cts +32 -28
  603. package/dist/plugins/kanban/client/index.d.mts +32 -28
  604. package/dist/plugins/kanban/client/index.d.ts +32 -28
  605. package/dist/plugins/kanban/permissions.cjs +101 -0
  606. package/dist/plugins/kanban/permissions.d.cts +109 -0
  607. package/dist/plugins/kanban/permissions.d.mts +109 -0
  608. package/dist/plugins/kanban/permissions.d.ts +109 -0
  609. package/dist/plugins/kanban/permissions.mjs +99 -0
  610. package/dist/plugins/kanban/query-keys.cjs +14 -15
  611. package/dist/plugins/kanban/query-keys.d.cts +63 -42
  612. package/dist/plugins/kanban/query-keys.d.mts +63 -42
  613. package/dist/plugins/kanban/query-keys.d.ts +63 -42
  614. package/dist/plugins/kanban/query-keys.mjs +14 -15
  615. package/dist/plugins/media/api/adapters/local.d.cts +1 -1
  616. package/dist/plugins/media/api/adapters/local.d.mts +1 -1
  617. package/dist/plugins/media/api/adapters/local.d.ts +1 -1
  618. package/dist/plugins/media/api/adapters/s3.d.cts +1 -1
  619. package/dist/plugins/media/api/adapters/s3.d.mts +1 -1
  620. package/dist/plugins/media/api/adapters/s3.d.ts +1 -1
  621. package/dist/plugins/media/api/adapters/vercel-blob.cjs +46 -0
  622. package/dist/plugins/media/api/adapters/vercel-blob.d.cts +6 -9
  623. package/dist/plugins/media/api/adapters/vercel-blob.d.mts +6 -9
  624. package/dist/plugins/media/api/adapters/vercel-blob.d.ts +6 -9
  625. package/dist/plugins/media/api/adapters/vercel-blob.mjs +46 -0
  626. package/dist/plugins/media/api/index.cjs +10 -0
  627. package/dist/plugins/media/api/index.d.cts +93 -6
  628. package/dist/plugins/media/api/index.d.mts +93 -6
  629. package/dist/plugins/media/api/index.d.ts +93 -6
  630. package/dist/plugins/media/api/index.mjs +2 -0
  631. package/dist/plugins/media/client/components/index.d.cts +1 -1
  632. package/dist/plugins/media/client/components/index.d.mts +1 -1
  633. package/dist/plugins/media/client/components/index.d.ts +1 -1
  634. package/dist/plugins/media/client/hooks/index.d.cts +20 -10
  635. package/dist/plugins/media/client/hooks/index.d.mts +20 -10
  636. package/dist/plugins/media/client/hooks/index.d.ts +20 -10
  637. package/dist/plugins/media/client/index.cjs +1 -0
  638. package/dist/plugins/media/client/index.d.cts +112 -100
  639. package/dist/plugins/media/client/index.d.mts +112 -100
  640. package/dist/plugins/media/client/index.d.ts +112 -100
  641. package/dist/plugins/media/client/index.mjs +1 -1
  642. package/dist/plugins/media/permissions.cjs +63 -0
  643. package/dist/plugins/media/permissions.d.cts +64 -0
  644. package/dist/plugins/media/permissions.d.mts +64 -0
  645. package/dist/plugins/media/permissions.d.ts +64 -0
  646. package/dist/plugins/media/permissions.mjs +61 -0
  647. package/dist/plugins/media/query-keys.cjs +29 -17
  648. package/dist/plugins/media/query-keys.d.cts +24 -31
  649. package/dist/plugins/media/query-keys.d.mts +24 -31
  650. package/dist/plugins/media/query-keys.d.ts +24 -31
  651. package/dist/plugins/media/query-keys.mjs +30 -18
  652. package/dist/plugins/open-api/api/index.d.cts +9 -4
  653. package/dist/plugins/open-api/api/index.d.mts +9 -4
  654. package/dist/plugins/open-api/api/index.d.ts +9 -4
  655. package/dist/plugins/route-docs/client/index.cjs +2 -2
  656. package/dist/plugins/route-docs/client/index.d.cts +54 -53
  657. package/dist/plugins/route-docs/client/index.d.mts +54 -53
  658. package/dist/plugins/route-docs/client/index.d.ts +54 -53
  659. package/dist/plugins/route-docs/client/index.mjs +2 -1
  660. package/dist/plugins/ui-builder/client/components/index.d.cts +8 -5
  661. package/dist/plugins/ui-builder/client/components/index.d.mts +8 -5
  662. package/dist/plugins/ui-builder/client/components/index.d.ts +8 -5
  663. package/dist/plugins/ui-builder/client/hooks/index.d.cts +5 -5
  664. package/dist/plugins/ui-builder/client/hooks/index.d.mts +5 -5
  665. package/dist/plugins/ui-builder/client/hooks/index.d.ts +5 -5
  666. package/dist/plugins/ui-builder/client/index.d.cts +151 -199
  667. package/dist/plugins/ui-builder/client/index.d.mts +151 -199
  668. package/dist/plugins/ui-builder/client/index.d.ts +151 -199
  669. package/dist/plugins/ui-builder/index.d.cts +11 -8
  670. package/dist/plugins/ui-builder/index.d.mts +11 -8
  671. package/dist/plugins/ui-builder/index.d.ts +11 -8
  672. package/dist/plugins/ui-builder/query-keys.d.cts +6 -6
  673. package/dist/plugins/ui-builder/query-keys.d.mts +6 -6
  674. package/dist/plugins/ui-builder/query-keys.d.ts +6 -6
  675. package/dist/react-router/index.cjs +2 -0
  676. package/dist/react-router/index.d.cts +41 -7
  677. package/dist/react-router/index.d.mts +41 -7
  678. package/dist/react-router/index.d.ts +41 -7
  679. package/dist/react-router/index.mjs +1 -0
  680. package/dist/shared/stack.0O62uXqP.d.ts +613 -0
  681. package/dist/shared/stack.0y6iTP03.d.ts +533 -0
  682. package/dist/shared/{stack.CbZenbej.d.cts → stack.1ukVJym7.d.cts} +3 -4
  683. package/dist/shared/{stack.CbZenbej.d.mts → stack.1ukVJym7.d.mts} +3 -4
  684. package/dist/shared/{stack.CbZenbej.d.ts → stack.1ukVJym7.d.ts} +3 -4
  685. package/dist/shared/stack.3Sr6qRtT.d.ts +507 -0
  686. package/dist/shared/{stack.9BAOaSqE.d.mts → stack.5_zzCejP.d.cts} +16 -14
  687. package/dist/shared/{stack.9BAOaSqE.d.ts → stack.5_zzCejP.d.mts} +16 -14
  688. package/dist/shared/{stack.9BAOaSqE.d.cts → stack.5_zzCejP.d.ts} +16 -14
  689. package/dist/shared/stack.B1UrNoVl.d.mts +533 -0
  690. package/dist/shared/{stack.B2xi4jj7.d.cts → stack.B1srlBud.d.mts} +2 -2
  691. package/dist/shared/stack.B3_aDcYL.d.cts +281 -0
  692. package/dist/shared/stack.B3_aDcYL.d.mts +281 -0
  693. package/dist/shared/stack.B3_aDcYL.d.ts +281 -0
  694. package/dist/shared/stack.B5yPgHsp.d.mts +507 -0
  695. package/dist/shared/stack.B8PG21zX.d.mts +764 -0
  696. package/dist/shared/stack.BFP_9pRX.d.cts +707 -0
  697. package/dist/shared/{stack.INBa9-TO.d.cts → stack.BGzgFx3R.d.cts} +5 -5
  698. package/dist/shared/stack.BJx1ZXrN.d.cts +118 -0
  699. package/dist/shared/{stack.7b3vsM8_.d.ts → stack.BK9Z2dcL.d.ts} +2 -2
  700. package/dist/shared/stack.BMHoxAn7.d.mts +707 -0
  701. package/dist/shared/stack.BMmvEBH_.d.ts +118 -0
  702. package/dist/shared/stack.BOZRaVpu.d.cts +1184 -0
  703. package/dist/shared/stack.BPLykw4s.d.ts +436 -0
  704. package/dist/shared/{stack.aqVZ6PEW.d.mts → stack.BRvqQWGt.d.cts} +40 -1
  705. package/dist/shared/{stack.aqVZ6PEW.d.cts → stack.BRvqQWGt.d.mts} +40 -1
  706. package/dist/shared/{stack.aqVZ6PEW.d.ts → stack.BRvqQWGt.d.ts} +40 -1
  707. package/dist/shared/stack.BSACE667.d.cts +23 -0
  708. package/dist/shared/stack.BYMentwB.d.cts +47 -0
  709. package/dist/shared/stack.BYMentwB.d.mts +47 -0
  710. package/dist/shared/stack.BYMentwB.d.ts +47 -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.BuxUQqL8.d.ts +408 -0
  716. package/dist/shared/stack.BzWGB5MG.d.cts +436 -0
  717. package/dist/shared/stack.C3bU9w6L.d.ts +351 -0
  718. package/dist/shared/stack.C4oVW2qK.d.cts +507 -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.CX83YNuS.d.cts +408 -0
  726. package/dist/shared/stack.Cbd7sD5M.d.mts +118 -0
  727. package/dist/shared/{stack.B9NtGpAR.d.ts → stack.CcjENrr4.d.cts} +1 -5
  728. package/dist/shared/stack.CfK5NKlK.d.mts +613 -0
  729. package/dist/shared/{stack.3di7vQs6.d.mts → stack.CjCSDfWy.d.mts} +5 -5
  730. package/dist/shared/stack.Cmg7lzzy.d.cts +44 -0
  731. package/dist/shared/stack.Cmg7lzzy.d.mts +44 -0
  732. package/dist/shared/stack.Cmg7lzzy.d.ts +44 -0
  733. package/dist/shared/stack.CpE1mS3p.d.ts +331 -0
  734. package/dist/shared/stack.CskhFw3z.d.mts +23 -0
  735. package/dist/shared/stack.CvlC5kqe.d.cts +331 -0
  736. package/dist/shared/stack.CxKc9evq.d.ts +23 -0
  737. package/dist/shared/stack.CyalJ0j6.d.ts +764 -0
  738. package/dist/shared/stack.D6Pg-ufX.d.cts +764 -0
  739. package/dist/shared/{stack.lkebw2nj.d.mts → stack.DVEjWKCT.d.cts} +19 -5
  740. package/dist/shared/{stack.lkebw2nj.d.ts → stack.DVEjWKCT.d.mts} +19 -5
  741. package/dist/shared/{stack.lkebw2nj.d.cts → stack.DVEjWKCT.d.ts} +19 -5
  742. package/dist/shared/{stack.Cp_6mO5s.d.mts → stack.DbbvHbhn.d.mts} +1 -5
  743. package/dist/shared/stack.DiuRuzIs.d.cts +613 -0
  744. package/dist/shared/{stack.BMlLOMED.d.mts → stack.DjGixVx3.d.cts} +6 -2
  745. package/dist/shared/{stack.BMlLOMED.d.ts → stack.DjGixVx3.d.mts} +6 -2
  746. package/dist/shared/{stack.BMlLOMED.d.cts → stack.DjGixVx3.d.ts} +6 -2
  747. package/dist/shared/stack.DlBoNqYu.d.ts +1184 -0
  748. package/dist/shared/stack.DlCycSM-.d.mts +331 -0
  749. package/dist/shared/{stack.DycBcTeg.d.mts → stack.DmpPDPxA.d.cts} +2 -2
  750. package/dist/shared/{stack.CRelKJfH.d.ts → stack.Dpg_JjIo.d.ts} +5 -5
  751. package/dist/shared/stack.Dvy7FmaA.d.mts +1184 -0
  752. package/dist/shared/stack.DxHPKr2R.d.mts +436 -0
  753. package/dist/shared/stack.Egr3RWhA.d.mts +408 -0
  754. package/dist/shared/stack.Mak7pzIV.d.cts +533 -0
  755. package/dist/shared/stack.OYT8WU4n.d.mts +351 -0
  756. package/dist/shared/{stack.CPsYC2-Z.d.cts → stack.fdi94T4S.d.cts} +7 -7
  757. package/dist/shared/{stack.CPsYC2-Z.d.mts → stack.fdi94T4S.d.mts} +7 -7
  758. package/dist/shared/{stack.CPsYC2-Z.d.ts → stack.fdi94T4S.d.ts} +7 -7
  759. package/dist/shared/{stack.Dlgtumru.d.cts → stack.kaCV7vEL.d.ts} +1 -5
  760. package/dist/shared/stack.v2O65JqF.d.cts +351 -0
  761. package/dist/tanstack/index.cjs +2 -0
  762. package/dist/tanstack/index.d.cts +44 -14
  763. package/dist/tanstack/index.d.mts +44 -14
  764. package/dist/tanstack/index.d.ts +44 -14
  765. package/dist/tanstack/index.mjs +1 -0
  766. package/dist/tanstack/server.cjs +9 -0
  767. package/dist/tanstack/server.d.cts +15 -0
  768. package/dist/tanstack/server.d.mts +15 -0
  769. package/dist/tanstack/server.d.ts +15 -0
  770. package/dist/tanstack/server.mjs +7 -0
  771. package/package.json +203 -8
  772. package/src/__tests__/ai-chat-client-runtime.test.ts +481 -0
  773. package/src/__tests__/ai-chat-client-runtime.typecheck.tsx +130 -0
  774. package/src/__tests__/ai-chat-lifecycle-migrations.typecheck.ts +61 -0
  775. package/src/__tests__/ai-chat-query-keys.test.ts +125 -22
  776. package/src/__tests__/auth-provider.test.tsx +41 -314
  777. package/src/__tests__/auth-test-utils.ts +24 -0
  778. package/src/__tests__/authorization-client.test.tsx +767 -0
  779. package/src/__tests__/authorization-contraction.test.ts +182 -0
  780. package/src/__tests__/authorization-remote.test.ts +222 -0
  781. package/src/__tests__/authorization-server.test.ts +90 -0
  782. package/src/__tests__/authorization.test.ts +652 -0
  783. package/src/__tests__/authorization.typecheck.ts +671 -0
  784. package/src/__tests__/backend-plugin-factories.test.ts +54 -0
  785. package/src/__tests__/backend-plugin-factories.typecheck.ts +133 -0
  786. package/src/__tests__/client-plugin-ssr-loaders.test.ts +304 -138
  787. package/src/__tests__/client-runtime.test.ts +1021 -0
  788. package/src/__tests__/client-runtime.typecheck.ts +107 -0
  789. package/src/__tests__/client-stack-test-utils.ts +36 -0
  790. package/src/__tests__/content-lifecycle-migrations.typecheck.ts +122 -0
  791. package/src/__tests__/endpoint-inventory.test.ts +768 -0
  792. package/src/__tests__/entry-factories.test.tsx +104 -4
  793. package/src/__tests__/form-builder-query-keys.test.ts +32 -0
  794. package/src/__tests__/i18n-provider.test.tsx +4 -3
  795. package/src/__tests__/initial-identity-hydration.test.tsx +156 -0
  796. package/src/__tests__/initial-identity-layouts.test.tsx +204 -0
  797. package/src/__tests__/kanban-query-keys.test.ts +189 -2
  798. package/src/__tests__/managed-origin-hydration.browser.test.tsx +163 -0
  799. package/src/__tests__/media-query-keys.test.ts +91 -17
  800. package/src/__tests__/notify-provider.test.tsx +3 -2
  801. package/src/__tests__/package-metadata.test.ts +315 -0
  802. package/src/__tests__/page-component-overrides.test.tsx +3 -4
  803. package/src/__tests__/plugin-registration.test.tsx +183 -0
  804. package/src/__tests__/plugin-registration.typecheck.tsx +139 -0
  805. package/src/__tests__/plugins.test.tsx +72 -42
  806. package/src/__tests__/resource-factory.test.tsx +79 -2
  807. package/src/__tests__/resource-use-form.test.tsx +2 -2
  808. package/src/__tests__/resource-use-select.test.tsx +2 -4
  809. package/src/__tests__/router-overrides.test.tsx +20 -8
  810. package/src/__tests__/sitemap.test.ts +38 -22
  811. package/src/__tests__/stack-api.test.ts +39 -34
  812. package/src/__tests__/stack-auth.test.ts +44 -140
  813. package/src/__tests__/stack-constructors.test.ts +96 -0
  814. package/src/__tests__/stack-constructors.typecheck.ts +115 -0
  815. package/src/__tests__/use-list-state.test.tsx +7 -6
  816. package/src/__tests__/workflow-lifecycle-migrations.typecheck.ts +150 -0
  817. package/src/api/index.ts +204 -99
  818. package/src/authorization/client.tsx +310 -0
  819. package/src/authorization/index.ts +873 -0
  820. package/src/authorization/json.ts +70 -0
  821. package/src/authorization/remote.ts +234 -0
  822. package/src/authorization/server.ts +171 -0
  823. package/src/client/__tests__/server-origin.test.ts +119 -0
  824. package/src/client/components/compose.tsx +126 -18
  825. package/src/client/hooks/index.ts +12 -0
  826. package/src/client/hooks/use-list-state.ts +7 -13
  827. package/src/client/index.ts +105 -50
  828. package/src/client/runtime.ts +414 -0
  829. package/src/client/server.ts +174 -0
  830. package/src/context/auth.tsx +205 -154
  831. package/src/context/index.ts +10 -4
  832. package/src/context/provider.tsx +96 -57
  833. package/src/context/router.tsx +7 -0
  834. package/src/context/site-navigation.ts +52 -0
  835. package/src/next/index.tsx +2 -0
  836. package/src/next/layout.tsx +81 -0
  837. package/src/next/page.tsx +33 -12
  838. package/src/next/router.tsx +1 -1
  839. package/src/next/server.ts +5 -0
  840. package/src/plugin-registration.ts +70 -0
  841. package/src/plugins/ai-chat/__tests__/authorization.test.ts +2051 -0
  842. package/src/plugins/ai-chat/__tests__/chat-hooks.test.tsx +147 -0
  843. package/src/plugins/ai-chat/__tests__/chat-input-authorization.test.tsx +188 -0
  844. package/src/plugins/ai-chat/__tests__/client-sweep.test.tsx +1506 -34
  845. package/src/plugins/ai-chat/__tests__/hooks.test.tsx +131 -23
  846. package/src/plugins/ai-chat/api/getters.ts +2 -2
  847. package/src/plugins/ai-chat/api/index.ts +6 -1
  848. package/src/plugins/ai-chat/api/lifecycle-migrations.ts +20 -0
  849. package/src/plugins/ai-chat/api/operations.ts +1865 -0
  850. package/src/plugins/ai-chat/api/plugin.ts +78 -1168
  851. package/src/plugins/ai-chat/api/serializers.ts +30 -0
  852. package/src/plugins/ai-chat/client/components/chat-input.tsx +228 -129
  853. package/src/plugins/ai-chat/client/components/chat-interface.tsx +776 -183
  854. package/src/plugins/ai-chat/client/components/chat-layout.tsx +6 -7
  855. package/src/plugins/ai-chat/client/components/chat-message.tsx +1 -1
  856. package/src/plugins/ai-chat/client/components/chat-sidebar.tsx +57 -37
  857. package/src/plugins/ai-chat/client/components/pages/404-page.tsx +1 -1
  858. package/src/plugins/ai-chat/client/components/pages/chat-page.internal.tsx +5 -3
  859. package/src/plugins/ai-chat/client/components/pages/chat-page.tsx +56 -15
  860. package/src/plugins/ai-chat/client/components/shared/default-error.tsx +1 -1
  861. package/src/plugins/ai-chat/client/components/tool-call-display.tsx +1 -1
  862. package/src/plugins/ai-chat/client/hooks/ai-chat-resource.ts +1 -1
  863. package/src/plugins/ai-chat/client/hooks/chat-hooks.tsx +253 -20
  864. package/src/plugins/ai-chat/client/index.ts +1 -0
  865. package/src/plugins/ai-chat/client/navigation.ts +11 -0
  866. package/src/plugins/ai-chat/client/overrides.ts +47 -11
  867. package/src/plugins/ai-chat/client/plugin.tsx +208 -111
  868. package/src/plugins/ai-chat/permissions.ts +89 -0
  869. package/src/plugins/ai-chat/query-keys.ts +183 -25
  870. package/src/plugins/ai-chat/types.ts +7 -5
  871. package/src/plugins/api/create-endpoint.ts +40 -22
  872. package/src/plugins/api/endpoint-inventory.ts +206 -0
  873. package/src/plugins/api/index.ts +38 -4
  874. package/src/plugins/api/operation.ts +600 -0
  875. package/src/plugins/blog/__tests__/authorization.test.ts +1366 -0
  876. package/src/plugins/blog/__tests__/client-runtime.browser.test.tsx +257 -0
  877. package/src/plugins/blog/__tests__/client-runtime.test.ts +283 -0
  878. package/src/plugins/blog/__tests__/client-runtime.typecheck.tsx +98 -0
  879. package/src/plugins/blog/__tests__/client-sweep.test.tsx +212 -37
  880. package/src/plugins/blog/api/getters.ts +3 -3
  881. package/src/plugins/blog/api/index.ts +2 -0
  882. package/src/plugins/blog/api/lifecycle-migrations.ts +19 -0
  883. package/src/plugins/blog/api/mutations.ts +26 -5
  884. package/src/plugins/blog/api/operations.ts +727 -0
  885. package/src/plugins/blog/api/plugin.ts +99 -504
  886. package/src/plugins/blog/client/components/forms/image-field.tsx +2 -1
  887. package/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.tsx +2 -1
  888. package/src/plugins/blog/client/components/forms/post-forms.tsx +61 -33
  889. package/src/plugins/blog/client/components/pages/404-page.tsx +3 -1
  890. package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +2 -1
  891. package/src/plugins/blog/client/components/pages/edit-post-page.tsx +28 -5
  892. package/src/plugins/blog/client/components/pages/home-page.internal.tsx +2 -1
  893. package/src/plugins/blog/client/components/pages/home-page.tsx +7 -4
  894. package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +2 -1
  895. package/src/plugins/blog/client/components/pages/new-post-page.tsx +5 -2
  896. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +2 -1
  897. package/src/plugins/blog/client/components/pages/post-page.tsx +38 -4
  898. package/src/plugins/blog/client/components/pages/tag-page.internal.tsx +2 -1
  899. package/src/plugins/blog/client/components/pages/tag-page.tsx +5 -1
  900. package/src/plugins/blog/client/components/shared/collapsible-tag-list.tsx +2 -1
  901. package/src/plugins/blog/client/components/shared/default-error.tsx +3 -1
  902. package/src/plugins/blog/client/components/shared/on-this-page.tsx +5 -2
  903. package/src/plugins/blog/client/components/shared/page-wrapper.tsx +2 -1
  904. package/src/plugins/blog/client/components/shared/post-card.tsx +2 -1
  905. package/src/plugins/blog/client/components/shared/posts-list.tsx +2 -1
  906. package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +2 -1
  907. package/src/plugins/blog/client/components/shared/search-input.tsx +1 -1
  908. package/src/plugins/blog/client/constants.ts +2 -0
  909. package/src/plugins/blog/client/hooks/blog-resource.ts +2 -1
  910. package/src/plugins/blog/client/overrides.ts +1 -6
  911. package/src/plugins/blog/client/plugin.tsx +145 -129
  912. package/src/plugins/blog/permissions.ts +44 -0
  913. package/src/plugins/client/index.ts +108 -7
  914. package/src/plugins/client/resource/hooks.tsx +41 -18
  915. package/src/plugins/client/resource/internal.ts +77 -61
  916. package/src/plugins/client/resource/queries.ts +3 -4
  917. package/src/plugins/client/resource/use-form.ts +23 -20
  918. package/src/plugins/client/resource/use-select.ts +40 -34
  919. package/src/plugins/cms/__tests__/authorization.test.ts +2188 -0
  920. package/src/plugins/cms/__tests__/client-runtime.browser.test.tsx +245 -0
  921. package/src/plugins/cms/__tests__/client-runtime.test.ts +320 -0
  922. package/src/plugins/cms/__tests__/client-runtime.typecheck.tsx +208 -0
  923. package/src/plugins/cms/__tests__/client-sweep.test.tsx +202 -50
  924. package/src/plugins/cms/api/getters.ts +4 -4
  925. package/src/plugins/cms/api/index.ts +20 -0
  926. package/src/plugins/cms/api/lifecycle-migrations.ts +15 -0
  927. package/src/plugins/cms/api/mutations.ts +2 -2
  928. package/src/plugins/cms/api/operations.ts +2218 -0
  929. package/src/plugins/cms/api/plugin.ts +169 -1047
  930. package/src/plugins/cms/api/relations.ts +3 -1
  931. package/src/plugins/cms/client/components/forms/content-form.tsx +2 -1
  932. package/src/plugins/cms/client/components/forms/file-upload.tsx +3 -1
  933. package/src/plugins/cms/client/components/forms/relation-field.tsx +3 -1
  934. package/src/plugins/cms/client/components/inverse-relations-panel.tsx +29 -17
  935. package/src/plugins/cms/client/components/pages/404-page.tsx +7 -5
  936. package/src/plugins/cms/client/components/pages/content-editor-page.internal.tsx +19 -10
  937. package/src/plugins/cms/client/components/pages/content-editor-page.tsx +50 -12
  938. package/src/plugins/cms/client/components/pages/content-list-page.internal.tsx +48 -34
  939. package/src/plugins/cms/client/components/pages/content-list-page.tsx +8 -1
  940. package/src/plugins/cms/client/components/pages/dashboard-page.internal.tsx +15 -8
  941. package/src/plugins/cms/client/components/pages/dashboard-page.tsx +5 -1
  942. package/src/plugins/cms/client/components/shared/page-wrapper.tsx +2 -1
  943. package/src/plugins/cms/client/constants.ts +2 -0
  944. package/src/plugins/cms/client/hooks/cms-resource.ts +2 -1
  945. package/src/plugins/cms/client/index.ts +6 -1
  946. package/src/plugins/cms/client/overrides.ts +46 -6
  947. package/src/plugins/cms/client/plugin.tsx +135 -80
  948. package/src/plugins/cms/permissions.ts +43 -0
  949. package/src/plugins/cms/types.ts +174 -46
  950. package/src/plugins/comments/__tests__/authorization.test.ts +1570 -0
  951. package/src/plugins/comments/__tests__/client-runtime.browser.test.tsx +207 -0
  952. package/src/plugins/comments/__tests__/client-runtime.test.ts +224 -0
  953. package/src/plugins/comments/__tests__/client-runtime.typecheck.tsx +85 -0
  954. package/src/plugins/comments/__tests__/client-sweep.test.tsx +465 -79
  955. package/src/plugins/comments/api/getters.ts +19 -3
  956. package/src/plugins/comments/api/index.ts +2 -6
  957. package/src/plugins/comments/api/lifecycle-migrations.ts +20 -0
  958. package/src/plugins/comments/api/mutations.ts +261 -88
  959. package/src/plugins/comments/api/operations.ts +742 -0
  960. package/src/plugins/comments/api/plugin.ts +76 -548
  961. package/src/plugins/comments/client/components/comment-count.tsx +38 -5
  962. package/src/plugins/comments/client/components/comment-thread.tsx +154 -112
  963. package/src/plugins/comments/client/components/pages/moderation-page.internal.tsx +144 -78
  964. package/src/plugins/comments/client/components/pages/moderation-page.tsx +18 -2
  965. package/src/plugins/comments/client/components/pages/moderation-state.ts +13 -0
  966. package/src/plugins/comments/client/components/pages/my-comments-page.internal.tsx +38 -30
  967. package/src/plugins/comments/client/components/pages/my-comments-page.tsx +3 -1
  968. package/src/plugins/comments/client/components/pages/resource-comments-page.internal.tsx +29 -30
  969. package/src/plugins/comments/client/components/pages/resource-comments-page.tsx +10 -1
  970. package/src/plugins/comments/client/components/shared/page-wrapper.tsx +2 -1
  971. package/src/plugins/comments/client/components/shared/pagination.tsx +2 -1
  972. package/src/plugins/comments/client/constants.ts +2 -0
  973. package/src/plugins/comments/client/hooks/use-comments.tsx +430 -421
  974. package/src/plugins/comments/client/localization/comments-thread.ts +1 -0
  975. package/src/plugins/comments/client/plugin.tsx +113 -72
  976. package/src/plugins/comments/permissions.ts +68 -0
  977. package/src/plugins/comments/query-keys.ts +9 -10
  978. package/src/plugins/comments/schemas.ts +7 -8
  979. package/src/plugins/form-builder/__tests__/authorization.test.ts +1600 -0
  980. package/src/plugins/form-builder/__tests__/client-runtime.browser.test.tsx +255 -0
  981. package/src/plugins/form-builder/__tests__/client-runtime.test.ts +132 -0
  982. package/src/plugins/form-builder/__tests__/client-runtime.typecheck.tsx +77 -0
  983. package/src/plugins/form-builder/__tests__/client-sweep.test.tsx +350 -54
  984. package/src/plugins/form-builder/__tests__/form-renderer-authorization.test.tsx +162 -0
  985. package/src/plugins/form-builder/api/getters.ts +21 -5
  986. package/src/plugins/form-builder/api/index.ts +31 -0
  987. package/src/plugins/form-builder/api/lifecycle-migrations.ts +17 -0
  988. package/src/plugins/form-builder/api/operations.ts +1493 -0
  989. package/src/plugins/form-builder/api/plugin.ts +125 -632
  990. package/src/plugins/form-builder/api/query-key-defs.ts +7 -0
  991. package/src/plugins/form-builder/api/serializers.ts +1 -0
  992. package/src/plugins/form-builder/client/components/forms/form-renderer.tsx +49 -19
  993. package/src/plugins/form-builder/client/components/pages/404-page.tsx +9 -9
  994. package/src/plugins/form-builder/client/components/pages/form-builder-page.internal.tsx +54 -30
  995. package/src/plugins/form-builder/client/components/pages/form-builder-page.tsx +42 -9
  996. package/src/plugins/form-builder/client/components/pages/form-list-page.internal.tsx +46 -34
  997. package/src/plugins/form-builder/client/components/pages/form-list-page.tsx +6 -2
  998. package/src/plugins/form-builder/client/components/pages/submissions-page.internal.tsx +98 -64
  999. package/src/plugins/form-builder/client/components/pages/submissions-page.tsx +29 -9
  1000. package/src/plugins/form-builder/client/components/shared/page-wrapper.tsx +2 -1
  1001. package/src/plugins/form-builder/client/constants.ts +2 -0
  1002. package/src/plugins/form-builder/client/hooks/form-builder-hooks.tsx +68 -4
  1003. package/src/plugins/form-builder/client/hooks/form-builder-resource.ts +2 -1
  1004. package/src/plugins/form-builder/client/hooks/index.tsx +1 -0
  1005. package/src/plugins/form-builder/client/overrides.ts +1 -6
  1006. package/src/plugins/form-builder/client/plugin.tsx +128 -96
  1007. package/src/plugins/form-builder/permissions.ts +94 -0
  1008. package/src/plugins/form-builder/query-keys.ts +28 -3
  1009. package/src/plugins/form-builder/schemas.ts +9 -1
  1010. package/src/plugins/form-builder/types.ts +173 -41
  1011. package/src/plugins/kanban/__tests__/authorization.test.ts +1382 -0
  1012. package/src/plugins/kanban/__tests__/client-runtime.browser.test.tsx +302 -0
  1013. package/src/plugins/kanban/__tests__/client-runtime.test.ts +130 -0
  1014. package/src/plugins/kanban/__tests__/client-runtime.typecheck.tsx +81 -0
  1015. package/src/plugins/kanban/__tests__/client-sweep.test.tsx +418 -33
  1016. package/src/plugins/kanban/__tests__/identity-partition.test.tsx +306 -0
  1017. package/src/plugins/kanban/api/getters.ts +65 -50
  1018. package/src/plugins/kanban/api/index.ts +55 -4
  1019. package/src/plugins/kanban/api/lifecycle-migrations.ts +25 -0
  1020. package/src/plugins/kanban/api/mutations.ts +3 -3
  1021. package/src/plugins/kanban/api/operations.ts +2065 -0
  1022. package/src/plugins/kanban/api/plugin.ts +83 -1013
  1023. package/src/plugins/kanban/api/serializers.ts +26 -0
  1024. package/src/plugins/kanban/client/components/forms/board-form.tsx +3 -1
  1025. package/src/plugins/kanban/client/components/forms/column-form.tsx +3 -1
  1026. package/src/plugins/kanban/client/components/forms/task-form.tsx +92 -74
  1027. package/src/plugins/kanban/client/components/pages/404-page.tsx +6 -9
  1028. package/src/plugins/kanban/client/components/pages/board-page.internal.tsx +57 -74
  1029. package/src/plugins/kanban/client/components/pages/board-page.tsx +31 -7
  1030. package/src/plugins/kanban/client/components/pages/boards-list-page.internal.tsx +54 -45
  1031. package/src/plugins/kanban/client/components/pages/boards-list-page.tsx +2 -1
  1032. package/src/plugins/kanban/client/components/pages/new-board-page.internal.tsx +8 -12
  1033. package/src/plugins/kanban/client/components/pages/new-board-page.tsx +2 -1
  1034. package/src/plugins/kanban/client/components/shared/column-content.tsx +61 -48
  1035. package/src/plugins/kanban/client/components/shared/default-error.tsx +3 -1
  1036. package/src/plugins/kanban/client/components/shared/kanban-board.tsx +6 -6
  1037. package/src/plugins/kanban/client/components/shared/permission-access-any.tsx +32 -0
  1038. package/src/plugins/kanban/client/components/shared/task-card.tsx +64 -20
  1039. package/src/plugins/kanban/client/components/shared/user-avatar.tsx +3 -1
  1040. package/src/plugins/kanban/client/constants.ts +2 -0
  1041. package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +55 -10
  1042. package/src/plugins/kanban/client/hooks/kanban-resource.ts +2 -1
  1043. package/src/plugins/kanban/client/overrides.ts +0 -5
  1044. package/src/plugins/kanban/client/plugin.tsx +201 -113
  1045. package/src/plugins/kanban/permissions.ts +100 -0
  1046. package/src/plugins/kanban/query-keys.ts +61 -21
  1047. package/src/plugins/kanban/schemas.ts +44 -18
  1048. package/src/plugins/kanban/types.ts +381 -1
  1049. package/src/plugins/media/__tests__/authorization.test.ts +1769 -0
  1050. package/src/plugins/media/__tests__/client-runtime.browser.test.tsx +975 -0
  1051. package/src/plugins/media/__tests__/client-runtime.test.ts +539 -0
  1052. package/src/plugins/media/__tests__/client-runtime.typecheck.tsx +135 -0
  1053. package/src/plugins/media/__tests__/client-sweep.test.tsx +292 -24
  1054. package/src/plugins/media/__tests__/identity-partition.test.tsx +741 -0
  1055. package/src/plugins/media/__tests__/plugin.test.ts +68 -28
  1056. package/src/plugins/media/__tests__/query-key-defs.test.ts +32 -2
  1057. package/src/plugins/media/api/adapters/vercel-blob.ts +84 -8
  1058. package/src/plugins/media/api/getters.ts +6 -6
  1059. package/src/plugins/media/api/index.ts +3 -0
  1060. package/src/plugins/media/api/lifecycle-migrations.ts +11 -0
  1061. package/src/plugins/media/api/mutations.ts +19 -13
  1062. package/src/plugins/media/api/operations.ts +1873 -0
  1063. package/src/plugins/media/api/plugin.ts +211 -899
  1064. package/src/plugins/media/api/query-key-defs.ts +66 -4
  1065. package/src/plugins/media/api/serializers.ts +4 -2
  1066. package/src/plugins/media/api/storage-adapter.ts +22 -4
  1067. package/src/plugins/media/asset-url.ts +14 -0
  1068. package/src/plugins/media/client/components/media-picker/asset-card.tsx +105 -98
  1069. package/src/plugins/media/client/components/media-picker/folder-tree.tsx +82 -60
  1070. package/src/plugins/media/client/components/media-picker/index.tsx +235 -171
  1071. package/src/plugins/media/client/components/media-picker/upload-tab.tsx +2 -10
  1072. package/src/plugins/media/client/components/media-picker/url-tab.tsx +1 -8
  1073. package/src/plugins/media/client/components/pages/library-page.internal.tsx +103 -82
  1074. package/src/plugins/media/client/components/pages/library-page.tsx +4 -2
  1075. package/src/plugins/media/client/components/upload-permission-check.tsx +75 -0
  1076. package/src/plugins/media/client/constants.ts +2 -0
  1077. package/src/plugins/media/client/hooks/media-resource.ts +2 -1
  1078. package/src/plugins/media/client/hooks/use-media.tsx +292 -49
  1079. package/src/plugins/media/client/index.ts +16 -3
  1080. package/src/plugins/media/client/overrides.ts +6 -17
  1081. package/src/plugins/media/client/plugin.tsx +188 -123
  1082. package/src/plugins/media/client/upload.ts +170 -53
  1083. package/src/plugins/media/db.ts +8 -0
  1084. package/src/plugins/media/permissions.ts +61 -0
  1085. package/src/plugins/media/query-keys.ts +63 -19
  1086. package/src/plugins/media/types.ts +8 -2
  1087. package/src/plugins/open-api/__tests__/route-introspection.test.ts +277 -0
  1088. package/src/plugins/open-api/api/generator.ts +49 -8
  1089. package/src/plugins/open-api/api/plugin.ts +36 -14
  1090. package/src/plugins/route-docs/client/components/pages/docs-page.tsx +63 -23
  1091. package/src/plugins/route-docs/client/constants.ts +2 -0
  1092. package/src/plugins/route-docs/client/hooks.ts +23 -13
  1093. package/src/plugins/route-docs/client/index.ts +7 -1
  1094. package/src/plugins/route-docs/client/plugin.tsx +222 -145
  1095. package/src/plugins/route-docs/client/schema.ts +31 -0
  1096. package/src/plugins/route-docs/generator.ts +9 -5
  1097. package/src/plugins/ui-builder/__tests__/client-sweep.test.tsx +427 -48
  1098. package/src/plugins/ui-builder/client/components/page-renderer.tsx +58 -16
  1099. package/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.tsx +47 -26
  1100. package/src/plugins/ui-builder/client/components/pages/page-builder-page.tsx +43 -8
  1101. package/src/plugins/ui-builder/client/components/pages/page-list-page.internal.tsx +38 -19
  1102. package/src/plugins/ui-builder/client/components/pages/page-list-page.tsx +8 -2
  1103. package/src/plugins/ui-builder/client/components/shared/default-error.tsx +2 -1
  1104. package/src/plugins/ui-builder/client/components/shared/page-wrapper.tsx +2 -1
  1105. package/src/plugins/ui-builder/client/constants.ts +2 -0
  1106. package/src/plugins/ui-builder/client/hooks/ui-builder-resource.ts +2 -1
  1107. package/src/plugins/ui-builder/client/index.ts +4 -1
  1108. package/src/plugins/ui-builder/client/overrides.ts +16 -21
  1109. package/src/plugins/ui-builder/client/plugin.tsx +119 -66
  1110. package/src/plugins/ui-builder/client/registry.ts +3 -5
  1111. package/src/plugins/ui-builder/types.ts +7 -4
  1112. package/src/plugins/utils.ts +5 -1
  1113. package/src/react-router/index.tsx +6 -0
  1114. package/src/react-router/layout.ts +43 -0
  1115. package/src/react-router/page.tsx +46 -17
  1116. package/src/react-router/router.tsx +1 -1
  1117. package/src/shared/auth-types.ts +19 -70
  1118. package/src/shared/entry-factories.ts +12 -3
  1119. package/src/shared/initial-identity.ts +73 -0
  1120. package/src/shared/list-state.ts +12 -0
  1121. package/src/shared/types.ts +1 -0
  1122. package/src/tanstack/index.tsx +7 -0
  1123. package/src/tanstack/layout.ts +36 -0
  1124. package/src/tanstack/page.tsx +35 -13
  1125. package/src/tanstack/router.tsx +1 -1
  1126. package/src/tanstack/server.ts +18 -0
  1127. package/src/types.ts +557 -65
  1128. package/dist/shared/stack.80-y2TTR.d.mts +0 -840
  1129. package/dist/shared/stack.B-hEIoUw.d.ts +0 -406
  1130. package/dist/shared/stack.B8vdOMnQ.d.cts +0 -329
  1131. package/dist/shared/stack.BISAZ5LX.d.mts +0 -492
  1132. package/dist/shared/stack.BL5PvShn.d.mts +0 -193
  1133. package/dist/shared/stack.Be1QIHEn.d.cts +0 -23
  1134. package/dist/shared/stack.Be1QIHEn.d.mts +0 -23
  1135. package/dist/shared/stack.Be1QIHEn.d.ts +0 -23
  1136. package/dist/shared/stack.BjvOk_Bs.d.cts +0 -492
  1137. package/dist/shared/stack.Bk5UB_BT.d.ts +0 -840
  1138. package/dist/shared/stack.BozPgbrZ.d.cts +0 -201
  1139. package/dist/shared/stack.BozPgbrZ.d.mts +0 -201
  1140. package/dist/shared/stack.BozPgbrZ.d.ts +0 -201
  1141. package/dist/shared/stack.BqTR6qi2.d.ts +0 -193
  1142. package/dist/shared/stack.BvxHSZYT.d.cts +0 -406
  1143. package/dist/shared/stack.C1ATQ3pd.d.ts +0 -416
  1144. package/dist/shared/stack.C4_gEENS.d.cts +0 -97
  1145. package/dist/shared/stack.C4_gEENS.d.mts +0 -97
  1146. package/dist/shared/stack.C4_gEENS.d.ts +0 -97
  1147. package/dist/shared/stack.C5Y5lViI.d.cts +0 -461
  1148. package/dist/shared/stack.C8SwdUz8.d.ts +0 -461
  1149. package/dist/shared/stack.CBsp9rDM.d.cts +0 -193
  1150. package/dist/shared/stack.CMbX8Q5C.d.ts +0 -560
  1151. package/dist/shared/stack.Cf-DbL1A.d.ts +0 -329
  1152. package/dist/shared/stack.DHTvwoNG.d.mts +0 -329
  1153. package/dist/shared/stack.DJaKVY7v.d.cts +0 -76
  1154. package/dist/shared/stack.DJaKVY7v.d.mts +0 -76
  1155. package/dist/shared/stack.DJaKVY7v.d.ts +0 -76
  1156. package/dist/shared/stack.DKZMaVr6.d.cts +0 -416
  1157. package/dist/shared/stack.DQq8DEIv.d.mts +0 -461
  1158. package/dist/shared/stack.Dd-8shBE.d.ts +0 -492
  1159. package/dist/shared/stack.Dj04W2c3.d.mts +0 -560
  1160. package/dist/shared/stack.DrUBX-QE.d.cts +0 -34
  1161. package/dist/shared/stack.DrUBX-QE.d.mts +0 -34
  1162. package/dist/shared/stack.DrUBX-QE.d.ts +0 -34
  1163. package/dist/shared/stack.H5B8miAV.d.cts +0 -840
  1164. package/dist/shared/stack.aXdBOJAR.d.cts +0 -173
  1165. package/dist/shared/stack.aXdBOJAR.d.mts +0 -173
  1166. package/dist/shared/stack.aXdBOJAR.d.ts +0 -173
  1167. package/dist/shared/stack.eq5eg1yt.d.cts +0 -560
  1168. package/dist/shared/stack.f8Vke-eH.d.mts +0 -406
  1169. package/dist/shared/stack.oBokjN_J.d.mts +0 -416
  1170. package/dist/shared/{stack.B0muOwUF.d.cts → stack.Csi-4Mgz.d.cts} +8 -8
  1171. package/dist/shared/{stack.B0muOwUF.d.mts → stack.Csi-4Mgz.d.mts} +8 -8
  1172. package/dist/shared/{stack.B0muOwUF.d.ts → stack.Csi-4Mgz.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
+ }