@btst/stack 2.3.0 → 2.5.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 (208) hide show
  1. package/dist/packages/stack/src/client/components/compose.cjs +1 -2
  2. package/dist/packages/stack/src/client/components/compose.mjs +1 -2
  3. package/dist/packages/stack/src/plugins/ai-chat/api/page-tools.cjs +71 -0
  4. package/dist/packages/stack/src/plugins/ai-chat/api/page-tools.mjs +68 -0
  5. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.cjs +87 -54
  6. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +87 -54
  7. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.cjs +2 -2
  8. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.mjs +2 -2
  9. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.cjs +89 -22
  10. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.mjs +90 -23
  11. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.cjs +110 -33
  12. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.mjs +112 -35
  13. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.cjs +1 -1
  14. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.mjs +1 -1
  15. package/dist/packages/stack/src/plugins/ai-chat/client/plugin.cjs +14 -21
  16. package/dist/packages/stack/src/plugins/ai-chat/client/plugin.mjs +15 -22
  17. package/dist/packages/stack/src/plugins/ai-chat/schemas.cjs +17 -1
  18. package/dist/packages/stack/src/plugins/ai-chat/schemas.mjs +17 -1
  19. package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +28 -45
  20. package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +22 -39
  21. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.cjs +15 -2
  22. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.mjs +16 -3
  23. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.cjs +24 -1
  24. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.mjs +24 -1
  25. package/dist/packages/stack/src/plugins/blog/client/components/pages/fill-blog-form-handler.cjs +26 -0
  26. package/dist/packages/stack/src/plugins/blog/client/components/pages/fill-blog-form-handler.mjs +24 -0
  27. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.cjs +30 -1
  28. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.mjs +30 -1
  29. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +18 -0
  30. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +18 -0
  31. package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +23 -27
  32. package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +24 -28
  33. package/dist/packages/stack/src/plugins/cms/api/mutations.cjs +48 -0
  34. package/dist/packages/stack/src/plugins/cms/api/mutations.mjs +46 -0
  35. package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +21 -18
  36. package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +21 -18
  37. package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +11 -15
  38. package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +12 -16
  39. package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +58 -62
  40. package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +58 -62
  41. package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +12 -12
  42. package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +13 -13
  43. package/dist/packages/stack/src/plugins/kanban/api/mutations.cjs +91 -0
  44. package/dist/packages/stack/src/plugins/kanban/api/mutations.mjs +87 -0
  45. package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +92 -118
  46. package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +89 -115
  47. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.cjs +7 -3
  48. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.mjs +7 -3
  49. package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +22 -29
  50. package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +23 -30
  51. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.cjs +89 -0
  52. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.mjs +89 -0
  53. package/dist/packages/stack/src/plugins/ui-builder/client/plugin.cjs +8 -8
  54. package/dist/packages/stack/src/plugins/ui-builder/client/plugin.mjs +9 -9
  55. package/dist/packages/stack/src/plugins/utils.cjs +42 -0
  56. package/dist/packages/stack/src/plugins/utils.mjs +41 -1
  57. package/dist/plugins/ai-chat/api/index.d.cts +1 -1
  58. package/dist/plugins/ai-chat/api/index.d.mts +1 -1
  59. package/dist/plugins/ai-chat/api/index.d.ts +1 -1
  60. package/dist/plugins/ai-chat/client/components/index.d.cts +1 -1
  61. package/dist/plugins/ai-chat/client/components/index.d.mts +1 -1
  62. package/dist/plugins/ai-chat/client/components/index.d.ts +1 -1
  63. package/dist/plugins/ai-chat/client/context/page-ai-context.cjs +92 -0
  64. package/dist/plugins/ai-chat/client/context/page-ai-context.d.cts +84 -0
  65. package/dist/plugins/ai-chat/client/context/page-ai-context.d.mts +84 -0
  66. package/dist/plugins/ai-chat/client/context/page-ai-context.d.ts +84 -0
  67. package/dist/plugins/ai-chat/client/context/page-ai-context.mjs +88 -0
  68. package/dist/plugins/ai-chat/client/hooks/index.d.cts +1 -1
  69. package/dist/plugins/ai-chat/client/hooks/index.d.mts +1 -1
  70. package/dist/plugins/ai-chat/client/hooks/index.d.ts +1 -1
  71. package/dist/plugins/ai-chat/client/index.d.cts +10 -10
  72. package/dist/plugins/ai-chat/client/index.d.mts +10 -10
  73. package/dist/plugins/ai-chat/client/index.d.ts +10 -10
  74. package/dist/plugins/ai-chat/query-keys.d.cts +1 -1
  75. package/dist/plugins/ai-chat/query-keys.d.mts +1 -1
  76. package/dist/plugins/ai-chat/query-keys.d.ts +1 -1
  77. package/dist/plugins/blog/api/index.d.cts +2 -2
  78. package/dist/plugins/blog/api/index.d.mts +2 -2
  79. package/dist/plugins/blog/api/index.d.ts +2 -2
  80. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  81. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  82. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  83. package/dist/plugins/blog/client/index.d.cts +13 -13
  84. package/dist/plugins/blog/client/index.d.mts +13 -13
  85. package/dist/plugins/blog/client/index.d.ts +13 -13
  86. package/dist/plugins/blog/query-keys.d.cts +2 -2
  87. package/dist/plugins/blog/query-keys.d.mts +2 -2
  88. package/dist/plugins/blog/query-keys.d.ts +2 -2
  89. package/dist/plugins/client/index.cjs +1 -0
  90. package/dist/plugins/client/index.d.cts +8 -1
  91. package/dist/plugins/client/index.d.mts +8 -1
  92. package/dist/plugins/client/index.d.ts +8 -1
  93. package/dist/plugins/client/index.mjs +1 -1
  94. package/dist/plugins/cms/api/index.cjs +2 -0
  95. package/dist/plugins/cms/api/index.d.cts +2 -2
  96. package/dist/plugins/cms/api/index.d.mts +2 -2
  97. package/dist/plugins/cms/api/index.d.ts +2 -2
  98. package/dist/plugins/cms/api/index.mjs +1 -0
  99. package/dist/plugins/cms/client/hooks/index.d.cts +1 -1
  100. package/dist/plugins/cms/client/hooks/index.d.mts +1 -1
  101. package/dist/plugins/cms/client/hooks/index.d.ts +1 -1
  102. package/dist/plugins/cms/client/index.d.cts +6 -6
  103. package/dist/plugins/cms/client/index.d.mts +6 -6
  104. package/dist/plugins/cms/client/index.d.ts +6 -6
  105. package/dist/plugins/cms/query-keys.d.cts +2 -2
  106. package/dist/plugins/cms/query-keys.d.mts +2 -2
  107. package/dist/plugins/cms/query-keys.d.ts +2 -2
  108. package/dist/plugins/form-builder/api/index.d.cts +2 -2
  109. package/dist/plugins/form-builder/api/index.d.mts +2 -2
  110. package/dist/plugins/form-builder/api/index.d.ts +2 -2
  111. package/dist/plugins/form-builder/client/components/index.d.cts +1 -1
  112. package/dist/plugins/form-builder/client/components/index.d.mts +1 -1
  113. package/dist/plugins/form-builder/client/components/index.d.ts +1 -1
  114. package/dist/plugins/form-builder/client/hooks/index.d.cts +1 -1
  115. package/dist/plugins/form-builder/client/hooks/index.d.mts +1 -1
  116. package/dist/plugins/form-builder/client/hooks/index.d.ts +1 -1
  117. package/dist/plugins/form-builder/client/index.d.cts +6 -6
  118. package/dist/plugins/form-builder/client/index.d.mts +6 -6
  119. package/dist/plugins/form-builder/client/index.d.ts +6 -6
  120. package/dist/plugins/form-builder/query-keys.d.cts +2 -2
  121. package/dist/plugins/form-builder/query-keys.d.mts +2 -2
  122. package/dist/plugins/form-builder/query-keys.d.ts +2 -2
  123. package/dist/plugins/kanban/api/index.cjs +4 -0
  124. package/dist/plugins/kanban/api/index.d.cts +1 -1
  125. package/dist/plugins/kanban/api/index.d.mts +1 -1
  126. package/dist/plugins/kanban/api/index.d.ts +1 -1
  127. package/dist/plugins/kanban/api/index.mjs +1 -0
  128. package/dist/plugins/kanban/client/index.d.cts +12 -12
  129. package/dist/plugins/kanban/client/index.d.mts +12 -12
  130. package/dist/plugins/kanban/client/index.d.ts +12 -12
  131. package/dist/plugins/kanban/query-keys.d.cts +1 -1
  132. package/dist/plugins/kanban/query-keys.d.mts +1 -1
  133. package/dist/plugins/kanban/query-keys.d.ts +1 -1
  134. package/dist/plugins/ui-builder/client/hooks/index.d.cts +1 -1
  135. package/dist/plugins/ui-builder/client/hooks/index.d.mts +1 -1
  136. package/dist/plugins/ui-builder/client/hooks/index.d.ts +1 -1
  137. package/dist/plugins/ui-builder/client/index.d.cts +3 -3
  138. package/dist/plugins/ui-builder/client/index.d.mts +3 -3
  139. package/dist/plugins/ui-builder/client/index.d.ts +3 -3
  140. package/dist/plugins/ui-builder/index.d.cts +2 -2
  141. package/dist/plugins/ui-builder/index.d.mts +2 -2
  142. package/dist/plugins/ui-builder/index.d.ts +2 -2
  143. package/dist/shared/{stack.C-WUPMT6.d.cts → stack.B2xZTSiO.d.cts} +4 -4
  144. package/dist/shared/{stack.B1EeBt1b.d.ts → stack.B58oHdqm.d.mts} +33 -3
  145. package/dist/shared/{stack.CVDTkMoO.d.mts → stack.B8QD11QU.d.cts} +7 -7
  146. package/dist/shared/{stack.CVDTkMoO.d.cts → stack.B8QD11QU.d.mts} +7 -7
  147. package/dist/shared/{stack.CVDTkMoO.d.ts → stack.B8QD11QU.d.ts} +7 -7
  148. package/dist/shared/{stack.CIP6QS9l.d.ts → stack.BDVEpue1.d.ts} +1 -1
  149. package/dist/shared/{stack.C5dtIncc.d.mts → stack.BTvbxZvw.d.cts} +1 -1
  150. package/dist/shared/{stack.DaOcgmrM.d.ts → stack.BV9hnvu4.d.cts} +31 -7
  151. package/dist/shared/{stack.DaOcgmrM.d.cts → stack.BV9hnvu4.d.mts} +31 -7
  152. package/dist/shared/{stack.DaOcgmrM.d.mts → stack.BV9hnvu4.d.ts} +31 -7
  153. package/dist/shared/{stack.DdI5W6MB.d.mts → stack.BozPgbrZ.d.cts} +19 -19
  154. package/dist/shared/{stack.DdI5W6MB.d.ts → stack.BozPgbrZ.d.mts} +19 -19
  155. package/dist/shared/{stack.DdI5W6MB.d.cts → stack.BozPgbrZ.d.ts} +19 -19
  156. package/dist/shared/{stack.CP68pFEH.d.mts → stack.C9Mg2Q46.d.cts} +33 -3
  157. package/dist/shared/{stack.BeSm90va.d.ts → stack.CTDVxbrA.d.ts} +72 -14
  158. package/dist/shared/{stack.C-Ptrz8s.d.ts → stack.Cj_zKww4.d.ts} +4 -4
  159. package/dist/shared/{stack.TIBF2AOx.d.ts → stack.CxaFNQCV.d.mts} +89 -34
  160. package/dist/shared/{stack.CMh_EdxW.d.cts → stack.D-b5zbPm.d.cts} +72 -14
  161. package/dist/shared/{stack.Dw0Ly2TM.d.cts → stack.DTtmJPQO.d.mts} +1 -1
  162. package/dist/shared/{stack.BKfolAyK.d.ts → stack.DXnclTG7.d.ts} +11 -11
  163. package/dist/shared/{stack.snB1EDP7.d.cts → stack.DaZM10cp.d.cts} +11 -11
  164. package/dist/shared/{stack.Dg09R0oB.d.mts → stack.FVWf2JhZ.d.mts} +72 -14
  165. package/dist/shared/{stack.BIXEI6v_.d.mts → stack.cfCkioTe.d.mts} +11 -11
  166. package/dist/shared/{stack.6fUOjLs9.d.mts → stack.dH7u-TJH.d.mts} +4 -4
  167. package/dist/shared/{stack.BpolpQpf.d.cts → stack.j75TpKh2.d.ts} +89 -34
  168. package/dist/shared/{stack.rTy7-wQU.d.mts → stack.n1_i1p2B.d.cts} +89 -34
  169. package/dist/shared/{stack.IdtKDRka.d.cts → stack.sO33ZDhK.d.ts} +33 -3
  170. package/package.json +14 -1
  171. package/src/client/components/compose.tsx +7 -4
  172. package/src/plugins/ai-chat/api/page-tools.ts +111 -0
  173. package/src/plugins/ai-chat/api/plugin.ts +228 -72
  174. package/src/plugins/ai-chat/client/components/chat-input.tsx +2 -2
  175. package/src/plugins/ai-chat/client/components/chat-interface.tsx +154 -58
  176. package/src/plugins/ai-chat/client/components/chat-layout.tsx +166 -32
  177. package/src/plugins/ai-chat/client/components/chat-sidebar.tsx +1 -1
  178. package/src/plugins/ai-chat/client/context/page-ai-context.tsx +240 -0
  179. package/src/plugins/ai-chat/client/plugin.tsx +23 -31
  180. package/src/plugins/ai-chat/schemas.ts +16 -0
  181. package/src/plugins/blog/api/plugin.ts +31 -47
  182. package/src/plugins/blog/client/components/forms/post-forms.tsx +29 -2
  183. package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +28 -0
  184. package/src/plugins/blog/client/components/pages/fill-blog-form-handler.ts +38 -0
  185. package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +33 -1
  186. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +20 -0
  187. package/src/plugins/blog/client/plugin.tsx +36 -39
  188. package/src/plugins/client/index.ts +5 -1
  189. package/src/plugins/cms/api/index.ts +4 -0
  190. package/src/plugins/cms/api/mutations.ts +84 -0
  191. package/src/plugins/cms/api/plugin.ts +23 -17
  192. package/src/plugins/cms/client/plugin.tsx +18 -21
  193. package/src/plugins/cms/types.ts +7 -7
  194. package/src/plugins/form-builder/api/plugin.ts +64 -64
  195. package/src/plugins/form-builder/client/plugin.tsx +19 -18
  196. package/src/plugins/form-builder/types.ts +19 -24
  197. package/src/plugins/kanban/api/index.ts +6 -0
  198. package/src/plugins/kanban/api/mutations.ts +169 -0
  199. package/src/plugins/kanban/api/plugin.ts +123 -136
  200. package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +4 -0
  201. package/src/plugins/kanban/client/plugin.tsx +35 -41
  202. package/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.tsx +132 -0
  203. package/src/plugins/ui-builder/client/plugin.tsx +11 -10
  204. package/src/plugins/ui-builder/types.ts +4 -4
  205. package/src/plugins/utils.ts +92 -1
  206. package/dist/shared/{stack.CBON0dWL.d.mts → stack.BQmuNl5p.d.cts} +2 -2
  207. package/dist/shared/{stack.CBON0dWL.d.ts → stack.BQmuNl5p.d.mts} +2 -2
  208. package/dist/shared/{stack.CBON0dWL.d.cts → stack.BQmuNl5p.d.ts} +2 -2
