@btst/stack 2.2.0 → 2.4.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 (237) 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 +54 -7
  6. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +54 -7
  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/schemas.cjs +17 -1
  16. package/dist/packages/stack/src/plugins/ai-chat/schemas.mjs +17 -1
  17. package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +52 -1
  18. package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +52 -1
  19. package/dist/packages/stack/src/plugins/blog/api/query-key-defs.cjs +18 -0
  20. package/dist/packages/stack/src/plugins/blog/api/query-key-defs.mjs +15 -0
  21. package/dist/packages/stack/src/plugins/blog/api/serializers.cjs +21 -0
  22. package/dist/packages/stack/src/plugins/blog/api/serializers.mjs +18 -0
  23. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.cjs +15 -2
  24. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.mjs +16 -3
  25. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.cjs +24 -1
  26. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.mjs +24 -1
  27. package/dist/packages/stack/src/plugins/blog/client/components/pages/fill-blog-form-handler.cjs +26 -0
  28. package/dist/packages/stack/src/plugins/blog/client/components/pages/fill-blog-form-handler.mjs +24 -0
  29. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.cjs +30 -1
  30. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.mjs +30 -1
  31. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +18 -0
  32. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +18 -0
  33. package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +15 -0
  34. package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +16 -1
  35. package/dist/packages/stack/src/plugins/cms/api/getters.cjs +10 -0
  36. package/dist/packages/stack/src/plugins/cms/api/getters.mjs +10 -1
  37. package/dist/packages/stack/src/plugins/cms/api/mutations.cjs +48 -0
  38. package/dist/packages/stack/src/plugins/cms/api/mutations.mjs +46 -0
  39. package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +75 -0
  40. package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +76 -1
  41. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.cjs +29 -0
  42. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.mjs +26 -0
  43. package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +15 -0
  44. package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +16 -1
  45. package/dist/packages/stack/src/plugins/form-builder/api/getters.cjs +9 -0
  46. package/dist/packages/stack/src/plugins/form-builder/api/getters.mjs +9 -1
  47. package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +62 -1
  48. package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +63 -2
  49. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.cjs +37 -0
  50. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.mjs +33 -0
  51. package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +15 -0
  52. package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +16 -1
  53. package/dist/packages/stack/src/plugins/kanban/api/mutations.cjs +91 -0
  54. package/dist/packages/stack/src/plugins/kanban/api/mutations.mjs +87 -0
  55. package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +34 -1
  56. package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +34 -1
  57. package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.cjs +26 -0
  58. package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.mjs +23 -0
  59. package/dist/packages/stack/src/plugins/kanban/api/serializers.cjs +30 -0
  60. package/dist/packages/stack/src/plugins/kanban/api/serializers.mjs +26 -0
  61. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.cjs +7 -3
  62. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.mjs +7 -3
  63. package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +10 -0
  64. package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +11 -1
  65. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.cjs +89 -0
  66. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.mjs +89 -0
  67. package/dist/packages/stack/src/plugins/utils.cjs +6 -0
  68. package/dist/packages/stack/src/plugins/utils.mjs +6 -1
  69. package/dist/plugins/ai-chat/api/index.d.cts +1 -1
  70. package/dist/plugins/ai-chat/api/index.d.mts +1 -1
  71. package/dist/plugins/ai-chat/api/index.d.ts +1 -1
  72. package/dist/plugins/ai-chat/client/components/index.d.cts +1 -1
  73. package/dist/plugins/ai-chat/client/components/index.d.mts +1 -1
  74. package/dist/plugins/ai-chat/client/components/index.d.ts +1 -1
  75. package/dist/plugins/ai-chat/client/context/page-ai-context.cjs +92 -0
  76. package/dist/plugins/ai-chat/client/context/page-ai-context.d.cts +84 -0
  77. package/dist/plugins/ai-chat/client/context/page-ai-context.d.mts +84 -0
  78. package/dist/plugins/ai-chat/client/context/page-ai-context.d.ts +84 -0
  79. package/dist/plugins/ai-chat/client/context/page-ai-context.mjs +88 -0
  80. package/dist/plugins/ai-chat/client/hooks/index.d.cts +1 -1
  81. package/dist/plugins/ai-chat/client/hooks/index.d.mts +1 -1
  82. package/dist/plugins/ai-chat/client/hooks/index.d.ts +1 -1
  83. package/dist/plugins/ai-chat/client/index.d.cts +2 -2
  84. package/dist/plugins/ai-chat/client/index.d.mts +2 -2
  85. package/dist/plugins/ai-chat/client/index.d.ts +2 -2
  86. package/dist/plugins/ai-chat/query-keys.d.cts +1 -1
  87. package/dist/plugins/ai-chat/query-keys.d.mts +1 -1
  88. package/dist/plugins/ai-chat/query-keys.d.ts +1 -1
  89. package/dist/plugins/blog/api/index.cjs +5 -0
  90. package/dist/plugins/blog/api/index.d.cts +19 -4
  91. package/dist/plugins/blog/api/index.d.mts +19 -4
  92. package/dist/plugins/blog/api/index.d.ts +19 -4
  93. package/dist/plugins/blog/api/index.mjs +2 -0
  94. package/dist/plugins/blog/client/hooks/index.d.cts +3 -3
  95. package/dist/plugins/blog/client/hooks/index.d.mts +3 -3
  96. package/dist/plugins/blog/client/hooks/index.d.ts +3 -3
  97. package/dist/plugins/blog/client/index.d.cts +1 -1
  98. package/dist/plugins/blog/client/index.d.mts +1 -1
  99. package/dist/plugins/blog/client/index.d.ts +1 -1
  100. package/dist/plugins/blog/query-keys.cjs +6 -5
  101. package/dist/plugins/blog/query-keys.d.cts +8 -387
  102. package/dist/plugins/blog/query-keys.d.mts +8 -387
  103. package/dist/plugins/blog/query-keys.d.ts +8 -387
  104. package/dist/plugins/blog/query-keys.mjs +6 -5
  105. package/dist/plugins/client/index.cjs +1 -0
  106. package/dist/plugins/client/index.d.cts +8 -1
  107. package/dist/plugins/client/index.d.mts +8 -1
  108. package/dist/plugins/client/index.d.ts +8 -1
  109. package/dist/plugins/client/index.mjs +1 -1
  110. package/dist/plugins/cms/api/index.cjs +8 -0
  111. package/dist/plugins/cms/api/index.d.cts +7 -219
  112. package/dist/plugins/cms/api/index.d.mts +7 -219
  113. package/dist/plugins/cms/api/index.d.ts +7 -219
  114. package/dist/plugins/cms/api/index.mjs +3 -1
  115. package/dist/plugins/cms/client/hooks/index.d.cts +1 -1
  116. package/dist/plugins/cms/client/hooks/index.d.mts +1 -1
  117. package/dist/plugins/cms/client/hooks/index.d.ts +1 -1
  118. package/dist/plugins/cms/query-keys.cjs +2 -1
  119. package/dist/plugins/cms/query-keys.d.cts +5 -9
  120. package/dist/plugins/cms/query-keys.d.mts +5 -9
  121. package/dist/plugins/cms/query-keys.d.ts +5 -9
  122. package/dist/plugins/cms/query-keys.mjs +2 -1
  123. package/dist/plugins/form-builder/api/index.cjs +6 -0
  124. package/dist/plugins/form-builder/api/index.d.cts +7 -211
  125. package/dist/plugins/form-builder/api/index.d.mts +7 -211
  126. package/dist/plugins/form-builder/api/index.d.ts +7 -211
  127. package/dist/plugins/form-builder/api/index.mjs +2 -1
  128. package/dist/plugins/form-builder/client/components/index.d.cts +1 -1
  129. package/dist/plugins/form-builder/client/components/index.d.mts +1 -1
  130. package/dist/plugins/form-builder/client/components/index.d.ts +1 -1
  131. package/dist/plugins/form-builder/client/hooks/index.d.cts +1 -1
  132. package/dist/plugins/form-builder/client/hooks/index.d.mts +1 -1
  133. package/dist/plugins/form-builder/client/hooks/index.d.ts +1 -1
  134. package/dist/plugins/form-builder/query-keys.cjs +3 -2
  135. package/dist/plugins/form-builder/query-keys.d.cts +6 -6
  136. package/dist/plugins/form-builder/query-keys.d.mts +6 -6
  137. package/dist/plugins/form-builder/query-keys.d.ts +6 -6
  138. package/dist/plugins/form-builder/query-keys.mjs +3 -2
  139. package/dist/plugins/kanban/api/index.cjs +10 -0
  140. package/dist/plugins/kanban/api/index.d.cts +17 -392
  141. package/dist/plugins/kanban/api/index.d.mts +17 -392
  142. package/dist/plugins/kanban/api/index.d.ts +17 -392
  143. package/dist/plugins/kanban/api/index.mjs +3 -0
  144. package/dist/plugins/kanban/client/components/index.d.cts +1 -1
  145. package/dist/plugins/kanban/client/components/index.d.mts +1 -1
  146. package/dist/plugins/kanban/client/components/index.d.ts +1 -1
  147. package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
  148. package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
  149. package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
  150. package/dist/plugins/kanban/client/index.d.cts +1 -1
  151. package/dist/plugins/kanban/client/index.d.mts +1 -1
  152. package/dist/plugins/kanban/client/index.d.ts +1 -1
  153. package/dist/plugins/kanban/query-keys.cjs +2 -9
  154. package/dist/plugins/kanban/query-keys.d.cts +4 -16
  155. package/dist/plugins/kanban/query-keys.d.mts +4 -16
  156. package/dist/plugins/kanban/query-keys.d.ts +4 -16
  157. package/dist/plugins/kanban/query-keys.mjs +2 -9
  158. package/dist/plugins/ui-builder/index.d.cts +1 -1
  159. package/dist/plugins/ui-builder/index.d.mts +1 -1
  160. package/dist/plugins/ui-builder/index.d.ts +1 -1
  161. package/dist/shared/stack.B7ONvlD_.d.mts +293 -0
  162. package/dist/shared/{stack.BeSm90va.d.ts → stack.BEn34wW6.d.ts} +60 -2
  163. package/dist/shared/stack.BUkC2EsZ.d.cts +327 -0
  164. package/dist/shared/{stack.DaOcgmrM.d.ts → stack.BV9hnvu4.d.cts} +31 -7
  165. package/dist/shared/{stack.DaOcgmrM.d.cts → stack.BV9hnvu4.d.mts} +31 -7
  166. package/dist/shared/{stack.DaOcgmrM.d.mts → stack.BV9hnvu4.d.ts} +31 -7
  167. package/dist/shared/stack.BepFXT3w.d.mts +500 -0
  168. package/dist/shared/stack.CL8ts1Mu.d.ts +419 -0
  169. package/dist/shared/{stack.CXjzTMsb.d.cts → stack.CVDTkMoO.d.cts} +7 -1
  170. package/dist/shared/{stack.CXjzTMsb.d.mts → stack.CVDTkMoO.d.mts} +7 -1
  171. package/dist/shared/{stack.CXjzTMsb.d.ts → stack.CVDTkMoO.d.ts} +7 -1
  172. package/dist/shared/stack.CczspVn2.d.mts +327 -0
  173. package/dist/shared/stack.CgWzG5jH.d.ts +500 -0
  174. package/dist/shared/stack.D3GB6wKv.d.cts +500 -0
  175. package/dist/shared/stack.DASmUVjX.d.ts +327 -0
  176. package/dist/shared/{stack.QD1y_7NY.d.cts → stack.DJaKVY7v.d.cts} +1 -1
  177. package/dist/shared/{stack.QD1y_7NY.d.mts → stack.DJaKVY7v.d.mts} +1 -1
  178. package/dist/shared/{stack.QD1y_7NY.d.ts → stack.DJaKVY7v.d.ts} +1 -1
  179. package/dist/shared/{stack.Dg09R0oB.d.mts → stack.DTDxgFj8.d.mts} +60 -2
  180. package/dist/shared/{stack.CMh_EdxW.d.cts → stack.DWoCZff7.d.cts} +60 -2
  181. package/dist/shared/{stack.CIrIsc-A.d.cts → stack.DdI5W6MB.d.cts} +7 -1
  182. package/dist/shared/{stack.CIrIsc-A.d.mts → stack.DdI5W6MB.d.mts} +7 -1
  183. package/dist/shared/{stack.CIrIsc-A.d.ts → stack.DdI5W6MB.d.ts} +7 -1
  184. package/dist/shared/stack.Dk5r4W1F.d.mts +419 -0
  185. package/dist/shared/stack.Kq2-QzOC.d.ts +293 -0
  186. package/dist/shared/stack.heOA9gzA.d.cts +419 -0
  187. package/dist/shared/stack.kcdnD4gA.d.cts +293 -0
  188. package/package.json +16 -3
  189. package/src/client/components/compose.tsx +7 -4
  190. package/src/plugins/ai-chat/api/page-tools.ts +111 -0
  191. package/src/plugins/ai-chat/api/plugin.ts +180 -9
  192. package/src/plugins/ai-chat/client/components/chat-input.tsx +2 -2
  193. package/src/plugins/ai-chat/client/components/chat-interface.tsx +154 -58
  194. package/src/plugins/ai-chat/client/components/chat-layout.tsx +166 -32
  195. package/src/plugins/ai-chat/client/components/chat-sidebar.tsx +1 -1
  196. package/src/plugins/ai-chat/client/context/page-ai-context.tsx +240 -0
  197. package/src/plugins/ai-chat/schemas.ts +16 -0
  198. package/src/plugins/blog/api/index.ts +2 -0
  199. package/src/plugins/blog/api/plugin.ts +85 -0
  200. package/src/plugins/blog/api/query-key-defs.ts +46 -0
  201. package/src/plugins/blog/api/serializers.ts +27 -0
  202. package/src/plugins/blog/client/components/forms/post-forms.tsx +29 -2
  203. package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +28 -0
  204. package/src/plugins/blog/client/components/pages/fill-blog-form-handler.ts +38 -0
  205. package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +33 -1
  206. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +20 -0
  207. package/src/plugins/blog/client/plugin.tsx +19 -0
  208. package/src/plugins/blog/query-keys.ts +5 -7
  209. package/src/plugins/client/index.ts +1 -1
  210. package/src/plugins/cms/api/getters.ts +24 -0
  211. package/src/plugins/cms/api/index.ts +14 -1
  212. package/src/plugins/cms/api/mutations.ts +84 -0
  213. package/src/plugins/cms/api/plugin.ts +114 -0
  214. package/src/plugins/cms/api/query-key-defs.ts +53 -0
  215. package/src/plugins/cms/api/serializers.ts +12 -0
  216. package/src/plugins/cms/client/plugin.tsx +19 -0
  217. package/src/plugins/cms/query-keys.ts +2 -1
  218. package/src/plugins/form-builder/api/getters.ts +23 -0
  219. package/src/plugins/form-builder/api/index.ts +15 -2
  220. package/src/plugins/form-builder/api/plugin.ts +91 -0
  221. package/src/plugins/form-builder/api/query-key-defs.ts +79 -0
  222. package/src/plugins/form-builder/api/serializers.ts +12 -0
  223. package/src/plugins/form-builder/client/plugin.tsx +19 -0
  224. package/src/plugins/form-builder/query-keys.ts +6 -2
  225. package/src/plugins/kanban/api/index.ts +9 -0
  226. package/src/plugins/kanban/api/mutations.ts +169 -0
  227. package/src/plugins/kanban/api/plugin.ts +61 -0
  228. package/src/plugins/kanban/api/query-key-defs.ts +54 -0
  229. package/src/plugins/kanban/api/serializers.ts +49 -0
  230. package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +4 -0
  231. package/src/plugins/kanban/client/plugin.tsx +13 -0
  232. package/src/plugins/kanban/query-keys.ts +2 -9
  233. package/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.tsx +132 -0
  234. package/src/plugins/utils.ts +19 -0
  235. package/dist/shared/{stack.BkYlUT_8.d.cts → stack.BQmuNl5p.d.cts} +6 -6
  236. package/dist/shared/{stack.BkYlUT_8.d.mts → stack.BQmuNl5p.d.mts} +6 -6
  237. package/dist/shared/{stack.BkYlUT_8.d.ts → stack.BQmuNl5p.d.ts} +6 -6
