@btst/stack 2.8.0 → 2.9.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 (214) hide show
  1. package/README.md +3 -2
  2. package/dist/components/markdown/index.d.cts +15 -2
  3. package/dist/components/markdown/index.d.mts +15 -2
  4. package/dist/components/markdown/index.d.ts +15 -2
  5. package/dist/packages/stack/src/plugins/blog/client/components/forms/image-field.cjs +30 -1
  6. package/dist/packages/stack/src/plugins/blog/client/components/forms/image-field.mjs +30 -1
  7. package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.cjs +49 -9
  8. package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.mjs +50 -10
  9. package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor.cjs +77 -9
  10. package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor.mjs +77 -9
  11. package/dist/packages/stack/src/plugins/cms/client/components/forms/content-form.cjs +24 -5
  12. package/dist/packages/stack/src/plugins/cms/client/components/forms/content-form.mjs +24 -5
  13. package/dist/packages/stack/src/plugins/cms/client/components/forms/file-upload.cjs +47 -13
  14. package/dist/packages/stack/src/plugins/cms/client/components/forms/file-upload.mjs +47 -13
  15. package/dist/packages/stack/src/plugins/kanban/client/components/forms/board-form.cjs +1 -1
  16. package/dist/packages/stack/src/plugins/kanban/client/components/forms/board-form.mjs +1 -1
  17. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.cjs +6 -2
  18. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.mjs +6 -2
  19. package/dist/packages/stack/src/plugins/media/api/adapters/local.cjs +55 -0
  20. package/dist/packages/stack/src/plugins/media/api/adapters/local.mjs +37 -0
  21. package/dist/packages/stack/src/plugins/media/api/getters.cjs +83 -0
  22. package/dist/packages/stack/src/plugins/media/api/getters.mjs +78 -0
  23. package/dist/packages/stack/src/plugins/media/api/mutations.cjs +88 -0
  24. package/dist/packages/stack/src/plugins/media/api/mutations.mjs +82 -0
  25. package/dist/packages/stack/src/plugins/media/api/plugin.cjs +525 -0
  26. package/dist/packages/stack/src/plugins/media/api/plugin.mjs +523 -0
  27. package/dist/packages/stack/src/plugins/media/api/query-key-defs.cjs +19 -0
  28. package/dist/packages/stack/src/plugins/media/api/query-key-defs.mjs +16 -0
  29. package/dist/packages/stack/src/plugins/media/api/serializers.cjs +17 -0
  30. package/dist/packages/stack/src/plugins/media/api/serializers.mjs +14 -0
  31. package/dist/packages/stack/src/plugins/media/api/storage-adapter.cjs +15 -0
  32. package/dist/packages/stack/src/plugins/media/api/storage-adapter.mjs +11 -0
  33. package/dist/packages/stack/src/plugins/media/client/components/media-picker/asset-card.cjs +129 -0
  34. package/dist/packages/stack/src/plugins/media/client/components/media-picker/asset-card.mjs +127 -0
  35. package/dist/packages/stack/src/plugins/media/client/components/media-picker/asset-preview-button.cjs +58 -0
  36. package/dist/packages/stack/src/plugins/media/client/components/media-picker/asset-preview-button.mjs +56 -0
  37. package/dist/packages/stack/src/plugins/media/client/components/media-picker/browse-tab.cjs +94 -0
  38. package/dist/packages/stack/src/plugins/media/client/components/media-picker/browse-tab.mjs +92 -0
  39. package/dist/packages/stack/src/plugins/media/client/components/media-picker/folder-tree.cjs +171 -0
  40. package/dist/packages/stack/src/plugins/media/client/components/media-picker/folder-tree.mjs +168 -0
  41. package/dist/packages/stack/src/plugins/media/client/components/media-picker/index.cjs +308 -0
  42. package/dist/packages/stack/src/plugins/media/client/components/media-picker/index.mjs +305 -0
  43. package/dist/packages/stack/src/plugins/media/client/components/media-picker/upload-tab.cjs +104 -0
  44. package/dist/packages/stack/src/plugins/media/client/components/media-picker/upload-tab.mjs +102 -0
  45. package/dist/packages/stack/src/plugins/media/client/components/media-picker/url-tab.cjs +70 -0
  46. package/dist/packages/stack/src/plugins/media/client/components/media-picker/url-tab.mjs +68 -0
  47. package/dist/packages/stack/src/plugins/media/client/components/media-picker/utils.cjs +21 -0
  48. package/dist/packages/stack/src/plugins/media/client/components/media-picker/utils.mjs +17 -0
  49. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.cjs +35 -0
  50. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.internal.cjs +125 -0
  51. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.internal.mjs +123 -0
  52. package/dist/packages/stack/src/plugins/media/client/components/pages/library-page.mjs +33 -0
  53. package/dist/packages/stack/src/plugins/media/client/hooks/use-media.cjs +222 -0
  54. package/dist/packages/stack/src/plugins/media/client/hooks/use-media.mjs +214 -0
  55. package/dist/packages/stack/src/plugins/media/client/plugin.cjs +94 -0
  56. package/dist/packages/stack/src/plugins/media/client/plugin.mjs +92 -0
  57. package/dist/packages/stack/src/plugins/media/client/upload.cjs +121 -0
  58. package/dist/packages/stack/src/plugins/media/client/upload.mjs +119 -0
  59. package/dist/packages/stack/src/plugins/media/client/utils/image-compression.cjs +67 -0
  60. package/dist/packages/stack/src/plugins/media/client/utils/image-compression.mjs +65 -0
  61. package/dist/packages/stack/src/plugins/media/db.cjs +62 -0
  62. package/dist/packages/stack/src/plugins/media/db.mjs +60 -0
  63. package/dist/packages/stack/src/plugins/media/schemas.cjs +41 -0
  64. package/dist/packages/stack/src/plugins/media/schemas.mjs +35 -0
  65. package/dist/packages/ui/src/components/minimal-tiptap/components/image/image-edit-block.cjs +18 -1
  66. package/dist/packages/ui/src/components/minimal-tiptap/components/image/image-edit-block.mjs +19 -2
  67. package/dist/packages/ui/src/components/minimal-tiptap/components/image/image-edit-dialog.cjs +2 -2
  68. package/dist/packages/ui/src/components/minimal-tiptap/components/image/image-edit-dialog.mjs +2 -2
  69. package/dist/packages/ui/src/components/minimal-tiptap/components/section/five.cjs +3 -2
  70. package/dist/packages/ui/src/components/minimal-tiptap/components/section/five.mjs +3 -2
  71. package/dist/packages/ui/src/components/minimal-tiptap/minimal-tiptap.cjs +12 -5
  72. package/dist/packages/ui/src/components/minimal-tiptap/minimal-tiptap.mjs +12 -5
  73. package/dist/plugins/blog/api/index.d.cts +2 -2
  74. package/dist/plugins/blog/api/index.d.mts +2 -2
  75. package/dist/plugins/blog/api/index.d.ts +2 -2
  76. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  77. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  78. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  79. package/dist/plugins/blog/client/index.d.cts +60 -3
  80. package/dist/plugins/blog/client/index.d.mts +60 -3
  81. package/dist/plugins/blog/client/index.d.ts +60 -3
  82. package/dist/plugins/blog/query-keys.d.cts +2 -2
  83. package/dist/plugins/blog/query-keys.d.mts +2 -2
  84. package/dist/plugins/blog/query-keys.d.ts +2 -2
  85. package/dist/plugins/cms/client/index.d.cts +73 -3
  86. package/dist/plugins/cms/client/index.d.mts +73 -3
  87. package/dist/plugins/cms/client/index.d.ts +73 -3
  88. package/dist/plugins/kanban/api/index.d.cts +1 -1
  89. package/dist/plugins/kanban/api/index.d.mts +1 -1
  90. package/dist/plugins/kanban/api/index.d.ts +1 -1
  91. package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
  92. package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
  93. package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
  94. package/dist/plugins/kanban/client/index.d.cts +1 -1
  95. package/dist/plugins/kanban/client/index.d.mts +1 -1
  96. package/dist/plugins/kanban/client/index.d.ts +1 -1
  97. package/dist/plugins/kanban/query-keys.d.cts +1 -1
  98. package/dist/plugins/kanban/query-keys.d.mts +1 -1
  99. package/dist/plugins/kanban/query-keys.d.ts +1 -1
  100. package/dist/plugins/media/api/adapters/s3.cjs +106 -0
  101. package/dist/plugins/media/api/adapters/s3.d.cts +60 -0
  102. package/dist/plugins/media/api/adapters/s3.d.mts +60 -0
  103. package/dist/plugins/media/api/adapters/s3.d.ts +60 -0
  104. package/dist/plugins/media/api/adapters/s3.mjs +104 -0
  105. package/dist/plugins/media/api/adapters/vercel-blob.cjs +54 -0
  106. package/dist/plugins/media/api/adapters/vercel-blob.d.cts +41 -0
  107. package/dist/plugins/media/api/adapters/vercel-blob.d.mts +41 -0
  108. package/dist/plugins/media/api/adapters/vercel-blob.d.ts +41 -0
  109. package/dist/plugins/media/api/adapters/vercel-blob.mjs +52 -0
  110. package/dist/plugins/media/api/index.cjs +26 -0
  111. package/dist/plugins/media/api/index.d.cts +116 -0
  112. package/dist/plugins/media/api/index.d.mts +116 -0
  113. package/dist/plugins/media/api/index.d.ts +116 -0
  114. package/dist/plugins/media/api/index.mjs +6 -0
  115. package/dist/plugins/media/client/components/index.cjs +10 -0
  116. package/dist/plugins/media/client/components/index.d.cts +55 -0
  117. package/dist/plugins/media/client/components/index.d.mts +55 -0
  118. package/dist/plugins/media/client/components/index.d.ts +55 -0
  119. package/dist/plugins/media/client/components/index.mjs +2 -0
  120. package/dist/plugins/media/client/hooks/index.cjs +13 -0
  121. package/dist/plugins/media/client/hooks/index.d.cts +53 -0
  122. package/dist/plugins/media/client/hooks/index.d.mts +53 -0
  123. package/dist/plugins/media/client/hooks/index.d.ts +53 -0
  124. package/dist/plugins/media/client/hooks/index.mjs +1 -0
  125. package/dist/plugins/media/client/index.cjs +9 -0
  126. package/dist/plugins/media/client/index.d.cts +242 -0
  127. package/dist/plugins/media/client/index.d.mts +242 -0
  128. package/dist/plugins/media/client/index.d.ts +242 -0
  129. package/dist/plugins/media/client/index.mjs +2 -0
  130. package/dist/plugins/media/client.css +1 -0
  131. package/dist/plugins/media/query-keys.cjs +72 -0
  132. package/dist/plugins/media/query-keys.d.cts +49 -0
  133. package/dist/plugins/media/query-keys.d.mts +49 -0
  134. package/dist/plugins/media/query-keys.d.ts +49 -0
  135. package/dist/plugins/media/query-keys.mjs +70 -0
  136. package/dist/plugins/media/style.css +1 -0
  137. package/dist/shared/{stack.DOZ1EXjM.d.mts → stack.6mEHS2WH.d.mts} +3 -3
  138. package/dist/shared/{stack.DX-tQ93o.d.cts → stack.AJTXI7kw.d.cts} +3 -3
  139. package/dist/shared/{stack.DRpeDS6X.d.ts → stack.BMx2QYOK.d.ts} +25 -0
  140. package/dist/shared/stack.BUTXWiG-.d.ts +286 -0
  141. package/dist/shared/stack.C7Y9sBDg.d.mts +286 -0
  142. package/dist/shared/stack.C7vfOBmO.d.mts +63 -0
  143. package/dist/shared/stack.CAni8dnD.d.cts +63 -0
  144. package/dist/shared/stack.CLcnSF_b.d.cts +25 -0
  145. package/dist/shared/stack.CLcnSF_b.d.mts +25 -0
  146. package/dist/shared/stack.CLcnSF_b.d.ts +25 -0
  147. package/dist/shared/stack.CYSwntXC.d.ts +63 -0
  148. package/dist/shared/{stack.Jb0kQDJC.d.mts → stack.Cd6McBu1.d.mts} +25 -0
  149. package/dist/shared/stack.CoBj86jf.d.cts +109 -0
  150. package/dist/shared/stack.CoBj86jf.d.mts +109 -0
  151. package/dist/shared/stack.CoBj86jf.d.ts +109 -0
  152. package/dist/shared/{stack.BXxrFL9R.d.ts → stack.D7HSzZdG.d.ts} +5 -5
  153. package/dist/shared/{stack.DzOhpIYM.d.mts → stack.DjgpFWq3.d.cts} +5 -5
  154. package/dist/shared/{stack.BxFl46lB.d.cts → stack.DxQl8Wa1.d.cts} +25 -0
  155. package/dist/shared/{stack.BSqJrCTM.d.cts → stack.IUeyQKrm.d.mts} +5 -5
  156. package/dist/shared/{stack.VF6FhyZw.d.ts → stack.QYn-Px94.d.ts} +3 -3
  157. package/dist/shared/stack.vxskCkim.d.cts +286 -0
  158. package/package.json +115 -6
  159. package/src/plugins/blog/client/components/forms/image-field.tsx +35 -4
  160. package/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.tsx +67 -12
  161. package/src/plugins/blog/client/components/forms/markdown-editor.tsx +106 -10
  162. package/src/plugins/blog/client/overrides.ts +58 -1
  163. package/src/plugins/cms/client/components/forms/content-form.tsx +26 -7
  164. package/src/plugins/cms/client/components/forms/file-upload.tsx +73 -15
  165. package/src/plugins/cms/client/overrides.ts +57 -2
  166. package/src/plugins/kanban/client/components/forms/board-form.tsx +1 -1
  167. package/src/plugins/kanban/client/components/forms/task-form.tsx +7 -1
  168. package/src/plugins/kanban/client/overrides.ts +25 -0
  169. package/src/plugins/media/__tests__/__stubs__/vercel-blob-server.ts +9 -0
  170. package/src/plugins/media/__tests__/getters.test.ts +274 -0
  171. package/src/plugins/media/__tests__/mutations.test.ts +299 -0
  172. package/src/plugins/media/__tests__/plugin.test.ts +752 -0
  173. package/src/plugins/media/__tests__/query-key-defs.test.ts +54 -0
  174. package/src/plugins/media/__tests__/storage-adapters.test.ts +351 -0
  175. package/src/plugins/media/api/adapters/local.ts +79 -0
  176. package/src/plugins/media/api/adapters/s3.ts +198 -0
  177. package/src/plugins/media/api/adapters/vercel-blob.ts +132 -0
  178. package/src/plugins/media/api/getters.ts +174 -0
  179. package/src/plugins/media/api/index.ts +41 -0
  180. package/src/plugins/media/api/mutations.ts +179 -0
  181. package/src/plugins/media/api/plugin.ts +855 -0
  182. package/src/plugins/media/api/query-key-defs.ts +41 -0
  183. package/src/plugins/media/api/serializers.ts +28 -0
  184. package/src/plugins/media/api/storage-adapter.ts +139 -0
  185. package/src/plugins/media/client/components/index.tsx +6 -0
  186. package/src/plugins/media/client/components/media-picker/asset-card.tsx +150 -0
  187. package/src/plugins/media/client/components/media-picker/asset-preview-button.tsx +67 -0
  188. package/src/plugins/media/client/components/media-picker/browse-tab.tsx +116 -0
  189. package/src/plugins/media/client/components/media-picker/folder-tree.tsx +188 -0
  190. package/src/plugins/media/client/components/media-picker/index.tsx +347 -0
  191. package/src/plugins/media/client/components/media-picker/upload-tab.tsx +108 -0
  192. package/src/plugins/media/client/components/media-picker/url-tab.tsx +72 -0
  193. package/src/plugins/media/client/components/media-picker/utils.ts +17 -0
  194. package/src/plugins/media/client/components/pages/library-page.internal.tsx +134 -0
  195. package/src/plugins/media/client/components/pages/library-page.tsx +42 -0
  196. package/src/plugins/media/client/hooks/index.tsx +9 -0
  197. package/src/plugins/media/client/hooks/use-media.tsx +289 -0
  198. package/src/plugins/media/client/index.ts +4 -0
  199. package/src/plugins/media/client/overrides.ts +127 -0
  200. package/src/plugins/media/client/plugin.tsx +184 -0
  201. package/src/plugins/media/client/upload.ts +171 -0
  202. package/src/plugins/media/client/utils/image-compression.ts +131 -0
  203. package/src/plugins/media/client.css +1 -0
  204. package/src/plugins/media/db.ts +62 -0
  205. package/src/plugins/media/query-keys.ts +96 -0
  206. package/src/plugins/media/schemas.ts +37 -0
  207. package/src/plugins/media/style.css +1 -0
  208. package/src/plugins/media/types.ts +26 -0
  209. package/dist/shared/{stack.BWp0hcm9.d.ts → stack.BQmuNl5p.d.cts} +3 -3
  210. package/dist/shared/{stack.BWp0hcm9.d.cts → stack.BQmuNl5p.d.mts} +3 -3
  211. package/dist/shared/{stack.BWp0hcm9.d.mts → stack.BQmuNl5p.d.ts} +3 -3
  212. package/dist/shared/{stack.BvCR4-9H.d.ts → stack.D4Cea8II.d.ts} +3 -3
  213. package/dist/shared/{stack.CWxAl9K3.d.mts → stack.HE_IvqV5.d.mts} +3 -3
  214. package/dist/shared/{stack.BOokfhZD.d.cts → stack.Rtcvl8sS.d.cts} +3 -3
