@btst/stack 1.0.1 → 1.1.1

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 (282) hide show
  1. package/README.md +156 -709
  2. package/dist/api/index.cjs +2 -1
  3. package/dist/api/index.d.cts +4 -3
  4. package/dist/api/index.d.mts +4 -3
  5. package/dist/api/index.d.ts +4 -3
  6. package/dist/api/index.mjs +1 -1
  7. package/dist/client/components/compose.cjs +68 -0
  8. package/dist/client/components/compose.mjs +65 -0
  9. package/dist/client/components/error-boundary.cjs +24 -0
  10. package/dist/client/components/error-boundary.mjs +22 -0
  11. package/dist/client/components/index.cjs +10 -0
  12. package/dist/client/components/index.d.cts +52 -0
  13. package/dist/client/components/index.d.mts +52 -0
  14. package/dist/client/components/index.d.ts +52 -0
  15. package/dist/client/components/index.mjs +2 -0
  16. package/dist/client/index.cjs +24 -5
  17. package/dist/client/index.d.cts +125 -8
  18. package/dist/client/index.d.mts +125 -8
  19. package/dist/client/index.d.ts +125 -8
  20. package/dist/client/index.mjs +21 -4
  21. package/dist/client/meta-utils.cjs +162 -0
  22. package/dist/client/meta-utils.mjs +160 -0
  23. package/dist/client/path-utils.cjs +15 -0
  24. package/dist/client/path-utils.mjs +13 -0
  25. package/dist/client/sitemap-utils.cjs +14 -0
  26. package/dist/client/sitemap-utils.mjs +12 -0
  27. package/dist/context/index.cjs +6 -63
  28. package/dist/context/index.d.cts +21 -24
  29. package/dist/context/index.d.mts +21 -24
  30. package/dist/context/index.d.ts +21 -24
  31. package/dist/context/index.mjs +1 -61
  32. package/dist/context/provider.cjs +51 -0
  33. package/dist/context/provider.mjs +46 -0
  34. package/dist/index.cjs +2 -3
  35. package/dist/index.d.cts +3 -2
  36. package/dist/index.d.mts +3 -2
  37. package/dist/index.d.ts +3 -2
  38. package/dist/index.mjs +1 -2
  39. package/dist/plugins/api/index.cjs +13 -0
  40. package/dist/plugins/api/index.d.cts +40 -0
  41. package/dist/plugins/api/index.d.mts +40 -0
  42. package/dist/plugins/api/index.d.ts +40 -0
  43. package/dist/plugins/api/index.mjs +8 -0
  44. package/dist/plugins/blog/api/index.cjs +11 -0
  45. package/dist/plugins/blog/api/index.d.cts +7 -0
  46. package/dist/plugins/blog/api/index.d.mts +7 -0
  47. package/dist/plugins/blog/api/index.d.ts +7 -0
  48. package/dist/plugins/blog/api/index.mjs +2 -0
  49. package/dist/plugins/blog/api/plugin.cjs +569 -0
  50. package/dist/plugins/blog/api/plugin.mjs +565 -0
  51. package/dist/plugins/blog/client/components/forms/image-field.cjs +133 -0
  52. package/dist/plugins/blog/client/components/forms/image-field.mjs +131 -0
  53. package/dist/plugins/blog/client/components/forms/markdown-editor-styles.css +30 -0
  54. package/dist/plugins/blog/client/components/forms/markdown-editor.cjs +106 -0
  55. package/dist/plugins/blog/client/components/forms/markdown-editor.mjs +104 -0
  56. package/dist/plugins/blog/client/components/forms/post-forms.cjs +401 -0
  57. package/dist/plugins/blog/client/components/forms/post-forms.mjs +398 -0
  58. package/dist/plugins/blog/client/components/forms/tags-multiselect.cjs +71 -0
  59. package/dist/plugins/blog/client/components/forms/tags-multiselect.mjs +65 -0
  60. package/dist/plugins/blog/client/components/index.cjs +17 -0
  61. package/dist/plugins/blog/client/components/index.d.cts +22 -0
  62. package/dist/plugins/blog/client/components/index.d.mts +22 -0
  63. package/dist/plugins/blog/client/components/index.d.ts +22 -0
  64. package/dist/plugins/blog/client/components/index.mjs +12 -0
  65. package/dist/plugins/blog/client/components/loading/form-page-skeleton.cjs +62 -0
  66. package/dist/plugins/blog/client/components/loading/form-page-skeleton.mjs +60 -0
  67. package/dist/plugins/blog/client/components/loading/index.cjs +20 -0
  68. package/dist/plugins/blog/client/components/loading/index.mjs +16 -0
  69. package/dist/plugins/blog/client/components/loading/list-page-skeleton.cjs +26 -0
  70. package/dist/plugins/blog/client/components/loading/list-page-skeleton.mjs +24 -0
  71. package/dist/plugins/blog/client/components/loading/page-header-skeleton.cjs +13 -0
  72. package/dist/plugins/blog/client/components/loading/page-header-skeleton.mjs +11 -0
  73. package/dist/plugins/blog/client/components/loading/post-card-skeleton.cjs +22 -0
  74. package/dist/plugins/blog/client/components/loading/post-card-skeleton.mjs +20 -0
  75. package/dist/plugins/blog/client/components/loading/post-page-skeleton.cjs +56 -0
  76. package/dist/plugins/blog/client/components/loading/post-page-skeleton.mjs +54 -0
  77. package/dist/plugins/blog/client/components/pages/404-page.cjs +19 -0
  78. package/dist/plugins/blog/client/components/pages/404-page.mjs +17 -0
  79. package/dist/plugins/blog/client/components/pages/edit-post-page.cjs +41 -0
  80. package/dist/plugins/blog/client/components/pages/edit-post-page.internal.cjs +57 -0
  81. package/dist/plugins/blog/client/components/pages/edit-post-page.internal.mjs +55 -0
  82. package/dist/plugins/blog/client/components/pages/edit-post-page.mjs +39 -0
  83. package/dist/plugins/blog/client/components/pages/home-page.cjs +41 -0
  84. package/dist/plugins/blog/client/components/pages/home-page.internal.cjs +61 -0
  85. package/dist/plugins/blog/client/components/pages/home-page.internal.mjs +59 -0
  86. package/dist/plugins/blog/client/components/pages/home-page.mjs +39 -0
  87. package/dist/plugins/blog/client/components/pages/new-post-page.cjs +37 -0
  88. package/dist/plugins/blog/client/components/pages/new-post-page.internal.cjs +53 -0
  89. package/dist/plugins/blog/client/components/pages/new-post-page.internal.mjs +51 -0
  90. package/dist/plugins/blog/client/components/pages/new-post-page.mjs +35 -0
  91. package/dist/plugins/blog/client/components/pages/post-page.cjs +39 -0
  92. package/dist/plugins/blog/client/components/pages/post-page.internal.cjs +101 -0
  93. package/dist/plugins/blog/client/components/pages/post-page.internal.mjs +99 -0
  94. package/dist/plugins/blog/client/components/pages/post-page.mjs +37 -0
  95. package/dist/plugins/blog/client/components/pages/tag-page.cjs +39 -0
  96. package/dist/plugins/blog/client/components/pages/tag-page.internal.cjs +61 -0
  97. package/dist/plugins/blog/client/components/pages/tag-page.internal.mjs +59 -0
  98. package/dist/plugins/blog/client/components/pages/tag-page.mjs +37 -0
  99. package/dist/plugins/blog/client/components/shared/better-blog-attribution.cjs +24 -0
  100. package/dist/plugins/blog/client/components/shared/better-blog-attribution.mjs +22 -0
  101. package/dist/plugins/blog/client/components/shared/default-error.cjs +18 -0
  102. package/dist/plugins/blog/client/components/shared/default-error.mjs +16 -0
  103. package/dist/plugins/blog/client/components/shared/defaults.cjs +13 -0
  104. package/dist/plugins/blog/client/components/shared/defaults.mjs +10 -0
  105. package/dist/plugins/blog/client/components/shared/empty-list.cjs +21 -0
  106. package/dist/plugins/blog/client/components/shared/empty-list.mjs +19 -0
  107. package/dist/plugins/blog/client/components/shared/error-placeholder.cjs +24 -0
  108. package/dist/plugins/blog/client/components/shared/error-placeholder.mjs +22 -0
  109. package/dist/plugins/blog/client/components/shared/highlight-text.cjs +53 -0
  110. package/dist/plugins/blog/client/components/shared/highlight-text.mjs +51 -0
  111. package/dist/plugins/blog/client/components/shared/markdown-content-styles.css +328 -0
  112. package/dist/plugins/blog/client/components/shared/markdown-content.cjs +324 -0
  113. package/dist/plugins/blog/client/components/shared/markdown-content.mjs +315 -0
  114. package/dist/plugins/blog/client/components/shared/on-this-page.cjs +161 -0
  115. package/dist/plugins/blog/client/components/shared/on-this-page.mjs +158 -0
  116. package/dist/plugins/blog/client/components/shared/page-header.cjs +40 -0
  117. package/dist/plugins/blog/client/components/shared/page-header.mjs +38 -0
  118. package/dist/plugins/blog/client/components/shared/page-layout.cjs +24 -0
  119. package/dist/plugins/blog/client/components/shared/page-layout.mjs +22 -0
  120. package/dist/plugins/blog/client/components/shared/page-wrapper.cjs +23 -0
  121. package/dist/plugins/blog/client/components/shared/page-wrapper.mjs +21 -0
  122. package/dist/plugins/blog/client/components/shared/post-card.cjs +279 -0
  123. package/dist/plugins/blog/client/components/shared/post-card.mjs +277 -0
  124. package/dist/plugins/blog/client/components/shared/post-navigation.cjs +74 -0
  125. package/dist/plugins/blog/client/components/shared/post-navigation.mjs +72 -0
  126. package/dist/plugins/blog/client/components/shared/posts-list.cjs +48 -0
  127. package/dist/plugins/blog/client/components/shared/posts-list.mjs +46 -0
  128. package/dist/plugins/blog/client/components/shared/recent-posts-carousel.cjs +59 -0
  129. package/dist/plugins/blog/client/components/shared/recent-posts-carousel.mjs +57 -0
  130. package/dist/plugins/blog/client/components/shared/search-input.cjs +136 -0
  131. package/dist/plugins/blog/client/components/shared/search-input.mjs +117 -0
  132. package/dist/plugins/blog/client/components/shared/search-modal.cjs +135 -0
  133. package/dist/plugins/blog/client/components/shared/search-modal.mjs +116 -0
  134. package/dist/plugins/blog/client/components/shared/tags-list.cjs +22 -0
  135. package/dist/plugins/blog/client/components/shared/tags-list.mjs +20 -0
  136. package/dist/plugins/blog/client/components/shared/use-route-lifecycle.cjs +50 -0
  137. package/dist/plugins/blog/client/components/shared/use-route-lifecycle.mjs +48 -0
  138. package/dist/plugins/blog/client/hooks/blog-hooks.cjs +380 -0
  139. package/dist/plugins/blog/client/hooks/blog-hooks.mjs +368 -0
  140. package/dist/plugins/blog/client/hooks/index.cjs +17 -0
  141. package/dist/plugins/blog/client/hooks/index.d.cts +150 -0
  142. package/dist/plugins/blog/client/hooks/index.d.mts +150 -0
  143. package/dist/plugins/blog/client/hooks/index.d.ts +150 -0
  144. package/dist/plugins/blog/client/hooks/index.mjs +1 -0
  145. package/dist/plugins/blog/client/hooks/use-debounce.cjs +16 -0
  146. package/dist/plugins/blog/client/hooks/use-debounce.mjs +14 -0
  147. package/dist/plugins/blog/client/index.cjs +7 -0
  148. package/dist/plugins/blog/client/index.d.cts +414 -0
  149. package/dist/plugins/blog/client/index.d.mts +414 -0
  150. package/dist/plugins/blog/client/index.d.ts +414 -0
  151. package/dist/plugins/blog/client/index.mjs +1 -0
  152. package/dist/plugins/blog/client/localization/blog-card.cjs +7 -0
  153. package/dist/plugins/blog/client/localization/blog-card.mjs +5 -0
  154. package/dist/plugins/blog/client/localization/blog-common.cjs +10 -0
  155. package/dist/plugins/blog/client/localization/blog-common.mjs +8 -0
  156. package/dist/plugins/blog/client/localization/blog-forms.cjs +40 -0
  157. package/dist/plugins/blog/client/localization/blog-forms.mjs +38 -0
  158. package/dist/plugins/blog/client/localization/blog-list.cjs +18 -0
  159. package/dist/plugins/blog/client/localization/blog-list.mjs +16 -0
  160. package/dist/plugins/blog/client/localization/blog-post.cjs +13 -0
  161. package/dist/plugins/blog/client/localization/blog-post.mjs +11 -0
  162. package/dist/plugins/blog/client/localization/index.cjs +17 -0
  163. package/dist/plugins/blog/client/localization/index.mjs +15 -0
  164. package/dist/plugins/blog/client/plugin.cjs +462 -0
  165. package/dist/plugins/blog/client/plugin.mjs +460 -0
  166. package/dist/plugins/blog/client.css +3 -0
  167. package/dist/plugins/blog/db.cjs +90 -0
  168. package/dist/plugins/blog/db.mjs +88 -0
  169. package/dist/plugins/blog/query-keys.cjs +181 -0
  170. package/dist/plugins/blog/query-keys.d.cts +530 -0
  171. package/dist/plugins/blog/query-keys.d.mts +530 -0
  172. package/dist/plugins/blog/query-keys.d.ts +530 -0
  173. package/dist/plugins/blog/query-keys.mjs +179 -0
  174. package/dist/plugins/blog/schemas.cjs +39 -0
  175. package/dist/plugins/blog/schemas.mjs +35 -0
  176. package/dist/plugins/blog/style.css +22 -0
  177. package/dist/plugins/blog/utils.cjs +97 -0
  178. package/dist/plugins/blog/utils.mjs +87 -0
  179. package/dist/plugins/client/index.cjs +15 -0
  180. package/dist/plugins/client/index.d.cts +57 -0
  181. package/dist/plugins/client/index.d.mts +57 -0
  182. package/dist/plugins/client/index.d.ts +57 -0
  183. package/dist/plugins/client/index.mjs +9 -0
  184. package/dist/{shared/stack.3OUyGp_E.mjs → plugins/utils.mjs} +1 -1
  185. package/dist/shared/{stack.DORw_1ps.d.cts → stack.ByOugz9d.d.cts} +17 -1
  186. package/dist/shared/{stack.DORw_1ps.d.mts → stack.ByOugz9d.d.mts} +17 -1
  187. package/dist/shared/{stack.DORw_1ps.d.ts → stack.ByOugz9d.d.ts} +17 -1
  188. package/dist/shared/stack.CoPoHVfV.d.cts +76 -0
  189. package/dist/shared/stack.CoPoHVfV.d.mts +76 -0
  190. package/dist/shared/stack.CoPoHVfV.d.ts +76 -0
  191. package/package.json +102 -14
  192. package/src/__tests__/plugins.test.tsx +539 -0
  193. package/src/__tests__/sitemap.test.ts +60 -0
  194. package/src/api/index.ts +75 -0
  195. package/src/client/components/compose.tsx +116 -0
  196. package/src/client/components/error-boundary.tsx +30 -0
  197. package/src/client/components/index.tsx +2 -0
  198. package/src/client/index.ts +109 -0
  199. package/src/client/meta-utils.ts +228 -0
  200. package/src/client/path-utils.ts +38 -0
  201. package/src/client/sitemap-utils.ts +46 -0
  202. package/src/context/index.ts +1 -0
  203. package/src/context/provider.tsx +157 -0
  204. package/src/index.ts +1 -0
  205. package/src/plugins/api/index.ts +50 -0
  206. package/src/plugins/blog/api/index.ts +2 -0
  207. package/src/plugins/blog/api/plugin.ts +759 -0
  208. package/src/plugins/blog/client/components/forms/image-field.tsx +165 -0
  209. package/src/plugins/blog/client/components/forms/markdown-editor-styles.css +30 -0
  210. package/src/plugins/blog/client/components/forms/markdown-editor.tsx +136 -0
  211. package/src/plugins/blog/client/components/forms/post-forms.tsx +531 -0
  212. package/src/plugins/blog/client/components/forms/tags-multiselect.tsx +79 -0
  213. package/src/plugins/blog/client/components/index.tsx +11 -0
  214. package/src/plugins/blog/client/components/loading/form-page-skeleton.tsx +75 -0
  215. package/src/plugins/blog/client/components/loading/index.tsx +27 -0
  216. package/src/plugins/blog/client/components/loading/list-page-skeleton.tsx +38 -0
  217. package/src/plugins/blog/client/components/loading/page-header-skeleton.tsx +10 -0
  218. package/src/plugins/blog/client/components/loading/post-card-skeleton.tsx +30 -0
  219. package/src/plugins/blog/client/components/loading/post-page-skeleton.tsx +75 -0
  220. package/src/plugins/blog/client/components/pages/404-page.tsx +23 -0
  221. package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +60 -0
  222. package/src/plugins/blog/client/components/pages/edit-post-page.tsx +40 -0
  223. package/src/plugins/blog/client/components/pages/home-page.internal.tsx +71 -0
  224. package/src/plugins/blog/client/components/pages/home-page.tsx +42 -0
  225. package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +59 -0
  226. package/src/plugins/blog/client/components/pages/new-post-page.tsx +36 -0
  227. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +142 -0
  228. package/src/plugins/blog/client/components/pages/post-page.tsx +38 -0
  229. package/src/plugins/blog/client/components/pages/tag-page.internal.tsx +74 -0
  230. package/src/plugins/blog/client/components/pages/tag-page.tsx +38 -0
  231. package/src/plugins/blog/client/components/shared/better-blog-attribution.tsx +19 -0
  232. package/src/plugins/blog/client/components/shared/default-error.tsx +20 -0
  233. package/src/plugins/blog/client/components/shared/defaults.tsx +9 -0
  234. package/src/plugins/blog/client/components/shared/empty-list.tsx +25 -0
  235. package/src/plugins/blog/client/components/shared/error-placeholder.tsx +20 -0
  236. package/src/plugins/blog/client/components/shared/highlight-text.tsx +80 -0
  237. package/src/plugins/blog/client/components/shared/markdown-content-styles.css +328 -0
  238. package/src/plugins/blog/client/components/shared/markdown-content.tsx +448 -0
  239. package/src/plugins/blog/client/components/shared/on-this-page.tsx +234 -0
  240. package/src/plugins/blog/client/components/shared/page-header.tsx +35 -0
  241. package/src/plugins/blog/client/components/shared/page-layout.tsx +23 -0
  242. package/src/plugins/blog/client/components/shared/page-wrapper.tsx +32 -0
  243. package/src/plugins/blog/client/components/shared/post-card.tsx +308 -0
  244. package/src/plugins/blog/client/components/shared/post-navigation.tsx +98 -0
  245. package/src/plugins/blog/client/components/shared/posts-list.tsx +67 -0
  246. package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +79 -0
  247. package/src/plugins/blog/client/components/shared/search-input.tsx +146 -0
  248. package/src/plugins/blog/client/components/shared/search-modal.tsx +162 -0
  249. package/src/plugins/blog/client/components/shared/tags-list.tsx +34 -0
  250. package/src/plugins/blog/client/components/shared/use-route-lifecycle.tsx +68 -0
  251. package/src/plugins/blog/client/hooks/blog-hooks.tsx +623 -0
  252. package/src/plugins/blog/client/hooks/index.tsx +1 -0
  253. package/src/plugins/blog/client/hooks/use-debounce.ts +43 -0
  254. package/src/plugins/blog/client/index.ts +9 -0
  255. package/src/plugins/blog/client/localization/blog-card.ts +3 -0
  256. package/src/plugins/blog/client/localization/blog-common.ts +7 -0
  257. package/src/plugins/blog/client/localization/blog-forms.ts +45 -0
  258. package/src/plugins/blog/client/localization/blog-list.ts +14 -0
  259. package/src/plugins/blog/client/localization/blog-post.ts +9 -0
  260. package/src/plugins/blog/client/localization/index.ts +15 -0
  261. package/src/plugins/blog/client/overrides.ts +123 -0
  262. package/src/plugins/blog/client/plugin.tsx +672 -0
  263. package/src/plugins/blog/client.css +3 -0
  264. package/src/plugins/blog/db.ts +90 -0
  265. package/src/plugins/blog/query-keys.ts +267 -0
  266. package/src/plugins/blog/schemas.ts +39 -0
  267. package/src/plugins/blog/style.css +22 -0
  268. package/src/plugins/blog/types.ts +37 -0
  269. package/src/plugins/blog/utils.ts +144 -0
  270. package/src/plugins/client/index.ts +53 -0
  271. package/src/plugins/index.ts +0 -0
  272. package/src/plugins/utils.ts +35 -0
  273. package/src/types.ts +209 -0
  274. package/dist/plugins/index.cjs +0 -15
  275. package/dist/plugins/index.d.cts +0 -64
  276. package/dist/plugins/index.d.mts +0 -64
  277. package/dist/plugins/index.d.ts +0 -64
  278. package/dist/plugins/index.mjs +0 -11
  279. package/dist/shared/stack.DrUAVfIH.d.cts +0 -17
  280. package/dist/shared/stack.DrUAVfIH.d.mts +0 -17
  281. package/dist/shared/stack.DrUAVfIH.d.ts +0 -17
  282. /package/dist/{shared/stack.CktCg4PJ.cjs → plugins/utils.cjs} +0 -0
