@btst/stack 2.1.0 → 2.3.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 (229) hide show
  1. package/dist/api/index.cjs +9 -1
  2. package/dist/api/index.d.cts +4 -4
  3. package/dist/api/index.d.mts +4 -4
  4. package/dist/api/index.d.ts +4 -4
  5. package/dist/api/index.mjs +9 -1
  6. package/dist/client/index.d.cts +2 -2
  7. package/dist/client/index.d.mts +2 -2
  8. package/dist/client/index.d.ts +2 -2
  9. package/dist/index.d.cts +1 -1
  10. package/dist/index.d.mts +1 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/packages/stack/src/plugins/ai-chat/api/getters.cjs +42 -0
  13. package/dist/packages/stack/src/plugins/ai-chat/api/getters.mjs +39 -0
  14. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.cjs +5 -0
  15. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +5 -0
  16. package/dist/packages/stack/src/plugins/blog/api/getters.cjs +131 -0
  17. package/dist/packages/stack/src/plugins/blog/api/getters.mjs +127 -0
  18. package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +60 -107
  19. package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +60 -107
  20. package/dist/packages/stack/src/plugins/blog/api/query-key-defs.cjs +18 -0
  21. package/dist/packages/stack/src/plugins/blog/api/query-key-defs.mjs +15 -0
  22. package/dist/packages/stack/src/plugins/blog/api/serializers.cjs +21 -0
  23. package/dist/packages/stack/src/plugins/blog/api/serializers.mjs +18 -0
  24. package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +16 -1
  25. package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +17 -2
  26. package/dist/packages/stack/src/plugins/cms/api/getters.cjs +156 -0
  27. package/dist/packages/stack/src/plugins/cms/api/getters.mjs +147 -0
  28. package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +624 -617
  29. package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +623 -616
  30. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.cjs +29 -0
  31. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.mjs +26 -0
  32. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.cjs +1 -1
  33. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.mjs +1 -1
  34. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.cjs +6 -3
  35. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.mjs +6 -3
  36. package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +15 -0
  37. package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +16 -1
  38. package/dist/packages/stack/src/plugins/form-builder/api/getters.cjs +120 -0
  39. package/dist/packages/stack/src/plugins/form-builder/api/getters.mjs +112 -0
  40. package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +75 -86
  41. package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +71 -82
  42. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.cjs +37 -0
  43. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.mjs +33 -0
  44. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.cjs +1 -1
  45. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.mjs +1 -1
  46. package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +15 -0
  47. package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +16 -1
  48. package/dist/packages/stack/src/plugins/kanban/api/getters.cjs +84 -0
  49. package/dist/packages/stack/src/plugins/kanban/api/getters.mjs +81 -0
  50. package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +37 -123
  51. package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +37 -123
  52. package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.cjs +26 -0
  53. package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.mjs +23 -0
  54. package/dist/packages/stack/src/plugins/kanban/api/serializers.cjs +30 -0
  55. package/dist/packages/stack/src/plugins/kanban/api/serializers.mjs +26 -0
  56. package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +11 -1
  57. package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +12 -2
  58. package/dist/packages/stack/src/plugins/utils.cjs +6 -0
  59. package/dist/packages/stack/src/plugins/utils.mjs +6 -1
  60. package/dist/plugins/ai-chat/api/index.cjs +3 -0
  61. package/dist/plugins/ai-chat/api/index.d.cts +27 -4
  62. package/dist/plugins/ai-chat/api/index.d.mts +27 -4
  63. package/dist/plugins/ai-chat/api/index.d.ts +27 -4
  64. package/dist/plugins/ai-chat/api/index.mjs +1 -0
  65. package/dist/plugins/ai-chat/client/hooks/index.d.cts +2 -2
  66. package/dist/plugins/ai-chat/client/hooks/index.d.mts +2 -2
  67. package/dist/plugins/ai-chat/client/hooks/index.d.ts +2 -2
  68. package/dist/plugins/ai-chat/query-keys.d.cts +9 -284
  69. package/dist/plugins/ai-chat/query-keys.d.mts +9 -284
  70. package/dist/plugins/ai-chat/query-keys.d.ts +9 -284
  71. package/dist/plugins/api/index.d.cts +4 -3
  72. package/dist/plugins/api/index.d.mts +4 -3
  73. package/dist/plugins/api/index.d.ts +4 -3
  74. package/dist/plugins/blog/api/index.cjs +9 -0
  75. package/dist/plugins/blog/api/index.d.cts +20 -4
  76. package/dist/plugins/blog/api/index.d.mts +20 -4
  77. package/dist/plugins/blog/api/index.d.ts +20 -4
  78. package/dist/plugins/blog/api/index.mjs +3 -0
  79. package/dist/plugins/blog/client/hooks/index.d.cts +5 -5
  80. package/dist/plugins/blog/client/hooks/index.d.mts +5 -5
  81. package/dist/plugins/blog/client/hooks/index.d.ts +5 -5
  82. package/dist/plugins/blog/client/index.d.cts +1 -1
  83. package/dist/plugins/blog/client/index.d.mts +1 -1
  84. package/dist/plugins/blog/client/index.d.ts +1 -1
  85. package/dist/plugins/blog/query-keys.cjs +13 -9
  86. package/dist/plugins/blog/query-keys.d.cts +8 -333
  87. package/dist/plugins/blog/query-keys.d.mts +8 -333
  88. package/dist/plugins/blog/query-keys.d.ts +8 -333
  89. package/dist/plugins/blog/query-keys.mjs +13 -9
  90. package/dist/plugins/client/index.cjs +1 -0
  91. package/dist/plugins/client/index.d.cts +10 -3
  92. package/dist/plugins/client/index.d.mts +10 -3
  93. package/dist/plugins/client/index.d.ts +10 -3
  94. package/dist/plugins/client/index.mjs +1 -1
  95. package/dist/plugins/cms/api/index.cjs +10 -0
  96. package/dist/plugins/cms/api/index.d.cts +7 -163
  97. package/dist/plugins/cms/api/index.d.mts +7 -163
  98. package/dist/plugins/cms/api/index.d.ts +7 -163
  99. package/dist/plugins/cms/api/index.mjs +2 -0
  100. package/dist/plugins/cms/client/hooks/index.d.cts +1 -1
  101. package/dist/plugins/cms/client/hooks/index.d.mts +1 -1
  102. package/dist/plugins/cms/client/hooks/index.d.ts +1 -1
  103. package/dist/plugins/cms/query-keys.cjs +2 -1
  104. package/dist/plugins/cms/query-keys.d.cts +6 -9
  105. package/dist/plugins/cms/query-keys.d.mts +6 -9
  106. package/dist/plugins/cms/query-keys.d.ts +6 -9
  107. package/dist/plugins/cms/query-keys.mjs +2 -1
  108. package/dist/plugins/form-builder/api/index.cjs +10 -0
  109. package/dist/plugins/form-builder/api/index.d.cts +7 -141
  110. package/dist/plugins/form-builder/api/index.d.mts +7 -141
  111. package/dist/plugins/form-builder/api/index.d.ts +7 -141
  112. package/dist/plugins/form-builder/api/index.mjs +2 -0
  113. package/dist/plugins/form-builder/client/components/index.d.cts +1 -1
  114. package/dist/plugins/form-builder/client/components/index.d.mts +1 -1
  115. package/dist/plugins/form-builder/client/components/index.d.ts +1 -1
  116. package/dist/plugins/form-builder/client/hooks/index.d.cts +1 -1
  117. package/dist/plugins/form-builder/client/hooks/index.d.mts +1 -1
  118. package/dist/plugins/form-builder/client/hooks/index.d.ts +1 -1
  119. package/dist/plugins/form-builder/query-keys.cjs +3 -2
  120. package/dist/plugins/form-builder/query-keys.d.cts +7 -6
  121. package/dist/plugins/form-builder/query-keys.d.mts +7 -6
  122. package/dist/plugins/form-builder/query-keys.d.ts +7 -6
  123. package/dist/plugins/form-builder/query-keys.mjs +3 -2
  124. package/dist/plugins/kanban/api/index.cjs +9 -0
  125. package/dist/plugins/kanban/api/index.d.cts +17 -395
  126. package/dist/plugins/kanban/api/index.d.mts +17 -395
  127. package/dist/plugins/kanban/api/index.d.ts +17 -395
  128. package/dist/plugins/kanban/api/index.mjs +3 -0
  129. package/dist/plugins/kanban/client/components/index.d.cts +1 -1
  130. package/dist/plugins/kanban/client/components/index.d.mts +1 -1
  131. package/dist/plugins/kanban/client/components/index.d.ts +1 -1
  132. package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
  133. package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
  134. package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
  135. package/dist/plugins/kanban/client/index.d.cts +1 -1
  136. package/dist/plugins/kanban/client/index.d.mts +1 -1
  137. package/dist/plugins/kanban/client/index.d.ts +1 -1
  138. package/dist/plugins/kanban/query-keys.cjs +6 -12
  139. package/dist/plugins/kanban/query-keys.d.cts +5 -16
  140. package/dist/plugins/kanban/query-keys.d.mts +5 -16
  141. package/dist/plugins/kanban/query-keys.d.ts +5 -16
  142. package/dist/plugins/kanban/query-keys.mjs +6 -12
  143. package/dist/plugins/open-api/api/index.d.cts +2 -2
  144. package/dist/plugins/open-api/api/index.d.mts +2 -2
  145. package/dist/plugins/open-api/api/index.d.ts +2 -2
  146. package/dist/plugins/route-docs/client/index.d.cts +1 -1
  147. package/dist/plugins/route-docs/client/index.d.mts +1 -1
  148. package/dist/plugins/route-docs/client/index.d.ts +1 -1
  149. package/dist/plugins/ui-builder/index.d.cts +1 -1
  150. package/dist/plugins/ui-builder/index.d.mts +1 -1
  151. package/dist/plugins/ui-builder/index.d.ts +1 -1
  152. package/dist/shared/{stack.BoA0xkJv.d.cts → stack.7n9Y_u7N.d.cts} +33 -7
  153. package/dist/shared/{stack.BoA0xkJv.d.mts → stack.7n9Y_u7N.d.mts} +33 -7
  154. package/dist/shared/{stack.BoA0xkJv.d.ts → stack.7n9Y_u7N.d.ts} +33 -7
  155. package/dist/shared/stack.B1EeBt1b.d.ts +297 -0
  156. package/dist/shared/stack.BIXEI6v_.d.mts +419 -0
  157. package/dist/shared/stack.BKfolAyK.d.ts +419 -0
  158. package/dist/shared/stack.BeSm90va.d.ts +289 -0
  159. package/dist/shared/stack.BpolpQpf.d.cts +445 -0
  160. package/dist/shared/stack.C5dtIncc.d.mts +293 -0
  161. package/dist/shared/stack.CIP6QS9l.d.ts +293 -0
  162. package/dist/shared/stack.CMh_EdxW.d.cts +289 -0
  163. package/dist/shared/stack.CP68pFEH.d.mts +297 -0
  164. package/dist/shared/{stack.BsXokfNh.d.mts → stack.CVDTkMoO.d.cts} +8 -2
  165. package/dist/shared/{stack.BsXokfNh.d.ts → stack.CVDTkMoO.d.mts} +8 -2
  166. package/dist/shared/{stack.BsXokfNh.d.cts → stack.CVDTkMoO.d.ts} +8 -2
  167. package/dist/shared/{stack.DKDMI-QO.d.mts → stack.DJaKVY7v.d.cts} +7 -1
  168. package/dist/shared/{stack.DKDMI-QO.d.ts → stack.DJaKVY7v.d.mts} +7 -1
  169. package/dist/shared/{stack.DKDMI-QO.d.cts → stack.DJaKVY7v.d.ts} +7 -1
  170. package/dist/shared/{stack.DzH_wcvr.d.mts → stack.DdI5W6MB.d.cts} +9 -3
  171. package/dist/shared/{stack.DzH_wcvr.d.ts → stack.DdI5W6MB.d.mts} +9 -3
  172. package/dist/shared/{stack.DzH_wcvr.d.cts → stack.DdI5W6MB.d.ts} +9 -3
  173. package/dist/shared/stack.Dg09R0oB.d.mts +289 -0
  174. package/dist/shared/stack.Dw0Ly2TM.d.cts +293 -0
  175. package/dist/shared/stack.IdtKDRka.d.cts +297 -0
  176. package/dist/shared/stack.TIBF2AOx.d.ts +445 -0
  177. package/dist/shared/stack.rTy7-wQU.d.mts +445 -0
  178. package/dist/shared/stack.snB1EDP7.d.cts +419 -0
  179. package/package.json +3 -3
  180. package/src/__tests__/stack-api.test.ts +118 -0
  181. package/src/api/index.ts +15 -1
  182. package/src/plugins/ai-chat/__tests__/getters.test.ts +109 -0
  183. package/src/plugins/ai-chat/api/getters.ts +71 -0
  184. package/src/plugins/ai-chat/api/index.ts +1 -0
  185. package/src/plugins/ai-chat/api/plugin.ts +8 -0
  186. package/src/plugins/api/index.ts +3 -1
  187. package/src/plugins/blog/__tests__/getters.test.ts +540 -0
  188. package/src/plugins/blog/api/getters.ts +243 -0
  189. package/src/plugins/blog/api/index.ts +9 -0
  190. package/src/plugins/blog/api/plugin.ts +98 -141
  191. package/src/plugins/blog/api/query-key-defs.ts +46 -0
  192. package/src/plugins/blog/api/serializers.ts +27 -0
  193. package/src/plugins/blog/client/plugin.tsx +21 -1
  194. package/src/plugins/blog/query-keys.ts +21 -20
  195. package/src/plugins/client/index.ts +1 -1
  196. package/src/plugins/cms/__tests__/getters.test.ts +206 -0
  197. package/src/plugins/cms/api/getters.ts +268 -0
  198. package/src/plugins/cms/api/index.ts +15 -1
  199. package/src/plugins/cms/api/plugin.ts +151 -150
  200. package/src/plugins/cms/api/query-key-defs.ts +53 -0
  201. package/src/plugins/cms/api/serializers.ts +12 -0
  202. package/src/plugins/cms/client/components/pages/content-editor-page.internal.tsx +1 -1
  203. package/src/plugins/cms/client/hooks/cms-hooks.tsx +3 -0
  204. package/src/plugins/cms/client/plugin.tsx +19 -0
  205. package/src/plugins/cms/query-keys.ts +2 -1
  206. package/src/plugins/cms/types.ts +1 -1
  207. package/src/plugins/form-builder/__tests__/getters.test.ts +159 -0
  208. package/src/plugins/form-builder/api/getters.ts +226 -0
  209. package/src/plugins/form-builder/api/index.ts +15 -1
  210. package/src/plugins/form-builder/api/plugin.ts +107 -109
  211. package/src/plugins/form-builder/api/query-key-defs.ts +79 -0
  212. package/src/plugins/form-builder/api/serializers.ts +12 -0
  213. package/src/plugins/form-builder/client/components/pages/submissions-page.internal.tsx +1 -1
  214. package/src/plugins/form-builder/client/plugin.tsx +19 -0
  215. package/src/plugins/form-builder/query-keys.ts +6 -2
  216. package/src/plugins/form-builder/types.ts +2 -2
  217. package/src/plugins/kanban/__tests__/getters.test.ts +172 -0
  218. package/src/plugins/kanban/api/getters.ts +149 -0
  219. package/src/plugins/kanban/api/index.ts +4 -0
  220. package/src/plugins/kanban/api/plugin.ts +65 -146
  221. package/src/plugins/kanban/api/query-key-defs.ts +54 -0
  222. package/src/plugins/kanban/api/serializers.ts +49 -0
  223. package/src/plugins/kanban/client/plugin.tsx +15 -1
  224. package/src/plugins/kanban/query-keys.ts +10 -14
  225. package/src/plugins/utils.ts +19 -0
  226. package/src/types.ts +44 -5
  227. package/dist/shared/{stack.CbuN2zVV.d.cts → stack.CBON0dWL.d.cts} +7 -7
  228. package/dist/shared/{stack.CbuN2zVV.d.mts → stack.CBON0dWL.d.mts} +7 -7
  229. package/dist/shared/{stack.CbuN2zVV.d.ts → stack.CBON0dWL.d.ts} +7 -7
