@btst/stack 1.11.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (580) hide show
  1. package/README.md +44 -30
  2. package/dist/api/index.cjs +2 -2
  3. package/dist/api/index.d.cts +5 -5
  4. package/dist/api/index.d.mts +5 -5
  5. package/dist/api/index.d.ts +5 -5
  6. package/dist/api/index.mjs +2 -2
  7. package/dist/client/components/index.cjs +2 -2
  8. package/dist/client/components/index.mjs +2 -2
  9. package/dist/client/index.cjs +3 -3
  10. package/dist/client/index.d.cts +2 -2
  11. package/dist/client/index.d.mts +2 -2
  12. package/dist/client/index.d.ts +2 -2
  13. package/dist/client/index.mjs +3 -3
  14. package/dist/context/index.cjs +3 -3
  15. package/dist/context/index.d.cts +11 -11
  16. package/dist/context/index.d.mts +11 -11
  17. package/dist/context/index.d.ts +11 -11
  18. package/dist/context/index.mjs +1 -1
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.d.cts +2 -2
  21. package/dist/index.d.mts +2 -2
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.mjs +1 -1
  24. package/dist/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.cjs +1 -1
  25. package/dist/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.mjs +1 -1
  26. package/dist/node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/sortable/dist/sortable.esm.cjs +77 -0
  27. package/dist/node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/sortable/dist/sortable.esm.mjs +79 -3
  28. package/dist/node_modules/.pnpm/@radix-ui_react-avatar@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react_850cfbef1935a6e49a6ad6c93c7ca70d/node_modules/@radix-ui/react-avatar/dist/index.cjs +140 -0
  29. package/dist/node_modules/.pnpm/@radix-ui_react-avatar@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react_850cfbef1935a6e49a6ad6c93c7ca70d/node_modules/@radix-ui/react-avatar/dist/index.mjs +119 -0
  30. package/dist/node_modules/.pnpm/@radix-ui_react-context@1.1.3_@types_react@19.2.6_react@19.2.0/node_modules/@radix-ui/react-context/dist/index.cjs +80 -0
  31. package/dist/node_modules/.pnpm/@radix-ui_react-context@1.1.3_@types_react@19.2.6_react@19.2.0/node_modules/@radix-ui/react-context/dist/index.mjs +64 -0
  32. package/dist/node_modules/.pnpm/@radix-ui_react-use-is-hydrated@0.1.0_@types_react@19.2.6_react@19.2.0/node_modules/@radix-ui/react-use-is-hydrated/dist/index.cjs +18 -0
  33. package/dist/node_modules/.pnpm/@radix-ui_react-use-is-hydrated@0.1.0_@types_react@19.2.6_react@19.2.0/node_modules/@radix-ui/react-use-is-hydrated/dist/index.mjs +16 -0
  34. package/dist/packages/{better-stack → stack}/src/context/provider.cjs +11 -13
  35. package/dist/packages/{better-stack → stack}/src/context/provider.mjs +10 -12
  36. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-interface.cjs +2 -2
  37. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-interface.mjs +2 -2
  38. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-common.cjs +1 -1
  39. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-common.mjs +1 -1
  40. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-common.cjs +1 -1
  41. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-common.mjs +1 -1
  42. package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +846 -0
  43. package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +844 -0
  44. package/dist/packages/stack/src/plugins/kanban/client/components/forms/board-form.cjs +85 -0
  45. package/dist/packages/stack/src/plugins/kanban/client/components/forms/board-form.mjs +83 -0
  46. package/dist/packages/stack/src/plugins/kanban/client/components/forms/column-form.cjs +72 -0
  47. package/dist/packages/stack/src/plugins/kanban/client/components/forms/column-form.mjs +70 -0
  48. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.cjs +200 -0
  49. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.mjs +198 -0
  50. package/dist/packages/stack/src/plugins/kanban/client/components/loading/board-skeleton.cjs +47 -0
  51. package/dist/packages/stack/src/plugins/kanban/client/components/loading/board-skeleton.mjs +45 -0
  52. package/dist/packages/stack/src/plugins/kanban/client/components/loading/boards-list-skeleton.cjs +30 -0
  53. package/dist/packages/stack/src/plugins/kanban/client/components/loading/boards-list-skeleton.mjs +28 -0
  54. package/dist/packages/stack/src/plugins/kanban/client/components/pages/404-page.cjs +27 -0
  55. package/dist/packages/stack/src/plugins/kanban/client/components/pages/404-page.mjs +25 -0
  56. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.cjs +31 -0
  57. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.cjs +458 -0
  58. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.mjs +456 -0
  59. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.mjs +29 -0
  60. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.cjs +30 -0
  61. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.internal.cjs +72 -0
  62. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.internal.mjs +70 -0
  63. package/dist/packages/stack/src/plugins/kanban/client/components/pages/boards-list-page.mjs +28 -0
  64. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.cjs +30 -0
  65. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.internal.cjs +51 -0
  66. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.internal.mjs +49 -0
  67. package/dist/packages/stack/src/plugins/kanban/client/components/pages/new-board-page.mjs +28 -0
  68. package/dist/packages/stack/src/plugins/kanban/client/components/shared/column-content.cjs +76 -0
  69. package/dist/packages/stack/src/plugins/kanban/client/components/shared/column-content.mjs +74 -0
  70. package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.cjs +27 -0
  71. package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.mjs +25 -0
  72. package/dist/packages/stack/src/plugins/kanban/client/components/shared/empty-state.cjs +32 -0
  73. package/dist/packages/stack/src/plugins/kanban/client/components/shared/empty-state.mjs +30 -0
  74. package/dist/packages/stack/src/plugins/kanban/client/components/shared/kanban-board.cjs +78 -0
  75. package/dist/packages/stack/src/plugins/kanban/client/components/shared/kanban-board.mjs +76 -0
  76. package/dist/packages/stack/src/plugins/kanban/client/components/shared/page-wrapper.cjs +15 -0
  77. package/dist/packages/stack/src/plugins/kanban/client/components/shared/page-wrapper.mjs +13 -0
  78. package/dist/packages/stack/src/plugins/kanban/client/components/shared/task-card.cjs +68 -0
  79. package/dist/packages/stack/src/plugins/kanban/client/components/shared/task-card.mjs +66 -0
  80. package/dist/packages/stack/src/plugins/kanban/client/components/shared/user-avatar.cjs +32 -0
  81. package/dist/packages/stack/src/plugins/kanban/client/components/shared/user-avatar.mjs +30 -0
  82. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.cjs +391 -0
  83. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.mjs +381 -0
  84. package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +290 -0
  85. package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +288 -0
  86. package/dist/packages/stack/src/plugins/kanban/db.cjs +125 -0
  87. package/dist/packages/stack/src/plugins/kanban/db.mjs +123 -0
  88. package/dist/packages/stack/src/plugins/kanban/schemas.cjs +117 -0
  89. package/dist/packages/stack/src/plugins/kanban/schemas.mjs +102 -0
  90. package/dist/packages/stack/src/plugins/kanban/utils.cjs +49 -0
  91. package/dist/packages/stack/src/plugins/kanban/utils.mjs +45 -0
  92. package/dist/packages/{better-stack → stack}/src/plugins/open-api/api/generator.cjs +2 -2
  93. package/dist/packages/{better-stack → stack}/src/plugins/open-api/api/generator.mjs +2 -2
  94. package/dist/packages/ui/src/components/avatar.cjs +58 -0
  95. package/dist/packages/ui/src/components/avatar.mjs +54 -0
  96. package/dist/packages/ui/src/components/command.cjs +3 -3
  97. package/dist/packages/ui/src/components/command.mjs +3 -3
  98. package/dist/packages/ui/src/components/form-builder/index.mjs +2 -2
  99. package/dist/packages/ui/src/components/kanban.cjs +835 -0
  100. package/dist/packages/ui/src/components/kanban.mjs +805 -0
  101. package/dist/packages/ui/src/components/page-wrapper.cjs +2 -2
  102. package/dist/packages/ui/src/components/page-wrapper.mjs +2 -2
  103. package/dist/packages/ui/src/components/popover.cjs +8 -3
  104. package/dist/packages/ui/src/components/popover.mjs +9 -4
  105. package/dist/packages/ui/src/components/search-select.cjs +75 -0
  106. package/dist/packages/ui/src/components/search-select.mjs +73 -0
  107. package/dist/packages/ui/src/components/{better-stack-attribution.cjs → stack-attribution.cjs} +5 -5
  108. package/dist/packages/ui/src/components/{better-stack-attribution.mjs → stack-attribution.mjs} +5 -5
  109. package/dist/packages/ui/src/lib/compose-refs.cjs +56 -0
  110. package/dist/packages/ui/src/lib/compose-refs.mjs +39 -0
  111. package/dist/plugins/ai-chat/api/index.cjs +1 -1
  112. package/dist/plugins/ai-chat/api/index.mjs +1 -1
  113. package/dist/plugins/ai-chat/client/components/index.cjs +12 -12
  114. package/dist/plugins/ai-chat/client/components/index.mjs +12 -12
  115. package/dist/plugins/ai-chat/client/hooks/index.cjs +1 -1
  116. package/dist/plugins/ai-chat/client/hooks/index.mjs +1 -1
  117. package/dist/plugins/ai-chat/client/index.cjs +8 -8
  118. package/dist/plugins/ai-chat/client/index.mjs +8 -8
  119. package/dist/plugins/api/index.d.cts +3 -3
  120. package/dist/plugins/api/index.d.mts +3 -3
  121. package/dist/plugins/api/index.d.ts +3 -3
  122. package/dist/plugins/blog/api/index.cjs +1 -1
  123. package/dist/plugins/blog/api/index.d.cts +1 -1
  124. package/dist/plugins/blog/api/index.d.mts +1 -1
  125. package/dist/plugins/blog/api/index.d.ts +1 -1
  126. package/dist/plugins/blog/api/index.mjs +1 -1
  127. package/dist/plugins/blog/client/components/index.cjs +4 -4
  128. package/dist/plugins/blog/client/components/index.mjs +4 -4
  129. package/dist/plugins/blog/client/hooks/index.cjs +1 -1
  130. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  131. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  132. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  133. package/dist/plugins/blog/client/hooks/index.mjs +1 -1
  134. package/dist/plugins/blog/client/index.cjs +1 -1
  135. package/dist/plugins/blog/client/index.d.cts +1 -1
  136. package/dist/plugins/blog/client/index.d.mts +1 -1
  137. package/dist/plugins/blog/client/index.d.ts +1 -1
  138. package/dist/plugins/blog/client/index.mjs +1 -1
  139. package/dist/plugins/blog/query-keys.d.cts +2 -2
  140. package/dist/plugins/blog/query-keys.d.mts +2 -2
  141. package/dist/plugins/blog/query-keys.d.ts +2 -2
  142. package/dist/plugins/client/index.cjs +1 -1
  143. package/dist/plugins/client/index.d.cts +3 -3
  144. package/dist/plugins/client/index.d.mts +3 -3
  145. package/dist/plugins/client/index.d.ts +3 -3
  146. package/dist/plugins/client/index.mjs +1 -1
  147. package/dist/plugins/cms/api/index.cjs +1 -1
  148. package/dist/plugins/cms/api/index.d.cts +1 -1
  149. package/dist/plugins/cms/api/index.d.mts +1 -1
  150. package/dist/plugins/cms/api/index.d.ts +1 -1
  151. package/dist/plugins/cms/api/index.mjs +1 -1
  152. package/dist/plugins/cms/client/components/index.cjs +3 -3
  153. package/dist/plugins/cms/client/components/index.mjs +3 -3
  154. package/dist/plugins/cms/client/hooks/index.cjs +1 -1
  155. package/dist/plugins/cms/client/hooks/index.mjs +1 -1
  156. package/dist/plugins/cms/client/index.cjs +2 -2
  157. package/dist/plugins/cms/client/index.mjs +2 -2
  158. package/dist/plugins/form-builder/api/index.cjs +1 -1
  159. package/dist/plugins/form-builder/api/index.mjs +1 -1
  160. package/dist/plugins/form-builder/client/components/index.cjs +10 -10
  161. package/dist/plugins/form-builder/client/components/index.mjs +10 -10
  162. package/dist/plugins/form-builder/client/hooks/index.cjs +1 -1
  163. package/dist/plugins/form-builder/client/hooks/index.mjs +1 -1
  164. package/dist/plugins/form-builder/client/index.cjs +1 -1
  165. package/dist/plugins/form-builder/client/index.mjs +1 -1
  166. package/dist/plugins/kanban/api/index.cjs +7 -0
  167. package/dist/plugins/kanban/api/index.d.cts +403 -0
  168. package/dist/plugins/kanban/api/index.d.mts +403 -0
  169. package/dist/plugins/kanban/api/index.d.ts +403 -0
  170. package/dist/plugins/kanban/api/index.mjs +1 -0
  171. package/dist/plugins/kanban/client/components/index.cjs +35 -0
  172. package/dist/plugins/kanban/client/components/index.d.cts +102 -0
  173. package/dist/plugins/kanban/client/components/index.d.mts +102 -0
  174. package/dist/plugins/kanban/client/components/index.d.ts +102 -0
  175. package/dist/plugins/kanban/client/components/index.mjs +15 -0
  176. package/dist/plugins/kanban/client/hooks/index.cjs +15 -0
  177. package/dist/plugins/kanban/client/hooks/index.d.cts +143 -0
  178. package/dist/plugins/kanban/client/hooks/index.d.mts +143 -0
  179. package/dist/plugins/kanban/client/hooks/index.d.ts +143 -0
  180. package/dist/plugins/kanban/client/hooks/index.mjs +1 -0
  181. package/dist/plugins/kanban/client/index.cjs +7 -0
  182. package/dist/plugins/kanban/client/index.d.cts +196 -0
  183. package/dist/plugins/kanban/client/index.d.mts +196 -0
  184. package/dist/plugins/kanban/client/index.d.ts +196 -0
  185. package/dist/plugins/kanban/client/index.mjs +1 -0
  186. package/dist/plugins/kanban/client.css +68 -0
  187. package/dist/plugins/kanban/query-keys.cjs +105 -0
  188. package/dist/plugins/kanban/query-keys.d.cts +59 -0
  189. package/dist/plugins/kanban/query-keys.d.mts +59 -0
  190. package/dist/plugins/kanban/query-keys.d.ts +59 -0
  191. package/dist/plugins/kanban/query-keys.mjs +103 -0
  192. package/dist/plugins/kanban/style.css +7 -0
  193. package/dist/plugins/open-api/api/index.cjs +2 -2
  194. package/dist/plugins/open-api/api/index.d.cts +6 -6
  195. package/dist/plugins/open-api/api/index.d.mts +6 -6
  196. package/dist/plugins/open-api/api/index.d.ts +6 -6
  197. package/dist/plugins/open-api/api/index.mjs +2 -2
  198. package/dist/plugins/route-docs/client/index.cjs +1 -1
  199. package/dist/plugins/route-docs/client/index.d.cts +1 -1
  200. package/dist/plugins/route-docs/client/index.d.mts +1 -1
  201. package/dist/plugins/route-docs/client/index.d.ts +1 -1
  202. package/dist/plugins/route-docs/client/index.mjs +1 -1
  203. package/dist/plugins/ui-builder/client/components/index.cjs +3 -3
  204. package/dist/plugins/ui-builder/client/components/index.mjs +3 -3
  205. package/dist/plugins/ui-builder/client/hooks/index.cjs +1 -1
  206. package/dist/plugins/ui-builder/client/hooks/index.mjs +1 -1
  207. package/dist/plugins/ui-builder/client/index.cjs +7 -7
  208. package/dist/plugins/ui-builder/client/index.mjs +7 -7
  209. package/dist/plugins/ui-builder/index.cjs +1 -1
  210. package/dist/plugins/ui-builder/index.mjs +1 -1
  211. package/dist/plugins/ui-builder/style.css +6 -0
  212. package/dist/shared/{stack.u9iYV6vt.d.mts → stack.BoA0xkJv.d.cts} +5 -5
  213. package/dist/shared/{stack.u9iYV6vt.d.cts → stack.BoA0xkJv.d.mts} +5 -5
  214. package/dist/shared/{stack.u9iYV6vt.d.ts → stack.BoA0xkJv.d.ts} +5 -5
  215. package/dist/shared/stack.DKDMI-QO.d.cts +70 -0
  216. package/dist/shared/stack.DKDMI-QO.d.mts +70 -0
  217. package/dist/shared/stack.DKDMI-QO.d.ts +70 -0
  218. package/dist/shared/stack.FeaWkglm.d.cts +190 -0
  219. package/dist/shared/stack.FeaWkglm.d.mts +190 -0
  220. package/dist/shared/stack.FeaWkglm.d.ts +190 -0
  221. package/package.json +56 -2
  222. package/src/__tests__/plugins.test.tsx +7 -7
  223. package/src/api/index.ts +5 -5
  224. package/src/context/provider.tsx +21 -27
  225. package/src/plugins/ai-chat/client/components/chat-interface.tsx +2 -2
  226. package/src/plugins/api/index.ts +1 -1
  227. package/src/plugins/client/index.ts +1 -1
  228. package/src/plugins/cms/client/localization/cms-common.ts +1 -1
  229. package/src/plugins/form-builder/client/localization/form-builder-common.ts +1 -1
  230. package/src/plugins/kanban/api/index.ts +6 -0
  231. package/src/plugins/kanban/api/plugin.ts +1245 -0
  232. package/src/plugins/kanban/client/components/forms/board-form.tsx +108 -0
  233. package/src/plugins/kanban/client/components/forms/column-form.tsx +97 -0
  234. package/src/plugins/kanban/client/components/forms/task-form.tsx +274 -0
  235. package/src/plugins/kanban/client/components/index.tsx +21 -0
  236. package/src/plugins/kanban/client/components/loading/board-skeleton.tsx +49 -0
  237. package/src/plugins/kanban/client/components/loading/boards-list-skeleton.tsx +34 -0
  238. package/src/plugins/kanban/client/components/loading/index.tsx +2 -0
  239. package/src/plugins/kanban/client/components/pages/404-page.tsx +28 -0
  240. package/src/plugins/kanban/client/components/pages/board-page.internal.tsx +575 -0
  241. package/src/plugins/kanban/client/components/pages/board-page.tsx +31 -0
  242. package/src/plugins/kanban/client/components/pages/boards-list-page.internal.tsx +101 -0
  243. package/src/plugins/kanban/client/components/pages/boards-list-page.tsx +26 -0
  244. package/src/plugins/kanban/client/components/pages/new-board-page.internal.tsx +65 -0
  245. package/src/plugins/kanban/client/components/pages/new-board-page.tsx +26 -0
  246. package/src/plugins/kanban/client/components/shared/column-content.tsx +108 -0
  247. package/src/plugins/kanban/client/components/shared/default-error.tsx +32 -0
  248. package/src/plugins/kanban/client/components/shared/empty-state.tsx +37 -0
  249. package/src/plugins/kanban/client/components/shared/kanban-board.tsx +87 -0
  250. package/src/plugins/kanban/client/components/shared/page-wrapper.tsx +20 -0
  251. package/src/plugins/kanban/client/components/shared/task-card.tsx +79 -0
  252. package/src/plugins/kanban/client/components/shared/user-avatar.tsx +63 -0
  253. package/src/plugins/kanban/client/hooks/index.tsx +11 -0
  254. package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +560 -0
  255. package/src/plugins/kanban/client/index.ts +8 -0
  256. package/src/plugins/kanban/client/localization/index.ts +28 -0
  257. package/src/plugins/kanban/client/localization/kanban-common.ts +69 -0
  258. package/src/plugins/kanban/client/localization/kanban-forms.ts +70 -0
  259. package/src/plugins/kanban/client/localization/kanban-list.ts +36 -0
  260. package/src/plugins/kanban/client/overrides.ts +145 -0
  261. package/src/plugins/kanban/client/plugin.tsx +463 -0
  262. package/src/plugins/kanban/client.css +68 -0
  263. package/src/plugins/kanban/db.ts +125 -0
  264. package/src/plugins/kanban/query-keys.ts +154 -0
  265. package/src/plugins/kanban/schemas.ts +143 -0
  266. package/src/plugins/kanban/style.css +7 -0
  267. package/src/plugins/kanban/types.ts +106 -0
  268. package/src/plugins/kanban/utils.ts +107 -0
  269. package/src/plugins/open-api/api/generator.ts +5 -6
  270. package/src/plugins/open-api/api/plugin.ts +5 -5
  271. package/src/plugins/open-api/logo.ts +1 -1
  272. package/src/plugins/ui-builder/style.css +6 -0
  273. package/src/types.ts +4 -4
  274. package/dist/packages/{better-stack → stack}/src/client/components/compose.cjs +0 -0
  275. package/dist/packages/{better-stack → stack}/src/client/components/compose.mjs +0 -0
  276. package/dist/packages/{better-stack → stack}/src/client/components/error-boundary.cjs +0 -0
  277. package/dist/packages/{better-stack → stack}/src/client/components/error-boundary.mjs +0 -0
  278. package/dist/packages/{better-stack → stack}/src/client/meta-utils.cjs +0 -0
  279. package/dist/packages/{better-stack → stack}/src/client/meta-utils.mjs +0 -0
  280. package/dist/packages/{better-stack → stack}/src/client/path-utils.cjs +0 -0
  281. package/dist/packages/{better-stack → stack}/src/client/path-utils.mjs +0 -0
  282. package/dist/packages/{better-stack → stack}/src/client/sitemap-utils.cjs +0 -0
  283. package/dist/packages/{better-stack → stack}/src/client/sitemap-utils.mjs +0 -0
  284. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/api/plugin.cjs +0 -0
  285. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/api/plugin.mjs +0 -0
  286. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-input.cjs +0 -0
  287. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-input.mjs +0 -0
  288. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-layout.cjs +0 -0
  289. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-layout.mjs +0 -0
  290. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-message.cjs +0 -0
  291. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-message.mjs +0 -0
  292. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-sidebar.cjs +0 -0
  293. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/chat-sidebar.mjs +0 -0
  294. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/loading/chat-page-skeleton.cjs +0 -0
  295. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/loading/chat-page-skeleton.mjs +0 -0
  296. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/loading/index.cjs +0 -0
  297. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/loading/index.mjs +0 -0
  298. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/pages/404-page.cjs +0 -0
  299. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/pages/404-page.mjs +0 -0
  300. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/pages/chat-page.cjs +0 -0
  301. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/pages/chat-page.internal.cjs +0 -0
  302. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/pages/chat-page.internal.mjs +0 -0
  303. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/pages/chat-page.mjs +0 -0
  304. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/shared/default-error.cjs +0 -0
  305. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/shared/default-error.mjs +0 -0
  306. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/shared/error-placeholder.cjs +0 -0
  307. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/shared/error-placeholder.mjs +0 -0
  308. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/tool-call-display.cjs +0 -0
  309. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/components/tool-call-display.mjs +0 -0
  310. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/hooks/chat-hooks.cjs +0 -0
  311. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/hooks/chat-hooks.mjs +0 -0
  312. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/localization/index.cjs +0 -0
  313. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/localization/index.mjs +0 -0
  314. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/overrides.cjs +0 -0
  315. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/overrides.mjs +0 -0
  316. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/plugin.cjs +0 -0
  317. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/client/plugin.mjs +0 -0
  318. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/db.cjs +0 -0
  319. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/db.mjs +0 -0
  320. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/schemas.cjs +0 -0
  321. package/dist/packages/{better-stack → stack}/src/plugins/ai-chat/schemas.mjs +0 -0
  322. package/dist/packages/{better-stack → stack}/src/plugins/blog/api/plugin.cjs +0 -0
  323. package/dist/packages/{better-stack → stack}/src/plugins/blog/api/plugin.mjs +0 -0
  324. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/forms/image-field.cjs +0 -0
  325. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/forms/image-field.mjs +0 -0
  326. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/forms/markdown-editor.cjs +0 -0
  327. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/forms/markdown-editor.mjs +0 -0
  328. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/forms/post-forms.cjs +0 -0
  329. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/forms/post-forms.mjs +0 -0
  330. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/forms/tags-multiselect.cjs +0 -0
  331. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/forms/tags-multiselect.mjs +0 -0
  332. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/form-page-skeleton.cjs +0 -0
  333. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/form-page-skeleton.mjs +0 -0
  334. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/index.cjs +0 -0
  335. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/index.mjs +0 -0
  336. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/list-page-skeleton.cjs +0 -0
  337. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/list-page-skeleton.mjs +0 -0
  338. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/page-header-skeleton.cjs +0 -0
  339. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/page-header-skeleton.mjs +0 -0
  340. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/post-card-skeleton.cjs +0 -0
  341. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/post-card-skeleton.mjs +0 -0
  342. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/post-page-skeleton.cjs +0 -0
  343. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/loading/post-page-skeleton.mjs +0 -0
  344. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/404-page.cjs +0 -0
  345. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/404-page.mjs +0 -0
  346. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/edit-post-page.cjs +0 -0
  347. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/edit-post-page.internal.cjs +0 -0
  348. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/edit-post-page.internal.mjs +0 -0
  349. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/edit-post-page.mjs +0 -0
  350. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/home-page.cjs +0 -0
  351. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/home-page.internal.cjs +0 -0
  352. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/home-page.internal.mjs +0 -0
  353. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/home-page.mjs +0 -0
  354. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/new-post-page.cjs +0 -0
  355. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/new-post-page.internal.cjs +0 -0
  356. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/new-post-page.internal.mjs +0 -0
  357. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/new-post-page.mjs +0 -0
  358. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/post-page.cjs +0 -0
  359. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/post-page.internal.cjs +0 -0
  360. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/post-page.internal.mjs +0 -0
  361. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/post-page.mjs +0 -0
  362. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/tag-page.cjs +0 -0
  363. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/tag-page.internal.cjs +0 -0
  364. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/tag-page.internal.mjs +0 -0
  365. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/pages/tag-page.mjs +0 -0
  366. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/default-error.cjs +0 -0
  367. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/default-error.mjs +0 -0
  368. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/defaults.cjs +0 -0
  369. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/defaults.mjs +0 -0
  370. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/empty-list.cjs +0 -0
  371. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/empty-list.mjs +0 -0
  372. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/error-placeholder.cjs +0 -0
  373. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/error-placeholder.mjs +0 -0
  374. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/highlight-text.cjs +0 -0
  375. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/highlight-text.mjs +0 -0
  376. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/markdown-content.cjs +0 -0
  377. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/markdown-content.mjs +0 -0
  378. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/on-this-page.cjs +0 -0
  379. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/on-this-page.mjs +0 -0
  380. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/page-header.cjs +0 -0
  381. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/page-header.mjs +0 -0
  382. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/page-wrapper.cjs +0 -0
  383. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/page-wrapper.mjs +0 -0
  384. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/post-card.cjs +0 -0
  385. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/post-card.mjs +0 -0
  386. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/post-navigation.cjs +0 -0
  387. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/post-navigation.mjs +0 -0
  388. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/posts-list.cjs +0 -0
  389. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/posts-list.mjs +0 -0
  390. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/recent-posts-carousel.cjs +0 -0
  391. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/recent-posts-carousel.mjs +0 -0
  392. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/search-input.cjs +0 -0
  393. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/search-input.mjs +0 -0
  394. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/search-modal.cjs +0 -0
  395. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/search-modal.mjs +0 -0
  396. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/tags-list.cjs +0 -0
  397. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/components/shared/tags-list.mjs +0 -0
  398. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/hooks/blog-hooks.cjs +0 -0
  399. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/hooks/blog-hooks.mjs +0 -0
  400. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/hooks/use-debounce.cjs +0 -0
  401. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/hooks/use-debounce.mjs +0 -0
  402. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-card.cjs +0 -0
  403. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-card.mjs +0 -0
  404. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-common.cjs +0 -0
  405. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-common.mjs +0 -0
  406. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-forms.cjs +0 -0
  407. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-forms.mjs +0 -0
  408. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-list.cjs +0 -0
  409. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-list.mjs +0 -0
  410. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-post.cjs +0 -0
  411. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/blog-post.mjs +0 -0
  412. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/index.cjs +0 -0
  413. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/localization/index.mjs +0 -0
  414. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/plugin.cjs +0 -0
  415. package/dist/packages/{better-stack → stack}/src/plugins/blog/client/plugin.mjs +0 -0
  416. package/dist/packages/{better-stack → stack}/src/plugins/blog/db.cjs +0 -0
  417. package/dist/packages/{better-stack → stack}/src/plugins/blog/db.mjs +0 -0
  418. package/dist/packages/{better-stack → stack}/src/plugins/blog/schemas.cjs +0 -0
  419. package/dist/packages/{better-stack → stack}/src/plugins/blog/schemas.mjs +0 -0
  420. package/dist/packages/{better-stack → stack}/src/plugins/blog/utils.cjs +0 -0
  421. package/dist/packages/{better-stack → stack}/src/plugins/blog/utils.mjs +0 -0
  422. package/dist/packages/{better-stack → stack}/src/plugins/cms/api/plugin.cjs +0 -0
  423. package/dist/packages/{better-stack → stack}/src/plugins/cms/api/plugin.mjs +0 -0
  424. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/forms/content-form.cjs +0 -0
  425. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/forms/content-form.mjs +0 -0
  426. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/forms/file-upload.cjs +0 -0
  427. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/forms/file-upload.mjs +0 -0
  428. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/forms/relation-field.cjs +0 -0
  429. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/forms/relation-field.mjs +0 -0
  430. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/inverse-relations-panel.cjs +0 -0
  431. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/inverse-relations-panel.mjs +0 -0
  432. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/loading/dashboard-skeleton.cjs +0 -0
  433. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/loading/dashboard-skeleton.mjs +0 -0
  434. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/loading/editor-skeleton.cjs +0 -0
  435. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/loading/editor-skeleton.mjs +0 -0
  436. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/loading/list-skeleton.cjs +0 -0
  437. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/loading/list-skeleton.mjs +0 -0
  438. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/404-page.cjs +0 -0
  439. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/404-page.mjs +0 -0
  440. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/content-editor-page.cjs +0 -0
  441. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/content-editor-page.internal.cjs +0 -0
  442. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/content-editor-page.internal.mjs +0 -0
  443. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/content-editor-page.mjs +0 -0
  444. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/content-list-page.cjs +0 -0
  445. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/content-list-page.internal.cjs +0 -0
  446. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/content-list-page.internal.mjs +0 -0
  447. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/content-list-page.mjs +0 -0
  448. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/dashboard-page.cjs +0 -0
  449. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/dashboard-page.internal.cjs +0 -0
  450. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/dashboard-page.internal.mjs +0 -0
  451. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/pages/dashboard-page.mjs +0 -0
  452. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/shared/default-error.cjs +0 -0
  453. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/shared/default-error.mjs +0 -0
  454. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/shared/empty-state.cjs +0 -0
  455. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/shared/empty-state.mjs +0 -0
  456. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/shared/page-wrapper.cjs +0 -0
  457. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/components/shared/page-wrapper.mjs +0 -0
  458. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/hooks/cms-hooks.cjs +0 -0
  459. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/hooks/cms-hooks.mjs +0 -0
  460. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-dashboard.cjs +0 -0
  461. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-dashboard.mjs +0 -0
  462. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-editor.cjs +0 -0
  463. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-editor.mjs +0 -0
  464. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-list.cjs +0 -0
  465. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-list.mjs +0 -0
  466. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-toasts.cjs +0 -0
  467. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/cms-toasts.mjs +0 -0
  468. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/index.cjs +0 -0
  469. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/localization/index.mjs +0 -0
  470. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/plugin.cjs +0 -0
  471. package/dist/packages/{better-stack → stack}/src/plugins/cms/client/plugin.mjs +0 -0
  472. package/dist/packages/{better-stack → stack}/src/plugins/cms/db.cjs +0 -0
  473. package/dist/packages/{better-stack → stack}/src/plugins/cms/db.mjs +0 -0
  474. package/dist/packages/{better-stack → stack}/src/plugins/cms/schemas.cjs +0 -0
  475. package/dist/packages/{better-stack → stack}/src/plugins/cms/schemas.mjs +0 -0
  476. package/dist/packages/{better-stack → stack}/src/plugins/cms/utils.cjs +0 -0
  477. package/dist/packages/{better-stack → stack}/src/plugins/cms/utils.mjs +0 -0
  478. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/api/plugin.cjs +0 -0
  479. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/api/plugin.mjs +0 -0
  480. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/forms/form-renderer.cjs +0 -0
  481. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/forms/form-renderer.mjs +0 -0
  482. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/loading/form-builder-skeleton.cjs +0 -0
  483. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/loading/form-builder-skeleton.mjs +0 -0
  484. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/loading/form-list-skeleton.cjs +0 -0
  485. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/loading/form-list-skeleton.mjs +0 -0
  486. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/loading/submissions-skeleton.cjs +0 -0
  487. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/loading/submissions-skeleton.mjs +0 -0
  488. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/404-page.cjs +0 -0
  489. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/404-page.mjs +0 -0
  490. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/form-builder-page.cjs +0 -0
  491. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/form-builder-page.internal.cjs +0 -0
  492. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/form-builder-page.internal.mjs +0 -0
  493. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/form-builder-page.mjs +0 -0
  494. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/form-list-page.cjs +0 -0
  495. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/form-list-page.internal.cjs +0 -0
  496. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/form-list-page.internal.mjs +0 -0
  497. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/form-list-page.mjs +0 -0
  498. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/submissions-page.cjs +0 -0
  499. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/submissions-page.internal.cjs +0 -0
  500. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/submissions-page.internal.mjs +0 -0
  501. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/pages/submissions-page.mjs +0 -0
  502. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/shared/default-error.cjs +0 -0
  503. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/shared/default-error.mjs +0 -0
  504. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/shared/empty-state.cjs +0 -0
  505. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/shared/empty-state.mjs +0 -0
  506. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/shared/page-wrapper.cjs +0 -0
  507. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/shared/page-wrapper.mjs +0 -0
  508. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/shared/pagination.cjs +0 -0
  509. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/components/shared/pagination.mjs +0 -0
  510. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/hooks/form-builder-hooks.cjs +0 -0
  511. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/hooks/form-builder-hooks.mjs +0 -0
  512. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-editor.cjs +0 -0
  513. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-editor.mjs +0 -0
  514. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-list.cjs +0 -0
  515. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-list.mjs +0 -0
  516. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-submissions.cjs +0 -0
  517. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-submissions.mjs +0 -0
  518. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-toasts.cjs +0 -0
  519. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/form-builder-toasts.mjs +0 -0
  520. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/index.cjs +0 -0
  521. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/localization/index.mjs +0 -0
  522. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/plugin.cjs +0 -0
  523. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/client/plugin.mjs +0 -0
  524. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/db.cjs +0 -0
  525. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/db.mjs +0 -0
  526. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/schemas.cjs +0 -0
  527. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/schemas.mjs +0 -0
  528. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/utils.cjs +0 -0
  529. package/dist/packages/{better-stack → stack}/src/plugins/form-builder/utils.mjs +0 -0
  530. package/dist/packages/{better-stack → stack}/src/plugins/open-api/api/plugin.cjs +0 -0
  531. package/dist/packages/{better-stack → stack}/src/plugins/open-api/api/plugin.mjs +0 -0
  532. package/dist/packages/{better-stack → stack}/src/plugins/open-api/db.cjs +0 -0
  533. package/dist/packages/{better-stack → stack}/src/plugins/open-api/db.mjs +0 -0
  534. package/dist/packages/{better-stack → stack}/src/plugins/open-api/logo.cjs +0 -0
  535. package/dist/packages/{better-stack → stack}/src/plugins/open-api/logo.mjs +0 -0
  536. package/dist/packages/{better-stack → stack}/src/plugins/route-docs/client/components/loading/docs-skeleton.cjs +0 -0
  537. package/dist/packages/{better-stack → stack}/src/plugins/route-docs/client/components/loading/docs-skeleton.mjs +0 -0
  538. package/dist/packages/{better-stack → stack}/src/plugins/route-docs/client/components/pages/docs-page.cjs +0 -0
  539. package/dist/packages/{better-stack → stack}/src/plugins/route-docs/client/components/pages/docs-page.mjs +0 -0
  540. package/dist/packages/{better-stack → stack}/src/plugins/route-docs/client/plugin.cjs +0 -0
  541. package/dist/packages/{better-stack → stack}/src/plugins/route-docs/client/plugin.mjs +0 -0
  542. package/dist/packages/{better-stack → stack}/src/plugins/route-docs/generator.cjs +0 -0
  543. package/dist/packages/{better-stack → stack}/src/plugins/route-docs/generator.mjs +0 -0
  544. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/loading/page-builder-skeleton.cjs +0 -0
  545. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/loading/page-builder-skeleton.mjs +0 -0
  546. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/loading/page-list-skeleton.cjs +0 -0
  547. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/loading/page-list-skeleton.mjs +0 -0
  548. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/page-renderer.cjs +0 -0
  549. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/page-renderer.mjs +0 -0
  550. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/pages/page-builder-page.cjs +0 -0
  551. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.cjs +0 -0
  552. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.mjs +0 -0
  553. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/pages/page-builder-page.mjs +0 -0
  554. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/pages/page-list-page.cjs +0 -0
  555. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/pages/page-list-page.internal.cjs +0 -0
  556. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/pages/page-list-page.internal.mjs +0 -0
  557. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/pages/page-list-page.mjs +0 -0
  558. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/shared/default-error.cjs +0 -0
  559. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/shared/default-error.mjs +0 -0
  560. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/shared/empty-state.cjs +0 -0
  561. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/shared/empty-state.mjs +0 -0
  562. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/shared/page-wrapper.cjs +0 -0
  563. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/shared/page-wrapper.mjs +0 -0
  564. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/shared/pagination.cjs +0 -0
  565. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/components/shared/pagination.mjs +0 -0
  566. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/hooks/ui-builder-hooks.cjs +0 -0
  567. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/hooks/ui-builder-hooks.mjs +0 -0
  568. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/localization/index.cjs +0 -0
  569. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/localization/index.mjs +0 -0
  570. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/plugin.cjs +0 -0
  571. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/plugin.mjs +0 -0
  572. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/registry.cjs +0 -0
  573. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/client/registry.mjs +0 -0
  574. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/schemas.cjs +0 -0
  575. package/dist/packages/{better-stack → stack}/src/plugins/ui-builder/schemas.mjs +0 -0
  576. package/dist/packages/{better-stack → stack}/src/plugins/utils.cjs +0 -0
  577. package/dist/packages/{better-stack → stack}/src/plugins/utils.mjs +0 -0
  578. package/dist/shared/{stack.DLhzx1-D.d.cts → stack.CcI4sYJP.d.cts} +1 -1
  579. package/dist/shared/{stack.DLhzx1-D.d.ts → stack.CcI4sYJP.d.mts} +1 -1
  580. package/dist/shared/{stack.DLhzx1-D.d.mts → stack.CcI4sYJP.d.ts} +1 -1