@@ -6,7 +6,57 @@ const db = require('../db.cjs');
6
6
  const utils = require('../utils.cjs');
7
7
  const schemas = require('../schemas.cjs');
8
8
  const getters = require('./getters.cjs');
9
+ const queryKeyDefs = require('./query-key-defs.cjs');
10
+ const serializers = require('./serializers.cjs');
9
11
 
12
+ function createBlogPrefetchForRoute(adapter) {
13
+ return async function prefetchForRoute(key, qc, params) {
14
+ switch (key) {
15
+ case "posts":
16
+ case "drafts": {
17
+ const published = key === "posts";
18
+ const [result, tags] = await Promise.all([
19
+ getters.getAllPosts(adapter, { published, limit: 10 }),
20
+ getters.getAllTags(adapter)
21
+ ]);
22
+ qc.setQueryData(queryKeyDefs.BLOG_QUERY_KEYS.postsList({ published, limit: 10 }), {
23
+ pages: [result.items.map(serializers.serializePost)],
24
+ pageParams: [0]
25
+ });
26
+ qc.setQueryData(queryKeyDefs.BLOG_QUERY_KEYS.tagsList(), tags.map(serializers.serializeTag));
27
+ break;
28
+ }
29
+ case "post":
30
+ case "editPost": {
31
+ const slug = params?.slug ?? "";
32
+ if (slug) {
33
+ const post = await getters.getPostBySlug(adapter, slug);
34
+ qc.setQueryData(
35
+ queryKeyDefs.BLOG_QUERY_KEYS.postDetail(slug),
36
+ post ? serializers.serializePost(post) : null
37
+ );
38
+ }
39
+ break;
40
+ }
41
+ case "tag": {
42
+ const tagSlug = params?.tagSlug ?? "";
43
+ const [result, tags] = await Promise.all([
44
+ getters.getAllPosts(adapter, { published: true, limit: 10, tagSlug }),
45
+ getters.getAllTags(adapter)
46
+ ]);
47
+ qc.setQueryData(
48
+ queryKeyDefs.BLOG_QUERY_KEYS.postsList({ published: true, limit: 10, tagSlug }),
49
+ {
50
+ pages: [result.items.map(serializers.serializePost)],
51
+ pageParams: [0]
52
+ }
53
+ );
54
+ qc.setQueryData(queryKeyDefs.BLOG_QUERY_KEYS.tagsList(), tags.map(serializers.serializeTag));
55
+ break;
56
+ }
57
+ }
58
+ };
59
+ }
10
60
  const PostListQuerySchema = z.z.object({
11
61
  slug: z.z.string().optional(),
12
62
  tagSlug: z.z.string().optional(),
@@ -29,7 +79,8 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
29
79
  api: (adapter) => ({
30
80
  getAllPosts: (params) => getters.getAllPosts(adapter, params),
31
81
  getPostBySlug: (slug) => getters.getPostBySlug(adapter, slug),
32
- getAllTags: () => getters.getAllTags(adapter)
82
+ getAllTags: () => getters.getAllTags(adapter),
83
+ prefetchForRoute: createBlogPrefetchForRoute(adapter)
33
84
  }),
34
85
  routes: (adapter) => {
35
86
  const findOrCreateTags = async (tagInputs) => {
@@ -4,7 +4,57 @@ import { blogSchema } from '../db.mjs';
4
4
  import { slugify } from '../utils.mjs';
5
5
  import { createPostSchema, updatePostSchema } from '../schemas.mjs';
6
6
  import { getAllTags, getPostBySlug, getAllPosts } from './getters.mjs';
7
+ import { BLOG_QUERY_KEYS } from './query-key-defs.mjs';
8
+ import { serializePost, serializeTag } from './serializers.mjs';
7
9
 
10
+ function createBlogPrefetchForRoute(adapter) {
11
+ return async function prefetchForRoute(key, qc, params) {
12
+ switch (key) {
13
+ case "posts":
14
+ case "drafts": {
15
+ const published = key === "posts";
16
+ const [result, tags] = await Promise.all([
17
+ getAllPosts(adapter, { published, limit: 10 }),
18
+ getAllTags(adapter)
19
+ ]);
20
+ qc.setQueryData(BLOG_QUERY_KEYS.postsList({ published, limit: 10 }), {
21
+ pages: [result.items.map(serializePost)],
22
+ pageParams: [0]
23
+ });
24
+ qc.setQueryData(BLOG_QUERY_KEYS.tagsList(), tags.map(serializeTag));
25
+ break;
26
+ }
27
+ case "post":
28
+ case "editPost": {
29
+ const slug = params?.slug ?? "";
30
+ if (slug) {
31
+ const post = await getPostBySlug(adapter, slug);
32
+ qc.setQueryData(
33
+ BLOG_QUERY_KEYS.postDetail(slug),
34
+ post ? serializePost(post) : null
35
+ );
36
+ }
37
+ break;
38
+ }
39
+ case "tag": {
40
+ const tagSlug = params?.tagSlug ?? "";
41
+ const [result, tags] = await Promise.all([
42
+ getAllPosts(adapter, { published: true, limit: 10, tagSlug }),
43
+ getAllTags(adapter)
44
+ ]);
45
+ qc.setQueryData(
46
+ BLOG_QUERY_KEYS.postsList({ published: true, limit: 10, tagSlug }),
47
+ {
48
+ pages: [result.items.map(serializePost)],
49
+ pageParams: [0]
50
+ }
51
+ );
52
+ qc.setQueryData(BLOG_QUERY_KEYS.tagsList(), tags.map(serializeTag));
53
+ break;
54
+ }
55
+ }
56
+ };
57
+ }
8
58
  const PostListQuerySchema = z.object({
9
59
  slug: z.string().optional(),
10
60
  tagSlug: z.string().optional(),
@@ -27,7 +77,8 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
27
77
  api: (adapter) => ({
28
78
  getAllPosts: (params) => getAllPosts(adapter, params),
29
79
  getPostBySlug: (slug) => getPostBySlug(adapter, slug),
30
- getAllTags: () => getAllTags(adapter)
80
+ getAllTags: () => getAllTags(adapter),
81
+ prefetchForRoute: createBlogPrefetchForRoute(adapter)
31
82
  }),
32
83
  routes: (adapter) => {
33
84
  const findOrCreateTags = async (tagInputs) => {
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ function postsListDiscriminator(params) {
4
+ return {
5
+ query: params.query !== void 0 && params.query.trim() === "" ? void 0 : params.query,
6
+ limit: params.limit ?? 10,
7
+ published: params.published,
8
+ tagSlug: params.tagSlug
9
+ };
10
+ }
11
+ const BLOG_QUERY_KEYS = {
12
+ postsList: (params) => ["posts", "list", postsListDiscriminator(params)],
13
+ postDetail: (slug) => ["posts", "detail", slug],
14
+ tagsList: () => ["tags", "list", "tags"]
15
+ };
16
+
17
+ exports.BLOG_QUERY_KEYS = BLOG_QUERY_KEYS;
18
+ exports.postsListDiscriminator = postsListDiscriminator;
@@ -0,0 +1,15 @@
1
+ function postsListDiscriminator(params) {
2
+ return {
3
+ query: params.query !== void 0 && params.query.trim() === "" ? void 0 : params.query,
4
+ limit: params.limit ?? 10,
5
+ published: params.published,
6
+ tagSlug: params.tagSlug
7
+ };
8
+ }
9
+ const BLOG_QUERY_KEYS = {
10
+ postsList: (params) => ["posts", "list", postsListDiscriminator(params)],
11
+ postDetail: (slug) => ["posts", "detail", slug],
12
+ tagsList: () => ["tags", "list", "tags"]
13
+ };
14
+
15
+ export { BLOG_QUERY_KEYS, postsListDiscriminator };
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ function serializeTag(tag) {
4
+ return {
5
+ ...tag,
6
+ createdAt: tag.createdAt.toISOString(),
7
+ updatedAt: tag.updatedAt.toISOString()
8
+ };
9
+ }
10
+ function serializePost(post) {
11
+ return {
12
+ ...post,
13
+ createdAt: post.createdAt.toISOString(),
14
+ updatedAt: post.updatedAt.toISOString(),
15
+ publishedAt: post.publishedAt?.toISOString(),
16
+ tags: post.tags.map(serializeTag)
17
+ };
18
+ }
19
+
20
+ exports.serializePost = serializePost;
21
+ exports.serializeTag = serializeTag;
@@ -0,0 +1,18 @@
1
+ function serializeTag(tag) {
2
+ return {
3
+ ...tag,
4
+ createdAt: tag.createdAt.toISOString(),
5
+ updatedAt: tag.updatedAt.toISOString()
6
+ };
7
+ }
8
+ function serializePost(post) {
9
+ return {
10
+ ...post,
11
+ createdAt: post.createdAt.toISOString(),
12
+ updatedAt: post.updatedAt.toISOString(),
13
+ publishedAt: post.publishedAt?.toISOString(),
14
+ tags: post.tags.map(serializeTag)
15
+ };
16
+ }
17
+
18
+ export { serializePost, serializeTag };
@@ -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
  }
@@ -64,6 +64,11 @@ function createPostsLoader(published, config) {
64
64
  }
65
65
  }
66
66
  } catch (error) {
67
+ if (client.isConnectionError(error)) {
68
+ console.warn(
69
+ "[btst/blog] route.loader() failed \u2014 no server running at build time. Use myStack.api.blog.prefetchForRoute() for SSG data prefetching."
70
+ );
71
+ }
67
72
  if (hooks?.onLoadError) {
68
73
  await hooks.onLoadError(error, context);
69
74
  }
@@ -112,6 +117,11 @@ function createPostLoader(slug, config, path) {
112
117
  }
113
118
  }
114
119
  } catch (error) {
120
+ if (client.isConnectionError(error)) {
121
+ console.warn(
122
+ "[btst/blog] route.loader() failed \u2014 no server running at build time. Use myStack.api.blog.prefetchForRoute() for SSG data prefetching."
123
+ );
124
+ }
115
125
  if (hooks?.onLoadError) {
116
126
  await hooks.onLoadError(error, context);
117
127
  }
@@ -190,6 +200,11 @@ function createTagLoader(tagSlug, config) {
190
200
  await hooks.onLoadError(error, context);
191
201
  }
192
202
  } catch (error) {
203
+ if (client.isConnectionError(error)) {
204
+ console.warn(
205
+ "[btst/blog] route.loader() failed \u2014 no server running at build time. Use myStack.api.blog.prefetchForRoute() for SSG data prefetching."
206
+ );
207
+ }
193
208
  if (hooks?.onLoadError) {
194
209
  await hooks.onLoadError(error, context);
195
210
  }