@@ -5,7 +5,58 @@ const z = require('zod');
5
5
  const db = require('../db.cjs');
6
6
  const utils = require('../utils.cjs');
7
7
  const schemas = require('../schemas.cjs');
8
+ const getters = require('./getters.cjs');
9
+ const queryKeyDefs = require('./query-key-defs.cjs');
10
+ const serializers = require('./serializers.cjs');
8
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
+ }
9
60
  const PostListQuerySchema = z.z.object({
10
61
  slug: z.z.string().optional(),
11
62
  tagSlug: z.z.string().optional(),
@@ -25,6 +76,12 @@ const NextPreviousPostsQuerySchema = z.z.object({
25
76
  const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
26
77
  name: "blog",
27
78
  dbPlugin: db.blogSchema,
79
+ api: (adapter) => ({
80
+ getAllPosts: (params) => getters.getAllPosts(adapter, params),
81
+ getPostBySlug: (slug) => getters.getPostBySlug(adapter, slug),
82
+ getAllTags: () => getters.getAllTags(adapter),
83
+ prefetchForRoute: createBlogPrefetchForRoute(adapter)
84
+ }),
28
85
  routes: (adapter) => {
29
86
  const findOrCreateTags = async (tagInputs) => {
30
87
  if (tagInputs.length === 0) return [];
@@ -105,111 +162,9 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
105
162
  });
106
163
  }
107
164
  }
108
- let tagFilterPostIds = null;
109
- if (query.tagSlug) {
110
- const tag = await adapter.findOne({
111
- model: "tag",
112
- where: [
113
- {
114
- field: "slug",
115
- value: query.tagSlug,
116
- operator: "eq"
117
- }
118
- ]
119
- });
120
- if (!tag) {
121
- return [];
122
- }
123
- const postTags = await adapter.findMany({
124
- model: "postTag",
125
- where: [
126
- {
127
- field: "tagId",
128
- value: tag.id,
129
- operator: "eq"
130
- }
131
- ]
132
- });
133
- tagFilterPostIds = new Set(postTags.map((pt) => pt.postId));
134
- if (tagFilterPostIds.size === 0) {
135
- return [];
136
- }
137
- }
138
- const whereConditions = [];
139
- if (query.published !== void 0) {
140
- whereConditions.push({
141
- field: "published",
142
- value: query.published,
143
- operator: "eq"
144
- });
145
- }
146
- if (query.slug) {
147
- whereConditions.push({
148
- field: "slug",
149
- value: query.slug,
150
- operator: "eq"
151
- });
152
- }
153
- const posts = await adapter.findMany({
154
- model: "post",
155
- limit: query.query || query.tagSlug ? void 0 : query.limit ?? 10,
156
- offset: query.query || query.tagSlug ? void 0 : query.offset ?? 0,
157
- where: whereConditions,
158
- sortBy: {
159
- field: "createdAt",
160
- direction: "desc"
161
- },
162
- join: {
163
- postTag: true
164
- }
165
- });
166
- const tagIds = /* @__PURE__ */ new Set();
167
- for (const post of posts) {
168
- if (post.postTag) {
169
- for (const pt of post.postTag) {
170
- tagIds.add(pt.tagId);
171
- }
172
- }
173
- }
174
- const tags = tagIds.size > 0 ? await adapter.findMany({
175
- model: "tag"
176
- }) : [];
177
- const tagMap = /* @__PURE__ */ new Map();
178
- for (const tag of tags) {
179
- if (tagIds.has(tag.id)) {
180
- tagMap.set(tag.id, tag);
181
- }
182
- }
183
- let result = posts.map((post) => {
184
- const postTags = (post.postTag || []).map((pt) => {
185
- const tag = tagMap.get(pt.tagId);
186
- return tag ? { ...tag } : void 0;
187
- }).filter((tag) => tag !== void 0);
188
- const { postTag: _, ...postWithoutJoin } = post;
189
- return {
190
- ...postWithoutJoin,
191
- tags: postTags
192
- };
193
- });
194
- if (tagFilterPostIds) {
195
- result = result.filter((post) => tagFilterPostIds.has(post.id));
196
- }
197
- if (query.query) {
198
- const searchLower = query.query.toLowerCase();
199
- result = result.filter((post) => {
200
- const titleMatch = post.title?.toLowerCase().includes(searchLower);
201
- const contentMatch = post.content?.toLowerCase().includes(searchLower);
202
- const excerptMatch = post.excerpt?.toLowerCase().includes(searchLower);
203
- return titleMatch || contentMatch || excerptMatch;
204
- });
205
- }
206
- if (query.tagSlug || query.query) {
207
- const offset = query.offset ?? 0;
208
- const limit = query.limit ?? 10;
209
- result = result.slice(offset, offset + limit);
210
- }
165
+ const result = await getters.getAllPosts(adapter, query);
211
166
  if (hooks?.onPostsRead) {
212
- await hooks.onPostsRead(result, query, context);
167
+ await hooks.onPostsRead(result.items, query, context);
213
168
  }
214
169
  return result;
215
170
  } catch (error) {
@@ -552,9 +507,7 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
552
507
  method: "GET"
553
508
  },
554
509
  async () => {
555
- return await adapter.findMany({
556
- model: "tag"
557
- });
510
+ return await getters.getAllTags(adapter);
558
511
  }
559
512
  );