@@ -0,0 +1,25 @@
1
+ type Asset = {
2
+ id: string;
3
+ filename: string;
4
+ originalName: string;
5
+ mimeType: string;
6
+ size: number;
7
+ url: string;
8
+ folderId?: string;
9
+ alt?: string;
10
+ createdAt: Date;
11
+ };
12
+ type Folder = {
13
+ id: string;
14
+ name: string;
15
+ parentId?: string;
16
+ createdAt: Date;
17
+ };
18
+ interface SerializedAsset extends Omit<Asset, "createdAt"> {
19
+ createdAt: string;
20
+ }
21
+ interface SerializedFolder extends Omit<Folder, "createdAt"> {
22
+ createdAt: string;
23
+ }
24
+
25
+ export type { Asset as A, Folder as F, SerializedAsset as S, SerializedFolder as a };
@@ -0,0 +1,25 @@
1
+ type Asset = {
2
+ id: string;
3
+ filename: string;
4
+ originalName: string;
5
+ mimeType: string;
6
+ size: number;
7
+ url: string;
8
+ folderId?: string;
9
+ alt?: string;
10
+ createdAt: Date;
11
+ };
12
+ type Folder = {
13
+ id: string;
14
+ name: string;
15
+ parentId?: string;
16
+ createdAt: Date;
17
+ };
18
+ interface SerializedAsset extends Omit<Asset, "createdAt"> {
19
+ createdAt: string;
20
+ }
21
+ interface SerializedFolder extends Omit<Folder, "createdAt"> {
22
+ createdAt: string;
23
+ }
24
+
25
+ export type { Asset as A, Folder as F, SerializedAsset as S, SerializedFolder as a };
@@ -0,0 +1,25 @@
1
+ type Asset = {
2
+ id: string;
3
+ filename: string;
4
+ originalName: string;
5
+ mimeType: string;
6
+ size: number;
7
+ url: string;
8
+ folderId?: string;
9
+ alt?: string;
10
+ createdAt: Date;
11
+ };
12
+ type Folder = {
13
+ id: string;
14
+ name: string;
15
+ parentId?: string;
16
+ createdAt: Date;
17
+ };
18
+ interface SerializedAsset extends Omit<Asset, "createdAt"> {
19
+ createdAt: string;
20
+ }
21
+ interface SerializedFolder extends Omit<Folder, "createdAt"> {
22
+ createdAt: string;
23
+ }
24
+
25
+ export type { Asset as A, Folder as F, SerializedAsset as S, SerializedFolder as a };
@@ -0,0 +1,63 @@
1
+ import { DBAdapter } from '@btst/db';
2
+ import { A as Asset, F as Folder } from './stack.CLcnSF_b.js';
3
+
4
+ /**
5
+ * Parameters for filtering and paginating the asset list.
6
+ */
7
+ interface AssetListParams {
8
+ folderId?: string;
9
+ mimeType?: string;
10
+ query?: string;
11
+ offset?: number;
12
+ limit?: number;
13
+ }
14
+ /**
15
+ * Paginated result returned by {@link listAssets}.
16
+ */
17
+ interface AssetListResult {
18
+ items: Asset[];
19
+ total: number;
20
+ limit?: number;
21
+ offset?: number;
22
+ }
23
+ /**
24
+ * Parameters for filtering the folder list.
25
+ */
26
+ interface FolderListParams {
27
+ parentId?: string | null;
28
+ }
29
+ /**
30
+ * Retrieve all assets matching optional filter criteria.
31
+ * Pure DB function — no hooks, no HTTP context. Safe for server-side use.
32
+ *
33
+ * @remarks **Security:** Authorization hooks are NOT called. The caller is
34
+ * responsible for any access-control checks before invoking this function.
35
+ */
36
+ declare function listAssets(adapter: DBAdapter, params?: AssetListParams): Promise<AssetListResult>;
37
+ /**
38
+ * Retrieve a single asset by its ID.
39
+ * Returns `null` if no asset is found.
40
+ * Pure DB function — no hooks, no HTTP context.
41
+ *
42
+ * @remarks **Security:** Authorization hooks are NOT called.
43
+ */
44
+ declare function getAssetById(adapter: DBAdapter, id: string): Promise<Asset | null>;
45
+ /**
46
+ * Retrieve all folders, optionally filtered by `parentId`.
47
+ * Pass `null` to list root-level folders (those without a parent).
48
+ * Pure DB function — no hooks, no HTTP context.
49
+ *
50
+ * @remarks **Security:** Authorization hooks are NOT called.
51
+ */
52
+ declare function listFolders(adapter: DBAdapter, params?: FolderListParams): Promise<Folder[]>;
53
+ /**
54
+ * Retrieve a single folder by its ID.
55
+ * Returns `null` if no folder is found.
56
+ * Pure DB function — no hooks, no HTTP context.
57
+ *
58
+ * @remarks **Security:** Authorization hooks are NOT called.
59
+ */
60
+ declare function getFolderById(adapter: DBAdapter, id: string): Promise<Folder | null>;
61
+
62
+ export { listFolders as a, getFolderById as b, getAssetById as g, listAssets as l };
63
+ export type { AssetListParams as A, FolderListParams as F, AssetListResult as c };
@@ -141,6 +141,31 @@ interface KanbanPluginOverrides {
141
141
  * Optional headers to pass with API requests (e.g., for SSR auth)
142
142
  */
143
143
  headers?: HeadersInit;
144
+ /**
145
+ * Function used to upload a new image file from the task description editor
146
+ * and return its URL. This is separate from `imagePicker`, which selects an
147
+ * existing asset URL.
148
+ */
149
+ uploadImage?: (file: File) => Promise<string>;
150
+ /**
151
+ * Optional trigger component for a media picker.
152
+ * When provided, it appears inside the image insertion dialog of the task description editor,
153
+ * letting users browse and select previously uploaded assets.
154
+ *
155
+ * @example
156
+ * ```tsx
157
+ * imagePicker: ({ onSelect }) => (
158
+ * <MediaPicker
159
+ * trigger={<Button size="sm" variant="outline">Browse media</Button>}
160
+ * accept={["image/*"]}
161
+ * onSelect={(assets) => onSelect(assets[0].url)}
162
+ * />
163
+ * )
164
+ * ```
165
+ */
166
+ imagePicker?: ComponentType<{
167
+ onSelect: (url: string) => void;
168
+ }>;
144
169
  /**
145
170
  * Resolve user info from an assigneeId
146
171
  * Called when rendering task cards/forms that have an assignee
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Options provided to storage adapters when initiating an upload.
3
+ */
4
+ interface UploadOptions {
5
+ filename: string;
6
+ mimeType: string;
7
+ size: number;
8
+ folderId?: string;
9
+ }
10
+ /**
11
+ * Local storage adapter — backend receives and stores file bytes directly.
12
+ * Suitable for development and self-hosted deployments.
13
+ */
14
+ interface DirectStorageAdapter {
15
+ readonly type: "local";
16
+ /**
17
+ * Store the file buffer and return the public URL.
18
+ */
19
+ upload(buffer: Buffer, options: UploadOptions): Promise<{
20
+ url: string;
21
+ }>;
22
+ /**
23
+ * Remove the stored file given its public URL.
24
+ */
25
+ delete(url: string): Promise<void>;
26
+ }
27
+ /**
28
+ * Token returned by the S3 adapter.
29
+ * The client performs a `PUT` to `payload.uploadUrl` with the file body,
30
+ * then saves `payload.publicUrl` as the asset URL.
31
+ */
32
+ interface S3UploadToken {
33
+ type: "presigned-url";
34
+ payload: {
35
+ uploadUrl: string;
36
+ publicUrl: string;
37
+ key: string;
38
+ method: "PUT";
39
+ headers: Record<string, string>;
40
+ };
41
+ }
42
+ /**
43
+ * S3 storage adapter — server issues a short-lived presigned PUT URL;
44
+ * the browser uploads directly to S3 (or R2 / MinIO).
45
+ */
46
+ interface S3StorageAdapter {
47
+ readonly type: "s3";
48
+ /**
49
+ * The public base URL prefix for all assets in this bucket
50
+ * (e.g. `"https://assets.example.com"`). Used by the plugin to
51
+ * automatically validate client-supplied URLs when no explicit
52
+ * `allowedUrlPrefixes` are configured.
53
+ */
54
+ readonly urlPrefix: string;
55
+ /**
56
+ * Generate a presigned PUT URL for direct client upload.
57
+ */
58
+ generateUploadToken(options: UploadOptions): Promise<S3UploadToken>;
59
+ /**
60
+ * Remove the stored object given its public URL.
61
+ */
62
+ delete(url: string): Promise<void>;
63
+ }
64
+ /**
65
+ * Options returned from onBeforeGenerateToken and passed to Vercel Blob's handleUpload.
66
+ */
67
+ interface VercelBlobTokenOptions {
68
+ addRandomSuffix?: boolean;
69
+ allowedContentTypes?: string[];
70
+ maximumSizeInBytes?: number;
71
+ }
72
+ /**
73
+ * Callbacks provided to the Vercel Blob adapter when handling a request.
74
+ */
75
+ interface VercelBlobHandlerCallbacks {
76
+ /**
77
+ * Called before a client token is generated.
78
+ * Throw to reject the upload (auth gate).
79
+ * Return options to enforce allowedContentTypes and maximumSizeInBytes at the edge.
80
+ */
81
+ onBeforeGenerateToken?: (pathname: string, clientPayload: string | null) => Promise<VercelBlobTokenOptions | void> | VercelBlobTokenOptions | void;
82
+ }
83
+ /**
84
+ * Vercel Blob storage adapter — uses the `@vercel/blob/server` `handleUpload`
85
+ * protocol. The same endpoint handles both token generation and upload
86
+ * completion notifications from Vercel's servers.
87
+ */
88
+ interface VercelBlobStorageAdapter {
89
+ readonly type: "vercel-blob";
90
+ /**
91
+ * Hostname suffix that all Vercel Blob public URLs end with.
92
+ * Used by the plugin to automatically validate client-supplied URLs.
93
+ * Always `".public.blob.vercel-storage.com"`.
94
+ */
95
+ readonly urlHostnameSuffix: string;
96
+ /**
97
+ * Process a raw request from `@vercel/blob/client`'s `upload()` or from
98
+ * Vercel Blob's upload-completion webhook. Returns a JSON-serialisable object
99
+ * that should be sent back as the response body.
100
+ */
101
+ handleRequest(request: Request, callbacks: VercelBlobHandlerCallbacks): Promise<unknown>;
102
+ /**
103
+ * Remove the stored blob given its public URL.
104
+ */
105
+ delete(url: string): Promise<void>;
106
+ }
107
+ type StorageAdapter = DirectStorageAdapter | S3StorageAdapter | VercelBlobStorageAdapter;
108
+
109
+ export type { DirectStorageAdapter as D, S3StorageAdapter as S, UploadOptions as U, VercelBlobStorageAdapter as V, StorageAdapter as a, S3UploadToken as b, VercelBlobHandlerCallbacks as c };
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Options provided to storage adapters when initiating an upload.
3
+ */
4
+ interface UploadOptions {
5
+ filename: string;
6
+ mimeType: string;
7
+ size: number;
8
+ folderId?: string;
9
+ }
10
+ /**
11
+ * Local storage adapter — backend receives and stores file bytes directly.
12
+ * Suitable for development and self-hosted deployments.
13
+ */
14
+ interface DirectStorageAdapter {
15
+ readonly type: "local";
16
+ /**
17
+ * Store the file buffer and return the public URL.
18
+ */
19
+ upload(buffer: Buffer, options: UploadOptions): Promise<{
20
+ url: string;
21
+ }>;
22
+ /**
23
+ * Remove the stored file given its public URL.
24
+ */
25
+ delete(url: string): Promise<void>;
26
+ }
27
+ /**
28
+ * Token returned by the S3 adapter.
29
+ * The client performs a `PUT` to `payload.uploadUrl` with the file body,
30
+ * then saves `payload.publicUrl` as the asset URL.
31
+ */
32
+ interface S3UploadToken {
33
+ type: "presigned-url";
34
+ payload: {
35
+ uploadUrl: string;
36
+ publicUrl: string;
37
+ key: string;
38
+ method: "PUT";
39
+ headers: Record<string, string>;
40
+ };
41
+ }
42
+ /**
43
+ * S3 storage adapter — server issues a short-lived presigned PUT URL;
44
+ * the browser uploads directly to S3 (or R2 / MinIO).
45
+ */
46
+ interface S3StorageAdapter {
47
+ readonly type: "s3";
48
+ /**
49
+ * The public base URL prefix for all assets in this bucket
50
+ * (e.g. `"https://assets.example.com"`). Used by the plugin to
51
+ * automatically validate client-supplied URLs when no explicit
52
+ * `allowedUrlPrefixes` are configured.
53
+ */
54
+ readonly urlPrefix: string;
55
+ /**
56
+ * Generate a presigned PUT URL for direct client upload.
57
+ */
58
+ generateUploadToken(options: UploadOptions): Promise<S3UploadToken>;
59
+ /**
60
+ * Remove the stored object given its public URL.
61
+ */
62
+ delete(url: string): Promise<void>;
63
+ }
64
+ /**
65
+ * Options returned from onBeforeGenerateToken and passed to Vercel Blob's handleUpload.
66
+ */
67
+ interface VercelBlobTokenOptions {
68
+ addRandomSuffix?: boolean;
69
+ allowedContentTypes?: string[];
70
+ maximumSizeInBytes?: number;
71
+ }
72
+ /**
73
+ * Callbacks provided to the Vercel Blob adapter when handling a request.
74
+ */
75
+ interface VercelBlobHandlerCallbacks {
76
+ /**
77
+ * Called before a client token is generated.
78
+ * Throw to reject the upload (auth gate).
79
+ * Return options to enforce allowedContentTypes and maximumSizeInBytes at the edge.
80
+ */
81
+ onBeforeGenerateToken?: (pathname: string, clientPayload: string | null) => Promise<VercelBlobTokenOptions | void> | VercelBlobTokenOptions | void;
82
+ }
83
+ /**
84
+ * Vercel Blob storage adapter — uses the `@vercel/blob/server` `handleUpload`
85
+ * protocol. The same endpoint handles both token generation and upload
86
+ * completion notifications from Vercel's servers.
87
+ */
88
+ interface VercelBlobStorageAdapter {
89
+ readonly type: "vercel-blob";
90
+ /**
91
+ * Hostname suffix that all Vercel Blob public URLs end with.
92
+ * Used by the plugin to automatically validate client-supplied URLs.
93
+ * Always `".public.blob.vercel-storage.com"`.
94
+ */
95
+ readonly urlHostnameSuffix: string;
96
+ /**
97
+ * Process a raw request from `@vercel/blob/client`'s `upload()` or from
98
+ * Vercel Blob's upload-completion webhook. Returns a JSON-serialisable object
99
+ * that should be sent back as the response body.
100
+ */
101
+ handleRequest(request: Request, callbacks: VercelBlobHandlerCallbacks): Promise<unknown>;
102
+ /**
103
+ * Remove the stored blob given its public URL.
104
+ */
105
+ delete(url: string): Promise<void>;
106
+ }
107
+ type StorageAdapter = DirectStorageAdapter | S3StorageAdapter | VercelBlobStorageAdapter;
108
+
109
+ export type { DirectStorageAdapter as D, S3StorageAdapter as S, UploadOptions as U, VercelBlobStorageAdapter as V, StorageAdapter as a, S3UploadToken as b, VercelBlobHandlerCallbacks as c };
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Options provided to storage adapters when initiating an upload.
3
+ */
4
+ interface UploadOptions {
5
+ filename: string;
6
+ mimeType: string;
7
+ size: number;
8
+ folderId?: string;
9
+ }
10
+ /**
11
+ * Local storage adapter — backend receives and stores file bytes directly.
12
+ * Suitable for development and self-hosted deployments.
13
+ */
14
+ interface DirectStorageAdapter {
15
+ readonly type: "local";
16
+ /**
17
+ * Store the file buffer and return the public URL.
18
+ */
19
+ upload(buffer: Buffer, options: UploadOptions): Promise<{
20
+ url: string;
21
+ }>;
22
+ /**
23
+ * Remove the stored file given its public URL.
24
+ */
25
+ delete(url: string): Promise<void>;
26
+ }
27
+ /**
28
+ * Token returned by the S3 adapter.
29
+ * The client performs a `PUT` to `payload.uploadUrl` with the file body,
30
+ * then saves `payload.publicUrl` as the asset URL.
31
+ */
32
+ interface S3UploadToken {
33
+ type: "presigned-url";
34
+ payload: {
35
+ uploadUrl: string;
36
+ publicUrl: string;
37
+ key: string;
38
+ method: "PUT";
39
+ headers: Record<string, string>;
40
+ };
41
+ }
42
+ /**
43
+ * S3 storage adapter — server issues a short-lived presigned PUT URL;
44
+ * the browser uploads directly to S3 (or R2 / MinIO).
45
+ */
46
+ interface S3StorageAdapter {
47
+ readonly type: "s3";
48
+ /**
49
+ * The public base URL prefix for all assets in this bucket
50
+ * (e.g. `"https://assets.example.com"`). Used by the plugin to
51
+ * automatically validate client-supplied URLs when no explicit
52
+ * `allowedUrlPrefixes` are configured.
53
+ */
54
+ readonly urlPrefix: string;
55
+ /**
56
+ * Generate a presigned PUT URL for direct client upload.
57
+ */
58
+ generateUploadToken(options: UploadOptions): Promise<S3UploadToken>;
59
+ /**
60
+ * Remove the stored object given its public URL.
61
+ */
62
+ delete(url: string): Promise<void>;
63
+ }
64
+ /**
65
+ * Options returned from onBeforeGenerateToken and passed to Vercel Blob's handleUpload.
66
+ */
67
+ interface VercelBlobTokenOptions {
68
+ addRandomSuffix?: boolean;
69
+ allowedContentTypes?: string[];
70
+ maximumSizeInBytes?: number;
71
+ }
72
+ /**
73
+ * Callbacks provided to the Vercel Blob adapter when handling a request.
74
+ */
75
+ interface VercelBlobHandlerCallbacks {
76
+ /**
77
+ * Called before a client token is generated.
78
+ * Throw to reject the upload (auth gate).
79
+ * Return options to enforce allowedContentTypes and maximumSizeInBytes at the edge.
80
+ */
81
+ onBeforeGenerateToken?: (pathname: string, clientPayload: string | null) => Promise<VercelBlobTokenOptions | void> | VercelBlobTokenOptions | void;
82
+ }
83
+ /**
84
+ * Vercel Blob storage adapter — uses the `@vercel/blob/server` `handleUpload`
85
+ * protocol. The same endpoint handles both token generation and upload
86
+ * completion notifications from Vercel's servers.
87
+ */
88
+ interface VercelBlobStorageAdapter {
89
+ readonly type: "vercel-blob";
90
+ /**
91
+ * Hostname suffix that all Vercel Blob public URLs end with.
92
+ * Used by the plugin to automatically validate client-supplied URLs.
93
+ * Always `".public.blob.vercel-storage.com"`.
94
+ */
95
+ readonly urlHostnameSuffix: string;
96
+ /**
97
+ * Process a raw request from `@vercel/blob/client`'s `upload()` or from
98
+ * Vercel Blob's upload-completion webhook. Returns a JSON-serialisable object
99
+ * that should be sent back as the response body.
100
+ */
101
+ handleRequest(request: Request, callbacks: VercelBlobHandlerCallbacks): Promise<unknown>;
102
+ /**
103
+ * Remove the stored blob given its public URL.
104
+ */
105
+ delete(url: string): Promise<void>;
106
+ }
107
+ type StorageAdapter = DirectStorageAdapter | S3StorageAdapter | VercelBlobStorageAdapter;
108
+
109
+ export type { DirectStorageAdapter as D, S3StorageAdapter as S, UploadOptions as U, VercelBlobStorageAdapter as V, StorageAdapter as a, S3UploadToken as b, VercelBlobHandlerCallbacks as c };
@@ -1,7 +1,7 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import { QueryClient } from '@tanstack/react-query';
3
3
  import { createApiClient } from '@btst/stack/plugins/client';
4
- import { P as Post, T as Tag, c as createPostSchema, u as updatePostSchema, S as SerializedPost, a as SerializedTag } from './stack.BWp0hcm9.js';
4
+ import { P as Post, T as Tag, c as createPostSchema, u as updatePostSchema, S as SerializedPost, a as SerializedTag } from './stack.BQmuNl5p.js';
5
5
  import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
6
6
  import { DBAdapter } from '@btst/db';
7
7
  import * as better_call from 'better-call';
@@ -244,11 +244,11 @@ declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugi
244
244
  slug: string;
245
245
  })[] | undefined;
