@btst/stack 1.0.0 → 1.1.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 (279) hide show
  1. package/README.md +237 -2
  2. package/dist/api/index.cjs +2 -2
  3. package/dist/api/index.d.cts +2 -2
  4. package/dist/api/index.d.mts +2 -2
  5. package/dist/api/index.d.ts +2 -2
  6. package/dist/api/index.mjs +2 -2
  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 +21 -16
  17. package/dist/client/index.d.cts +102 -14
  18. package/dist/client/index.d.mts +102 -14
  19. package/dist/client/index.d.ts +102 -14
  20. package/dist/client/index.mjs +19 -10
  21. package/dist/client/meta-utils.cjs +162 -0
  22. package/dist/client/meta-utils.mjs +160 -0
  23. package/dist/client/sitemap-utils.cjs +14 -0
  24. package/dist/client/sitemap-utils.mjs +12 -0
  25. package/dist/context/index.cjs +6 -51
  26. package/dist/context/index.d.cts +26 -26
  27. package/dist/context/index.d.mts +26 -26
  28. package/dist/context/index.d.ts +26 -26
  29. package/dist/context/index.mjs +1 -50
  30. package/dist/context/provider.cjs +51 -0
  31. package/dist/context/provider.mjs +46 -0
  32. package/dist/index.cjs +0 -2
  33. package/dist/index.d.cts +1 -1
  34. package/dist/index.d.mts +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.mjs +0 -2
  37. package/dist/plugins/api/index.cjs +15 -0
  38. package/dist/plugins/api/index.d.cts +41 -0
  39. package/dist/plugins/api/index.d.mts +41 -0
  40. package/dist/plugins/api/index.d.ts +41 -0
  41. package/dist/plugins/api/index.mjs +9 -0
  42. package/dist/plugins/blog/api/index.cjs +11 -0
  43. package/dist/plugins/blog/api/index.d.cts +7 -0
  44. package/dist/plugins/blog/api/index.d.mts +7 -0
  45. package/dist/plugins/blog/api/index.d.ts +7 -0
  46. package/dist/plugins/blog/api/index.mjs +2 -0
  47. package/dist/plugins/blog/api/plugin.cjs +569 -0
  48. package/dist/plugins/blog/api/plugin.mjs +565 -0
  49. package/dist/plugins/blog/client/components/forms/image-field.cjs +133 -0
  50. package/dist/plugins/blog/client/components/forms/image-field.mjs +131 -0
  51. package/dist/plugins/blog/client/components/forms/markdown-editor-styles.css +30 -0
  52. package/dist/plugins/blog/client/components/forms/markdown-editor.cjs +106 -0
  53. package/dist/plugins/blog/client/components/forms/markdown-editor.mjs +104 -0
  54. package/dist/plugins/blog/client/components/forms/post-forms.cjs +401 -0
  55. package/dist/plugins/blog/client/components/forms/post-forms.mjs +398 -0
  56. package/dist/plugins/blog/client/components/forms/tags-multiselect.cjs +71 -0
  57. package/dist/plugins/blog/client/components/forms/tags-multiselect.mjs +65 -0
  58. package/dist/plugins/blog/client/components/index.cjs +17 -0
  59. package/dist/plugins/blog/client/components/index.d.cts +22 -0
  60. package/dist/plugins/blog/client/components/index.d.mts +22 -0
  61. package/dist/plugins/blog/client/components/index.d.ts +22 -0
  62. package/dist/plugins/blog/client/components/index.mjs +12 -0
  63. package/dist/plugins/blog/client/components/loading/form-page-skeleton.cjs +62 -0
  64. package/dist/plugins/blog/client/components/loading/form-page-skeleton.mjs +60 -0
  65. package/dist/plugins/blog/client/components/loading/index.cjs +20 -0
  66. package/dist/plugins/blog/client/components/loading/index.mjs +16 -0
  67. package/dist/plugins/blog/client/components/loading/list-page-skeleton.cjs +26 -0
  68. package/dist/plugins/blog/client/components/loading/list-page-skeleton.mjs +24 -0
  69. package/dist/plugins/blog/client/components/loading/page-header-skeleton.cjs +13 -0
  70. package/dist/plugins/blog/client/components/loading/page-header-skeleton.mjs +11 -0
  71. package/dist/plugins/blog/client/components/loading/post-card-skeleton.cjs +22 -0
  72. package/dist/plugins/blog/client/components/loading/post-card-skeleton.mjs +20 -0
  73. package/dist/plugins/blog/client/components/loading/post-page-skeleton.cjs +56 -0
  74. package/dist/plugins/blog/client/components/loading/post-page-skeleton.mjs +54 -0
  75. package/dist/plugins/blog/client/components/pages/404-page.cjs +19 -0
  76. package/dist/plugins/blog/client/components/pages/404-page.mjs +17 -0
  77. package/dist/plugins/blog/client/components/pages/edit-post-page.cjs +41 -0
  78. package/dist/plugins/blog/client/components/pages/edit-post-page.internal.cjs +57 -0
  79. package/dist/plugins/blog/client/components/pages/edit-post-page.internal.mjs +55 -0
  80. package/dist/plugins/blog/client/components/pages/edit-post-page.mjs +39 -0
  81. package/dist/plugins/blog/client/components/pages/home-page.cjs +41 -0
  82. package/dist/plugins/blog/client/components/pages/home-page.internal.cjs +61 -0
  83. package/dist/plugins/blog/client/components/pages/home-page.internal.mjs +59 -0
  84. package/dist/plugins/blog/client/components/pages/home-page.mjs +39 -0
  85. package/dist/plugins/blog/client/components/pages/new-post-page.cjs +37 -0
  86. package/dist/plugins/blog/client/components/pages/new-post-page.internal.cjs +53 -0
  87. package/dist/plugins/blog/client/components/pages/new-post-page.internal.mjs +51 -0
  88. package/dist/plugins/blog/client/components/pages/new-post-page.mjs +35 -0
  89. package/dist/plugins/blog/client/components/pages/post-page.cjs +39 -0
  90. package/dist/plugins/blog/client/components/pages/post-page.internal.cjs +101 -0
  91. package/dist/plugins/blog/client/components/pages/post-page.internal.mjs +99 -0
  92. package/dist/plugins/blog/client/components/pages/post-page.mjs +37 -0
  93. package/dist/plugins/blog/client/components/pages/tag-page.cjs +39 -0
  94. package/dist/plugins/blog/client/components/pages/tag-page.internal.cjs +61 -0
  95. package/dist/plugins/blog/client/components/pages/tag-page.internal.mjs +59 -0
  96. package/dist/plugins/blog/client/components/pages/tag-page.mjs +37 -0
  97. package/dist/plugins/blog/client/components/shared/better-blog-attribution.cjs +24 -0
  98. package/dist/plugins/blog/client/components/shared/better-blog-attribution.mjs +22 -0
  99. package/dist/plugins/blog/client/components/shared/default-error.cjs +18 -0
  100. package/dist/plugins/blog/client/components/shared/default-error.mjs +16 -0
  101. package/dist/plugins/blog/client/components/shared/defaults.cjs +13 -0
  102. package/dist/plugins/blog/client/components/shared/defaults.mjs +10 -0
  103. package/dist/plugins/blog/client/components/shared/empty-list.cjs +21 -0
  104. package/dist/plugins/blog/client/components/shared/empty-list.mjs +19 -0
  105. package/dist/plugins/blog/client/components/shared/error-placeholder.cjs +24 -0
  106. package/dist/plugins/blog/client/components/shared/error-placeholder.mjs +22 -0
  107. package/dist/plugins/blog/client/components/shared/highlight-text.cjs +53 -0
  108. package/dist/plugins/blog/client/components/shared/highlight-text.mjs +51 -0
  109. package/dist/plugins/blog/client/components/shared/markdown-content-styles.css +328 -0
  110. package/dist/plugins/blog/client/components/shared/markdown-content.cjs +324 -0
  111. package/dist/plugins/blog/client/components/shared/markdown-content.mjs +315 -0
  112. package/dist/plugins/blog/client/components/shared/on-this-page.cjs +161 -0
  113. package/dist/plugins/blog/client/components/shared/on-this-page.mjs +158 -0
  114. package/dist/plugins/blog/client/components/shared/page-header.cjs +40 -0
  115. package/dist/plugins/blog/client/components/shared/page-header.mjs +38 -0
  116. package/dist/plugins/blog/client/components/shared/page-layout.cjs +24 -0
  117. package/dist/plugins/blog/client/components/shared/page-layout.mjs +22 -0
  118. package/dist/plugins/blog/client/components/shared/page-wrapper.cjs +23 -0
  119. package/dist/plugins/blog/client/components/shared/page-wrapper.mjs +21 -0
  120. package/dist/plugins/blog/client/components/shared/post-card.cjs +279 -0
  121. package/dist/plugins/blog/client/components/shared/post-card.mjs +277 -0
  122. package/dist/plugins/blog/client/components/shared/post-navigation.cjs +74 -0
  123. package/dist/plugins/blog/client/components/shared/post-navigation.mjs +72 -0
  124. package/dist/plugins/blog/client/components/shared/posts-list.cjs +48 -0
  125. package/dist/plugins/blog/client/components/shared/posts-list.mjs +46 -0
  126. package/dist/plugins/blog/client/components/shared/recent-posts-carousel.cjs +59 -0
  127. package/dist/plugins/blog/client/components/shared/recent-posts-carousel.mjs +57 -0
  128. package/dist/plugins/blog/client/components/shared/search-input.cjs +136 -0
  129. package/dist/plugins/blog/client/components/shared/search-input.mjs +117 -0
  130. package/dist/plugins/blog/client/components/shared/search-modal.cjs +135 -0
  131. package/dist/plugins/blog/client/components/shared/search-modal.mjs +116 -0
  132. package/dist/plugins/blog/client/components/shared/tags-list.cjs +22 -0
  133. package/dist/plugins/blog/client/components/shared/tags-list.mjs +20 -0
  134. package/dist/plugins/blog/client/components/shared/use-route-lifecycle.cjs +50 -0
  135. package/dist/plugins/blog/client/components/shared/use-route-lifecycle.mjs +48 -0
  136. package/dist/plugins/blog/client/hooks/blog-hooks.cjs +380 -0
  137. package/dist/plugins/blog/client/hooks/blog-hooks.mjs +368 -0
  138. package/dist/plugins/blog/client/hooks/index.cjs +17 -0
  139. package/dist/plugins/blog/client/hooks/index.d.cts +150 -0
  140. package/dist/plugins/blog/client/hooks/index.d.mts +150 -0
  141. package/dist/plugins/blog/client/hooks/index.d.ts +150 -0
  142. package/dist/plugins/blog/client/hooks/index.mjs +1 -0
  143. package/dist/plugins/blog/client/hooks/use-debounce.cjs +16 -0
  144. package/dist/plugins/blog/client/hooks/use-debounce.mjs +14 -0
  145. package/dist/plugins/blog/client/index.cjs +7 -0
  146. package/dist/plugins/blog/client/index.d.cts +414 -0
  147. package/dist/plugins/blog/client/index.d.mts +414 -0
  148. package/dist/plugins/blog/client/index.d.ts +414 -0
  149. package/dist/plugins/blog/client/index.mjs +1 -0
  150. package/dist/plugins/blog/client/localization/blog-card.cjs +7 -0
  151. package/dist/plugins/blog/client/localization/blog-card.mjs +5 -0
  152. package/dist/plugins/blog/client/localization/blog-common.cjs +10 -0
  153. package/dist/plugins/blog/client/localization/blog-common.mjs +8 -0
  154. package/dist/plugins/blog/client/localization/blog-forms.cjs +40 -0
  155. package/dist/plugins/blog/client/localization/blog-forms.mjs +38 -0
  156. package/dist/plugins/blog/client/localization/blog-list.cjs +18 -0
  157. package/dist/plugins/blog/client/localization/blog-list.mjs +16 -0
  158. package/dist/plugins/blog/client/localization/blog-post.cjs +13 -0
  159. package/dist/plugins/blog/client/localization/blog-post.mjs +11 -0
  160. package/dist/plugins/blog/client/localization/index.cjs +17 -0
  161. package/dist/plugins/blog/client/localization/index.mjs +15 -0
  162. package/dist/plugins/blog/client/plugin.cjs +462 -0
  163. package/dist/plugins/blog/client/plugin.mjs +460 -0
  164. package/dist/plugins/blog/client.css +3 -0
  165. package/dist/plugins/blog/db.cjs +90 -0
  166. package/dist/plugins/blog/db.mjs +88 -0
  167. package/dist/plugins/blog/query-keys.cjs +181 -0
  168. package/dist/plugins/blog/query-keys.d.cts +530 -0
  169. package/dist/plugins/blog/query-keys.d.mts +530 -0
  170. package/dist/plugins/blog/query-keys.d.ts +530 -0
  171. package/dist/plugins/blog/query-keys.mjs +179 -0
  172. package/dist/plugins/blog/schemas.cjs +39 -0
  173. package/dist/plugins/blog/schemas.mjs +35 -0
  174. package/dist/plugins/blog/style.css +22 -0
  175. package/dist/plugins/blog/utils.cjs +97 -0
  176. package/dist/plugins/blog/utils.mjs +87 -0
  177. package/dist/plugins/client/index.cjs +15 -0
  178. package/dist/plugins/client/index.d.cts +57 -0
  179. package/dist/plugins/client/index.d.mts +57 -0
  180. package/dist/plugins/client/index.d.ts +57 -0
  181. package/dist/plugins/client/index.mjs +9 -0
  182. package/dist/{shared/stack.Br2KMECJ.cjs → plugins/utils.cjs} +1 -8
  183. package/dist/{shared/stack.CwGEQ10b.mjs → plugins/utils.mjs} +2 -8
  184. package/dist/shared/{stack.Dva9muUy.d.cts → stack.ByOugz9d.d.cts} +17 -23
  185. package/dist/shared/{stack.Dva9muUy.d.mts → stack.ByOugz9d.d.mts} +17 -23
  186. package/dist/shared/{stack.Dva9muUy.d.ts → stack.ByOugz9d.d.ts} +17 -23
  187. package/dist/shared/stack.Cr2JoQdo.d.cts +76 -0
  188. package/dist/shared/stack.Cr2JoQdo.d.mts +76 -0
  189. package/dist/shared/stack.Cr2JoQdo.d.ts +76 -0
  190. package/package.json +104 -16
  191. package/src/__tests__/plugins.test.tsx +539 -0
  192. package/src/__tests__/sitemap.test.ts +60 -0
  193. package/src/api/index.ts +73 -0
  194. package/src/client/components/compose.tsx +116 -0
  195. package/src/client/components/error-boundary.tsx +30 -0
  196. package/src/client/components/index.tsx +2 -0
  197. package/src/client/index.ts +107 -0
  198. package/src/client/meta-utils.ts +228 -0
  199. package/src/client/sitemap-utils.ts +46 -0
  200. package/src/context/index.ts +1 -0
  201. package/src/context/provider.tsx +157 -0
  202. package/src/index.ts +1 -0
  203. package/src/plugins/api/index.ts +51 -0
  204. package/src/plugins/blog/api/index.ts +2 -0
  205. package/src/plugins/blog/api/plugin.ts +759 -0
  206. package/src/plugins/blog/client/components/forms/image-field.tsx +165 -0
  207. package/src/plugins/blog/client/components/forms/markdown-editor-styles.css +30 -0
  208. package/src/plugins/blog/client/components/forms/markdown-editor.tsx +136 -0
  209. package/src/plugins/blog/client/components/forms/post-forms.tsx +531 -0
  210. package/src/plugins/blog/client/components/forms/tags-multiselect.tsx +79 -0
  211. package/src/plugins/blog/client/components/index.tsx +11 -0
  212. package/src/plugins/blog/client/components/loading/form-page-skeleton.tsx +75 -0
  213. package/src/plugins/blog/client/components/loading/index.tsx +27 -0
  214. package/src/plugins/blog/client/components/loading/list-page-skeleton.tsx +38 -0
  215. package/src/plugins/blog/client/components/loading/page-header-skeleton.tsx +10 -0
  216. package/src/plugins/blog/client/components/loading/post-card-skeleton.tsx +30 -0
  217. package/src/plugins/blog/client/components/loading/post-page-skeleton.tsx +75 -0
  218. package/src/plugins/blog/client/components/pages/404-page.tsx +23 -0
  219. package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +60 -0
  220. package/src/plugins/blog/client/components/pages/edit-post-page.tsx +40 -0
  221. package/src/plugins/blog/client/components/pages/home-page.internal.tsx +71 -0
  222. package/src/plugins/blog/client/components/pages/home-page.tsx +42 -0
  223. package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +59 -0
  224. package/src/plugins/blog/client/components/pages/new-post-page.tsx +36 -0
  225. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +142 -0
  226. package/src/plugins/blog/client/components/pages/post-page.tsx +38 -0
  227. package/src/plugins/blog/client/components/pages/tag-page.internal.tsx +74 -0
  228. package/src/plugins/blog/client/components/pages/tag-page.tsx +38 -0
  229. package/src/plugins/blog/client/components/shared/better-blog-attribution.tsx +19 -0
  230. package/src/plugins/blog/client/components/shared/default-error.tsx +20 -0
  231. package/src/plugins/blog/client/components/shared/defaults.tsx +9 -0
  232. package/src/plugins/blog/client/components/shared/empty-list.tsx +25 -0
  233. package/src/plugins/blog/client/components/shared/error-placeholder.tsx +20 -0
  234. package/src/plugins/blog/client/components/shared/highlight-text.tsx +80 -0
  235. package/src/plugins/blog/client/components/shared/markdown-content-styles.css +328 -0
  236. package/src/plugins/blog/client/components/shared/markdown-content.tsx +448 -0
  237. package/src/plugins/blog/client/components/shared/on-this-page.tsx +234 -0
  238. package/src/plugins/blog/client/components/shared/page-header.tsx +35 -0
  239. package/src/plugins/blog/client/components/shared/page-layout.tsx +23 -0
  240. package/src/plugins/blog/client/components/shared/page-wrapper.tsx +32 -0
  241. package/src/plugins/blog/client/components/shared/post-card.tsx +308 -0
  242. package/src/plugins/blog/client/components/shared/post-navigation.tsx +98 -0
  243. package/src/plugins/blog/client/components/shared/posts-list.tsx +67 -0
  244. package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +79 -0
  245. package/src/plugins/blog/client/components/shared/search-input.tsx +146 -0
  246. package/src/plugins/blog/client/components/shared/search-modal.tsx +162 -0
  247. package/src/plugins/blog/client/components/shared/tags-list.tsx +34 -0
  248. package/src/plugins/blog/client/components/shared/use-route-lifecycle.tsx +68 -0
  249. package/src/plugins/blog/client/hooks/blog-hooks.tsx +623 -0
  250. package/src/plugins/blog/client/hooks/index.tsx +1 -0
  251. package/src/plugins/blog/client/hooks/use-debounce.ts +43 -0
  252. package/src/plugins/blog/client/index.ts +9 -0
  253. package/src/plugins/blog/client/localization/blog-card.ts +3 -0
  254. package/src/plugins/blog/client/localization/blog-common.ts +7 -0
  255. package/src/plugins/blog/client/localization/blog-forms.ts +45 -0
  256. package/src/plugins/blog/client/localization/blog-list.ts +14 -0
  257. package/src/plugins/blog/client/localization/blog-post.ts +9 -0
  258. package/src/plugins/blog/client/localization/index.ts +15 -0
  259. package/src/plugins/blog/client/overrides.ts +123 -0
  260. package/src/plugins/blog/client/plugin.tsx +672 -0
  261. package/src/plugins/blog/client.css +3 -0
  262. package/src/plugins/blog/db.ts +90 -0
  263. package/src/plugins/blog/query-keys.ts +267 -0
  264. package/src/plugins/blog/schemas.ts +39 -0
  265. package/src/plugins/blog/style.css +22 -0
  266. package/src/plugins/blog/types.ts +37 -0
  267. package/src/plugins/blog/utils.ts +144 -0
  268. package/src/plugins/client/index.ts +53 -0
  269. package/src/plugins/index.ts +0 -0
  270. package/src/plugins/utils.ts +35 -0
  271. package/src/types.ts +209 -0
  272. package/dist/plugins/index.cjs +0 -16
  273. package/dist/plugins/index.d.cts +0 -64
  274. package/dist/plugins/index.d.mts +0 -64
  275. package/dist/plugins/index.d.ts +0 -64
  276. package/dist/plugins/index.mjs +0 -11
  277. package/dist/shared/stack.DvFqFlOV.d.cts +0 -22
  278. package/dist/shared/stack.DvFqFlOV.d.mts +0 -22
  279. package/dist/shared/stack.DvFqFlOV.d.ts +0 -22
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ const zod = require('zod');
4
+
5
+ const dateFields = {
6
+ publishedAt: zod.z.coerce.date().optional(),
7
+ createdAt: zod.z.coerce.date().optional(),
8
+ updatedAt: zod.z.coerce.date().optional()
9
+ };
10
+ const coreFields = {
11
+ title: zod.z.string().min(1, "Title is required"),
12
+ content: zod.z.string().min(1, "Content is required"),
13
+ excerpt: zod.z.string().min(1, "Excerpt is required"),
14
+ image: zod.z.string().optional(),
15
+ published: zod.z.boolean().optional().default(false),
16
+ slug: zod.z.string().min(1, "Slug is required"),
17
+ tags: zod.z.array(
18
+ zod.z.union([
19
+ zod.z.object({ name: zod.z.string() }),
20
+ zod.z.object({ id: zod.z.string(), name: zod.z.string(), slug: zod.z.string() })
21
+ ])
22
+ ).optional().default([])
23
+ };
24
+ const PostDomainSchema = zod.z.object({
25
+ id: zod.z.string().optional(),
26
+ ...coreFields,
27
+ ...dateFields
28
+ });
29
+ const createPostSchema = PostDomainSchema.extend({
30
+ slug: PostDomainSchema.shape.slug.optional()
31
+ }).omit({ id: true });
32
+ const updatePostSchema = PostDomainSchema.extend({
33
+ id: zod.z.string()
34
+ // required on update
35
+ });
36
+
37
+ exports.PostDomainSchema = PostDomainSchema;
38
+ exports.createPostSchema = createPostSchema;
39
+ exports.updatePostSchema = updatePostSchema;
@@ -0,0 +1,35 @@
1
+ import { z } from 'zod';
2
+
3
+ const dateFields = {
4
+ publishedAt: z.coerce.date().optional(),
5
+ createdAt: z.coerce.date().optional(),
6
+ updatedAt: z.coerce.date().optional()
7
+ };
8
+ const coreFields = {
9
+ title: z.string().min(1, "Title is required"),
10
+ content: z.string().min(1, "Content is required"),
11
+ excerpt: z.string().min(1, "Excerpt is required"),
12
+ image: z.string().optional(),
13
+ published: z.boolean().optional().default(false),
14
+ slug: z.string().min(1, "Slug is required"),
15
+ tags: z.array(
16
+ z.union([
17
+ z.object({ name: z.string() }),
18
+ z.object({ id: z.string(), name: z.string(), slug: z.string() })
19
+ ])
20
+ ).optional().default([])
21
+ };
22
+ const PostDomainSchema = z.object({
23
+ id: z.string().optional(),
24
+ ...coreFields,
25
+ ...dateFields
26
+ });
27
+ const createPostSchema = PostDomainSchema.extend({
28
+ slug: PostDomainSchema.shape.slug.optional()
29
+ }).omit({ id: true });
30
+ const updatePostSchema = PostDomainSchema.extend({
31
+ id: z.string()
32
+ // required on update
33
+ });
34
+
35
+ export { PostDomainSchema, createPostSchema, updatePostSchema };
@@ -0,0 +1,22 @@
1
+ @import "./client.css";
2
+
3
+ /*
4
+ * Blog Plugin CSS - Includes Tailwind class scanning
5
+ *
6
+ * When consumed from npm, Tailwind v4 will automatically scan this package's
7
+ * source files for Tailwind classes. Consumers only need:
8
+ * @import "@btst/stack/plugins/blog/css";
9
+ */
10
+
11
+ /* Scan this package's source files for Tailwind classes */
12
+ @source "../../../src/**/*.{ts,tsx}";
13
+
14
+ /* Scan UI package components (if in monorepo) */
15
+ @source "../../../../@workspace/ui/src/**/*.{ts,tsx}";
16
+
17
+ /* Scan UI package components (if installed as npm package) */
18
+ @source "../../../node_modules/@workspace/ui/src/**/*.{ts,tsx}";
19
+
20
+ /*
21
+ * alternatively consumer can use @source "../node_modules/@btst/stack/src/**\/*.{ts,tsx}";
22
+ */
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ const clsx = require('clsx');
4
+ const tailwindMerge = require('tailwind-merge');
5
+ const slug = require('slug');
6
+
7
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
8
+
9
+ const slug__default = /*#__PURE__*/_interopDefaultCompat(slug);
10
+
11
+ function slugify(text, locale = "en") {
12
+ return slug__default(text, { lower: true, locale });
13
+ }
14
+ function cn(...inputs) {
15
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
16
+ }
17
+ function throttle(callback, waitMs) {
18
+ let timerId = null;
19
+ let lastInvokeTime = 0;
20
+ let trailingArgs = null;
21
+ const invoke = (args) => {
22
+ lastInvokeTime = Date.now();
23
+ callback(...args);
24
+ };
25
+ const throttled = (...args) => {
26
+ const now = Date.now();
27
+ const remaining = waitMs - (now - lastInvokeTime);
28
+ if (lastInvokeTime === 0) {
29
+ invoke(args);
30
+ return;
31
+ }
32
+ if (remaining <= 0 || remaining > waitMs) {
33
+ if (timerId) {
34
+ clearTimeout(timerId);
35
+ timerId = null;
36
+ }
37
+ invoke(args);
38
+ } else {
39
+ trailingArgs = args;
40
+ if (!timerId) {
41
+ timerId = setTimeout(() => {
42
+ timerId = null;
43
+ if (trailingArgs) {
44
+ invoke(trailingArgs);
45
+ trailingArgs = null;
46
+ }
47
+ }, remaining);
48
+ }
49
+ }
50
+ };
51
+ throttled.cancel = () => {
52
+ if (timerId) {
53
+ clearTimeout(timerId);
54
+ timerId = null;
55
+ }
56
+ trailingArgs = null;
57
+ lastInvokeTime = 0;
58
+ };
59
+ throttled.flush = () => {
60
+ if (timerId && trailingArgs) {
61
+ clearTimeout(timerId);
62
+ timerId = null;
63
+ invoke(trailingArgs);
64
+ trailingArgs = null;
65
+ }
66
+ };
67
+ return throttled;
68
+ }
69
+ function stripHtml(html) {
70
+ let text = html.replace(/<[^>]*>/g, "");
71
+ text = text.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#x27;/g, "'").replace(/&#x2F;/g, "/").replace(/&nbsp;/g, " ").replace(/&hellip;/g, "...");
72
+ return text.replace(/\s+/g, " ").trim();
73
+ }
74
+ function stripMarkdown(markdown) {
75
+ let text = markdown;
76
+ text = text.replace(/^#{1,6}\s+/gm, "");
77
+ text = text.replace(/\*\*([^*]+)\*\*/g, "$1");
78
+ text = text.replace(/\*([^*]+)\*/g, "$1");
79
+ text = text.replace(/__([^_]+)__/g, "$1");
80
+ text = text.replace(/_([^_]+)_/g, "$1");
81
+ text = text.replace(/~~([^~]+)~~/g, "$1");
82
+ text = text.replace(/`([^`]+)`/g, "$1");
83
+ text = text.replace(/```[\s\S]*?```/g, "");
84
+ text = text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
85
+ text = text.replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1");
86
+ text = text.replace(/^>\s+/gm, "");
87
+ text = text.replace(/^[-*]{3,}$/gm, "");
88
+ text = text.replace(/^[\s]*[-*+]\s+/gm, "");
89
+ text = text.replace(/^[\s]*\d+\.\s+/gm, "");
90
+ return text.replace(/\n\s*\n/g, "\n").replace(/\s+/g, " ").trim();
91
+ }
92
+
93
+ exports.cn = cn;
94
+ exports.slugify = slugify;
95
+ exports.stripHtml = stripHtml;
96
+ exports.stripMarkdown = stripMarkdown;
97
+ exports.throttle = throttle;
@@ -0,0 +1,87 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ import slug from 'slug';
4
+
5
+ function slugify(text, locale = "en") {
6
+ return slug(text, { lower: true, locale });
7
+ }
8
+ function cn(...inputs) {
9
+ return twMerge(clsx(inputs));
10
+ }
11
+ function throttle(callback, waitMs) {
12
+ let timerId = null;
13
+ let lastInvokeTime = 0;
14
+ let trailingArgs = null;
15
+ const invoke = (args) => {
16
+ lastInvokeTime = Date.now();
17
+ callback(...args);
18
+ };
19
+ const throttled = (...args) => {
20
+ const now = Date.now();
21
+ const remaining = waitMs - (now - lastInvokeTime);
22
+ if (lastInvokeTime === 0) {
23
+ invoke(args);
24
+ return;
25
+ }
26
+ if (remaining <= 0 || remaining > waitMs) {
27
+ if (timerId) {
28
+ clearTimeout(timerId);
29
+ timerId = null;
30
+ }
31
+ invoke(args);
32
+ } else {
33
+ trailingArgs = args;
34
+ if (!timerId) {
35
+ timerId = setTimeout(() => {
36
+ timerId = null;
37
+ if (trailingArgs) {
38
+ invoke(trailingArgs);
39
+ trailingArgs = null;
40
+ }
41
+ }, remaining);
42
+ }
43
+ }
44
+ };
45
+ throttled.cancel = () => {
46
+ if (timerId) {
47
+ clearTimeout(timerId);
48
+ timerId = null;
49
+ }
50
+ trailingArgs = null;
51
+ lastInvokeTime = 0;
52
+ };
53
+ throttled.flush = () => {
54
+ if (timerId && trailingArgs) {
55
+ clearTimeout(timerId);
56
+ timerId = null;
57
+ invoke(trailingArgs);
58
+ trailingArgs = null;
59
+ }
60
+ };
61
+ return throttled;
62
+ }
63
+ function stripHtml(html) {
64
+ let text = html.replace(/<[^>]*>/g, "");
65
+ text = text.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#x27;/g, "'").replace(/&#x2F;/g, "/").replace(/&nbsp;/g, " ").replace(/&hellip;/g, "...");
66
+ return text.replace(/\s+/g, " ").trim();
67
+ }
68
+ function stripMarkdown(markdown) {
69
+ let text = markdown;
70
+ text = text.replace(/^#{1,6}\s+/gm, "");
71
+ text = text.replace(/\*\*([^*]+)\*\*/g, "$1");
72
+ text = text.replace(/\*([^*]+)\*/g, "$1");
73
+ text = text.replace(/__([^_]+)__/g, "$1");
74
+ text = text.replace(/_([^_]+)_/g, "$1");
75
+ text = text.replace(/~~([^~]+)~~/g, "$1");
76
+ text = text.replace(/`([^`]+)`/g, "$1");
77
+ text = text.replace(/```[\s\S]*?```/g, "");
78
+ text = text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
79
+ text = text.replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1");
80
+ text = text.replace(/^>\s+/gm, "");
81
+ text = text.replace(/^[-*]{3,}$/gm, "");
82
+ text = text.replace(/^[\s]*[-*+]\s+/gm, "");
83
+ text = text.replace(/^[\s]*\d+\.\s+/gm, "");
84
+ return text.replace(/\n\s*\n/g, "\n").replace(/\s+/g, " ").trim();
85
+ }
86
+
87
+ export { cn, slugify, stripHtml, stripMarkdown, throttle };
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ const utils = require('../utils.cjs');
4
+ const yar = require('@btst/yar');
5
+ const client = require('better-call/client');
6
+
7
+ function defineClientPlugin(plugin) {
8
+ return plugin;
9
+ }
10
+
11
+ exports.createApiClient = utils.createApiClient;
12
+ exports.createRoute = yar.createRoute;
13
+ exports.createRouter = yar.createRouter;
14
+ exports.createClient = client.createClient;
15
+ exports.defineClientPlugin = defineClientPlugin;
@@ -0,0 +1,57 @@
1
+ import { C as ClientPlugin } from '../../shared/stack.ByOugz9d.cjs';
2
+ export { P as PluginOverrides } from '../../shared/stack.ByOugz9d.cjs';
3
+ import { createClient } from 'better-call/client';
4
+ export { createClient } from 'better-call/client';
5
+ import { Router, Endpoint } from 'better-call';
6
+ export { Route, createRoute, createRouter } from '@btst/yar';
7
+ import '@btst/db';
8
+
9
+ interface CreateApiClientOptions {
10
+ baseURL?: string;
11
+ basePath?: string;
12
+ }
13
+ /**
14
+ * Creates a Better Call API client with proper URL handling for both server and client side
15
+ * @param options - Configuration options
16
+ * @param options.baseURL - The base URL (e.g., 'http://localhost:3000'). If not provided, uses relative URLs (same domain)
17
+ * @param options.basePath - The API base path (defaults to '/')
18
+ * @template TRouter - The router type (Router or Record<string, Endpoint>)
19
+ */
20
+ declare function createApiClient<TRouter extends Router | Record<string, Endpoint> = Record<string, Endpoint>>(options?: CreateApiClientOptions): ReturnType<typeof createClient<TRouter>>;
21
+
22
+ /**
23
+ * Plugin utilities and types for building standalone plugins
24
+ *
25
+ * This module exports everything needed to create custom plugins
26
+ * for Better Stack outside of this package.
27
+ *
28
+ * Note: Backend and Client plugins are separate to prevent SSR issues
29
+ * and enable better code splitting. Import them separately:
30
+ * - Backend: import type { BackendPlugin } from "@btst/stack/plugins/api"
31
+ * - Client: import type { ClientPlugin } from "@btst/stack/plugins/client"
32
+ */
33
+
34
+ /**
35
+ * Helper to define a client plugin with full type inference
36
+ *
37
+ * Automatically infers route keys, hook names, and their types without needing casts.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const messagesPlugin = defineClientPlugin({
42
+ * name: "messages",
43
+ * routes: () => ({
44
+ * messagesList: createRoute("/messages", () => ({ ... }))
45
+ * }),
46
+ * hooks: () => ({
47
+ * useMessages: () => { ... }
48
+ * })
49
+ * });
50
+ * // No casts needed - route keys, hook names, and types are all preserved!
51
+ * ```
52
+ *
53
+ * @template TPlugin - The exact plugin definition (auto-inferred)
54
+ */
55
+ declare function defineClientPlugin<TPlugin extends ClientPlugin<any, any>>(plugin: TPlugin): TPlugin;
56
+
57
+ export { ClientPlugin, createApiClient, defineClientPlugin };
@@ -0,0 +1,57 @@
1
+ import { C as ClientPlugin } from '../../shared/stack.ByOugz9d.mjs';
2
+ export { P as PluginOverrides } from '../../shared/stack.ByOugz9d.mjs';
3
+ import { createClient } from 'better-call/client';
4
+ export { createClient } from 'better-call/client';
5
+ import { Router, Endpoint } from 'better-call';
6
+ export { Route, createRoute, createRouter } from '@btst/yar';
7
+ import '@btst/db';
8
+
9
+ interface CreateApiClientOptions {
10
+ baseURL?: string;
11
+ basePath?: string;
12
+ }
13
+ /**
14
+ * Creates a Better Call API client with proper URL handling for both server and client side
15
+ * @param options - Configuration options
16
+ * @param options.baseURL - The base URL (e.g., 'http://localhost:3000'). If not provided, uses relative URLs (same domain)
17
+ * @param options.basePath - The API base path (defaults to '/')
18
+ * @template TRouter - The router type (Router or Record<string, Endpoint>)
19
+ */
20
+ declare function createApiClient<TRouter extends Router | Record<string, Endpoint> = Record<string, Endpoint>>(options?: CreateApiClientOptions): ReturnType<typeof createClient<TRouter>>;
21
+
22
+ /**
23
+ * Plugin utilities and types for building standalone plugins
24
+ *
25
+ * This module exports everything needed to create custom plugins
26
+ * for Better Stack outside of this package.
27
+ *
28
+ * Note: Backend and Client plugins are separate to prevent SSR issues
29
+ * and enable better code splitting. Import them separately:
30
+ * - Backend: import type { BackendPlugin } from "@btst/stack/plugins/api"
31
+ * - Client: import type { ClientPlugin } from "@btst/stack/plugins/client"
32
+ */
33
+
34
+ /**
35
+ * Helper to define a client plugin with full type inference
36
+ *
37
+ * Automatically infers route keys, hook names, and their types without needing casts.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const messagesPlugin = defineClientPlugin({
42
+ * name: "messages",
43
+ * routes: () => ({
44
+ * messagesList: createRoute("/messages", () => ({ ... }))
45
+ * }),
46
+ * hooks: () => ({
47
+ * useMessages: () => { ... }
48
+ * })
49
+ * });
50
+ * // No casts needed - route keys, hook names, and types are all preserved!
51
+ * ```
52
+ *
53
+ * @template TPlugin - The exact plugin definition (auto-inferred)
54
+ */
55
+ declare function defineClientPlugin<TPlugin extends ClientPlugin<any, any>>(plugin: TPlugin): TPlugin;
56
+
57
+ export { ClientPlugin, createApiClient, defineClientPlugin };
@@ -0,0 +1,57 @@
1
+ import { C as ClientPlugin } from '../../shared/stack.ByOugz9d.js';
2
+ export { P as PluginOverrides } from '../../shared/stack.ByOugz9d.js';
3
+ import { createClient } from 'better-call/client';
4
+ export { createClient } from 'better-call/client';
5
+ import { Router, Endpoint } from 'better-call';
6
+ export { Route, createRoute, createRouter } from '@btst/yar';
7
+ import '@btst/db';
8
+
9
+ interface CreateApiClientOptions {
10
+ baseURL?: string;
11
+ basePath?: string;
12
+ }
13
+ /**
14
+ * Creates a Better Call API client with proper URL handling for both server and client side
15
+ * @param options - Configuration options
16
+ * @param options.baseURL - The base URL (e.g., 'http://localhost:3000'). If not provided, uses relative URLs (same domain)
17
+ * @param options.basePath - The API base path (defaults to '/')
18
+ * @template TRouter - The router type (Router or Record<string, Endpoint>)
19
+ */
20
+ declare function createApiClient<TRouter extends Router | Record<string, Endpoint> = Record<string, Endpoint>>(options?: CreateApiClientOptions): ReturnType<typeof createClient<TRouter>>;
21
+
22
+ /**
23
+ * Plugin utilities and types for building standalone plugins
24
+ *
25
+ * This module exports everything needed to create custom plugins
26
+ * for Better Stack outside of this package.
27
+ *
28
+ * Note: Backend and Client plugins are separate to prevent SSR issues
29
+ * and enable better code splitting. Import them separately:
30
+ * - Backend: import type { BackendPlugin } from "@btst/stack/plugins/api"
31
+ * - Client: import type { ClientPlugin } from "@btst/stack/plugins/client"
32
+ */
33
+
34
+ /**
35
+ * Helper to define a client plugin with full type inference
36
+ *
37
+ * Automatically infers route keys, hook names, and their types without needing casts.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const messagesPlugin = defineClientPlugin({
42
+ * name: "messages",
43
+ * routes: () => ({
44
+ * messagesList: createRoute("/messages", () => ({ ... }))
45
+ * }),
46
+ * hooks: () => ({
47
+ * useMessages: () => { ... }
48
+ * })
49
+ * });
50
+ * // No casts needed - route keys, hook names, and types are all preserved!
51
+ * ```
52
+ *
53
+ * @template TPlugin - The exact plugin definition (auto-inferred)
54
+ */
55
+ declare function defineClientPlugin<TPlugin extends ClientPlugin<any, any>>(plugin: TPlugin): TPlugin;
56
+
57
+ export { ClientPlugin, createApiClient, defineClientPlugin };
@@ -0,0 +1,9 @@
1
+ export { createApiClient } from '../utils.mjs';
2
+ export { createRoute, createRouter } from '@btst/yar';
3
+ export { createClient } from 'better-call/client';
4
+
5
+ function defineClientPlugin(plugin) {
6
+ return plugin;
7
+ }
8
+
9
+ export { defineClientPlugin };
@@ -3,7 +3,7 @@
3
3
  const client = require('better-call/client');
4
4
 
5
5
  function createApiClient(options) {
6
- const { baseURL = "", basePath = "/api" } = options ?? {};
6
+ const { baseURL = "", basePath = "/" } = options ?? {};
7
7
  const normalizedBaseURL = baseURL ? baseURL.replace(/\/$/, "") : "";
8
8
  const normalizedBasePath = basePath.startsWith("/") ? basePath : `/${basePath}`;
9
9
  const finalBasePath = normalizedBasePath.replace(/\/$/, "");
@@ -12,12 +12,5 @@ function createApiClient(options) {
12
12
  baseURL: apiPath
13
13
  });
14
14
  }