560
513
  return {
@@ -3,7 +3,58 @@ import { z } from 'zod';
3
3
  import { blogSchema } from '../db.mjs';
4
4
  import { slugify } from '../utils.mjs';
5
5
  import { createPostSchema, updatePostSchema } from '../schemas.mjs';
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';
6
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
+ }
7
58
  const PostListQuerySchema = z.object({
8
59
  slug: z.string().optional(),
9
60
  tagSlug: z.string().optional(),
@@ -23,6 +74,12 @@ const NextPreviousPostsQuerySchema = z.object({
23
74
  const blogBackendPlugin = (hooks) => defineBackendPlugin({
24
75
  name: "blog",
25
76
  dbPlugin: blogSchema,
77
+ api: (adapter) => ({
78
+ getAllPosts: (params) => getAllPosts(adapter, params),
79
+ getPostBySlug: (slug) => getPostBySlug(adapter, slug),
80
+ getAllTags: () => getAllTags(adapter),
81
+ prefetchForRoute: createBlogPrefetchForRoute(adapter)
82
+ }),
26
83
  routes: (adapter) => {
27
84
  const findOrCreateTags = async (tagInputs) => {
28
85
  if (tagInputs.length === 0) return [];
@@ -103,111 +160,9 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
103
160
  });
104
161
  }
105
162
  }
106
- let tagFilterPostIds = null;
107
- if (query.tagSlug) {
108
- const tag = await adapter.findOne({
109
- model: "tag",
110
- where: [
111
- {
112
- field: "slug",
113
- value: query.tagSlug,
114
- operator: "eq"
115
- }
116
- ]
117
- });
118
- if (!tag) {
119
- return [];
120
- }
121
- const postTags = await adapter.findMany({
122
- model: "postTag",
123
- where: [
124
- {
125
- field: "tagId",
126
- value: tag.id,
127
- operator: "eq"
128
- }
129
- ]
130
- });
131
- tagFilterPostIds = new Set(postTags.map((pt) => pt.postId));
132
- if (tagFilterPostIds.size === 0) {
133
- return [];
134
- }
135
- }
136
- const whereConditions = [];
137
- if (query.published !== void 0) {
138
- whereConditions.push({
139
- field: "published",
140
- value: query.published,
141
- operator: "eq"
142
- });
143
- }
144
- if (query.slug) {
145
- whereConditions.push({
146
- field: "slug",
147
- value: query.slug,
148
- operator: "eq"
149
- });
150
- }
151
- const posts = await adapter.findMany({
152
- model: "post",
153
- limit: query.query || query.tagSlug ? void 0 : query.limit ?? 10,
154
- offset: query.query || query.tagSlug ? void 0 : query.offset ?? 0,
155
- where: whereConditions,
156
- sortBy: {
157
- field: "createdAt",
158
- direction: "desc"
159
- },
160
- join: {
161
- postTag: true
162
- }
163
- });
164
- const tagIds = /* @__PURE__ */ new Set();
165
- for (const post of posts) {
166
- if (post.postTag) {
167
- for (const pt of post.postTag) {
168
- tagIds.add(pt.tagId);
169
- }
170
- }
171
- }
172
- const tags = tagIds.size > 0 ? await adapter.findMany({
173
- model: "tag"
174
- }) : [];
175
- const tagMap = /* @__PURE__ */ new Map();
176
- for (const tag of tags) {
177
- if (tagIds.has(tag.id)) {
178
- tagMap.set(tag.id, tag);
179
- }
180
- }
181
- let result = posts.map((post) => {
182
- const postTags = (post.postTag || []).map((pt) => {
183
- const tag = tagMap.get(pt.tagId);
184
- return tag ? { ...tag } : void 0;
185
- }).filter((tag) => tag !== void 0);
186
- const { postTag: _, ...postWithoutJoin } = post;
187
- return {
188
- ...postWithoutJoin,
189
- tags: postTags
190
- };
191
- });
192
- if (tagFilterPostIds) {
193
- result = result.filter((post) => tagFilterPostIds.has(post.id));
194
- }
195
- if (query.query) {
196
- const searchLower = query.query.toLowerCase();
197
- result = result.filter((post) => {
198
- const titleMatch = post.title?.toLowerCase().includes(searchLower);
199
- const contentMatch = post.content?.toLowerCase().includes(searchLower);
200
- const excerptMatch = post.excerpt?.toLowerCase().includes(searchLower);
201
- return titleMatch || contentMatch || excerptMatch;
202
- });
203
- }
204
- if (query.tagSlug || query.query) {
205
- const offset = query.offset ?? 0;
206
- const limit = query.limit ?? 10;
207
- result = result.slice(offset, offset + limit);
208
- }
163
+ const result = await getAllPosts(adapter, query);
209
164
  if (hooks?.onPostsRead) {
210
- await hooks.onPostsRead(result, query, context);
165
+ await hooks.onPostsRead(result.items, query, context);
211
166
  }
212
167
  return result;
213
168
  } catch (error) {
@@ -550,9 +505,7 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
550
505
  method: "GET"
551
506
  },
552
507
  async () => {
553
- return await adapter.findMany({
554
- model: "tag"
555
- });
508
+ return await getAllTags(adapter);
556
509
  }
557
510
  );
558
511
  return {
@@ -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 };
@@ -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
  }
@@ -472,7 +487,7 @@ const blogClientPlugin = (config) => client.defineClientPlugin({
472
487
  published: "true"
473
488
  }
474
489
  });