246
246
  slug?: string | undefined;
247
- published?: boolean | undefined;
248
- publishedAt?: unknown;
249
247
  createdAt?: unknown;
250
248
  updatedAt?: unknown;
249
+ publishedAt?: unknown;
251
250
  image?: string | undefined;
251
+ published?: boolean | undefined;
252
252
  }, {
253
253
  title: string;
254
254
  content: string;
@@ -261,11 +261,11 @@ declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugi
261
261
  slug: string;
262
262
  })[] | undefined;
263
263
  slug?: string | undefined;
264
- published?: boolean | undefined;
265
- publishedAt?: unknown;
266
264
  createdAt?: unknown;
267
265
  updatedAt?: unknown;
266
+ publishedAt?: unknown;
268
267
  image?: string | undefined;
268
+ published?: boolean | undefined;
269
269
  }>;
270
270
  }, Post>;
271
271
  readonly updatePost: better_call.StrictEndpoint<"/posts/:id", {} & {
@@ -1,7 +1,7 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import { QueryClient } from '@tanstack/react-query';
3
3
  import { createApiClient } from '@btst/stack/plugins/client';
4
- import { P as Post, T as Tag, c as createPostSchema, u as updatePostSchema, S as SerializedPost, a as SerializedTag } from './stack.BWp0hcm9.mjs';
4
+ import { P as Post, T as Tag, c as createPostSchema, u as updatePostSchema, S as SerializedPost, a as SerializedTag } from './stack.BQmuNl5p.cjs';
5
5
  import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
6
6
  import { DBAdapter } from '@btst/db';
7
7
  import * as better_call from 'better-call';
@@ -244,11 +244,11 @@ declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugi
244
244
  slug: string;
245
245
  })[] | undefined;