@@ -250,9 +250,14 @@ const CustomPostUpdateSchema = schemas.updatePostSchema.omit({
250
250
  const addPostFormPropsAreEqual = (prevProps, nextProps) => {
251
251
  if (prevProps.onClose !== nextProps.onClose) return false;
252
252
  if (prevProps.onSuccess !== nextProps.onSuccess) return false;
253
+ if (prevProps.onFormReady !== nextProps.onFormReady) return false;
253
254
  return true;
254
255
  };
255
- const AddPostFormComponent = ({ onClose, onSuccess }) => {
256
+ const AddPostFormComponent = ({
257
+ onClose,
258
+ onSuccess,
259
+ onFormReady
260
+ }) => {
256
261
  const [featuredImageUploading, setFeaturedImageUploading] = React.useState(false);
257
262
  const { localization } = context.usePluginOverrides("blog", {
258
263
  localization: index.BLOG_LOCALIZATION
@@ -290,6 +295,9 @@ const AddPostFormComponent = ({ onClose, onSuccess }) => {
290
295
  tags: []
291
296
  }
292
297
  });
298
+ React.useEffect(() => {
299
+ onFormReady?.(form);
300
+ }, []);
293
301
  return /* @__PURE__ */ jsxRuntime.jsx(
294
302
  PostFormBody,
295
303
  {
@@ -309,13 +317,15 @@ const editPostFormPropsAreEqual = (prevProps, nextProps) => {
309
317
  if (prevProps.onClose !== nextProps.onClose) return false;
310
318
  if (prevProps.onSuccess !== nextProps.onSuccess) return false;
311
319
  if (prevProps.onDelete !== nextProps.onDelete) return false;
320
+ if (prevProps.onFormReady !== nextProps.onFormReady) return false;
312
321
  return true;
313
322
  };
314
323
  const EditPostFormComponent = ({
315
324
  postSlug,
316
325
  onClose,
317
326
  onSuccess,
318
- onDelete
327
+ onDelete,
328
+ onFormReady
319
329
  }) => {
320
330
  const [featuredImageUploading, setFeaturedImageUploading] = React.useState(false);
321
331
  const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false);
@@ -391,6 +401,9 @@ const EditPostFormComponent = ({
391
401
  },
392
402
  values: initialData
393
403
  });
404
+ React.useEffect(() => {
405
+ onFormReady?.(form);
406
+ }, []);
394
407
  if (!post) {
395
408
  return /* @__PURE__ */ jsxRuntime.jsx(emptyList.EmptyList, { message: localization.BLOG_PAGE_NOT_FOUND_DESCRIPTION });
396
409
  }
@@ -11,7 +11,7 @@ import { slugify } from '../../../utils.mjs';
11
11
  import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction } from '../../../../../../../ui/src/components/alert-dialog.mjs';
12
12
  import { zodResolver } from '@hookform/resolvers/zod';
13
13
  import { Loader2 } from 'lucide-react';
14
- import { memo, useState, useMemo, Suspense, lazy } from 'react';
14
+ import { memo, useState, useEffect, useMemo, Suspense, lazy } from 'react';
15
15
  import { useForm } from 'react-hook-form';
16
16
  import { toast } from 'sonner';
17
17
  import { FeaturedImageField } from './image-field.mjs';
@@ -248,9 +248,14 @@ const CustomPostUpdateSchema = updatePostSchema.omit({
248
248
  const addPostFormPropsAreEqual = (prevProps, nextProps) => {
249
249
  if (prevProps.onClose !== nextProps.onClose) return false;
250
250
  if (prevProps.onSuccess !== nextProps.onSuccess) return false;
251
+ if (prevProps.onFormReady !== nextProps.onFormReady) return false;
251
252
  return true;
252
253
  };
253
- const AddPostFormComponent = ({ onClose, onSuccess }) => {
254
+ const AddPostFormComponent = ({
255
+ onClose,
256
+ onSuccess,
257
+ onFormReady
258
+ }) => {
254
259
  const [featuredImageUploading, setFeaturedImageUploading] = useState(false);
255
260
  const { localization } = usePluginOverrides("blog", {
256
261
  localization: BLOG_LOCALIZATION
@@ -288,6 +293,9 @@ const AddPostFormComponent = ({ onClose, onSuccess }) => {
288
293
  tags: []
289
294
  }
290
295
  });
296
+ useEffect(() => {
297
+ onFormReady?.(form);
298
+ }, []);
291
299
  return /* @__PURE__ */ jsx(
292
300
  PostFormBody,
293
301
  {
@@ -307,13 +315,15 @@ const editPostFormPropsAreEqual = (prevProps, nextProps) => {
307
315
  if (prevProps.onClose !== nextProps.onClose) return false;
308
316
  if (prevProps.onSuccess !== nextProps.onSuccess) return false;
309
317
  if (prevProps.onDelete !== nextProps.onDelete) return false;
318
+ if (prevProps.onFormReady !== nextProps.onFormReady) return false;
310
319
  return true;
311
320
  };
312
321
  const EditPostFormComponent = ({
313
322
  postSlug,
314
323
  onClose,
315
324
  onSuccess,
316
- onDelete
325
+ onDelete,
326
+ onFormReady
317
327
  }) => {
318
328
  const [featuredImageUploading, setFeaturedImageUploading] = useState(false);
319
329
  const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
@@ -389,6 +399,9 @@ const EditPostFormComponent = ({
389
399
  },
390
400
  values: initialData
391
401
  });
402
+ useEffect(() => {
403
+ onFormReady?.(form);
404
+ }, []);
392
405
  if (!post) {
393
406
  return /* @__PURE__ */ jsx(EmptyList, { message: localization.BLOG_PAGE_NOT_FOUND_DESCRIPTION });
394
407
  }
@@ -8,6 +8,9 @@ const pageHeader = require('../shared/page-header.cjs');
8
8
  const pageWrapper = require('../shared/page-wrapper.cjs');
9
9
  const index = require('../../localization/index.cjs');
10
10
  const useRouteLifecycle = require('../../../../../../../ui/src/hooks/use-route-lifecycle.cjs');
11
+ const context$1 = require('@btst/stack/plugins/ai-chat/client/context');
12
+ const React = require('react');
13
+ const fillBlogFormHandler = require('./fill-blog-form-handler.cjs');
11
14
 
12
15
  function EditPostPage({ slug }) {
13
16
  const overrides = context.usePluginOverrides("blog", {
@@ -30,6 +33,25 @@ function EditPostPage({ slug }) {
30
33
  return true;
31
34
  }
32
35
  });
36
+ const formRef = React.useRef(null);
37
+ const handleFormReady = React.useCallback((form) => {
38
+ formRef.current = form;
39
+ }, []);
40
+ context$1.useRegisterPageAIContext({
41
+ routeName: "blog-edit-post",
42
+ pageDescription: `User is editing a blog post (slug: "${slug}") in the admin editor.`,
43
+ suggestions: [
44
+ "Improve this post's title",
45
+ "Rewrite the intro paragraph",
46
+ "Suggest better tags"
47
+ ],
48
+ clientTools: {
49
+ fillBlogForm: fillBlogFormHandler.createFillBlogFormHandler(
50
+ formRef,
51
+ "Form updated successfully"
52
+ )
53
+ }
54
+ });
33
55
  const handleClose = () => {
34
56
  navigate(`${basePath}/blog`);
35
57
  };
@@ -53,7 +75,8 @@ function EditPostPage({ slug }) {
53
75
  postSlug: slug,
54
76
  onClose: handleClose,
55
77
  onSuccess: handleSuccess,
56
- onDelete: handleDelete
78
+ onDelete: handleDelete,
79
+ onFormReady: handleFormReady
57
80
  }
58
81
  )
59
82
  ] });
@@ -6,6 +6,9 @@ import { PageHeader } from '../shared/page-header.mjs';
6
6
  import { PageWrapper } from '../shared/page-wrapper.mjs';
7
7
  import { BLOG_LOCALIZATION } from '../../localization/index.mjs';
8
8
  import { useRouteLifecycle } from '../../../../../../../ui/src/hooks/use-route-lifecycle.mjs';
9
+ import { useRegisterPageAIContext } from '@btst/stack/plugins/ai-chat/client/context';
10
+ import { useRef, useCallback } from 'react';
11
+ import { createFillBlogFormHandler } from './fill-blog-form-handler.mjs';
9
12
 
10
13
  function EditPostPage({ slug }) {
11
14
  const overrides = usePluginOverrides("blog", {
@@ -28,6 +31,25 @@ function EditPostPage({ slug }) {
28
31
  return true;
29
32
  }
30
33
  });
34
+ const formRef = useRef(null);
35
+ const handleFormReady = useCallback((form) => {
36
+ formRef.current = form;
37
+ }, []);
38
+ useRegisterPageAIContext({
39
+ routeName: "blog-edit-post",
40
+ pageDescription: `User is editing a blog post (slug: "${slug}") in the admin editor.`,
41
+ suggestions: [
42
+ "Improve this post's title",
43
+ "Rewrite the intro paragraph",
44
+ "Suggest better tags"
45
+ ],
46
+ clientTools: {
47
+ fillBlogForm: createFillBlogFormHandler(
48
+ formRef,
49
+ "Form updated successfully"
50
+ )
51
+ }
52
+ });
31
53
  const handleClose = () => {
32
54
  navigate(`${basePath}/blog`);
33
55
  };
@@ -51,7 +73,8 @@ function EditPostPage({ slug }) {
51
73
  postSlug: slug,
52
74
  onClose: handleClose,
53
75
  onSuccess: handleSuccess,
54
- onDelete: handleDelete
76
+ onDelete: handleDelete,
77
+ onFormReady: handleFormReady
55
78
  }
56
79
  )
57
80
  ] });
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ function createFillBlogFormHandler(formRef, successMessage) {
4
+ return async ({
5
+ title,
6
+ content,
7
+ excerpt,
8
+ tags
9
+ }) => {
10
+ const form = formRef.current;
11
+ if (!form) return { success: false, message: "Form not ready" };
12
+ if (title !== void 0)
13
+ form.setValue("title", title, { shouldValidate: true });
14
+ if (content !== void 0)
15
+ form.setValue("content", content, { shouldValidate: true });
16
+ if (excerpt !== void 0) form.setValue("excerpt", excerpt);
17
+ if (tags !== void 0)
18
+ form.setValue(
19
+ "tags",
20
+ tags.map((name) => ({ name }))
21
+ );
22
+ return { success: true, message: successMessage };
23
+ };
24
+ }
25
+
26
+ exports.createFillBlogFormHandler = createFillBlogFormHandler;
@@ -0,0 +1,24 @@
1
+ function createFillBlogFormHandler(formRef, successMessage) {
2
+ return async ({
3
+ title,
4
+ content,
5
+ excerpt,
6
+ tags
7
+ }) => {
8
+ const form = formRef.current;
9
+ if (!form) return { success: false, message: "Form not ready" };
10
+ if (title !== void 0)
11
+ form.setValue("title", title, { shouldValidate: true });
12
+ if (content !== void 0)
13
+ form.setValue("content", content, { shouldValidate: true });
14
+ if (excerpt !== void 0) form.setValue("excerpt", excerpt);
15
+ if (tags !== void 0)
16
+ form.setValue(
17
+ "tags",
18
+ tags.map((name) => ({ name }))
19
+ );
20
+ return { success: true, message: successMessage };
21
+ };
22
+ }
23
+
24
+ export { createFillBlogFormHandler };
@@ -8,6 +8,9 @@ const pageHeader = require('../shared/page-header.cjs');
8
8
  const pageWrapper = require('../shared/page-wrapper.cjs');
9
9
  const index = require('../../localization/index.cjs');
10
10
  const useRouteLifecycle = require('../../../../../../../ui/src/hooks/use-route-lifecycle.cjs');
11
+ const context$1 = require('@btst/stack/plugins/ai-chat/client/context');
12
+ const React = require('react');
13
+ const fillBlogFormHandler = require('./fill-blog-form-handler.cjs');
11
14
 
12
15
  function NewPostPage() {
13
16
  const overrides = context.usePluginOverrides("blog", {
@@ -29,6 +32,25 @@ function NewPostPage() {
29
32
  return true;
30
33
  }
31
34
  });
35
+ const formRef = React.useRef(null);
36
+ const handleFormReady = React.useCallback((form) => {
37
+ formRef.current = form;
38
+ }, []);
39
+ context$1.useRegisterPageAIContext({
40
+ routeName: "blog-new-post",
41
+ pageDescription: "User is creating a new blog post in the admin editor. IMPORTANT: When asked to write, draft, or create a blog post, you MUST call the fillBlogForm tool to populate the form fields directly \u2014 do NOT just output the text in your response.",
42
+ suggestions: [
43
+ "Write a post about AI trends",
44
+ "Draft an intro paragraph",
45
+ "Suggest 5 tags for this post"
46
+ ],
47
+ clientTools: {
48
+ fillBlogForm: fillBlogFormHandler.createFillBlogFormHandler(
49
+ formRef,
50
+ "Form filled successfully"
51
+ )
52
+ }
53
+ });
32
54
  const handleClose = () => {
33
55
  navigate(`${basePath}/blog`);
34
56
  };
@@ -47,7 +69,14 @@ function NewPostPage() {
47
69
  description: localization.BLOG_POST_ADD_DESCRIPTION
48
70
  }
49
71
  ),
50
- /* @__PURE__ */ jsxRuntime.jsx(postForms.AddPostForm, { onClose: handleClose, onSuccess: handleSuccess })
72
+ /* @__PURE__ */ jsxRuntime.jsx(
73
+ postForms.AddPostForm,
74
+ {
75
+ onClose: handleClose,
76
+ onSuccess: handleSuccess,
77
+ onFormReady: handleFormReady
78
+ }
79
+ )
51
80
  ] });
52
81
  }