15
- function getServerBaseURL() {
16
- if (typeof window === "undefined") {
17
- return process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000";
18
- }
19
- return void 0;
20
- }
21
15
 
22
16
  exports.createApiClient = createApiClient;
23
- exports.getServerBaseURL = getServerBaseURL;
@@ -1,7 +1,7 @@
1
1
  import { createClient } from 'better-call/client';
2
2
 
3
3
  function createApiClient(options) {
4
- const { baseURL = "", basePath = "/api" } = options ?? {};
4
+ const { baseURL = "", basePath = "/" } = options ?? {};
5
5
  const normalizedBaseURL = baseURL ? baseURL.replace(/\/$/, "") : "";
6
6
  const normalizedBasePath = basePath.startsWith("/") ? basePath : `/${basePath}`;
7
7
  const finalBasePath = normalizedBasePath.replace(/\/$/, "");
@@ -10,11 +10,5 @@ function createApiClient(options) {
10
10
  baseURL: apiPath
11
11
  });
12
12
  }
13
- function getServerBaseURL() {
14
- if (typeof window === "undefined") {
15
- return process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000";
16
- }
17
- return void 0;
18
- }
19
13
 
20
- export { createApiClient as c, getServerBaseURL as g };
14
+ export { createApiClient };
@@ -24,11 +24,6 @@ interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string
24
24
  routes: (adapter: Adapter) => TRoutes;