@@ -0,0 +1,1245 @@
1
+ import type { Adapter } from "@btst/db";
2
+ import { defineBackendPlugin } from "@btst/stack/plugins/api";
3
+ import { createEndpoint } from "@btst/stack/plugins/api";
4
+ import { z } from "zod";
5
+ import { kanbanSchema as dbSchema } from "../db";
6
+ import type {
7
+ Board,
8
+ BoardWithKanbanColumn,
9
+ Column,
10
+ ColumnWithTasks,
11
+ Task,
12
+ } from "../types";
13
+ import { slugify } from "../utils";
14
+ import {
15
+ BoardListQuerySchema,
16
+ createBoardSchema,
17
+ createColumnSchema,
18
+ createTaskSchema,
19
+ moveTaskSchema,
20
+ reorderColumnsSchema,
21
+ reorderTasksSchema,
22
+ updateBoardSchema,
23
+ updateColumnSchema,
24
+ updateTaskSchema,
25
+ } from "../schemas";
26
+
27
+ /**
28
+ * Context passed to kanban API hooks
29
+ */
30
+ export interface KanbanApiContext<
31
+ TBody = unknown,
32
+ TParams = unknown,
33
+ TQuery = unknown,
34
+ > {
35
+ body?: TBody;
36
+ params?: TParams;
37
+ query?: TQuery;
38
+ request?: Request;
39
+ headers?: Headers;
40
+ [key: string]: unknown;
41
+ }
42
+
43
+ /**
44
+ * Configuration hooks for kanban backend plugin
45
+ * All hooks are optional and allow consumers to customize behavior
46
+ */
47
+ export interface KanbanBackendHooks {
48
+ // ============ Board Hooks ============
49
+ /**
50
+ * Called before listing boards. Return false to deny access.
51
+ */
52
+ onBeforeListBoards?: (
53
+ filter: z.infer<typeof BoardListQuerySchema>,
54
+ context: KanbanApiContext,
55
+ ) => Promise<boolean> | boolean;
56
+ /**
57
+ * Called before creating a board. Return false to deny access.
58
+ */
59
+ onBeforeCreateBoard?: (
60
+ data: z.infer<typeof createBoardSchema>,
61
+ context: KanbanApiContext,
62
+ ) => Promise<boolean> | boolean;
63
+ /**
64
+ * Called before reading a single board. Return false to deny access.
65
+ */
66
+ onBeforeReadBoard?: (
67
+ boardId: string,
68
+ context: KanbanApiContext,
69
+ ) => Promise<boolean> | boolean;
70
+ /**
71
+ * Called before updating a board. Return false to deny access.
72
+ */
73
+ onBeforeUpdateBoard?: (
74
+ boardId: string,
75
+ data: z.infer<typeof updateBoardSchema>,
76
+ context: KanbanApiContext,
77
+ ) => Promise<boolean> | boolean;
78
+ /**
79
+ * Called before deleting a board. Return false to deny access.
80
+ */
81
+ onBeforeDeleteBoard?: (
82
+ boardId: string,
83
+ context: KanbanApiContext,
84
+ ) => Promise<boolean> | boolean;
85
+
86
+ /**
87
+ * Called after boards are listed successfully
88
+ */
89
+ onBoardsRead?: (
90
+ boards: Board[],
91
+ filter: z.infer<typeof BoardListQuerySchema>,
92
+ context: KanbanApiContext,
93
+ ) => Promise<void> | void;
94
+ /**
95
+ * Called after a single board is read successfully
96
+ */
97
+ onBoardRead?: (
98
+ board: Board,
99
+ context: KanbanApiContext,
100
+ ) => Promise<void> | void;
101
+ /**
102
+ * Called after a board is created successfully
103
+ */
104
+ onBoardCreated?: (
105
+ board: Board,
106
+ context: KanbanApiContext,
107
+ ) => Promise<void> | void;
108
+ /**
109
+ * Called after a board is updated successfully
110
+ */
111
+ onBoardUpdated?: (
112
+ board: Board,
113
+ context: KanbanApiContext,
114
+ ) => Promise<void> | void;
115
+ /**
116
+ * Called after a board is deleted successfully
117
+ */
118
+ onBoardDeleted?: (
119
+ boardId: string,
120
+ context: KanbanApiContext,
121
+ ) => Promise<void> | void;
122
+
123
+ /**
124
+ * Called when listing boards fails
125
+ */
126
+ onListBoardsError?: (
127
+ error: Error,
128
+ context: KanbanApiContext,
129
+ ) => Promise<void> | void;
130
+ /**
131
+ * Called when reading a single board fails
132
+ */
133
+ onReadBoardError?: (
134
+ error: Error,
135
+ context: KanbanApiContext,
136
+ ) => Promise<void> | void;
137
+ /**
138
+ * Called when creating a board fails
139
+ */
140
+ onCreateBoardError?: (
141
+ error: Error,
142
+ context: KanbanApiContext,
143
+ ) => Promise<void> | void;
144
+ /**
145
+ * Called when updating a board fails
146
+ */
147
+ onUpdateBoardError?: (
148
+ error: Error,
149
+ context: KanbanApiContext,
150
+ ) => Promise<void> | void;
151
+ /**
152
+ * Called when deleting a board fails
153
+ */
154
+ onDeleteBoardError?: (
155
+ error: Error,
156
+ context: KanbanApiContext,
157
+ ) => Promise<void> | void;
158
+
159
+ // ============ Column Hooks ============
160
+ /**
161
+ * Called before creating a column. Return false to deny access.
162
+ */
163
+ onBeforeCreateColumn?: (
164
+ data: z.infer<typeof createColumnSchema>,
165
+ context: KanbanApiContext,
166
+ ) => Promise<boolean> | boolean;
167
+ /**
168
+ * Called before updating a column. Return false to deny access.
169
+ */
170
+ onBeforeUpdateColumn?: (
171
+ columnId: string,
172
+ data: z.infer<typeof updateColumnSchema>,
173
+ context: KanbanApiContext,
174
+ ) => Promise<boolean> | boolean;
175
+ /**
176
+ * Called before deleting a column. Return false to deny access.
177
+ */
178
+ onBeforeDeleteColumn?: (
179
+ columnId: string,
180
+ context: KanbanApiContext,
181
+ ) => Promise<boolean> | boolean;
182
+
183
+ /**
184
+ * Called after a column is created successfully
185
+ */
186
+ onColumnCreated?: (
187
+ column: Column,
188
+ context: KanbanApiContext,
189
+ ) => Promise<void> | void;
190
+ /**
191
+ * Called after a column is updated successfully
192
+ */
193
+ onColumnUpdated?: (
194
+ column: Column,
195
+ context: KanbanApiContext,
196
+ ) => Promise<void> | void;
197
+ /**
198
+ * Called after a column is deleted successfully
199
+ */
200
+ onColumnDeleted?: (
201
+ columnId: string,
202
+ context: KanbanApiContext,
203
+ ) => Promise<void> | void;
204
+
205
+ // ============ Task Hooks ============
206
+ /**
207
+ * Called before creating a task. Return false to deny access.
208
+ */
209
+ onBeforeCreateTask?: (
210
+ data: z.infer<typeof createTaskSchema>,
211
+ context: KanbanApiContext,
212
+ ) => Promise<boolean> | boolean;
213
+ /**
214
+ * Called before updating a task. Return false to deny access.
215
+ */
216
+ onBeforeUpdateTask?: (
217
+ taskId: string,
218
+ data: z.infer<typeof updateTaskSchema>,
219
+ context: KanbanApiContext,
220
+ ) => Promise<boolean> | boolean;
221
+ /**
222
+ * Called before deleting a task. Return false to deny access.
223
+ */
224
+ onBeforeDeleteTask?: (
225
+ taskId: string,
226
+ context: KanbanApiContext,
227
+ ) => Promise<boolean> | boolean;
228
+
229
+ /**
230
+ * Called after a task is created successfully
231
+ */
232
+ onTaskCreated?: (
233
+ task: Task,
234
+ context: KanbanApiContext,
235
+ ) => Promise<void> | void;
236
+ /**
237
+ * Called after a task is updated successfully
238
+ */
239
+ onTaskUpdated?: (
240
+ task: Task,
241
+ context: KanbanApiContext,
242
+ ) => Promise<void> | void;
243
+ /**
244
+ * Called after a task is deleted successfully
245
+ */
246
+ onTaskDeleted?: (
247
+ taskId: string,
248
+ context: KanbanApiContext,
249
+ ) => Promise<void> | void;
250
+ }
251
+
252
+ /**
253
+ * Kanban backend plugin
254
+ * Provides API endpoints for managing kanban boards, columns, and tasks
255
+ *
256
+ * @param hooks - Optional configuration hooks for customizing plugin behavior
257
+ */
258
+ export const kanbanBackendPlugin = (hooks?: KanbanBackendHooks) =>
259
+ defineBackendPlugin({
260
+ name: "kanban",
261
+
262
+ dbPlugin: dbSchema,
263
+
264
+ routes: (adapter: Adapter) => {
265
+ // ============ Board Endpoints ============
266
+
267
+ const listBoards = createEndpoint(
268
+ "/boards",
269
+ {
270
+ method: "GET",
271
+ query: BoardListQuerySchema,
272
+ },
273
+ async (ctx) => {
274
+ const { query, headers } = ctx;
275
+ const context: KanbanApiContext = { query, headers };
276
+
277
+ try {
278
+ if (hooks?.onBeforeListBoards) {
279
+ const canList = await hooks.onBeforeListBoards(query, context);
280
+ if (!canList) {
281
+ throw ctx.error(403, {
282
+ message: "Unauthorized: Cannot list boards",
283
+ });
284
+ }
285
+ }
286
+
287
+ const whereConditions = [];
288
+
289
+ if (query.slug) {
290
+ whereConditions.push({
291
+ field: "slug",
292
+ value: query.slug,
293
+ operator: "eq" as const,
294
+ });
295
+ }
296
+
297
+ if (query.ownerId) {
298
+ whereConditions.push({
299
+ field: "ownerId",
300
+ value: query.ownerId,
301
+ operator: "eq" as const,
302
+ });
303
+ }
304
+
305
+ if (query.organizationId) {
306
+ whereConditions.push({
307
+ field: "organizationId",
308
+ value: query.organizationId,
309
+ operator: "eq" as const,
310
+ });
311
+ }
312
+
313
+ const boards = await adapter.findMany<BoardWithKanbanColumn>({
314
+ model: "kanbanBoard",
315
+ limit: query.limit ?? 50,
316
+ offset: query.offset ?? 0,
317
+ where: whereConditions,
318
+ sortBy: {
319
+ field: "createdAt",
320
+ direction: "desc",
321
+ },
322
+ join: {
323
+ kanbanColumn: true,
324
+ },
325
+ });
326
+
327
+ // Get all column IDs to fetch tasks
328
+ // Note: adapter returns joined data under schema key name ("column"), not model name
329
+ const columnIds: string[] = [];
330
+ for (const board of boards) {
331
+ if (board.column) {
332
+ for (const col of board.column) {
333
+ columnIds.push(col.id);
334
+ }
335
+ }
336
+ }
337
+
338
+ // Fetch tasks for each column in parallel (avoids loading all tasks from DB)
339
+ const tasksByColumn = new Map<string, Task[]>();
340
+ if (columnIds.length > 0) {
341
+ const taskQueries = columnIds.map((columnId) =>
342
+ adapter.findMany<Task>({
343
+ model: "kanbanTask",
344
+ where: [
345
+ {
346
+ field: "columnId",
347
+ value: columnId,
348
+ operator: "eq" as const,
349
+ },
350
+ ],
351
+ sortBy: { field: "order", direction: "asc" },
352
+ }),
353
+ );
354
+ const taskResults = await Promise.all(taskQueries);
355
+ for (let i = 0; i < columnIds.length; i++) {
356
+ const columnId = columnIds[i];
357
+ const tasks = taskResults[i];
358
+ if (columnId && tasks) {
359
+ tasksByColumn.set(columnId, tasks);
360
+ }
361
+ }
362
+ }
363
+
364
+ // Map boards with columns and tasks
365
+ const result = boards.map((board) => {
366
+ const columns = (board.column || [])
367
+ .sort((a, b) => a.order - b.order)
368
+ .map((col) => ({
369
+ ...col,
370
+ tasks: tasksByColumn.get(col.id) || [],
371
+ }));
372
+ const { column: _, ...boardWithoutJoin } = board;
373
+ return {
374
+ ...boardWithoutJoin,
375
+ columns,
376
+ };
377
+ });
378
+
379
+ if (hooks?.onBoardsRead) {
380
+ await hooks.onBoardsRead(result, query, context);
381
+ }
382
+
383
+ return result;
384
+ } catch (error) {
385
+ if (hooks?.onListBoardsError) {
386
+ await hooks.onListBoardsError(error as Error, context);
387
+ }
388
+ throw error;
389
+ }
390
+ },
391
+ );
392
+
393
+ const getBoard = createEndpoint(
394
+ "/boards/:id",
395
+ {
396
+ method: "GET",
397
+ },
398
+ async (ctx) => {
399
+ const { params, headers } = ctx;
400
+ const context: KanbanApiContext = { params, headers };
401
+
402
+ try {
403
+ if (hooks?.onBeforeReadBoard) {
404
+ const canRead = await hooks.onBeforeReadBoard(params.id, context);
405
+ if (!canRead) {
406
+ throw ctx.error(403, {
407
+ message: "Unauthorized: Cannot read board",
408
+ });
409
+ }
410
+ }
411
+
412
+ const board = await adapter.findOne<BoardWithKanbanColumn>({
413
+ model: "kanbanBoard",
414
+ where: [
415
+ { field: "id", value: params.id, operator: "eq" as const },
416
+ ],
417
+ join: {
418
+ kanbanColumn: true,
419
+ },
420
+ });
421
+
422
+ if (!board) {
423
+ throw ctx.error(404, { message: "Board not found" });
424
+ }
425
+
426
+ // Fetch tasks for each column in parallel (avoids loading all tasks from DB)
427
+ // Note: adapter returns joined data under schema key name ("column"), not model name
428
+ const columnIds = (board.column || []).map((c) => c.id);
429
+ const tasksByColumn = new Map<string, Task[]>();
430
+ if (columnIds.length > 0) {
431
+ const taskQueries = columnIds.map((columnId) =>
432
+ adapter.findMany<Task>({
433
+ model: "kanbanTask",
434
+ where: [
435
+ {
436
+ field: "columnId",
437
+ value: columnId,
438
+ operator: "eq" as const,
439
+ },
440
+ ],
441
+ sortBy: { field: "order", direction: "asc" },
442
+ }),
443
+ );
444
+ const taskResults = await Promise.all(taskQueries);
445
+ for (let i = 0; i < columnIds.length; i++) {
446
+ const columnId = columnIds[i];
447
+ const tasks = taskResults[i];
448
+ if (columnId && tasks) {
449
+ tasksByColumn.set(columnId, tasks);
450
+ }
451
+ }
452
+ }
453
+
454
+ const columns = (board.column || [])
455
+ .sort((a, b) => a.order - b.order)
456
+ .map((col) => ({
457
+ ...col,
458
+ tasks: tasksByColumn.get(col.id) || [],
459
+ }));
460
+
461
+ const { column: _, ...boardWithoutJoin } = board;
462
+ const result = {
463
+ ...boardWithoutJoin,
464
+ columns,
465
+ };
466
+
467
+ if (hooks?.onBoardRead) {
468
+ await hooks.onBoardRead(result, context);
469
+ }
470
+
471
+ return result;
472
+ } catch (error) {
473
+ if (hooks?.onReadBoardError) {
474
+ await hooks.onReadBoardError(error as Error, context);
475
+ }
476
+ throw error;
477
+ }
478
+ },
479
+ );
480
+
481
+ const createBoard = createEndpoint(
482
+ "/boards",
483
+ {
484
+ method: "POST",
485
+ body: createBoardSchema,
486
+ },
487
+ async (ctx) => {
488
+ const context: KanbanApiContext = {
489
+ body: ctx.body,
490
+ headers: ctx.headers,
491
+ };
492
+
493
+ try {
494
+ if (hooks?.onBeforeCreateBoard) {
495
+ const canCreate = await hooks.onBeforeCreateBoard(
496
+ ctx.body,
497
+ context,
498
+ );
499
+ if (!canCreate) {
500
+ throw ctx.error(403, {
501
+ message: "Unauthorized: Cannot create board",
502
+ });
503
+ }
504
+ }
505
+
506
+ const { ...boardData } = ctx.body;
507
+ const slug = slugify(boardData.slug || boardData.name);
508
+
509
+ if (!slug) {
510
+ throw ctx.error(400, {
511
+ message:
512
+ "Invalid slug: must contain at least one alphanumeric character",
513
+ });
514
+ }
515
+
516
+ // Use transaction to ensure board and default columns are created atomically
517
+ let newBoard: Board | undefined;
518
+ const createdColumns: ColumnWithTasks[] = [];
519
+
520
+ await adapter.transaction(async (tx) => {
521
+ newBoard = await tx.create<Board>({
522
+ model: "kanbanBoard",
523
+ data: {
524
+ ...boardData,
525
+ slug,
526
+ createdAt: new Date(),
527
+ updatedAt: new Date(),
528
+ },
529
+ });
530
+
531
+ // Create default columns
532
+ const defaultColumns = [
533
+ { title: "To Do", order: 0, boardId: newBoard.id },
534
+ { title: "In Progress", order: 1, boardId: newBoard.id },
535
+ { title: "Done", order: 2, boardId: newBoard.id },
536
+ ];
537
+
538
+ for (const colData of defaultColumns) {
539
+ const col = await tx.create<Column>({
540
+ model: "kanbanColumn",
541
+ data: {
542
+ ...colData,
543
+ createdAt: new Date(),
544
+ updatedAt: new Date(),
545
+ },
546
+ });
547
+ createdColumns.push({ ...col, tasks: [] });
548
+ }
549
+ });
550
+
551
+ if (!newBoard) {
552
+ throw ctx.error(500, {
553
+ message: "Failed to create board",
554
+ });
555
+ }
556
+
557
+ const result = { ...newBoard, columns: createdColumns };
558
+
559
+ if (hooks?.onBoardCreated) {
560
+ await hooks.onBoardCreated(result, context);
561
+ }
562
+
563
+ return result;
564
+ } catch (error) {
565
+ if (hooks?.onCreateBoardError) {
566
+ await hooks.onCreateBoardError(error as Error, context);
567
+ }
568
+ throw error;
569
+ }
570
+ },
571
+ );
572
+
573
+ const updateBoard = createEndpoint(
574
+ "/boards/:id",
575
+ {
576
+ method: "PUT",
577
+ body: updateBoardSchema.omit({ id: true }),
578
+ },
579
+ async (ctx) => {
580
+ const context: KanbanApiContext = {
581
+ body: ctx.body,
582
+ params: ctx.params,
583
+ headers: ctx.headers,
584
+ };
585
+
586
+ try {
587
+ if (hooks?.onBeforeUpdateBoard) {
588
+ const canUpdate = await hooks.onBeforeUpdateBoard(
589
+ ctx.params.id,
590
+ { ...ctx.body, id: ctx.params.id },
591
+ context,
592
+ );
593
+ if (!canUpdate) {
594
+ throw ctx.error(403, {
595
+ message: "Unauthorized: Cannot update board",
596
+ });
597
+ }
598
+ }
599
+
600
+ const { slug: rawSlug, ...restBoardData } = ctx.body;
601
+ const slugified = rawSlug ? slugify(rawSlug) : undefined;
602
+
603
+ if (rawSlug && !slugified) {
604
+ throw ctx.error(400, {
605
+ message:
606
+ "Invalid slug: must contain at least one alphanumeric character",
607
+ });
608
+ }
609
+
610
+ const boardData = {
611
+ ...restBoardData,
612
+ ...(slugified ? { slug: slugified } : {}),
613
+ };
614
+
615
+ const updated = await adapter.update<Board>({
616
+ model: "kanbanBoard",
617
+ where: [{ field: "id", value: ctx.params.id }],
618
+ update: {
619
+ ...boardData,
620
+ updatedAt: new Date(),
621
+ },
622
+ });
623
+
624
+ if (!updated) {
625
+ throw ctx.error(404, { message: "Board not found" });
626
+ }
627
+
628
+ if (hooks?.onBoardUpdated) {
629
+ await hooks.onBoardUpdated(updated, context);
630
+ }
631
+
632
+ return updated;
633
+ } catch (error) {
634
+ if (hooks?.onUpdateBoardError) {
635
+ await hooks.onUpdateBoardError(error as Error, context);
636
+ }
637
+ throw error;
638
+ }
639
+ },
640
+ );
641
+
642
+ const deleteBoard = createEndpoint(
643
+ "/boards/:id",
644
+ {
645
+ method: "DELETE",
646
+ },
647
+ async (ctx) => {
648
+ const context: KanbanApiContext = {
649
+ params: ctx.params,
650
+ headers: ctx.headers,
651
+ };
652
+
653
+ try {
654
+ // Verify the board exists before attempting deletion
655
+ const existingBoard = await adapter.findOne<Board>({
656
+ model: "kanbanBoard",
657
+ where: [
658
+ { field: "id", value: ctx.params.id, operator: "eq" as const },
659
+ ],
660
+ });
661
+
662
+ if (!existingBoard) {
663
+ throw ctx.error(404, { message: "Board not found" });
664
+ }
665
+
666
+ if (hooks?.onBeforeDeleteBoard) {
667
+ const canDelete = await hooks.onBeforeDeleteBoard(
668
+ ctx.params.id,
669
+ context,
670
+ );
671
+ if (!canDelete) {
672
+ throw ctx.error(403, {
673
+ message: "Unauthorized: Cannot delete board",
674
+ });
675
+ }
676
+ }
677
+
678
+ await adapter.delete<Board>({
679
+ model: "kanbanBoard",
680
+ where: [{ field: "id", value: ctx.params.id }],
681
+ });
682
+
683
+ if (hooks?.onBoardDeleted) {
684
+ await hooks.onBoardDeleted(ctx.params.id, context);
685
+ }
686
+
687
+ return { success: true };
688
+ } catch (error) {
689
+ if (hooks?.onDeleteBoardError) {
690
+ await hooks.onDeleteBoardError(error as Error, context);
691
+ }
692
+ throw error;
693
+ }
694
+ },
695
+ );
696
+
697
+ // ============ Column Endpoints ============
698
+
699
+ const createColumn = createEndpoint(
700
+ "/columns",
701
+ {
702
+ method: "POST",
703
+ body: createColumnSchema,
704
+ },
705
+ async (ctx) => {
706
+ const context: KanbanApiContext = {
707
+ body: ctx.body,
708
+ headers: ctx.headers,
709
+ };
710
+
711
+ try {
712
+ if (hooks?.onBeforeCreateColumn) {
713
+ const canCreate = await hooks.onBeforeCreateColumn(
714
+ ctx.body,
715
+ context,
716
+ );
717
+ if (!canCreate) {
718
+ throw ctx.error(403, {
719
+ message: "Unauthorized: Cannot create column",
720
+ });
721
+ }
722
+ }
723
+
724
+ // Get existing columns to determine order
725
+ const existingColumns = await adapter.findMany<Column>({
726
+ model: "kanbanColumn",
727
+ where: [
728
+ {
729
+ field: "boardId",
730
+ value: ctx.body.boardId,
731
+ operator: "eq" as const,
732
+ },
733
+ ],
734
+ });
735
+ const nextOrder =
736
+ existingColumns.length > 0
737
+ ? Math.max(...existingColumns.map((c) => c.order)) + 1
738
+ : 0;
739
+
740
+ const newColumn = await adapter.create<Column>({
741
+ model: "kanbanColumn",
742
+ data: {
743
+ ...ctx.body,
744
+ order: ctx.body.order ?? nextOrder,
745
+ createdAt: new Date(),
746
+ updatedAt: new Date(),
747
+ },
748
+ });
749
+
750
+ if (hooks?.onColumnCreated) {
751
+ await hooks.onColumnCreated(newColumn, context);
752
+ }
753
+
754
+ return newColumn;
755
+ } catch (error) {
756
+ throw error;
757
+ }
758
+ },
759
+ );
760
+
761
+ const updateColumn = createEndpoint(
762
+ "/columns/:id",
763
+ {
764
+ method: "PUT",
765
+ body: updateColumnSchema.omit({ id: true }),
766
+ },
767
+ async (ctx) => {
768
+ const context: KanbanApiContext = {
769
+ body: ctx.body,
770
+ params: ctx.params,
771
+ headers: ctx.headers,
772
+ };
773
+
774
+ try {
775
+ if (hooks?.onBeforeUpdateColumn) {
776
+ const canUpdate = await hooks.onBeforeUpdateColumn(
777
+ ctx.params.id,
778
+ { ...ctx.body, id: ctx.params.id },
779
+ context,
780
+ );
781
+ if (!canUpdate) {
782
+ throw ctx.error(403, {
783
+ message: "Unauthorized: Cannot update column",
784
+ });
785
+ }
786
+ }
787
+
788
+ const updated = await adapter.update<Column>({
789
+ model: "kanbanColumn",
790
+ where: [{ field: "id", value: ctx.params.id }],
791
+ update: {
792
+ ...ctx.body,
793
+ updatedAt: new Date(),
794
+ },
795
+ });
796
+
797
+ if (!updated) {
798
+ throw ctx.error(404, { message: "Column not found" });
799
+ }
800
+
801
+ if (hooks?.onColumnUpdated) {
802
+ await hooks.onColumnUpdated(updated, context);
803
+ }
804
+
805
+ return updated;
806
+ } catch (error) {
807
+ throw error;
808
+ }
809
+ },
810
+ );
811
+
812
+ const deleteColumn = createEndpoint(
813
+ "/columns/:id",
814
+ {
815
+ method: "DELETE",
816
+ },
817
+ async (ctx) => {
818
+ const context: KanbanApiContext = {
819
+ params: ctx.params,
820
+ headers: ctx.headers,
821
+ };
822
+
823
+ try {
824
+ // Verify the column exists before attempting deletion
825
+ const existingColumn = await adapter.findOne<Column>({
826
+ model: "kanbanColumn",
827
+ where: [
828
+ { field: "id", value: ctx.params.id, operator: "eq" as const },
829
+ ],
830
+ });
831
+
832
+ if (!existingColumn) {
833
+ throw ctx.error(404, { message: "Column not found" });
834
+ }
835
+
836
+ if (hooks?.onBeforeDeleteColumn) {
837
+ const canDelete = await hooks.onBeforeDeleteColumn(
838
+ ctx.params.id,
839
+ context,
840
+ );
841
+ if (!canDelete) {
842
+ throw ctx.error(403, {
843
+ message: "Unauthorized: Cannot delete column",
844
+ });
845
+ }
846
+ }
847
+
848
+ await adapter.delete<Column>({
849
+ model: "kanbanColumn",
850
+ where: [{ field: "id", value: ctx.params.id }],
851
+ });
852
+
853
+ if (hooks?.onColumnDeleted) {
854
+ await hooks.onColumnDeleted(ctx.params.id, context);
855
+ }
856
+
857
+ return { success: true };
858
+ } catch (error) {
859
+ throw error;
860
+ }
861
+ },
862
+ );
863
+
864
+ const reorderColumns = createEndpoint(
865
+ "/columns/reorder",
866
+ {
867
+ method: "POST",
868
+ body: reorderColumnsSchema,
869
+ },
870
+ async (ctx) => {
871
+ const { boardId, columnIds } = ctx.body;
872
+ const context: KanbanApiContext = {
873
+ body: ctx.body,
874
+ headers: ctx.headers,
875
+ };
876
+
877
+ // Check authorization for each column being reordered
878
+ if (hooks?.onBeforeUpdateColumn) {
879
+ for (let i = 0; i < columnIds.length; i++) {
880
+ const columnId = columnIds[i];
881
+ if (!columnId) continue;
882
+ const canUpdate = await hooks.onBeforeUpdateColumn(
883
+ columnId,
884
+ { id: columnId, order: i },
885
+ context,
886
+ );
887
+ if (!canUpdate) {
888
+ throw ctx.error(403, {
889
+ message: "Unauthorized: Cannot reorder columns",
890
+ });
891
+ }
892
+ }
893
+ }
894
+
895
+ const updatedColumns: Column[] = [];
896
+ await adapter.transaction(async (tx) => {
897
+ for (let i = 0; i < columnIds.length; i++) {
898
+ const columnId = columnIds[i];
899
+ if (!columnId) continue;
900
+ const updated = await tx.update<Column>({
901
+ model: "kanbanColumn",
902
+ where: [
903
+ { field: "id", value: columnId },
904
+ { field: "boardId", value: boardId, operator: "eq" as const },
905
+ ],
906
+ update: { order: i, updatedAt: new Date() },
907
+ });
908
+ if (updated) {
909
+ updatedColumns.push(updated);
910
+ }
911
+ }
912
+ });
913
+
914
+ // Call onColumnUpdated for each reordered column
915
+ if (hooks?.onColumnUpdated) {
916
+ for (const column of updatedColumns) {
917
+ await hooks.onColumnUpdated(column, context);
918
+ }
919
+ }
920
+
921
+ return { success: true };
922
+ },
923
+ );
924
+
925
+ // ============ Task Endpoints ============
926
+
927
+ const createTask = createEndpoint(
928
+ "/tasks",
929
+ {
930
+ method: "POST",
931
+ body: createTaskSchema,
932
+ },
933
+ async (ctx) => {
934
+ const context: KanbanApiContext = {
935
+ body: ctx.body,
936
+ headers: ctx.headers,
937
+ };
938
+
939
+ try {
940
+ if (hooks?.onBeforeCreateTask) {
941
+ const canCreate = await hooks.onBeforeCreateTask(
942
+ ctx.body,
943
+ context,
944
+ );
945
+ if (!canCreate) {
946
+ throw ctx.error(403, {
947
+ message: "Unauthorized: Cannot create task",
948
+ });
949
+ }
950
+ }
951
+
952
+ // Get existing tasks in column to determine order
953
+ const existingTasks = await adapter.findMany<Task>({
954
+ model: "kanbanTask",
955
+ where: [
956
+ {
957
+ field: "columnId",
958
+ value: ctx.body.columnId,
959
+ operator: "eq" as const,
960
+ },
961
+ ],
962
+ });
963
+ const nextOrder =
964
+ existingTasks.length > 0
965
+ ? Math.max(...existingTasks.map((t) => t.order)) + 1
966
+ : 0;
967
+
968
+ const taskData: Omit<Task, "id"> = {
969
+ title: ctx.body.title,
970
+ columnId: ctx.body.columnId,
971
+ description: ctx.body.description,
972
+ priority: ctx.body.priority || "MEDIUM",
973
+ order: ctx.body.order ?? nextOrder,
974
+ assigneeId: ctx.body.assigneeId ?? undefined,
975
+ isArchived: ctx.body.isArchived ?? false,
976
+ createdAt: new Date(),
977
+ updatedAt: new Date(),
978
+ };
979
+
980
+ const newTask = await adapter.create<Task>({
981
+ model: "kanbanTask",
982
+ data: taskData,
983
+ });
984
+
985
+ if (hooks?.onTaskCreated) {
986
+ await hooks.onTaskCreated(newTask, context);
987
+ }
988
+
989
+ return newTask;
990
+ } catch (error) {
991
+ throw error;
992
+ }
993
+ },
994
+ );
995
+
996
+ const updateTask = createEndpoint(
997
+ "/tasks/:id",
998
+ {
999
+ method: "PUT",
1000
+ body: updateTaskSchema.omit({ id: true }),
1001
+ },
1002
+ async (ctx) => {
1003
+ const context: KanbanApiContext = {
1004
+ body: ctx.body,
1005
+ params: ctx.params,
1006
+ headers: ctx.headers,
1007
+ };
1008
+
1009
+ try {
1010
+ if (hooks?.onBeforeUpdateTask) {
1011
+ const canUpdate = await hooks.onBeforeUpdateTask(
1012
+ ctx.params.id,
1013
+ { ...ctx.body, id: ctx.params.id },
1014
+ context,
1015
+ );
1016
+ if (!canUpdate) {
1017
+ throw ctx.error(403, {
1018
+ message: "Unauthorized: Cannot update task",
1019
+ });
1020
+ }
1021
+ }
1022
+
1023
+ const updated = await adapter.update<Task>({
1024
+ model: "kanbanTask",
1025
+ where: [{ field: "id", value: ctx.params.id }],
1026
+ update: {
1027
+ ...ctx.body,
1028
+ updatedAt: new Date(),
1029
+ },
1030
+ });
1031
+
1032
+ if (!updated) {
1033
+ throw ctx.error(404, { message: "Task not found" });
1034
+ }
1035
+
1036
+ if (hooks?.onTaskUpdated) {
1037
+ await hooks.onTaskUpdated(updated, context);
1038
+ }
1039
+
1040
+ return updated;
1041
+ } catch (error) {
1042
+ throw error;
1043
+ }
1044
+ },
1045
+ );
1046
+
1047
+ const deleteTask = createEndpoint(
1048
+ "/tasks/:id",
1049
+ {
1050
+ method: "DELETE",
1051
+ },
1052
+ async (ctx) => {
1053
+ const context: KanbanApiContext = {
1054
+ params: ctx.params,
1055
+ headers: ctx.headers,
1056
+ };
1057
+
1058
+ try {
1059
+ // Verify the task exists before attempting deletion
1060
+ const existingTask = await adapter.findOne<Task>({
1061
+ model: "kanbanTask",
1062
+ where: [
1063
+ { field: "id", value: ctx.params.id, operator: "eq" as const },
1064
+ ],
1065
+ });
1066
+
1067
+ if (!existingTask) {
1068
+ throw ctx.error(404, { message: "Task not found" });
1069
+ }
1070
+
1071
+ if (hooks?.onBeforeDeleteTask) {
1072
+ const canDelete = await hooks.onBeforeDeleteTask(
1073
+ ctx.params.id,
1074
+ context,
1075
+ );
1076
+ if (!canDelete) {
1077
+ throw ctx.error(403, {
1078
+ message: "Unauthorized: Cannot delete task",
1079
+ });
1080
+ }
1081
+ }
1082
+
1083
+ await adapter.delete<Task>({
1084
+ model: "kanbanTask",
1085
+ where: [{ field: "id", value: ctx.params.id }],
1086
+ });
1087
+
1088
+ if (hooks?.onTaskDeleted) {
1089
+ await hooks.onTaskDeleted(ctx.params.id, context);
1090
+ }
1091
+
1092
+ return { success: true };
1093
+ } catch (error) {
1094
+ throw error;
1095
+ }
1096
+ },
1097
+ );
1098
+
1099
+ const moveTask = createEndpoint(
1100
+ "/tasks/move",
1101
+ {
1102
+ method: "POST",
1103
+ body: moveTaskSchema,
1104
+ },
1105
+ async (ctx) => {
1106
+ const { taskId, targetColumnId, targetOrder } = ctx.body;
1107
+ const context: KanbanApiContext = {
1108
+ body: ctx.body,
1109
+ headers: ctx.headers,
1110
+ };
1111
+
1112
+ // Get current task
1113
+ const task = await adapter.findOne<Task>({
1114
+ model: "kanbanTask",
1115
+ where: [{ field: "id", value: taskId, operator: "eq" as const }],
1116
+ });
1117
+
1118
+ if (!task) {
1119
+ throw ctx.error(404, { message: "Task not found" });
1120
+ }
1121
+
1122
+ // Check authorization before moving task
1123
+ if (hooks?.onBeforeUpdateTask) {
1124
+ const canUpdate = await hooks.onBeforeUpdateTask(
1125
+ taskId,
1126
+ { id: taskId, columnId: targetColumnId, order: targetOrder },
1127
+ context,
1128
+ );
1129
+ if (!canUpdate) {
1130
+ throw ctx.error(403, {
1131
+ message: "Unauthorized: Cannot move task",
1132
+ });
1133
+ }
1134
+ }
1135
+
1136
+ // Update task with new column and order
1137
+ const updated = await adapter.update<Task>({
1138
+ model: "kanbanTask",
1139
+ where: [{ field: "id", value: taskId }],
1140
+ update: {
1141
+ columnId: targetColumnId,
1142
+ order: targetOrder,
1143
+ updatedAt: new Date(),
1144
+ },
1145
+ });
1146
+
1147
+ if (!updated) {
1148
+ throw ctx.error(404, { message: "Task not found" });
1149
+ }
1150
+
1151
+ if (hooks?.onTaskUpdated) {
1152
+ await hooks.onTaskUpdated(updated, context);
1153
+ }
1154
+
1155
+ return updated;
1156
+ },
1157
+ );
1158
+
1159
+ const reorderTasks = createEndpoint(
1160
+ "/tasks/reorder",
1161
+ {
1162
+ method: "POST",
1163
+ body: reorderTasksSchema,
1164
+ },
1165
+ async (ctx) => {
1166
+ const { columnId, taskIds } = ctx.body;
1167
+ const context: KanbanApiContext = {
1168
+ body: ctx.body,
1169
+ headers: ctx.headers,
1170
+ };
1171
+
1172
+ // Check authorization for each task being reordered
1173
+ if (hooks?.onBeforeUpdateTask) {
1174
+ for (let i = 0; i < taskIds.length; i++) {
1175
+ const taskId = taskIds[i];
1176
+ if (!taskId) continue;
1177
+ const canUpdate = await hooks.onBeforeUpdateTask(
1178
+ taskId,
1179
+ { id: taskId, order: i },
1180
+ context,
1181
+ );
1182
+ if (!canUpdate) {
1183
+ throw ctx.error(403, {
1184
+ message: "Unauthorized: Cannot reorder tasks",
1185
+ });
1186
+ }
1187
+ }
1188
+ }
1189
+
1190
+ const updatedTasks: Task[] = [];
1191
+ await adapter.transaction(async (tx) => {
1192
+ for (let i = 0; i < taskIds.length; i++) {
1193
+ const taskId = taskIds[i];
1194
+ if (!taskId) continue;
1195
+ const updated = await tx.update<Task>({
1196
+ model: "kanbanTask",
1197
+ where: [
1198
+ { field: "id", value: taskId },
1199
+ {
1200
+ field: "columnId",
1201
+ value: columnId,
1202
+ operator: "eq" as const,
1203
+ },
1204
+ ],
1205
+ update: { order: i, updatedAt: new Date() },
1206
+ });
1207
+ if (updated) {
1208
+ updatedTasks.push(updated);
1209
+ }
1210
+ }
1211
+ });
1212
+
1213
+ // Call onTaskUpdated for each reordered task
1214
+ if (hooks?.onTaskUpdated) {
1215
+ for (const task of updatedTasks) {
1216
+ await hooks.onTaskUpdated(task, context);
1217
+ }
1218
+ }
1219
+
1220
+ return { success: true };
1221
+ },
1222
+ );
1223
+
1224
+ return {
1225
+ listBoards,
1226
+ getBoard,
1227
+ createBoard,
1228
+ updateBoard,
1229
+ deleteBoard,
1230
+ createColumn,
1231
+ updateColumn,
1232
+ deleteColumn,
1233
+ reorderColumns,
1234
+ createTask,
1235
+ updateTask,
1236
+ deleteTask,
1237
+ moveTask,
1238
+ reorderTasks,
1239
+ } as const;
1240
+ },
1241
+ });
1242
+
1243
+ export type KanbanApiRouter = ReturnType<
1244
+ ReturnType<typeof kanbanBackendPlugin>["routes"]
1245
+ >;