53
82
 
@@ -6,6 +6,9 @@ import { PageHeader } from '../shared/page-header.mjs';
6
6
  import { PageWrapper } from '../shared/page-wrapper.mjs';
7
7
  import { BLOG_LOCALIZATION } from '../../localization/index.mjs';
8
8
  import { useRouteLifecycle } from '../../../../../../../ui/src/hooks/use-route-lifecycle.mjs';
9
+ import { useRegisterPageAIContext } from '@btst/stack/plugins/ai-chat/client/context';
10
+ import { useRef, useCallback } from 'react';
11
+ import { createFillBlogFormHandler } from './fill-blog-form-handler.mjs';
9
12
 
10
13
  function NewPostPage() {
11
14
  const overrides = usePluginOverrides("blog", {
@@ -27,6 +30,25 @@ function NewPostPage() {
27
30
  return true;
28
31
  }
29
32
  });
33
+ const formRef = useRef(null);
34
+ const handleFormReady = useCallback((form) => {
35
+ formRef.current = form;
36
+ }, []);
37
+ useRegisterPageAIContext({
38
+ routeName: "blog-new-post",
39
+ pageDescription: "User is creating a new blog post in the admin editor. IMPORTANT: When asked to write, draft, or create a blog post, you MUST call the fillBlogForm tool to populate the form fields directly \u2014 do NOT just output the text in your response.",
40
+ suggestions: [
41
+ "Write a post about AI trends",
42
+ "Draft an intro paragraph",
43
+ "Suggest 5 tags for this post"
44
+ ],
45
+ clientTools: {
46
+ fillBlogForm: createFillBlogFormHandler(
47
+ formRef,
48
+ "Form filled successfully"
49
+ )
50
+ }
51
+ });
30
52
  const handleClose = () => {
31
53
  navigate(`${basePath}/blog`);
32
54
  };
@@ -45,7 +67,14 @@ function NewPostPage() {
45
67
  description: localization.BLOG_POST_ADD_DESCRIPTION
46
68
  }
47
69
  ),