25
25
  dbPlugin: DbPlugin;
26
26
  }
27
- /**
28
- * Hook function type
29
- * Generic function type for React hooks returned by plugins
30
- */
31
- type HookFunction = (...args: unknown[]) => unknown;
32
27
  /**
33
28
  * Frontend plugin definition
34
29
  * Defines pages, components, loaders, and React Query hooks for a feature
@@ -45,20 +40,16 @@ interface ClientPlugin<TOverrides = Record<string, never>, TRoutes extends Recor
45
40
  */
46
41
  routes: () => TRoutes;
47
42
  /**
48
- * Optional: Create React Query hooks for this plugin
49
- * These can be used directly in components without the loader
43
+ * Optional sitemap generator for this plugin. Should return absolute URLs.
44
+ * Implementations can call their own API endpoints to include dynamic routes.
50
45
  */
51
- hooks?: () => Record<string, HookFunction>;
52
- /**
53
- * Optional: Default implementations for overridable components/functions
54
- * These will be used if no override is provided in BetterStackContext
55
- */
56
- defaultOverrides?: Partial<TOverrides>;
46
+ sitemap?: () => Promise<Sitemap> | Sitemap;
57
47
  }
58
48
  /**
59
49
  * Configuration for creating the backend library
60
50
  */
61
51
  interface BackendLibConfig<TPlugins extends Record<string, BackendPlugin<any>> = Record<string, BackendPlugin<any>>> {
52
+ basePath: string;
62
53
  dbSchema?: DatabaseDefinition;
63
54
  plugins: TPlugins;
64
55
  adapter: (db: DatabaseDefinition) => Adapter;
@@ -89,13 +80,6 @@ type PluginOverrides<TPlugins extends Record<string, ClientPlugin<any, any>>> =
89
80
  * Extract all routes from all client plugins, merging them into a single record
90
81
  */
91
82
  type PluginRoutes<TPlugins extends Record<string, ClientPlugin<any, any>>> = MergeAllPluginRoutes<TPlugins>;
92
- /**
93
- * Extract all hooks from all client plugins, organized by plugin name
94
- * For plugins without hooks, the type will be an empty object
95
- */
96
- type PluginHooks<TPlugins extends Record<string, ClientPlugin<any, any>>> = {
97
- [K in keyof TPlugins]: TPlugins[K]["hooks"] extends () => infer H ? H : {};
98
- };
99
83
  /**
100
84
  * Prefix all backend plugin route keys with the plugin name
101
85
  * Example: { messages: { list: Endpoint } } => { messages_list: Endpoint }
@@ -130,9 +114,19 @@ type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) exten
130
114
  /**
131
115
  * Result of creating the client library
132
116
  */
133
- interface ClientLib<TRoutes extends Record<string, Route> = Record<string, Route>, THooks extends Record<string, any> = Record<string, any>> {
117
+ interface ClientLib<TRoutes extends Record<string, Route> = Record<string, Route>> {
134
118
  router: ReturnType<typeof createRouter<TRoutes, {}>>;
135
- hooks: THooks;
119
+ generateSitemap: () => Promise<Sitemap>;
136
120
  }
121
+ /**
122
+ * Minimal sitemap entry shape aligned with Next.js MetadataRoute.Sitemap
123
+ */
124
+ type SitemapEntry = {
125
+ url: string;
126
+ lastModified?: string | Date;
127
+ changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
128
+ priority?: number;
129
+ };
130
+ type Sitemap = Array<SitemapEntry>;
137
131
 
138
- export type { BackendPlugin as B, ClientPlugin as C, InferPluginOverrides as I, PluginRoutes as P, PluginHooks as a, ClientLibConfig as b, ClientLib as c, PluginOverrides as d, PrefixedPluginRoutes as e, BackendLibConfig as f, BackendLib as g };
132
+ export type { BackendPlugin as B, ClientPlugin as C, PluginOverrides as P, Sitemap as S, PluginRoutes as a, ClientLibConfig as b, ClientLib as c, PrefixedPluginRoutes as d, BackendLibConfig as e, BackendLib as f };
@@ -24,11 +24,6 @@ interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string
24
24
  routes: (adapter: Adapter) => TRoutes;
25
25
  dbPlugin: DbPlugin;
26
26
  }
27
- /**
28
- * Hook function type
29
- * Generic function type for React hooks returned by plugins
30
- */
31
- type HookFunction = (...args: unknown[]) => unknown;
32
27
  /**
33
28
  * Frontend plugin definition
34
29
  * Defines pages, components, loaders, and React Query hooks for a feature
@@ -45,20 +40,16 @@ interface ClientPlugin<TOverrides = Record<string, never>, TRoutes extends Recor
45
40
  */
46
41
  routes: () => TRoutes;
47
42
  /**
48
- * Optional: Create React Query hooks for this plugin
49
- * These can be used directly in components without the loader
43
+ * Optional sitemap generator for this plugin. Should return absolute URLs.
44
+ * Implementations can call their own API endpoints to include dynamic routes.
50
45
  */
51
- hooks?: () => Record<string, HookFunction>;
52
- /**
53
- * Optional: Default implementations for overridable components/functions
54
- * These will be used if no override is provided in BetterStackContext
55
- */
56
- defaultOverrides?: Partial<TOverrides>;
46
+ sitemap?: () => Promise<Sitemap> | Sitemap;
57
47
  }
