@btst/stack 1.1.10 → 1.2.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.
package/README.md CHANGED
@@ -30,21 +30,6 @@ Better Stack lets you **add these features in minutes** as composable plugins th
30
30
  - **Lifecycle hooks** - Intercept at any point: authorization, data transformation, analytics, caching, webhooks
31
31
  - **Horizontal features** - Perfect for blog, scheduling, feedback, newsletters, AI assistants, comments—anything reusable across apps
32
32
 
33
- ## What Can You Add?
34
-
35
- **Blog** - Content management, editor, drafts, publishing, SEO, RSS feeds
36
-
37
- **Scheduling** - Calendar views, time slot booking, availability management, reminders
38
-
39
- **Feedback** - In-app feedback widgets, user surveys, bug reporting, feature requests
40
-
41
- **Newsletters** - Subscriber management, email campaigns, unsubscribe handling, analytics
42
-
43
- **AI Assistant** - Chat interfaces, prompt templates, conversation history, streaming responses
44
-
45
- **Comments** - Threaded discussions, moderation, reactions, notifications
46
-
47
- And any other horizontal feature your app needs. Each comes with a complete UI, backend, and data layer.
48
33
 
49
34
  ## Installation
50
35
 
@@ -60,165 +45,15 @@ npm install -D @btst/cli
60
45
 
61
46
  The CLI helps generate migrations, Prisma schemas, and other database artifacts from your plugin schemas.
62
47
 