48
- /* @__PURE__ */ jsx(AddPostForm, { onClose: handleClose, onSuccess: handleSuccess })
70
+ /* @__PURE__ */ jsx(
71
+ AddPostForm,
72
+ {
73
+ onClose: handleClose,
74
+ onSuccess: handleSuccess,
75
+ onFormReady: handleFormReady
76
+ }
77
+ )
49
78
  ] });
50
79
  }
51
80
 
@@ -16,6 +16,7 @@ const recentPostsCarousel = require('../shared/recent-posts-carousel.cjs');
16
16
  const badge = require('../../../../../../../ui/src/components/badge.cjs');
17
17
  const useRouteLifecycle = require('../../../../../../../ui/src/hooks/use-route-lifecycle.cjs');
18
18
  const onThisPage = require('../shared/on-this-page.cjs');
19
+ const context$1 = require('@btst/stack/plugins/ai-chat/client/context');
19
20
 
20
21
  function PostPage({ slug }) {
21
22
  const overrides = context.usePluginOverrides("blog", {
@@ -50,6 +51,23 @@ function PostPage({ slug }) {
50
51
  excludeSlug: slug,
51
52
  enabled: !!post
52
53
  });
54
+ context$1.useRegisterPageAIContext(
55
+ post ? {
56
+ routeName: "blog-post",
57
+ pageDescription: `Blog post: "${post.title}"
58
+ Author: ${post.authorId ?? "Unknown"}
59
+
60
+ ${post.content ?? ""}`.slice(
61
+ 0,
62
+ 16e3
63
+ ),
64
+ suggestions: [
65
+ "Summarize this post",
66
+ "What are the key takeaways?",
67
+ "Explain this in simpler terms"
68
+ ]
69
+ } : null
70
+ );
53
71
  if (!slug || !post) {
54
72
  return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(emptyList.EmptyList, { message: localization.BLOG_PAGE_NOT_FOUND_DESCRIPTION }) });
55
73
  }
