import * as _tanstack_react_query from '@tanstack/react-query';
import { QueryClient } from '@tanstack/react-query';
import { createApiClient } from '@btst/stack/plugins/client';
import { P as Post, T as Tag, c as createPostSchema, u as updatePostSchema, S as SerializedPost, a as SerializedTag } from './stack.BWp0hcm9.js';
import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
import * as better_call from 'better-call';
import { Adapter } from '@btst/db';
import { z } from 'zod';

/**
 * Parameters for filtering/paginating posts.
 * Mirrors the shape of the list API query schema.
 */
interface PostListParams {
    slug?: string;
    tagSlug?: string;
    offset?: number;
    limit?: number;
    query?: string;
    published?: boolean;
}
/**
 * Paginated result returned by {@link getAllPosts}.
 */
interface PostListResult {
    items: Array<Post & {
        tags: Tag[];
    }>;
    total: number;
    limit?: number;
    offset?: number;
}
/**
 * Retrieve all posts matching optional filter criteria.
 * Pure DB function — no hooks, no HTTP context. Safe for SSG and server-side use.
 *
 * @remarks **Security:** Authorization hooks (e.g. `onBeforeListPosts`) are NOT
 * called. The caller is responsible for any access-control checks before
 * invoking this function.
 *
 * @param adapter - The database adapter
 * @param params - Optional filter/pagination parameters (same shape as the list API query)
 */
declare function getAllPosts(adapter: Adapter, params?: PostListParams): Promise<PostListResult>;
/**
 * Retrieve a single post by its slug, including associated tags.
 * Returns null if no post is found.
 * Pure DB function — no hooks, no HTTP context. Safe for SSG and server-side use.
 *
 * @remarks **Security:** Authorization hooks are NOT called. The caller is
 * responsible for any access-control checks before invoking this function.
 *
 * @param adapter - The database adapter
 * @param slug - The post slug
 */
declare function getPostBySlug(adapter: Adapter, slug: string): Promise<(Post & {
    tags: Tag[];
}) | null>;
/**
 * Retrieve all tags, sorted alphabetically by name.
 * Pure DB function — no hooks, no HTTP context. Safe for SSG and server-side use.
 *
 * @remarks **Security:** Authorization hooks are NOT called. The caller is
 * responsible for any access-control checks before invoking this function.
 *
 * @param adapter - The database adapter
 */
declare function getAllTags(adapter: Adapter): Promise<Tag[]>;

/**
 * Route keys for the blog plugin — matches the keys returned by
 * `stackClient.router.getRoute(path).routeKey`.
 */
type BlogRouteKey = "posts" | "drafts" | "post" | "tag" | "newPost" | "editPost";
/**
 * Overloaded signature for `prefetchForRoute`.
 * TypeScript enforces the correct params for each routeKey at call sites.
 */
interface BlogPrefetchForRoute {
    (key: "posts" | "drafts" | "newPost", qc: QueryClient): Promise<void>;
    (key: "post" | "editPost", qc: QueryClient, params: {
        slug: string;
    }): Promise<void>;
    (key: "tag", qc: QueryClient, params: {
        tagSlug: string;
    }): Promise<void>;
}
declare const PostListQuerySchema: z.ZodObject<{
    slug: z.ZodOptional<z.ZodString>;
    tagSlug: z.ZodOptional<z.ZodString>;
    offset: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
    limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
    query: z.ZodOptional<z.ZodString>;
    published: z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<boolean | undefined, string | undefined>>;
}, z.core.$strip>;
declare const NextPreviousPostsQuerySchema: z.ZodObject<{
    date: z.ZodCoercedDate<unknown>;
}, z.core.$strip>;
/**
 * Context passed to blog API hooks
 */
interface BlogApiContext<TBody = any, TParams = any, TQuery = any> {
    body?: TBody;
    params?: TParams;
    query?: TQuery;
    request?: Request;
    headers?: Headers;
    [key: string]: any;
}
/**
 * Configuration hooks for blog backend plugin
 * All hooks are optional and allow consumers to customize behavior
 */