@@ -0,0 +1,530 @@
1
+ import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
2
+ import * as better_call from 'better-call';
3
+ import { z } from 'zod';
4
+ import { c as createPostSchema, u as updatePostSchema, P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../shared/stack.CoPoHVfV.js';
5
+ import * as _tanstack_react_query from '@tanstack/react-query';
6
+ import { createApiClient } from '@btst/stack/plugins/client';
7
+
8
+ declare const PostListQuerySchema: z.ZodObject<{
9
+ slug: z.ZodOptional<z.ZodString>;
10
+ tagSlug: z.ZodOptional<z.ZodString>;
11
+ offset: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
12
+ limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
13
+ query: z.ZodOptional<z.ZodString>;
14
+ published: z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<boolean | undefined, string | undefined>>;
15
+ }, z.core.$strip>;
16
+ declare const NextPreviousPostsQuerySchema: z.ZodObject<{
17
+ date: z.ZodCoercedDate<unknown>;
18
+ }, z.core.$strip>;
19
+ /**
20
+ * Context passed to blog API hooks
21
+ */
22
+ interface BlogApiContext<TBody = any, TParams = any, TQuery = any> {
23
+ body?: TBody;
24
+ params?: TParams;
25
+ query?: TQuery;
26
+ request?: Request;
27
+ [key: string]: any;
28
+ }
29
+ /**
30
+ * Configuration hooks for blog backend plugin
31
+ * All hooks are optional and allow consumers to customize behavior
32
+ */
33
+ interface BlogBackendHooks {
34
+ onBeforeListPosts?: (filter: z.infer<typeof PostListQuerySchema>, context: BlogApiContext) => Promise<boolean> | boolean;
35
+ onBeforeCreatePost?: (data: z.infer<typeof createPostSchema>, context: BlogApiContext) => Promise<boolean> | boolean;
36
+ onBeforeUpdatePost?: (postId: string, data: z.infer<typeof updatePostSchema>, context: BlogApiContext) => Promise<boolean> | boolean;
37
+ onBeforeDeletePost?: (postId: string, context: BlogApiContext) => Promise<boolean> | boolean;
38
+ onPostsRead?: (posts: Post[], filter: z.infer<typeof PostListQuerySchema>, context: BlogApiContext) => Promise<void> | void;
39
+ onPostCreated?: (post: Post, context: BlogApiContext) => Promise<void> | void;
40
+ onPostUpdated?: (post: Post, context: BlogApiContext) => Promise<void> | void;
41
+ onPostDeleted?: (postId: string, context: BlogApiContext) => Promise<void> | void;
42
+ onListPostsError?: (error: Error, context: BlogApiContext) => Promise<void> | void;
43
+ onCreatePostError?: (error: Error, context: BlogApiContext) => Promise<void> | void;
44
+ onUpdatePostError?: (error: Error, context: BlogApiContext) => Promise<void> | void;
45
+ onDeletePostError?: (error: Error, context: BlogApiContext) => Promise<void> | void;
46
+ }
47
+ /**
48
+ * Blog backend plugin
49
+ * Provides API endpoints for managing blog posts
50
+ * Uses better-db adapter for database operations
51
+ *
52
+ * @param hooks - Optional configuration hooks for customizing plugin behavior
53
+ */
54
+ declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugins_api.BackendPlugin<{
55
+ readonly listPosts: {
56
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
57
+ body?: undefined;
58
+ } & {
59
+ method?: "GET" | undefined;
60
+ } & {
61
+ query: {
62
+ slug?: string | undefined;
63
+ tagSlug?: string | undefined;
64
+ offset?: unknown;
65
+ limit?: unknown;
66
+ query?: string | undefined;
67
+ published?: string | undefined;
68
+ };
69
+ } & {
70
+ params?: Record<string, any>;
71
+ } & {
72
+ request?: Request;
73
+ } & {
74
+ headers?: HeadersInit;
75
+ } & {
76
+ asResponse?: boolean;
77
+ returnHeaders?: boolean;
78
+ use?: better_call.Middleware[];
79
+ path?: string;
80
+ } & {
81
+ asResponse?: AsResponse | undefined;
82
+ returnHeaders?: ReturnHeaders | undefined;
83
+ }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
84
+ headers: Headers;
85
+ response: {
86
+ tags: Tag[];
87
+ id: string;
88
+ authorId?: string;
89
+ defaultLocale?: string;
90
+ slug: string;
91
+ title: string;
92
+ content: string;
93
+ excerpt: string;
94
+ image?: string;
95
+ published: boolean;
96
+ status?: "DRAFT" | "PUBLISHED";
97
+ publishedAt?: Date;
98
+ createdAt: Date;
99
+ updatedAt: Date;
100
+ }[];
101
+ } : {
102
+ tags: Tag[];
103
+ id: string;
104
+ authorId?: string;
105
+ defaultLocale?: string;
106
+ slug: string;
107
+ title: string;
108
+ content: string;
109
+ excerpt: string;
110
+ image?: string;
111
+ published: boolean;
112
+ status?: "DRAFT" | "PUBLISHED";
113
+ publishedAt?: Date;
114
+ createdAt: Date;
115
+ updatedAt: Date;
116
+ }[]>;
117
+ options: {
118
+ method: "GET";
119
+ query: z.ZodObject<{
120
+ slug: z.ZodOptional<z.ZodString>;
121
+ tagSlug: z.ZodOptional<z.ZodString>;
122
+ offset: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
123
+ limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
124
+ query: z.ZodOptional<z.ZodString>;
125
+ published: z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<boolean | undefined, string | undefined>>;
126
+ }, z.core.$strip>;
127
+ };
128
+ path: "/posts";
129
+ };
130
+ readonly createPost: {
131
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
132
+ body: {
133
+ title: string;
134
+ content: string;
135
+ excerpt: string;
136
+ slug?: string | undefined;
137
+ published?: boolean | undefined;
138
+ createdAt?: unknown;
139
+ publishedAt?: unknown;
140
+ updatedAt?: unknown;
141
+ image?: string | undefined;
142
+ tags?: ({
143
+ name: string;
144
+ } | {
145
+ id: string;
146
+ name: string;
147
+ slug: string;
148
+ })[] | undefined;
149
+ };
150
+ } & {
151
+ method?: "POST" | undefined;
152
+ } & {
153
+ query?: Record<string, any> | undefined;
154
+ } & {
155
+ params?: Record<string, any>;
156
+ } & {
157
+ request?: Request;
158
+ } & {
159
+ headers?: HeadersInit;
160
+ } & {
161
+ asResponse?: boolean;
162
+ returnHeaders?: boolean;
163
+ use?: better_call.Middleware[];
164
+ path?: string;
165
+ } & {
166
+ asResponse?: AsResponse | undefined;
167
+ returnHeaders?: ReturnHeaders | undefined;
168
+ }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
169
+ headers: Headers;
170
+ response: Post;
171
+ } : Post>;
172
+ options: {
173
+ method: "POST";
174
+ body: z.ZodObject<{
175
+ slug: z.ZodOptional<z.ZodString>;
176
+ published: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
177
+ createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
178
+ publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
179
+ updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
180
+ title: z.ZodString;
181
+ content: z.ZodString;
182
+ excerpt: z.ZodString;
183
+ image: z.ZodOptional<z.ZodString>;
184
+ tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
185
+ name: z.ZodString;
186
+ }, z.core.$strip>, z.ZodObject<{
187
+ id: z.ZodString;
188
+ name: z.ZodString;
189
+ slug: z.ZodString;
190
+ }, z.core.$strip>]>>>>;
191
+ }, z.core.$strip>;
192
+ };
193
+ path: "/posts";
194
+ };
195
+ readonly updatePost: {
196
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
197
+ body: {
198
+ title: string;
199
+ content: string;
200
+ excerpt: string;
201
+ slug: string;
202
+ id: string;
203
+ publishedAt?: unknown;
204
+ createdAt?: unknown;
205
+ updatedAt?: unknown;
206
+ image?: string | undefined;
207
+ published?: boolean | undefined;
208
+ tags?: ({
209
+ name: string;
210
+ } | {
211
+ id: string;
212
+ name: string;
213
+ slug: string;
214
+ })[] | undefined;
215
+ };
216
+ } & {
217
+ method?: "PUT" | undefined;
218
+ } & {
219
+ query?: Record<string, any> | undefined;
220
+ } & {
221
+ params: {
222
+ id: string;
223
+ };
224
+ } & {
225
+ request?: Request;
226
+ } & {
227
+ headers?: HeadersInit;
228
+ } & {
229
+ asResponse?: boolean;
230
+ returnHeaders?: boolean;
231
+ use?: better_call.Middleware[];
232
+ path?: string;
233
+ } & {
234
+ asResponse?: AsResponse | undefined;
235
+ returnHeaders?: ReturnHeaders | undefined;
236
+ }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
237
+ headers: Headers;
238
+ response: Post;
239
+ } : Post>;
240
+ options: {
241
+ method: "PUT";
242
+ body: z.ZodObject<{
243
+ publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
244
+ createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
245
+ updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
246
+ title: z.ZodString;
247
+ content: z.ZodString;
248
+ excerpt: z.ZodString;
249
+ image: z.ZodOptional<z.ZodString>;
250
+ published: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
251
+ slug: z.ZodString;
252
+ tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
253
+ name: z.ZodString;
254
+ }, z.core.$strip>, z.ZodObject<{
255
+ id: z.ZodString;
256
+ name: z.ZodString;
257
+ slug: z.ZodString;
258
+ }, z.core.$strip>]>>>>;
259
+ id: z.ZodString;
260
+ }, z.core.$strip>;
261
+ };
262
+ path: "/posts/:id";
263
+ };
264
+ readonly deletePost: {
265
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
266
+ body?: undefined;
267
+ } & {
268
+ method?: "DELETE" | undefined;
269
+ } & {
270
+ query?: Record<string, any> | undefined;
271
+ } & {
272
+ params: {
273
+ id: string;
274
+ };
275
+ } & {
276
+ request?: Request;
277
+ } & {
278
+ headers?: HeadersInit;
279
+ } & {
280
+ asResponse?: boolean;
281
+ returnHeaders?: boolean;
282
+ use?: better_call.Middleware[];
283
+ path?: string;
284
+ } & {
285
+ asResponse?: AsResponse | undefined;
286
+ returnHeaders?: ReturnHeaders | undefined;
287
+ }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
288
+ headers: Headers;
289
+ response: {
290
+ success: boolean;
291
+ };
292
+ } : {
293
+ success: boolean;
294
+ }>;
295
+ options: {
296
+ method: "DELETE";
297
+ };
298
+ path: "/posts/:id";
299
+ };
300
+ readonly getNextPreviousPosts: {
301
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
302
+ body?: undefined;
303
+ } & {
304
+ method?: "GET" | undefined;
305
+ } & {
306
+ query: {
307
+ date: unknown;
308
+ };
309
+ } & {
310
+ params?: Record<string, any>;
311
+ } & {
312
+ request?: Request;
313
+ } & {
314
+ headers?: HeadersInit;
315
+ } & {
316
+ asResponse?: boolean;
317
+ returnHeaders?: boolean;
318
+ use?: better_call.Middleware[];
319
+ path?: string;
320
+ } & {
321
+ asResponse?: AsResponse | undefined;
322
+ returnHeaders?: ReturnHeaders | undefined;
323
+ }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
324
+ headers: Headers;
325
+ response: {
326
+ previous: {
327
+ tags: Tag[];
328
+ id: string;
329
+ authorId?: string;
330
+ defaultLocale?: string;
331
+ slug: string;
332
+ title: string;
333
+ content: string;
334
+ excerpt: string;
335
+ image?: string;
336
+ published: boolean;
337
+ status?: "DRAFT" | "PUBLISHED";
338
+ publishedAt?: Date;
339
+ createdAt: Date;
340
+ updatedAt: Date;
341
+ } | null;
342
+ next: {
343
+ tags: Tag[];
344
+ id: string;
345
+ authorId?: string;
346
+ defaultLocale?: string;
347
+ slug: string;
348
+ title: string;
349
+ content: string;
350
+ excerpt: string;
351
+ image?: string;
352
+ published: boolean;
353
+ status?: "DRAFT" | "PUBLISHED";
354
+ publishedAt?: Date;
355
+ createdAt: Date;
356
+ updatedAt: Date;
357
+ } | null;
358
+ };
359
+ } : {
360
+ previous: {
361
+ tags: Tag[];
362
+ id: string;
363
+ authorId?: string;
364
+ defaultLocale?: string;
365
+ slug: string;
366
+ title: string;
367
+ content: string;
368
+ excerpt: string;
369
+ image?: string;
370
+ published: boolean;
371
+ status?: "DRAFT" | "PUBLISHED";
372
+ publishedAt?: Date;
373
+ createdAt: Date;
374
+ updatedAt: Date;
375
+ } | null;
376
+ next: {
377
+ tags: Tag[];
378
+ id: string;
379
+ authorId?: string;
380
+ defaultLocale?: string;
381
+ slug: string;
382
+ title: string;
383
+ content: string;
384
+ excerpt: string;
385
+ image?: string;
386
+ published: boolean;
387
+ status?: "DRAFT" | "PUBLISHED";
388
+ publishedAt?: Date;
389
+ createdAt: Date;
390
+ updatedAt: Date;
391
+ } | null;
392
+ }>;
393
+ options: {
394
+ method: "GET";
395
+ query: z.ZodObject<{
396
+ date: z.ZodCoercedDate<unknown>;
397
+ }, z.core.$strip>;
398
+ };
399
+ path: "/posts/next-previous";
400
+ };
401
+ readonly listTags: {
402
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0?: ({
403
+ body?: undefined;
404
+ } & {
405
+ method?: "GET" | undefined;
406
+ } & {
407
+ query?: Record<string, any> | undefined;
408
+ } & {
409
+ params?: Record<string, any>;
410
+ } & {
411
+ request?: Request;
412
+ } & {
413
+ headers?: HeadersInit;
414
+ } & {
415
+ asResponse?: boolean;
416
+ returnHeaders?: boolean;
417
+ use?: better_call.Middleware[];
418
+ path?: string;
419
+ } & {
420
+ asResponse?: AsResponse | undefined;
421
+ returnHeaders?: ReturnHeaders | undefined;
422
+ }) | undefined): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
423
+ headers: Headers;
424
+ response: Tag[];
425
+ } : Tag[]>;
426
+ options: {
427
+ method: "GET";
428
+ };
429
+ path: "/tags";
430
+ };
431
+ }>;
432
+ type BlogApiRouter = ReturnType<ReturnType<typeof blogBackendPlugin>["routes"]>;
433
+
434
+ interface PostsListParams {
435
+ query?: string;
436
+ limit?: number;
437
+ published?: boolean;
438
+ tagSlug?: string;
439
+ }
440
+ declare function createBlogQueryKeys(client: ReturnType<typeof createApiClient<BlogApiRouter>>): {
441
+ posts: {
442
+ _def: readonly ["posts"];
443
+ } & {
444
+ list: ((params?: PostsListParams | undefined) => Omit<Omit<{
445
+ queryKey: readonly ["posts", "list", {
446
+ query: string | undefined;
447
+ limit: number;
448
+ published: boolean;
449
+ tagSlug: string | undefined;
450
+ }];
451
+ queryFn: _tanstack_react_query.QueryFunction<unknown, readonly ["posts", "list", {
452
+ query: string | undefined;
453
+ limit: number;
454
+ published: boolean;
455
+ tagSlug: string | undefined;
456
+ }]>;
457
+ }, "queryFn"> & {
458
+ _def: readonly ["posts", "list"];
459
+ }, "_def">) & {
460
+ _def: readonly ["posts", "list"];
461
+ };
462
+ detail: ((slug: string) => Omit<{
463
+ queryKey: readonly ["posts", "detail", string];
464
+ queryFn: _tanstack_react_query.QueryFunction<SerializedPost | null, readonly ["posts", "detail", string]>;
465
+ } & {
466
+ _def: readonly ["posts", "detail"];
467
+ }, "_def">) & {
468
+ _def: readonly ["posts", "detail"];
469
+ };
470
+ nextPrevious: ((date: string | Date) => Omit<{
471
+ queryKey: readonly ["posts", "nextPrevious", string, string | Date];
472
+ queryFn: _tanstack_react_query.QueryFunction<{
473
+ previous: SerializedPost | null;
474
+ next: SerializedPost | null;
475
+ }, readonly ["posts", "nextPrevious", string, string | Date]>;
476
+ } & {
477
+ _def: readonly ["posts", "nextPrevious"];
478
+ }, "_def">) & {
479
+ _def: readonly ["posts", "nextPrevious"];
480
+ };
481
+ recent: ((params?: {
482
+ limit?: number;
483
+ excludeSlug?: string;
484
+ } | undefined) => Omit<{
485
+ queryKey: readonly ["posts", "recent", string, {
486
+ limit?: number;
487
+ excludeSlug?: string;
488
+ } | undefined];
489
+ queryFn: _tanstack_react_query.QueryFunction<SerializedPost[], readonly ["posts", "recent", string, {
490
+ limit?: number;
491
+ excludeSlug?: string;
492
+ } | undefined]>;
493
+ } & {
494
+ _def: readonly ["posts", "recent"];
495
+ }, "_def">) & {
496
+ _def: readonly ["posts", "recent"];
497
+ };
498
+ };
499
+ drafts: {
500
+ _def: readonly ["drafts"];
501
+ } & {
502
+ list: ((params?: PostsListParams | undefined) => Omit<Omit<{
503
+ queryKey: readonly ["drafts", "list", {
504
+ limit?: number | undefined;
505
+ }];
506
+ queryFn: _tanstack_react_query.QueryFunction<unknown, readonly ["drafts", "list", {
507
+ limit?: number | undefined;
508
+ }]>;
509
+ }, "queryFn"> & {
510
+ _def: readonly ["drafts", "list"];
511
+ }, "_def">) & {
512
+ _def: readonly ["drafts", "list"];
513
+ };
514
+ };
515
+ tags: {
516
+ _def: readonly ["tags"];
517
+ } & {
518
+ list: (() => Omit<{
519
+ queryKey: readonly ["tags", "list", string];
520
+ queryFn: _tanstack_react_query.QueryFunction<SerializedTag[], readonly ["tags", "list", string]>;
521
+ } & {
522
+ _def: readonly ["tags", "list"];
523
+ }, "_def">) & {
524
+ _def: readonly ["tags", "list"];
525
+ };
526
+ };
527
+ };
528
+
529
+ export { NextPreviousPostsQuerySchema as N, PostListQuerySchema as P, blogBackendPlugin as b, createBlogQueryKeys };
530
+ export type { BlogApiContext as B, BlogBackendHooks as a, BlogApiRouter as c };
@@ -0,0 +1,179 @@
1
+ import { mergeQueryKeys, createQueryKeys } from '@lukemorales/query-key-factory';
2
+
3
+ function isErrorResponse(response) {
4
+ return typeof response === "object" && response !== null && "error" in response && response.error !== null && response.error !== void 0;
5
+ }
6
+ function toError(error) {
7
+ if (error instanceof Error) {
8
+ return error;
9
+ }
10
+ if (typeof error === "object" && error !== null) {
11
+ const errorObj = error;
12
+ const message = (typeof errorObj.message === "string" ? errorObj.message : null) || (typeof errorObj.error === "string" ? errorObj.error : null) || JSON.stringify(error);
13
+ const err = new Error(message);
14
+ Object.assign(err, error);
15
+ return err;
16
+ }
17
+ return new Error(String(error));
18
+ }
19
+ function createBlogQueryKeys(client) {
20
+ const posts = createPostsQueries(client);
21
+ const drafts = createDraftsQueries(client);
22
+ const tags = createTagsQueries(client);
23
+ return mergeQueryKeys(posts, drafts, tags);
24
+ }
25
+ function createPostsQueries(client) {
26
+ return createQueryKeys("posts", {
27
+ list: (params) => ({
28
+ queryKey: [
29
+ {
30
+ query: params?.query !== void 0 && params?.query?.trim() === "" ? void 0 : params?.query,
31
+ limit: params?.limit ?? 10,
32
+ published: params?.published ?? true,
33
+ tagSlug: params?.tagSlug
34
+ }
35
+ ],
36
+ queryFn: async ({ pageParam }) => {
37
+ try {
38
+ const response = await client("/posts", {
39
+ method: "GET",
40
+ query: {
41
+ query: params?.query,
42
+ offset: pageParam ?? 0,
43
+ limit: params?.limit ?? 10,
44
+ published: params?.published !== void 0 ? params.published ? "true" : "false" : void 0,
45
+ tagSlug: params?.tagSlug
46
+ }
47
+ });
48
+ if (isErrorResponse(response)) {
49
+ const errorResponse = response;
50
+ throw toError(errorResponse.error);
51
+ }
52
+ return response.data ?? [];
53
+ } catch (error) {
54
+ throw error;
55
+ }
56
+ }
57
+ }),
58
+ // Simplified detail query
59
+ detail: (slug) => ({
60
+ queryKey: [slug],
61
+ queryFn: async () => {
62
+ if (!slug) return null;
63
+ try {
64
+ const response = await client("/posts", {
65
+ method: "GET",
66
+ query: { slug, limit: 1 }
67
+ });
68
+ if (isErrorResponse(response)) {
69
+ const errorResponse = response;
70
+ throw toError(errorResponse.error);
71
+ }
72
+ const dataResponse = response;
73
+ return dataResponse.data?.[0] ?? null;
74
+ } catch (error) {
75
+ throw error;
76
+ }
77
+ }
78
+ }),
79
+ // Next/previous posts query
80
+ nextPrevious: (date) => ({
81
+ queryKey: ["nextPrevious", date],
82
+ queryFn: async () => {
83
+ const dateValue = typeof date === "string" ? new Date(date) : date;
84
+ const response = await client("/posts/next-previous", {
85
+ method: "GET",
86
+ query: {
87
+ date: dateValue.toISOString()
88
+ }
89
+ });
90
+ if (isErrorResponse(response)) {
91
+ const errorResponse = response;
92
+ throw toError(errorResponse.error);
93
+ }
94
+ const dataResponse = response;
95
+ return dataResponse.data;
96
+ }
97
+ }),
98
+ // Recent posts query (separate from main list to avoid cache conflicts)
99
+ recent: (params) => ({
100
+ queryKey: ["recent", params],
101
+ queryFn: async () => {
102
+ try {
103
+ const response = await client("/posts", {
104
+ method: "GET",
105
+ query: {
106
+ limit: params?.limit ?? 5,
107
+ published: "true"
108
+ }
109
+ });
110
+ if (isErrorResponse(response)) {
111
+ const errorResponse = response;
112
+ throw toError(errorResponse.error);
113
+ }
114
+ let posts = response.data ?? [];
115
+ if (params?.excludeSlug) {
116
+ posts = posts.filter((post) => post.slug !== params.excludeSlug);
117
+ }
118
+ return posts;
119
+ } catch (error) {
120
+ throw error;
121
+ }
122
+ }
123
+ })
124
+ });
125
+ }
126
+ function createDraftsQueries(client) {
127
+ return createQueryKeys("drafts", {
128
+ list: (params) => ({
129
+ queryKey: [
130
+ {
131
+ ...params?.limit && { limit: params.limit }
132
+ }
133
+ ],
134
+ queryFn: async ({ pageParam }) => {
135
+ try {
136
+ const response = await client("/posts", {
137
+ method: "GET",
138
+ query: {
139
+ query: params?.query,
140
+ offset: pageParam ?? 0,
141
+ limit: params?.limit ?? 10,
142
+ published: "false"
143
+ }
144
+ });
145
+ if (isErrorResponse(response)) {
146
+ const errorResponse = response;
147
+ throw toError(errorResponse.error);
148
+ }
149
+ return response.data ?? [];
150
+ } catch (error) {
151
+ throw error;
152
+ }
153
+ }
154
+ })
155
+ });
156
+ }
157
+ function createTagsQueries(client) {
158
+ return createQueryKeys("tags", {
159
+ list: () => ({
160
+ queryKey: ["tags"],
161
+ queryFn: async () => {
162
+ try {
163
+ const response = await client("/tags", {
164
+ method: "GET"
165
+ });
166
+ if (isErrorResponse(response)) {
167
+ const errorResponse = response;
168
+ throw toError(errorResponse.error);
169
+ }
170
+ return response.data ?? [];
171
+ } catch (error) {
172
+ throw error;
173
+ }
174
+ }
175
+ })
176
+ });
177
+ }
178
+
179
+ export { createBlogQueryKeys };