58
48
  /**
59
49
  * Configuration for creating the backend library
60
50
  */
61
51
  interface BackendLibConfig<TPlugins extends Record<string, BackendPlugin<any>> = Record<string, BackendPlugin<any>>> {
52
+ basePath: string;
62
53
  dbSchema?: DatabaseDefinition;
63
54
  plugins: TPlugins;
64
55
  adapter: (db: DatabaseDefinition) => Adapter;
@@ -89,13 +80,6 @@ type PluginOverrides<TPlugins extends Record<string, ClientPlugin<any, any>>> =
89
80
  * Extract all routes from all client plugins, merging them into a single record
90
81
  */
91
82
  type PluginRoutes<TPlugins extends Record<string, ClientPlugin<any, any>>> = MergeAllPluginRoutes<TPlugins>;
92
- /**
93
- * Extract all hooks from all client plugins, organized by plugin name
94
- * For plugins without hooks, the type will be an empty object
95
- */
96
- type PluginHooks<TPlugins extends Record<string, ClientPlugin<any, any>>> = {
97
- [K in keyof TPlugins]: TPlugins[K]["hooks"] extends () => infer H ? H : {};
98
- };
99
83
  /**
100
84
  * Prefix all backend plugin route keys with the plugin name
101
85
  * Example: { messages: { list: Endpoint } } => { messages_list: Endpoint }
@@ -130,9 +114,19 @@ type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) exten
130
114
  /**
131
115
  * Result of creating the client library
132
116
  */
133
- interface ClientLib<TRoutes extends Record<string, Route> = Record<string, Route>, THooks extends Record<string, any> = Record<string, any>> {
117
+ interface ClientLib<TRoutes extends Record<string, Route> = Record<string, Route>> {
134
118
  router: ReturnType<typeof createRouter<TRoutes, {}>>;
135
- hooks: THooks;
119
+ generateSitemap: () => Promise<Sitemap>;
136
120
  }
121
+ /**
122
+ * Minimal sitemap entry shape aligned with Next.js MetadataRoute.Sitemap
123
+ */
124
+ type SitemapEntry = {
125
+ url: string;
126
+ lastModified?: string | Date;
127
+ changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
128
+ priority?: number;
129
+ };
130
+ type Sitemap = Array<SitemapEntry>;
137
131
 
138
- export type { BackendPlugin as B, ClientPlugin as C, InferPluginOverrides as I, PluginRoutes as P, PluginHooks as a, ClientLibConfig as b, ClientLib as c, PluginOverrides as d, PrefixedPluginRoutes as e, BackendLibConfig as f, BackendLib as g };
132
+ export type { BackendPlugin as B, ClientPlugin as C, PluginOverrides as P, Sitemap as S, PluginRoutes as a, ClientLibConfig as b, ClientLib as c, PrefixedPluginRoutes as d, BackendLibConfig as e, BackendLib as f };