475
- const page = res.data ?? [];
490
+ const page = res.data?.items ?? [];
476
491
  posts.push(...page);
477
492
  if (page.length < limit) break;
478
493
  offset += limit;
@@ -1,5 +1,5 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { defineClientPlugin, createApiClient } from '@btst/stack/plugins/client';
2
+ import { defineClientPlugin, createApiClient, 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';
@@ -62,6 +62,11 @@ function createPostsLoader(published, config) {
62
62
  }
63
63
  }
64
64
  } catch (error) {
65
+ if (isConnectionError(error)) {
66
+ console.warn(
67
+ "[btst/blog] route.loader() failed \u2014 no server running at build time. Use myStack.api.blog.prefetchForRoute() for SSG data prefetching."
68
+ );
69
+ }
65
70
  if (hooks?.onLoadError) {
66
71
  await hooks.onLoadError(error, context);
67
72
  }
@@ -110,6 +115,11 @@ function createPostLoader(slug, config, path) {
110
115
  }
111
116
  }
112
117
  } catch (error) {
118
+ if (isConnectionError(error)) {
119
+ console.warn(
120
+ "[btst/blog] route.loader() failed \u2014 no server running at build time. Use myStack.api.blog.prefetchForRoute() for SSG data prefetching."
121
+ );
122
+ }
113
123
  if (hooks?.onLoadError) {
114
124
  await hooks.onLoadError(error, context);
115
125
  }
@@ -188,6 +198,11 @@ function createTagLoader(tagSlug, config) {
188
198
  await hooks.onLoadError(error, context);
189
199
  }
190
200
  } catch (error) {
201
+ if (isConnectionError(error)) {
202
+ console.warn(
203
+ "[btst/blog] route.loader() failed \u2014 no server running at build time. Use myStack.api.blog.prefetchForRoute() for SSG data prefetching."
204
+ );
205
+ }
191
206
  if (hooks?.onLoadError) {
192
207
  await hooks.onLoadError(error, context);
193
208
  }
@@ -470,7 +485,7 @@ const blogClientPlugin = (config) => defineClientPlugin({
470
485
  published: "true"
471
486
  }
472
487
  });
473
- const page = res.data ?? [];
488
+ const page = res.data?.items ?? [];
474
489
  posts.push(...page);
475
490
  if (page.length < limit) break;
476
491
  offset += limit;