@@ -14,6 +14,7 @@ import { RecentPostsCarousel } from '../shared/recent-posts-carousel.mjs';
14
14
  import { Badge } from '../../../../../../../ui/src/components/badge.mjs';
15
15
  import { useRouteLifecycle } from '../../../../../../../ui/src/hooks/use-route-lifecycle.mjs';
16
16
  import { OnThisPageSelect, OnThisPage } from '../shared/on-this-page.mjs';
17
+ import { useRegisterPageAIContext } from '@btst/stack/plugins/ai-chat/client/context';
17
18
 
18
19
  function PostPage({ slug }) {
19
20
  const overrides = usePluginOverrides("blog", {
@@ -48,6 +49,23 @@ function PostPage({ slug }) {
48
49
  excludeSlug: slug,
49
50
  enabled: !!post
50
51
  });
52
+ useRegisterPageAIContext(
53
+ post ? {
54
+ routeName: "blog-post",
55
+ pageDescription: `Blog post: "${post.title}"
56
+ Author: ${post.authorId ?? "Unknown"}
57
+
58
+ ${post.content ?? ""}`.slice(
59
+ 0,
60
+ 16e3
61
+ ),
62
+ suggestions: [
63
+ "Summarize this post",
64
+ "What are the key takeaways?",
65
+ "Explain this in simpler terms"
66
+ ]
67
+ } : null
68
+ );
51
69
  if (!slug || !post) {
52
70
  return /* @__PURE__ */ jsx(PageWrapper, { children: /* @__PURE__ */ jsx(EmptyList, { message: localization.BLOG_PAGE_NOT_FOUND_DESCRIPTION }) });
53
71
  }
@@ -23,10 +23,10 @@ function createPostsLoader(published, config) {
23
23
  };
24
24
  try {
25
25
  if (hooks?.beforeLoadPosts) {
26
- const canLoad = await hooks.beforeLoadPosts({ published }, context);
27
- if (!canLoad) {
28
- throw new Error("Load prevented by beforeLoadPosts hook");
29
- }
26
+ await client.runClientHookWithShim(
27
+ () => hooks.beforeLoadPosts({ published }, context),
28
+ "Load prevented by beforeLoadPosts hook"
29
+ );
30
30
  }
31
31
  const limit = 10;
32
32
  const client$1 = client.createApiClient({
@@ -47,14 +47,10 @@ function createPostsLoader(published, config) {
47
47
  await queryClient.prefetchQuery(tagsQuery);
48
48
  if (hooks?.afterLoadPosts) {
49
49
  const posts = queryClient.getQueryData(listQuery.queryKey) || null;
50
- const canContinue = await hooks.afterLoadPosts(
51
- posts,
52
- { published },
53
- context
50
+ await client.runClientHookWithShim(
51
+ () => hooks.afterLoadPosts(posts, { published }, context),
52
+ "Load prevented by afterLoadPosts hook"
54
53
  );
55
- if (canContinue === false) {
56
- throw new Error("Load prevented by afterLoadPosts hook");
57
- }
58
54
  }
59
55
  const queryState = queryClient.getQueryState(listQuery.queryKey);
60
56
  if (queryState?.error) {
@@ -90,10 +86,10 @@ function createPostLoader(slug, config, path) {
90
86
  };
91
87
  try {
92
88
  if (hooks?.beforeLoadPost) {
93
- const canLoad = await hooks.beforeLoadPost(slug, context);
94
- if (!canLoad) {
95
- throw new Error("Load prevented by beforeLoadPost hook");
96
- }
89
+ await client.runClientHookWithShim(
90
+ () => hooks.beforeLoadPost(slug, context),
91
+ "Load prevented by beforeLoadPost hook"
92
+ );
97
93
  }
98
94
  const client$1 = client.createApiClient({
99
95
  baseURL: apiBaseURL,
@@ -104,10 +100,10 @@ function createPostLoader(slug, config, path) {
104
100
  await queryClient.prefetchQuery(postQuery);
105
101
  if (hooks?.afterLoadPost) {
106
102
  const post = queryClient.getQueryData(postQuery.queryKey) || null;
107
- const canContinue = await hooks.afterLoadPost(post, slug, context);
108
- if (canContinue === false) {
109
- throw new Error("Load prevented by afterLoadPost hook");
110
- }
103
+ await client.runClientHookWithShim(
104
+ () => hooks.afterLoadPost(post, slug, context),
105
+ "Load prevented by afterLoadPost hook"
106
+ );
111
107
  }
112
108
  const queryState = queryClient.getQueryState(postQuery.queryKey);
113
109
  if (queryState?.error) {
@@ -142,16 +138,16 @@ function createNewPostLoader(config) {
142
138
  };
143
139
  try {
144
140
  if (hooks?.beforeLoadNewPost) {
145
- const canLoad = await hooks.beforeLoadNewPost(context);
146
- if (!canLoad) {
147
- throw new Error("Load prevented by beforeLoadNewPost hook");
148
- }
141
+ await client.runClientHookWithShim(
142
+ () => hooks.beforeLoadNewPost(context),
143
+ "Load prevented by beforeLoadNewPost hook"
144
+ );
149
145
  }
150
146
  if (hooks?.afterLoadNewPost) {
151
- const canContinue = await hooks.afterLoadNewPost(context);
152
- if (canContinue === false) {
153
- throw new Error("Load prevented by afterLoadNewPost hook");
154
- }
147
+ await client.runClientHookWithShim(
148
+ () => hooks.afterLoadNewPost(context),
149
+ "Load prevented by afterLoadNewPost hook"
150
+ );
155
151
  }
156
152
  } catch (error) {
157
153
  if (hooks?.onLoadError) {
@@ -1,5 +1,5 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { defineClientPlugin, createApiClient, isConnectionError } from '@btst/stack/plugins/client';
2
+ import { defineClientPlugin, createApiClient, runClientHookWithShim, isConnectionError } from '@btst/stack/plugins/client';
3
3
  import { createRoute } from '@btst/yar';
4
4
  import { createBlogQueryKeys } from '../../../../../../plugins/blog/query-keys.mjs';
5
5
  import { HomePageComponent } from './components/pages/home-page.mjs';
@@ -21,10 +21,10 @@ function createPostsLoader(published, config) {
21
21
  };
22
22
  try {
23
23
  if (hooks?.beforeLoadPosts) {
24
- const canLoad = await hooks.beforeLoadPosts({ published }, context);
25
- if (!canLoad) {
26
- throw new Error("Load prevented by beforeLoadPosts hook");
27
- }
24
+ await runClientHookWithShim(
25
+ () => hooks.beforeLoadPosts({ published }, context),
26
+ "Load prevented by beforeLoadPosts hook"
27
+ );
28
28
  }
29
29
  const limit = 10;
30
30
  const client = createApiClient({
@@ -45,14 +45,10 @@ function createPostsLoader(published, config) {
45
45
  await queryClient.prefetchQuery(tagsQuery);
46
46
  if (hooks?.afterLoadPosts) {
47
47
  const posts = queryClient.getQueryData(listQuery.queryKey) || null;
48
- const canContinue = await hooks.afterLoadPosts(
49
- posts,
50
- { published },
51
- context
48
+ await runClientHookWithShim(
49
+ () => hooks.afterLoadPosts(posts, { published }, context),
50
+ "Load prevented by afterLoadPosts hook"
52
51
  );
53
- if (canContinue === false) {
54
- throw new Error("Load prevented by afterLoadPosts hook");
55
- }
56
52
  }
57
53
  const queryState = queryClient.getQueryState(listQuery.queryKey);
58
54
  if (queryState?.error) {
@@ -88,10 +84,10 @@ function createPostLoader(slug, config, path) {
88
84
  };
89
85
  try {
90
86
  if (hooks?.beforeLoadPost) {
91
- const canLoad = await hooks.beforeLoadPost(slug, context);
92
- if (!canLoad) {
93
- throw new Error("Load prevented by beforeLoadPost hook");
94
- }
87
+ await runClientHookWithShim(
88
+ () => hooks.beforeLoadPost(slug, context),
89
+ "Load prevented by beforeLoadPost hook"
90
+ );
95
91
  }
96
92
  const client = createApiClient({
97
93
  baseURL: apiBaseURL,
@@ -102,10 +98,10 @@ function createPostLoader(slug, config, path) {
102
98
  await queryClient.prefetchQuery(postQuery);
103
99
  if (hooks?.afterLoadPost) {
104
100
  const post = queryClient.getQueryData(postQuery.queryKey) || null;
105
- const canContinue = await hooks.afterLoadPost(post, slug, context);
106
- if (canContinue === false) {
107
- throw new Error("Load prevented by afterLoadPost hook");
108
- }
101
+ await runClientHookWithShim(
102
+ () => hooks.afterLoadPost(post, slug, context),
103
+ "Load prevented by afterLoadPost hook"
104
+ );
109
105
  }
110
106
  const queryState = queryClient.getQueryState(postQuery.queryKey);
111
107
  if (queryState?.error) {
@@ -140,16 +136,16 @@ function createNewPostLoader(config) {
140
136
  };
141
137
  try {
142
138
  if (hooks?.beforeLoadNewPost) {
143
- const canLoad = await hooks.beforeLoadNewPost(context);
144
- if (!canLoad) {
145
- throw new Error("Load prevented by beforeLoadNewPost hook");
146
- }
139
+ await runClientHookWithShim(
140
+ () => hooks.beforeLoadNewPost(context),
141
+ "Load prevented by beforeLoadNewPost hook"
142
+ );
147
143
  }
148
144
  if (hooks?.afterLoadNewPost) {
149
- const canContinue = await hooks.afterLoadNewPost(context);
150
- if (canContinue === false) {
151
- throw new Error("Load prevented by afterLoadNewPost hook");
152
- }
145
+ await runClientHookWithShim(
146
+ () => hooks.afterLoadNewPost(context),
147
+ "Load prevented by afterLoadNewPost hook"
148
+ );
153
149
  }
154
150
  } catch (error) {
155
151
  if (hooks?.onLoadError) {
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ const getters = require('./getters.cjs');
4
+
5
+ async function createCMSContentItem(adapter, contentTypeSlug, input) {
6
+ const contentType = await adapter.findOne({
7
+ model: "contentType",
8
+ where: [
9
+ {
10
+ field: "slug",
11
+ value: contentTypeSlug,
12
+ operator: "eq"
13
+ }
14
+ ]
15
+ });
16
+ if (!contentType) {
17
+ throw new Error(`Content type "${contentTypeSlug}" not found`);
18
+ }
19
+ const existing = await adapter.findOne({
20
+ model: "contentItem",
21
+ where: [
22
+ {
23
+ field: "contentTypeId",
24
+ value: contentType.id,
25
+ operator: "eq"
26
+ },
27
+ { field: "slug", value: input.slug, operator: "eq" }
28
+ ]
29
+ });
30
+ if (existing) {
31
+ throw new Error(
32
+ `Content item with slug "${input.slug}" already exists in type "${contentTypeSlug}"`
33
+ );
34
+ }
35
+ const item = await adapter.create({
36
+ model: "contentItem",
37
+ data: {
38
+ contentTypeId: contentType.id,
39
+ slug: input.slug,
40
+ data: JSON.stringify(input.data),
41
+ createdAt: /* @__PURE__ */ new Date(),
42
+ updatedAt: /* @__PURE__ */ new Date()
43
+ }
44
+ });
45
+ return getters.serializeContentItem(item);
46
+ }
47
+
48
+ exports.createCMSContentItem = createCMSContentItem;