246
246
  slug?: string | undefined;
247
- published?: boolean | undefined;
248
- publishedAt?: unknown;
249
247
  createdAt?: unknown;
250
248
  updatedAt?: unknown;
249
+ publishedAt?: unknown;
251
250
  image?: string | undefined;
251
+ published?: boolean | undefined;
252
252
  }, {
253
253
  title: string;
254
254
  content: string;
@@ -261,11 +261,11 @@ declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugi
261
261
  slug: string;
262
262
  })[] | undefined;
263
263
  slug?: string | undefined;
264
- published?: boolean | undefined;
265
- publishedAt?: unknown;
266
264
  createdAt?: unknown;
267
265
  updatedAt?: unknown;
266
+ publishedAt?: unknown;
268
267
  image?: string | undefined;
268
+ published?: boolean | undefined;
269
269
  }>;
270
270
  }, Post>;
271
271
  readonly updatePost: better_call.StrictEndpoint<"/posts/:id", {} & {
@@ -141,6 +141,31 @@ interface KanbanPluginOverrides {
141
141
  * Optional headers to pass with API requests (e.g., for SSR auth)
142
142
  */
143
143
  headers?: HeadersInit;
144
+ /**
145
+ * Function used to upload a new image file from the task description editor
146
+ * and return its URL. This is separate from `imagePicker`, which selects an
147
+ * existing asset URL.
148
+ */
149
+ uploadImage?: (file: File) => Promise<string>;
150
+ /**
151
+ * Optional trigger component for a media picker.
152
+ * When provided, it appears inside the image insertion dialog of the task description editor,
153
+ * letting users browse and select previously uploaded assets.
154
+ *
155
+ * @example
156
+ * ```tsx
157
+ * imagePicker: ({ onSelect }) => (
158
+ * <MediaPicker
159
+ * trigger={<Button size="sm" variant="outline">Browse media</Button>}
160
+ * accept={["image/*"]}
161
+ * onSelect={(assets) => onSelect(assets[0].url)}
162
+ * />
163
+ * )
164
+ * ```
165
+ */
166
+ imagePicker?: ComponentType<{
167
+ onSelect: (url: string) => void;
168
+ }>;
144
169
  /**
145
170
  * Resolve user info from an assigneeId
146
171
  * Called when rendering task cards/forms that have an assignee
@@ -1,7 +1,7 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import { QueryClient } from '@tanstack/react-query';
3
3
  import { createApiClient } from '@btst/stack/plugins/client';
4
- import { P as Post, T as Tag, c as createPostSchema, u as updatePostSchema, S as SerializedPost, a as SerializedTag } from './stack.BWp0hcm9.cjs';
4
+ import { P as Post, T as Tag, c as createPostSchema, u as updatePostSchema, S as SerializedPost, a as SerializedTag } from './stack.BQmuNl5p.mjs';
5
5
  import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
6
6
  import { DBAdapter } from '@btst/db';
7
7
  import * as better_call from 'better-call';
@@ -244,11 +244,11 @@ declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugi
244
244
  slug: string;
245
245
  })[] | undefined;
246
246
  slug?: string | undefined;
247
- published?: boolean | undefined;
248
- publishedAt?: unknown;
249
247
  createdAt?: unknown;
250
248
  updatedAt?: unknown;
249
+ publishedAt?: unknown;
251
250
  image?: string | undefined;
251
+ published?: boolean | undefined;
252
252
  }, {
253
253
  title: string;
254
254
  content: string;
@@ -261,11 +261,11 @@ declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugi
261
261
  slug: string;
262
262
  })[] | undefined;
263
263
  slug?: string | undefined;
264
- published?: boolean | undefined;
265
- publishedAt?: unknown;
266
264
  createdAt?: unknown;
267
265
  updatedAt?: unknown;
266
+ publishedAt?: unknown;
268
267
  image?: string | undefined;
268
+ published?: boolean | undefined;
269
269
  }>;
270
270
  }, Post>;
271
271
  readonly updatePost: better_call.StrictEndpoint<"/posts/:id", {} & {
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { S as SerializedPost, c as createPostSchema, u as updatePostSchema, a as SerializedTag } from './stack.BWp0hcm9.js';
2
+ import { S as SerializedPost, c as createPostSchema, u as updatePostSchema, a as SerializedTag } from './stack.BQmuNl5p.js';
3
3
  import { z } from 'zod';
4
4
 
5
5
  /**
@@ -135,14 +135,14 @@ declare function useCreatePost(): _tanstack_react_query.UseMutationResult<Serial
135
135
  name: string;
136
136
  slug: string;
137
137
  })[];
138
- published: boolean;
139
138
  title: string;
140
139
  content: string;
141
140
  excerpt: string;
141
+ published: boolean;
142
142
  slug?: string | undefined;
143
- publishedAt?: Date | undefined;
144
143
  createdAt?: Date | undefined;
145
144
  updatedAt?: Date | undefined;
145
+ publishedAt?: Date | undefined;
146
146
  image?: string | undefined;
147
147
  }, unknown>;
148
148
  /** Update an existing post by id */