63
- ## Quick Example: Add a Blog to Next.js
64
-
65
- ### 1. Backend API (`lib/better-stack.ts`)
66
-
67
- ```ts
68
- import { betterStack } from "@btst/stack"
69
- import { blogBackendPlugin } from "@btst/stack/plugins/blog/api"
70
- import { createPrismaAdapter } from "@btst/adapter-prisma"
71
-
72
- const { handler, dbSchema } = betterStack({
73
- basePath: "/api/data",
74
- plugins: {
75
- blog: blogBackendPlugin()
76
- },
77
- adapter: (db) => createPrismaAdapter(db)({})
78
- })
79
-
80
- export { handler, dbSchema }
81
- ```
82
-
83
- **Note:** `betterStack()` returns both `handler` and `dbSchema`. The `dbSchema` contains all merged database schemas from your plugins. Use [@btst/cli](https://www.npmjs.com/package/@btst/cli) to generate migrations, Prisma schemas, or other database artifacts from your `dbSchema`.
84
-
85
- For example, to generate a Prisma schema from your `dbSchema`:
86
-
87
- ```bash
88
- npx @btst/cli generate --orm prisma --config lib/better-db.ts --output prisma/schema.prisma --filter-auth
89
- ```
90
-
91
- This reads your `dbSchema` export and generates the corresponding Prisma schema file.
92
-
93
- ### 2. API Route (`app/api/[[...]]/route.ts`)
94
-
95
- ```ts
96
- import { handler } from "@/lib/better-stack"
97
-
98
- export const GET = handler
99
- export const POST = handler
100
- ```
101
-
102
- ### 3. Client Setup (`lib/better-stack-client.tsx`)
103
-
104
- ```ts
105
- import { createStackClient } from "@btst/stack/client"
106
- import { blogClientPlugin } from "@btst/stack/plugins/blog/client"
107
-
108
- export const getStackClient = (queryClient: QueryClient) => {
109
- return createStackClient({
110
- plugins: {
111
- blog: blogClientPlugin({
112
- queryClient,
113
- apiBaseURL: baseURL,
114
- apiBasePath: "/api/data",
115
- siteBaseURL: baseURL,
116
- siteBasePath: "/pages"
117
- })
118
- }
119
- })
120
- }
121
- ```
122
-
123
- ### 4. Page Handler (`app/pages/[[...all]]/page.tsx`)
124
-
125
- ```ts
126
- export default async function Page({ params }) {
127
- const path = `/${(await params).all?.join("/") || ""}`
128
- const stackClient = getStackClient(queryClient)
129
- const route = stackClient.router.getRoute(path)
130
-
131
- if (route?.loader) await route.loader()
132
-
133
- return (
134
- <HydrationBoundary state={dehydrate(queryClient)}>
135
- <ClientRouteResolver path={path} />
136
- </HydrationBoundary>
137
- )
138
- }
139
- ```
140
-
141
- ### 5. Layout Provider (`app/pages/[[...all]]/layout.tsx`)
142
-
143
- ```ts
144
- import { BetterStackProvider } from "@btst/stack/context"
145
- import Link from "next/link"
146
- import Image from "next/image"
147
- import { useRouter } from "next/navigation"
148
-
149
- export default function Layout({ children }) {
150
- const router = useRouter()
151
-
152
- return (
153
- <BetterStackProvider
154
- basePath="/pages"
155
- overrides={{
156
- blog: {
157
- // Use Next.js optimized Image component
158
- Image: (props) => (
159
- <Image
160
- alt={props.alt || ""}
161
- src={props.src || ""}
162
- width={400}
163
- height={300}
164
- />
165
- ),
166
- // Use Next.js Link for client-side navigation
167
- navigate: (path) => router.push(path),
168
- refresh: () => router.refresh()
169
- }
170
- }}
171
- >
172
- {children}
173
- </BetterStackProvider>
174
- )
175
- }
176
- ```
177
-
178
- ### 6. Sitemap Generation (`app/sitemap.ts`)
179
-
180
- ```ts
181
- import type { MetadataRoute } from "next"
182
- import { QueryClient } from "@tanstack/react-query"
183
- import { getStackClient } from "@/lib/better-stack-client"
184
-
185
- export const dynamic = "force-dynamic"
186
-
187
- export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
188
- const queryClient = new QueryClient()
189
- const stackClient = getStackClient(queryClient)
190
- const entries = await stackClient.generateSitemap()
191
-
192
- return entries.map((e) => ({
193
- url: e.url,
194
- lastModified: e.lastModified,
195
- changeFrequency: e.changeFrequency,
196
- priority: e.priority,
197
- }))
198
- }
199
- ```
200
-
201
- **That's it.** Your blog feature is live with:
202
- - ✅ `/blog` - Post listing page
203
- - ✅ `/blog/[slug]` - Individual post pages
204
- - ✅ `/blog/new` - Create post editor
205
- - ✅ `/blog/[slug]/edit` - Edit post page
206
- - ✅ Full CRUD API (`/api/data/blog/*`)
207
- - ✅ Server-side rendering
208
- - ✅ Automatic metadata generation
209
- - ✅ Automatic sitemap generation
210
- - ✅ React Query hooks (`usePosts`, `usePost`, etc.)
211
-
212
- Now add scheduling, feedback, or newsletters the same way. Each feature is independent and composable.
48
+ Learn more about Better Stack, full installation, usage instructions and available plugins in the [documentation](https://www.better-stack.ai/docs).
213
49
 
214
50
  ## The Bigger Picture
215
51
 
216
52
  Better Stack transforms how you think about building apps:
217
53
 
218
54
  - **Open source** - Share complete features, not just code snippets. Someone can add a newsletter plugin to their Next.js app in minutes
219
- - **Fast development** - Add 5 features in an afternoon instead of 5 weeks. Validate ideas faster
220
- - **Agencies** - Create a library of reusable features. Drop scheduling into client A's app, feedback into client B's app.
221
- - **SaaS platforms** - Offer feature plugins your customers can compose. They pick blog + scheduling + AI assistant, mix and match to build their ideal app
55
+ - **Fast development** - Add 5 features in an afternoon instead of 5 months. Validate ideas faster
56
+ - **Framework and Database Agnostic** - Use any framework and database you want. Better Stack works with any modern framework and database.
222
57
 
223
58
 
224
59
  Each plugin is a complete, self-contained horizontal full-stack feature. No framework lock-in. Just add it and it works.
@@ -28,6 +28,19 @@ declare function RouteRenderer({ router, path, NotFoundComponent, onNotFound, on
28
28
  onError: (error: Error, info: ErrorInfo) => void;
29
29
  props?: any;
30
30
  }): react_jsx_runtime.JSX.Element;
31
+ /**
32
+ * Renders a route with Suspense and ErrorBoundary wrappers.
33
+ * Handles loading states, error boundaries, and not-found scenarios for a single route.
34
+ *
35
+ * @param path - The current route path
36
+ * @param PageComponent - The page component to render
37
+ * @param ErrorComponent - Optional error fallback component
38
+ * @param LoadingComponent - Component to show during suspense
39
+ * @param onNotFound - Optional callback when route is not found
40
+ * @param NotFoundComponent - Optional component to show for 404s
41
+ * @param props - Additional props to pass to the page component
42
+ * @param onError - Error handler callback for the error boundary
43
+ */
31
44
  declare function ComposedRoute({ path, PageComponent, ErrorComponent, LoadingComponent, onNotFound, NotFoundComponent, props, onError, }: {
32
45
  path: string;
33
46
  PageComponent: react__default.ComponentType<any>;
@@ -41,6 +54,15 @@ declare function ComposedRoute({ path, PageComponent, ErrorComponent, LoadingCom
41
54
  onError: (error: Error, info: ErrorInfo) => void;
42
55
  }): react_jsx_runtime.JSX.Element | undefined;
43
56
 
57
+ /**
58
+ * Error boundary wrapper component for catching and handling React errors.
59
+ * Wraps react-error-boundary with a simplified API.
60
+ *
61
+ * @param children - Child components to wrap with error boundary
62
+ * @param FallbackComponent - Component to render when an error occurs
63
+ * @param resetKeys - Array of values that will reset the error boundary when changed
64
+ * @param onError - Callback invoked when an error is caught
65
+ */
44
66
  declare function ErrorBoundary({ children, FallbackComponent, resetKeys, onError, }: {
45
67
  children: React.ReactNode;
46
68
  FallbackComponent: React.ComponentType<FallbackProps>;
@@ -28,6 +28,19 @@ declare function RouteRenderer({ router, path, NotFoundComponent, onNotFound, on
28
28
  onError: (error: Error, info: ErrorInfo) => void;
29
29
  props?: any;
30
30
  }): react_jsx_runtime.JSX.Element;
31
+ /**
32
+ * Renders a route with Suspense and ErrorBoundary wrappers.
33
+ * Handles loading states, error boundaries, and not-found scenarios for a single route.
34
+ *
35
+ * @param path - The current route path
36
+ * @param PageComponent - The page component to render
37
+ * @param ErrorComponent - Optional error fallback component
38
+ * @param LoadingComponent - Component to show during suspense
39
+ * @param onNotFound - Optional callback when route is not found
40
+ * @param NotFoundComponent - Optional component to show for 404s
41
+ * @param props - Additional props to pass to the page component
42
+ * @param onError - Error handler callback for the error boundary
43
+ */
31
44
  declare function ComposedRoute({ path, PageComponent, ErrorComponent, LoadingComponent, onNotFound, NotFoundComponent, props, onError, }: {
32
45
  path: string;
33
46
  PageComponent: react__default.ComponentType<any>;
@@ -41,6 +54,15 @@ declare function ComposedRoute({ path, PageComponent, ErrorComponent, LoadingCom
41
54
  onError: (error: Error, info: ErrorInfo) => void;
42
55
  }): react_jsx_runtime.JSX.Element | undefined;
43
56
 
57
+ /**
58
+ * Error boundary wrapper component for catching and handling React errors.
59
+ * Wraps react-error-boundary with a simplified API.
60
+ *
61
+ * @param children - Child components to wrap with error boundary
62
+ * @param FallbackComponent - Component to render when an error occurs
63
+ * @param resetKeys - Array of values that will reset the error boundary when changed
64
+ * @param onError - Callback invoked when an error is caught
65
+ */
44
66
  declare function ErrorBoundary({ children, FallbackComponent, resetKeys, onError, }: {
45
67
  children: React.ReactNode;
46
68
  FallbackComponent: React.ComponentType<FallbackProps>;
@@ -28,6 +28,19 @@ declare function RouteRenderer({ router, path, NotFoundComponent, onNotFound, on
28
28
  onError: (error: Error, info: ErrorInfo) => void;
29
29
  props?: any;
30
30
  }): react_jsx_runtime.JSX.Element;
31
+ /**
32
+ * Renders a route with Suspense and ErrorBoundary wrappers.
33
+ * Handles loading states, error boundaries, and not-found scenarios for a single route.
34
+ *
35
+ * @param path - The current route path
36
+ * @param PageComponent - The page component to render
37
+ * @param ErrorComponent - Optional error fallback component
38
+ * @param LoadingComponent - Component to show during suspense
39
+ * @param onNotFound - Optional callback when route is not found
40
+ * @param NotFoundComponent - Optional component to show for 404s
41
+ * @param props - Additional props to pass to the page component
42
+ * @param onError - Error handler callback for the error boundary
43
+ */
31
44
  declare function ComposedRoute({ path, PageComponent, ErrorComponent, LoadingComponent, onNotFound, NotFoundComponent, props, onError, }: {
32
45
  path: string;
33
46
  PageComponent: react__default.ComponentType<any>;
@@ -41,6 +54,15 @@ declare function ComposedRoute({ path, PageComponent, ErrorComponent, LoadingCom
41
54
  onError: (error: Error, info: ErrorInfo) => void;
42
55
  }): react_jsx_runtime.JSX.Element | undefined;
43
56
 
57
+ /**
58
+ * Error boundary wrapper component for catching and handling React errors.
59
+ * Wraps react-error-boundary with a simplified API.
60
+ *
61
+ * @param children - Child components to wrap with error boundary
62
+ * @param FallbackComponent - Component to render when an error occurs
63
+ * @param resetKeys - Array of values that will reset the error boundary when changed
64
+ * @param onError - Callback invoked when an error is caught
65
+ */
44
66
  declare function ErrorBoundary({ children, FallbackComponent, resetKeys, onError, }: {
45
67
  children: React.ReactNode;
46
68
  FallbackComponent: React.ComponentType<FallbackProps>;
@@ -50,8 +50,16 @@ declare function BetterStackProvider<TPluginOverrides extends Record<string, any
50
50
  basePath: string;
51
51
  }): react_jsx_runtime.JSX.Element;
52
52
  /**
53
- * Hook to access the entire context
53
+ * Hook to access the entire BetterStack context
54
54
  * Useful if you need access to multiple plugins or the full context
55
+ *
56
+ * @returns The full context value including overrides and basePath
57
+ * @throws Error if used outside of BetterStackProvider
58
+ *
59
+ * @example
60
+ * ```tsx
61
+ * const { overrides, basePath } = useBetterStack<MyPluginOverrides>();
62
+ * ```
55
63
  */
56
64
  declare function useBetterStack<TPluginOverrides extends Record<string, any> = Record<string, any>>(): BetterStackContextValue<TPluginOverrides>;
57
65
  type OverridesResult<TOverrides, TDefaults> = undefined extends TDefaults ? TOverrides : TOverrides & Required<Pick<TDefaults & {}, keyof TDefaults>>;
@@ -81,6 +89,18 @@ type OverridesResult<TOverrides, TDefaults> = undefined extends TDefaults ? TOve
81
89
  * ```
82
90
  */
83
91
  declare function usePluginOverrides<TOverrides = any, TDefaults extends Partial<TOverrides> | undefined = undefined>(pluginName: string, defaultValues?: TDefaults): OverridesResult<TOverrides, TDefaults>;
92
+ /**
93
+ * Hook to access the base path where the client router is mounted
94
+ *
95
+ * @returns The base path string (e.g., "/pages")
96
+ * @throws Error if used outside of BetterStackProvider
97
+ *
98
+ * @example
99
+ * ```tsx
100
+ * const basePath = useBasePath();
101
+ * // basePath = "/pages"
102
+ * ```
103
+ */
84
104
  declare function useBasePath(): string;
85
105
 
86
106
  export { BetterStackProvider, useBasePath, useBetterStack, usePluginOverrides };
@@ -50,8 +50,16 @@ declare function BetterStackProvider<TPluginOverrides extends Record<string, any
50
50
  basePath: string;
51
51
  }): react_jsx_runtime.JSX.Element;
52
52
  /**
53
- * Hook to access the entire context
53
+ * Hook to access the entire BetterStack context
54
54
  * Useful if you need access to multiple plugins or the full context
55
+ *
56
+ * @returns The full context value including overrides and basePath
57
+ * @throws Error if used outside of BetterStackProvider
58
+ *
59
+ * @example
60
+ * ```tsx
61
+ * const { overrides, basePath } = useBetterStack<MyPluginOverrides>();
62
+ * ```
55
63
  */
56
64
  declare function useBetterStack<TPluginOverrides extends Record<string, any> = Record<string, any>>(): BetterStackContextValue<TPluginOverrides>;
57
65
  type OverridesResult<TOverrides, TDefaults> = undefined extends TDefaults ? TOverrides : TOverrides & Required<Pick<TDefaults & {}, keyof TDefaults>>;
@@ -81,6 +89,18 @@ type OverridesResult<TOverrides, TDefaults> = undefined extends TDefaults ? TOve
81
89
  * ```
82
90
  */
83
91
  declare function usePluginOverrides<TOverrides = any, TDefaults extends Partial<TOverrides> | undefined = undefined>(pluginName: string, defaultValues?: TDefaults): OverridesResult<TOverrides, TDefaults>;
92
+ /**
93
+ * Hook to access the base path where the client router is mounted
94
+ *
95
+ * @returns The base path string (e.g., "/pages")
96
+ * @throws Error if used outside of BetterStackProvider
97
+ *
98
+ * @example
99
+ * ```tsx
100
+ * const basePath = useBasePath();
101
+ * // basePath = "/pages"
102
+ * ```
103
+ */
84
104
  declare function useBasePath(): string;
85
105
 
86
106
  export { BetterStackProvider, useBasePath, useBetterStack, usePluginOverrides };
@@ -50,8 +50,16 @@ declare function BetterStackProvider<TPluginOverrides extends Record<string, any
50
50
  basePath: string;
51
51
  }): react_jsx_runtime.JSX.Element;
52
52
  /**
53
- * Hook to access the entire context
53
+ * Hook to access the entire BetterStack context
54
54
  * Useful if you need access to multiple plugins or the full context
55
+ *
56
+ * @returns The full context value including overrides and basePath
57
+ * @throws Error if used outside of BetterStackProvider
58
+ *
59
+ * @example
60
+ * ```tsx
61
+ * const { overrides, basePath } = useBetterStack<MyPluginOverrides>();
62
+ * ```
55
63
  */
56
64
  declare function useBetterStack<TPluginOverrides extends Record<string, any> = Record<string, any>>(): BetterStackContextValue<TPluginOverrides>;
57
65
  type OverridesResult<TOverrides, TDefaults> = undefined extends TDefaults ? TOverrides : TOverrides & Required<Pick<TDefaults & {}, keyof TDefaults>>;
@@ -81,6 +89,18 @@ type OverridesResult<TOverrides, TDefaults> = undefined extends TDefaults ? TOve
81
89
  * ```
82
90
  */
83
91
  declare function usePluginOverrides<TOverrides = any, TDefaults extends Partial<TOverrides> | undefined = undefined>(pluginName: string, defaultValues?: TDefaults): OverridesResult<TOverrides, TDefaults>;
92
+ /**
93
+ * Hook to access the base path where the client router is mounted
94
+ *
95
+ * @returns The base path string (e.g., "/pages")
96
+ * @throws Error if used outside of BetterStackProvider
97
+ *
98
+ * @example
99
+ * ```tsx
100
+ * const basePath = useBasePath();
101
+ * // basePath = "/pages"
102
+ * ```
103
+ */
84
104
  declare function useBasePath(): string;
85
105
 
86
106
  export { BetterStackProvider, useBasePath, useBetterStack, usePluginOverrides };
@@ -7,6 +7,7 @@ const utils = require('../../../utils.cjs');
7
7
  const context = require('@btst/stack/context');
8
8
  const index = require('../../localization/index.cjs');
9
9
  const select = require('../../../../../../../ui/src/components/select.cjs');
10
+ const lucideReact = require('lucide-react');
10
11
 
11
12
  function OnThisPage({ markdown, className }) {
12
13
  const { localization } = context.usePluginOverrides("blog", {
@@ -39,8 +40,12 @@ function OnThisPage({ markdown, className }) {
39
40
  className
40
41
  ),
41
42
  "aria-label": "Table of contents",
42
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto px-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 p-4 pt-0 text-sm", children: [
43
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-muted-foreground sticky top-0 h-6 text-xs", children: localization.BLOG_POST_ON_THIS_PAGE }),
43
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto px-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 p-4 pt-0 text-sm", children: [
44
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 font-semibold text-muted-foreground sticky top-0 h-6 text-xs", children: [
45
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TextAlignStart, { className: "w-3 h-3" }),
46
+ " ",
47
+ localization.BLOG_POST_ON_THIS_PAGE
48
+ ] }),
44
49
  headings.map(({ id, text, level }) => {
45
50
  const paddingLeft = level === 1 ? "0" : level === 2 ? "0.5rem" : level === 3 ? "1rem" : level === 4 ? "1.5rem" : level === 5 ? "2rem" : level === 6 ? "2.5rem" : "0";
46
51
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -5,6 +5,7 @@ import { cn, slugify } from '../../../utils.mjs';
5
5
  import { usePluginOverrides } from '@btst/stack/context';
6
6
  import { BLOG_LOCALIZATION } from '../../localization/index.mjs';
7
7
  import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../../../../../../../ui/src/components/select.mjs';
8
+ import { TextAlignStart } from 'lucide-react';
8
9
 
9
10
  function OnThisPage({ markdown, className }) {
10
11
  const { localization } = usePluginOverrides("blog", {
@@ -37,8 +38,12 @@ function OnThisPage({ markdown, className }) {
37
38
  className
38
39
  ),
39
40
  "aria-label": "Table of contents",
40
- children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto px-2", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 p-4 pt-0 text-sm", children: [
41
- /* @__PURE__ */ jsx("p", { className: "font-semibold text-muted-foreground sticky top-0 h-6 text-xs", children: localization.BLOG_POST_ON_THIS_PAGE }),
41
+ children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto px-2", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 p-4 pt-0 text-sm", children: [
42
+ /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 font-semibold text-muted-foreground sticky top-0 h-6 text-xs", children: [
43
+ /* @__PURE__ */ jsx(TextAlignStart, { className: "w-3 h-3" }),
44
+ " ",
45
+ localization.BLOG_POST_ON_THIS_PAGE
46
+ ] }),
42
47
  headings.map(({ id, text, level }) => {
43
48
  const paddingLeft = level === 1 ? "0" : level === 2 ? "0.5rem" : level === 3 ? "1rem" : level === 4 ? "1.5rem" : level === 5 ? "2rem" : level === 6 ? "2.5rem" : "0";
44
49
  return /* @__PURE__ */ jsx(
@@ -2,47 +2,94 @@ import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import { S as SerializedPost, c as createPostSchema, u as updatePostSchema, a as SerializedTag } from '../../../../shared/stack.Cr2JoQdo.cjs';
3
3
  import { z } from 'zod';
4
4
 
5
+ /**
6
+ * Options for the usePosts hook
7
+ */
5
8
  interface UsePostsOptions {
9
+ /** Filter posts by tag name */
6
10
  tag?: string;
11
+ /** Filter posts by tag slug */
7
12
  tagSlug?: string;
13
+ /** Number of posts to fetch per page (default: 10) */
8
14
  limit?: number;
15
+ /** Whether to enable the query (default: true) */
9
16
  enabled?: boolean;
17
+ /** Search query to filter posts by title, content, or excerpt */
10
18
  query?: string;
19
+ /** Filter by published status */
11
20
  published?: boolean;
21
+ /** Filter by specific post slug */
12
22
  slug?: string;
13
23
  }
24
+ /**
25
+ * Result from the usePosts hook
26
+ */
14
27
  interface UsePostsResult {
28
+ /** Array of fetched posts */
15
29
  posts: SerializedPost[];
30
+ /** Whether the initial load is in progress */
16
31
  isLoading: boolean;
32
+ /** Error if the query failed */
17
33
  error: Error | null;
34
+ /** Function to load the next page of posts */
18
35
  loadMore: () => void;
36
+ /** Whether there are more posts to load */
19
37
  hasMore: boolean;
38
+ /** Whether the next page is being loaded */
20
39
  isLoadingMore: boolean;
40
+ /** Function to refetch the posts */
21
41
  refetch: () => void;
22
42
  }
43
+ /**
44
+ * Options for the usePostSearch hook
45
+ */
23
46
  interface UsePostSearchOptions {
47
+ /** Search query string to filter posts */
24
48
  query: string;
49
+ /** Whether to enable the search query (default: true) */
25
50
  enabled?: boolean;
51
+ /** Debounce delay in milliseconds (default: 300) */
26
52
  debounceMs?: number;
53
+ /** Number of results to return (default: 10) */
27
54
  limit?: number;
55
+ /** Filter by published status (default: true) */
28
56
  published?: boolean;
29
57
  }
58
+ /**
59
+ * Result from the usePostSearch hook
60
+ */
30
61
  interface UsePostSearchResult {
62
+ /** Array of posts matching the search query */
31
63
  posts: SerializedPost[];
64
+ /** Alias for posts (React Query compatibility) */
32
65
  data: SerializedPost[];
66
+ /** Whether the search is in progress */
33
67
  isLoading: boolean;
68
+ /** Error if the search failed */
34
69
  error: Error | null;
70
+ /** Function to refetch the search results */
35
71
  refetch: () => void;
72
+ /** Whether a search is currently in progress (includes debounce time) */
36
73
  isSearching: boolean;
74
+ /** The debounced search query being used */
37
75
  searchQuery: string;
38
76
  }
77
+ /**
78
+ * Result from the usePost hook
79
+ */
39
80
  interface UsePostResult {
81
+ /** The fetched post, or null if not found */
40
82
  post: SerializedPost | null;
83
+ /** Whether the post is being loaded */
41
84
  isLoading: boolean;
85
+ /** Error if the query failed */
42
86
  error: Error | null;
87
+ /** Function to refetch the post */
43
88
  refetch: () => void;
44
89
  }
90
+ /** Input type for creating a new post */
45
91
  type PostCreateInput = z.infer<typeof createPostSchema>;
92
+ /** Input type for updating an existing post */
46
93
  type PostUpdateInput = z.infer<typeof updatePostSchema>;
47
94
  /**
48
95
  * Hook for fetching paginated posts with load more functionality
@@ -114,14 +161,26 @@ declare function useDeletePost(): _tanstack_react_query.UseMutationResult<{
114
161
  * Debounces the query and preserves last successful results to avoid flicker.
115
162
  */
116
163
  declare function usePostSearch({ query, enabled, debounceMs, limit, published, }: UsePostSearchOptions): UsePostSearchResult;
164
+ /**
165
+ * Options for the useNextPreviousPosts hook
166
+ */
117
167
  interface UseNextPreviousPostsOptions {
168
+ /** Whether to enable the query (default: true) */
118
169
  enabled?: boolean;
119
170
  }
171
+ /**
172
+ * Result from the useNextPreviousPosts hook
173
+ */
120
174
  interface UseNextPreviousPostsResult {
175
+ /** The previous post (older), or null if none exists */
121
176
  previousPost: SerializedPost | null;
177
+ /** The next post (newer), or null if none exists */
122
178
  nextPost: SerializedPost | null;
179
+ /** Whether the query is loading */
123
180
  isLoading: boolean;
181
+ /** Error if the query failed */
124
182
  error: Error | null;
183
+ /** Function to refetch the posts */
125
184
  refetch: () => void;
126
185
  }
127
186
  /**
@@ -132,15 +191,28 @@ declare function useNextPreviousPosts(createdAt: string | Date, options?: UseNex
132
191
  ref: (node: Element | null) => void;
133
192
  inView: boolean;
134
193
  };
194
+ /**
195
+ * Options for the useRecentPosts hook
196
+ */
135
197
  interface UseRecentPostsOptions {
198
+ /** Maximum number of recent posts to fetch (default: 5) */
136
199
  limit?: number;
200
+ /** Slug of a post to exclude from results */
137
201
  excludeSlug?: string;
202
+ /** Whether to enable the query (default: true) */
138
203
  enabled?: boolean;
139
204
  }
205
+ /**
206
+ * Result from the useRecentPosts hook
207
+ */
140
208
  interface UseRecentPostsResult {
209
+ /** Array of recent posts */
141
210
  recentPosts: SerializedPost[];
211
+ /** Whether the query is loading */
142
212
  isLoading: boolean;
213
+ /** Error if the query failed */
143
214
  error: Error | null;
215
+ /** Function to refetch the posts */
144
216
  refetch: () => void;
145
217
  }
146
218
  /**