interface BlogBackendHooks {
    /**
     * Called before listing posts. Throw an error to deny access.
     * @param filter - Query parameters for filtering posts
     * @param context - Request context with headers, etc.
     */
    onBeforeListPosts?: (filter: z.infer<typeof PostListQuerySchema>, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called before creating a post. Throw an error to deny access.
     * @param data - Post data being created
     * @param context - Request context with headers, etc.
     */
    onBeforeCreatePost?: (data: z.infer<typeof createPostSchema>, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called before updating a post. Throw an error to deny access.
     * @param postId - ID of the post being updated
     * @param data - Updated post data
     * @param context - Request context with headers, etc.
     */
    onBeforeUpdatePost?: (postId: string, data: z.infer<typeof updatePostSchema>, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called before deleting a post. Throw an error to deny access.
     * @param postId - ID of the post being deleted
     * @param context - Request context with headers, etc.
     */
    onBeforeDeletePost?: (postId: string, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called after posts are read successfully
     * @param posts - The list of posts returned by the query
     * @param filter - Query parameters used for filtering
     * @param context - Request context
     */
    onPostsRead?: (posts: Array<Post & {
        tags: Tag[];
    }>, filter: z.infer<typeof PostListQuerySchema>, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called after a post is created successfully
     * @param post - The created post
     * @param context - Request context
     */
    onPostCreated?: (post: Post, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called after a post is updated successfully
     * @param post - The updated post
     * @param context - Request context
     */
    onPostUpdated?: (post: Post, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called after a post is deleted successfully
     * @param postId - ID of the deleted post
     * @param context - Request context
     */
    onPostDeleted?: (postId: string, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called when listing posts fails
     * @param error - The error that occurred
     * @param context - Request context
     */
    onListPostsError?: (error: Error, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called when creating a post fails
     * @param error - The error that occurred
     * @param context - Request context
     */
    onCreatePostError?: (error: Error, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called when updating a post fails
     * @param error - The error that occurred
     * @param context - Request context
     */
    onUpdatePostError?: (error: Error, context: BlogApiContext) => Promise<void> | void;
    /**
     * Called when deleting a post fails
     * @param error - The error that occurred
     * @param context - Request context
     */
    onDeletePostError?: (error: Error, context: BlogApiContext) => Promise<void> | void;
}
/**
 * Blog backend plugin
 * Provides API endpoints for managing blog posts
 * Uses better-db adapter for database operations
 *
 * @param hooks - Optional configuration hooks for customizing plugin behavior
 */
declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugins_api.BackendPlugin<{
    readonly listPosts: better_call.StrictEndpoint<"/posts", {
        method: "GET";
        query: z.ZodObject<{
            slug: z.ZodOptional<z.ZodString>;
            tagSlug: z.ZodOptional<z.ZodString>;
            offset: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
            limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
            query: z.ZodOptional<z.ZodString>;
            published: z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<boolean | undefined, string | undefined>>;
        }, z.core.$strip>;
    }, PostListResult>;
    readonly createPost: better_call.StrictEndpoint<"/posts", {
        method: "POST";
        body: z.ZodObject<{
            tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
                name: z.ZodString;
            }, z.core.$strip>, z.ZodObject<{
                id: z.ZodString;
                name: z.ZodString;
                slug: z.ZodString;
            }, z.core.$strip>]>>>>;
            slug: z.ZodOptional<z.ZodString>;
            published: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
            publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
            createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
            updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
            title: z.ZodString;
            content: z.ZodString;
            excerpt: z.ZodString;
            image: z.ZodOptional<z.ZodString>;
        }, z.core.$strip>;
    }, Post>;
    readonly updatePost: better_call.StrictEndpoint<"/posts/:id", {
        method: "PUT";
        body: z.ZodObject<{
            publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
            createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
            updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
            title: z.ZodString;
            content: z.ZodString;
            excerpt: z.ZodString;
            image: z.ZodOptional<z.ZodString>;
            published: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
            slug: z.ZodString;
            tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
                name: z.ZodString;
            }, z.core.$strip>, z.ZodObject<{
                id: z.ZodString;
                name: z.ZodString;
                slug: z.ZodString;
            }, z.core.$strip>]>>>>;
            id: z.ZodString;
        }, z.core.$strip>;
    }, Post>;
    readonly deletePost: better_call.StrictEndpoint<"/posts/:id", {
        method: "DELETE";
    }, {
        success: boolean;
    }>;
    readonly getNextPreviousPosts: better_call.StrictEndpoint<"/posts/next-previous", {
        method: "GET";
        query: z.ZodObject<{
            date: z.ZodCoercedDate<unknown>;
        }, z.core.$strip>;
    }, {
        previous: {
            tags: Tag[];
            id: string;
            authorId?: string;
            defaultLocale?: string;
            slug: string;
            title: string;
            content: string;
            excerpt: string;
            image?: string;
            published: boolean;
            status?: "DRAFT" | "PUBLISHED";
            publishedAt?: Date;
            createdAt: Date;
            updatedAt: Date;
        } | null;
        next: {
            tags: Tag[];
            id: string;
            authorId?: string;
            defaultLocale?: string;
            slug: string;
            title: string;
            content: string;
            excerpt: string;
            image?: string;
            published: boolean;
            status?: "DRAFT" | "PUBLISHED";
            publishedAt?: Date;
            createdAt: Date;
            updatedAt: Date;
        } | null;
    }>;
    readonly listTags: better_call.StrictEndpoint<"/tags", {
        method: "GET";
    }, Tag[]>;
}, {
    getAllPosts: (params?: Parameters<typeof getAllPosts>[1]) => Promise<PostListResult>;
    getPostBySlug: (slug: string) => Promise<(Post & {
        tags: Tag[];
    }) | null>;
    getAllTags: () => Promise<Tag[]>;
    prefetchForRoute: BlogPrefetchForRoute;
}>;
type BlogApiRouter = ReturnType<ReturnType<typeof blogBackendPlugin>["routes"]>;

/**
 * Internal query key constants for the blog plugin.
 * Shared between query-keys.ts (HTTP path) and prefetchForRoute (DB path)
 * to prevent key drift between SSR loaders and SSG prefetching.
 */
interface PostsListDiscriminator {
    query: string | undefined;
    limit: number;
    published: boolean;
    tagSlug: string | undefined;
}
/** Full query key builders — use these with queryClient.setQueryData() */
declare const BLOG_QUERY_KEYS: {
    postsList: (params: {
        published: boolean;
        limit?: number;
        tagSlug?: string;
    }) => readonly ["posts", "list", PostsListDiscriminator];
    postDetail: (slug: string) => readonly ["posts", "detail", string];
    tagsList: () => readonly ["tags", "list", "tags"];
};

interface PostsListParams {
    query?: string;
    limit?: number;
    published?: boolean;
    tagSlug?: string;
}
declare function createBlogQueryKeys(client: ReturnType<typeof createApiClient<BlogApiRouter>>, headers?: HeadersInit): {
    posts: {
        _def: readonly ["posts"];
    } & {
        list: ((params?: PostsListParams | undefined) => Omit<Omit<{
            queryKey: readonly ["posts", "list", PostsListDiscriminator];
            queryFn: _tanstack_react_query.QueryFunction<unknown, readonly ["posts", "list", PostsListDiscriminator]>;
        }, "queryFn"> & {
            _def: readonly ["posts", "list"];
        }, "_def">) & {
            _def: readonly ["posts", "list"];
        };
        detail: ((slug: string) => Omit<{
            queryKey: readonly ["posts", "detail", string];
            queryFn: _tanstack_react_query.QueryFunction<SerializedPost | null, readonly ["posts", "detail", string]>;
        } & {
            _def: readonly ["posts", "detail"];
        }, "_def">) & {
            _def: readonly ["posts", "detail"];
        };
        nextPrevious: ((date: string | Date) => Omit<{
            queryKey: readonly ["posts", "nextPrevious", string, string | Date];
            queryFn: _tanstack_react_query.QueryFunction<{
                previous: SerializedPost | null;
                next: SerializedPost | null;
            }, readonly ["posts", "nextPrevious", string, string | Date]>;
        } & {
            _def: readonly ["posts", "nextPrevious"];
        }, "_def">) & {
            _def: readonly ["posts", "nextPrevious"];
        };
        recent: ((params?: {
            limit?: number;
            excludeSlug?: string;
        } | undefined) => Omit<{
            queryKey: readonly ["posts", "recent", string, {
                limit?: number;
                excludeSlug?: string;
            } | undefined];
            queryFn: _tanstack_react_query.QueryFunction<SerializedPost[], readonly ["posts", "recent", string, {
                limit?: number;
                excludeSlug?: string;
            } | undefined]>;
        } & {
            _def: readonly ["posts", "recent"];
        }, "_def">) & {
            _def: readonly ["posts", "recent"];
        };
    };
    drafts: {
        _def: readonly ["drafts"];
    } & {
        list: ((params?: PostsListParams | undefined) => Omit<Omit<{
            queryKey: readonly ["drafts", "list", {
                limit?: number | undefined;
            }];
            queryFn: _tanstack_react_query.QueryFunction<unknown, readonly ["drafts", "list", {
                limit?: number | undefined;
            }]>;
        }, "queryFn"> & {
            _def: readonly ["drafts", "list"];
        }, "_def">) & {
            _def: readonly ["drafts", "list"];
        };
    };
    tags: {
        _def: readonly ["tags"];
    } & {
        list: (() => Omit<{
            queryKey: readonly ["tags", "list", string];
            queryFn: _tanstack_react_query.QueryFunction<SerializedTag[], readonly ["tags", "list", string]>;
        } & {
            _def: readonly ["tags", "list"];
        }, "_def">) & {
            _def: readonly ["tags", "list"];
        };
    };
};

export { BLOG_QUERY_KEYS as B, NextPreviousPostsQuerySchema as N, getPostBySlug as a, getAllTags as b, createBlogQueryKeys as d, PostListQuerySchema as f, getAllPosts as g, blogBackendPlugin as j };
export type { PostListParams as P, PostListResult as c, BlogRouteKey as e, BlogApiContext as h, BlogBackendHooks as i, BlogApiRouter as k };
