m14i-blogging 0.4.0 → 0.4.2
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 +1 -0
- package/dist/client/index.cjs +12 -12
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.mjs +12 -12
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.cjs +12 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +12 -12
- package/dist/index.mjs.map +1 -1
- package/dist/m14i-blogging-0.4.2.tgz +0 -0
- package/package.json +2 -3
- package/supabase/migrations/20260405000001_add_taxonomy_tables.sql +44 -43
- package/dist/m14i-blogging-0.4.0.tgz +0 -0
package/README.md
CHANGED
package/dist/client/index.cjs
CHANGED
|
@@ -334,7 +334,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
334
334
|
* List all categories
|
|
335
335
|
*/
|
|
336
336
|
async list() {
|
|
337
|
-
const { data, error } = await supabase.from("
|
|
337
|
+
const { data, error } = await supabase.from("blog_categories").select("*").order("display_order", { ascending: true });
|
|
338
338
|
if (error) {
|
|
339
339
|
throw new Error(`Failed to fetch categories: ${error.message}`);
|
|
340
340
|
}
|
|
@@ -354,7 +354,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
354
354
|
* Get category by ID
|
|
355
355
|
*/
|
|
356
356
|
async getById(id) {
|
|
357
|
-
const { data, error } = await supabase.from("
|
|
357
|
+
const { data, error } = await supabase.from("blog_categories").select("*").eq("id", id).single();
|
|
358
358
|
if (error) {
|
|
359
359
|
if (error.code === "PGRST116") return null;
|
|
360
360
|
throw new Error(`Failed to fetch category: ${error.message}`);
|
|
@@ -365,7 +365,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
365
365
|
* Get category by slug
|
|
366
366
|
*/
|
|
367
367
|
async getBySlug(slug) {
|
|
368
|
-
const { data, error } = await supabase.from("
|
|
368
|
+
const { data, error } = await supabase.from("blog_categories").select("*").eq("slug", slug).single();
|
|
369
369
|
if (error) {
|
|
370
370
|
if (error.code === "PGRST116") return null;
|
|
371
371
|
throw new Error(`Failed to fetch category: ${error.message}`);
|
|
@@ -376,7 +376,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
376
376
|
* Create a new category
|
|
377
377
|
*/
|
|
378
378
|
async create(category) {
|
|
379
|
-
const { data, error } = await supabase.from("
|
|
379
|
+
const { data, error } = await supabase.from("blog_categories").insert(category).select().single();
|
|
380
380
|
if (error) {
|
|
381
381
|
throw new Error(`Failed to create category: ${error.message}`);
|
|
382
382
|
}
|
|
@@ -386,7 +386,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
386
386
|
* Update an existing category
|
|
387
387
|
*/
|
|
388
388
|
async update(id, updates) {
|
|
389
|
-
const { data, error } = await supabase.from("
|
|
389
|
+
const { data, error } = await supabase.from("blog_categories").update(updates).eq("id", id).select().single();
|
|
390
390
|
if (error) {
|
|
391
391
|
throw new Error(`Failed to update category: ${error.message}`);
|
|
392
392
|
}
|
|
@@ -396,7 +396,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
396
396
|
* Delete a category
|
|
397
397
|
*/
|
|
398
398
|
async delete(id) {
|
|
399
|
-
const { error } = await supabase.from("
|
|
399
|
+
const { error } = await supabase.from("blog_categories").delete().eq("id", id);
|
|
400
400
|
if (error) {
|
|
401
401
|
throw new Error(`Failed to delete category: ${error.message}`);
|
|
402
402
|
}
|
|
@@ -410,7 +410,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
410
410
|
* List all tags
|
|
411
411
|
*/
|
|
412
412
|
async list() {
|
|
413
|
-
const { data, error } = await supabase.from("
|
|
413
|
+
const { data, error } = await supabase.from("blog_tags").select("*").order("name", { ascending: true });
|
|
414
414
|
if (error) {
|
|
415
415
|
throw new Error(`Failed to fetch tags: ${error.message}`);
|
|
416
416
|
}
|
|
@@ -430,7 +430,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
430
430
|
* Get tag by ID
|
|
431
431
|
*/
|
|
432
432
|
async getById(id) {
|
|
433
|
-
const { data, error } = await supabase.from("
|
|
433
|
+
const { data, error } = await supabase.from("blog_tags").select("*").eq("id", id).single();
|
|
434
434
|
if (error) {
|
|
435
435
|
if (error.code === "PGRST116") return null;
|
|
436
436
|
throw new Error(`Failed to fetch tag: ${error.message}`);
|
|
@@ -441,7 +441,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
441
441
|
* Get tag by slug
|
|
442
442
|
*/
|
|
443
443
|
async getBySlug(slug) {
|
|
444
|
-
const { data, error } = await supabase.from("
|
|
444
|
+
const { data, error } = await supabase.from("blog_tags").select("*").eq("slug", slug).single();
|
|
445
445
|
if (error) {
|
|
446
446
|
if (error.code === "PGRST116") return null;
|
|
447
447
|
throw new Error(`Failed to fetch tag: ${error.message}`);
|
|
@@ -452,7 +452,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
452
452
|
* Create a new tag
|
|
453
453
|
*/
|
|
454
454
|
async create(tag) {
|
|
455
|
-
const { data, error } = await supabase.from("
|
|
455
|
+
const { data, error } = await supabase.from("blog_tags").insert(tag).select().single();
|
|
456
456
|
if (error) {
|
|
457
457
|
throw new Error(`Failed to create tag: ${error.message}`);
|
|
458
458
|
}
|
|
@@ -462,7 +462,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
462
462
|
* Update an existing tag
|
|
463
463
|
*/
|
|
464
464
|
async update(id, updates) {
|
|
465
|
-
const { data, error } = await supabase.from("
|
|
465
|
+
const { data, error } = await supabase.from("blog_tags").update(updates).eq("id", id).select().single();
|
|
466
466
|
if (error) {
|
|
467
467
|
throw new Error(`Failed to update tag: ${error.message}`);
|
|
468
468
|
}
|
|
@@ -472,7 +472,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
472
472
|
* Delete a tag
|
|
473
473
|
*/
|
|
474
474
|
async delete(id) {
|
|
475
|
-
const { error } = await supabase.from("
|
|
475
|
+
const { error } = await supabase.from("blog_tags").delete().eq("id", id);
|
|
476
476
|
if (error) {
|
|
477
477
|
throw new Error(`Failed to delete tag: ${error.message}`);
|
|
478
478
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/index.ts","../../src/client/supabase.ts"],"sourcesContent":["/**\n * Client exports for m14i-blogging\n *\n * Pre-built data access layer for Supabase integration\n *\n * @example\n * ```typescript\n * import { createBlogClient } from 'm14i-blogging/client';\n * import { createClient } from '@supabase/supabase-js';\n *\n * const supabase = createClient(url, key);\n * const blog = createBlogClient(supabase);\n *\n * // Use the client\n * const { posts } = await blog.posts.list({ status: 'published' });\n * ```\n */\n\nexport { createBlogClient } from './supabase';\nexport type { BlogClient, BlogClientConfig, SupabaseClient } from './supabase';\n","/**\n * Supabase Data Access Layer for m14i-blogging\n *\n * Provides pre-built CRUD operations for blog posts and media.\n * Works with the blog_posts and blog_media tables.\n *\n * @example\n * ```typescript\n * import { createBlogClient } from 'm14i-blogging/client';\n * import { createClient } from '@supabase/supabase-js';\n *\n * const supabase = createClient(url, key);\n * const blog = createBlogClient(supabase);\n *\n * // Use it\n * const posts = await blog.posts.list({ status: 'published' });\n * const post = await blog.posts.getBySlug('my-post');\n * ```\n */\n\nimport type {\n BlogPostRow,\n BlogPostInsert,\n BlogPostUpdate,\n BlogPostWithAuthor,\n BlogFilterParams,\n BlogPostListResponse,\n BlogMediaRow,\n BlogMediaInsert,\n BlogMediaUpdate,\n BlogStats,\n BlogCategory,\n BlogTag,\n} from \"../types/database\";\n\n// ============================================================================\n// Supabase Client Type\n// ============================================================================\n\nexport interface SupabaseClient {\n from(table: string): {\n select(query: string, options?: { count?: string }): any;\n insert(data: any): any;\n update(data: any): any;\n delete(): any;\n upsert(data: any): any;\n };\n rpc(functionName: string, params?: any): any;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport interface BlogClientConfig {\n /**\n * Table name for blog posts (default: \"blog_posts\")\n */\n postsTable?: string;\n /**\n * Table name for blog media (default: \"blog_media\")\n */\n mediaTable?: string;\n /**\n * Enable/disable author joins (default: true)\n */\n includeAuthor?: boolean;\n /**\n * Users table name for author joins (default: \"users\")\n */\n usersTable?: string;\n}\n\nconst DEFAULT_CONFIG: Required<BlogClientConfig> = {\n postsTable: \"blog_posts\",\n mediaTable: \"blog_media\",\n includeAuthor: true,\n usersTable: \"users\",\n};\n\n// ============================================================================\n// Blog Client Factory\n// ============================================================================\n\n/**\n * Creates a blog client with pre-built CRUD operations\n */\nexport function createBlogClient(\n supabase: SupabaseClient,\n config: BlogClientConfig = {}\n) {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n\n return {\n /**\n * Blog post operations\n */\n posts: {\n /**\n * List blog posts with filtering and pagination\n */\n async list(\n params: BlogFilterParams = {}\n ): Promise<BlogPostListResponse> {\n const {\n page = 1,\n pageSize = 10,\n status,\n category,\n tag,\n search,\n orderBy = \"created_at\",\n orderDirection = \"desc\",\n } = params;\n\n const from = (page - 1) * pageSize;\n const to = from + pageSize - 1;\n\n let query = supabase\n .from(cfg.postsTable)\n .select(\n cfg.includeAuthor\n ? `\n *,\n author:${cfg.usersTable}!created_by(full_name, email, avatar_url)\n `\n : \"*\",\n { count: \"exact\" }\n )\n .range(from, to)\n .order(orderBy, { ascending: orderDirection === \"asc\" });\n\n if (status) {\n query = query.eq(\"status\", status);\n }\n\n if (category) {\n query = query.eq(\"category\", category);\n }\n\n if (tag) {\n query = query.contains(\"tags\", [tag]);\n }\n\n if (search) {\n query = query.or(\n `title.ilike.%${search}%,excerpt.ilike.%${search}%,category.ilike.%${search}%`\n );\n }\n\n const { data, error, count } = await query;\n\n if (error) {\n throw new Error(`Failed to fetch blog posts: ${error.message}`);\n }\n\n return {\n posts: (data as unknown as BlogPostWithAuthor[]) || [],\n total: count || 0,\n page,\n pageSize,\n totalPages: Math.ceil((count || 0) / pageSize),\n };\n },\n\n /**\n * Get a single post by slug\n */\n async getBySlug(slug: string): Promise<BlogPostWithAuthor | null> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\n cfg.includeAuthor\n ? `\n *,\n author:${cfg.usersTable}!created_by(full_name, email, avatar_url)\n `\n : \"*\"\n )\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n return null;\n }\n throw new Error(`Failed to fetch blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostWithAuthor;\n },\n\n /**\n * Get a single post by ID\n */\n async getById(id: string): Promise<BlogPostRow | null> {\n const { data, error} = await supabase\n .from(cfg.postsTable)\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n return null;\n }\n throw new Error(`Failed to fetch blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Create a new blog post\n */\n async create(post: BlogPostInsert): Promise<BlogPostRow> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .insert(post)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Update an existing blog post\n */\n async update(\n id: string,\n updates: BlogPostUpdate\n ): Promise<BlogPostRow> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Delete a blog post\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(cfg.postsTable)\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete blog post: ${error.message}`);\n }\n },\n\n /**\n * Publish a draft post\n */\n async publish(id: string): Promise<BlogPostRow> {\n return this.update(id, { status: \"published\" });\n },\n\n /**\n * Unpublish (archive) a post\n */\n async archive(id: string): Promise<BlogPostRow> {\n return this.update(id, { status: \"archived\" });\n },\n\n /**\n * Search posts using full-text search\n */\n async search(query: string, limit: number = 10): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_search_posts\", { search_query: query })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to search blog posts: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get posts by tag\n */\n async getByTag(tag: string, limit: number = 10): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_get_posts_by_tag\", { tag_name: tag })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get posts by tag: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get posts by category\n */\n async getByCategory(\n category: string,\n limit: number = 10\n ): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_get_posts_by_category\", { category_name: category })\n .limit(limit);\n\n if (error) {\n throw new Error(\n `Failed to get posts by category: ${error.message}`\n );\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get related posts (by tags and category)\n */\n async getRelated(postId: string, limit: number = 3): Promise<BlogPostRow[]> {\n const post = await this.getById(postId);\n if (!post) return [];\n\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"*\")\n .eq(\"status\", \"published\")\n .neq(\"id\", postId)\n .or(`category.eq.${post.category},tags.ov.{${post.tags.join(\",\")}}`)\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get related posts: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n },\n\n /**\n * Blog media operations\n */\n media: {\n /**\n * List all media files\n */\n async list(\n type?: string,\n limit: number = 50\n ): Promise<BlogMediaRow[]> {\n let query = supabase\n .from(cfg.mediaTable)\n .select(\"*\")\n .order(\"uploaded_at\", { ascending: false })\n .limit(limit);\n\n if (type) {\n query = query.eq(\"type\", type);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new Error(`Failed to fetch blog media: ${error.message}`);\n }\n\n return (data as unknown as BlogMediaRow[]) || [];\n },\n\n /**\n * Create new media record\n */\n async create(media: BlogMediaInsert): Promise<BlogMediaRow> {\n const { data, error } = await supabase\n .from(cfg.mediaTable)\n .insert(media)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create blog media: ${error.message}`);\n }\n\n return data as unknown as BlogMediaRow;\n },\n\n /**\n * Update media record\n */\n async update(id: string, updates: BlogMediaUpdate): Promise<BlogMediaRow> {\n const { data, error } = await supabase\n .from(cfg.mediaTable)\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update blog media: ${error.message}`);\n }\n\n return data as unknown as BlogMediaRow;\n },\n\n /**\n * Delete media record\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(cfg.mediaTable)\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete blog media: ${error.message}`);\n }\n },\n },\n\n /**\n * Statistics and analytics\n */\n stats: {\n /**\n * Get blog statistics\n */\n async getStats(): Promise<BlogStats> {\n const { data: posts, error } = await supabase\n .from(cfg.postsTable)\n .select(\"status, category, tags\");\n\n if (error) {\n throw new Error(`Failed to fetch blog stats: ${error.message}`);\n }\n\n const stats: BlogStats = {\n totalPosts: posts.length,\n publishedPosts: 0,\n draftPosts: 0,\n archivedPosts: 0,\n categoryCounts: {},\n tagCounts: {},\n };\n\n posts.forEach((post: any) => {\n if (post.status === \"published\") stats.publishedPosts++;\n if (post.status === \"draft\") stats.draftPosts++;\n if (post.status === \"archived\") stats.archivedPosts++;\n\n if (post.category) {\n stats.categoryCounts[post.category] =\n (stats.categoryCounts[post.category] || 0) + 1;\n }\n\n post.tags?.forEach((tag: string) => {\n stats.tagCounts[tag] = (stats.tagCounts[tag] || 0) + 1;\n });\n });\n\n return stats;\n },\n\n /**\n * Get all categories with post counts\n */\n async getCategories(): Promise<BlogCategory[]> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"category\")\n .eq(\"status\", \"published\")\n .not(\"category\", \"is\", null);\n\n if (error) {\n throw new Error(`Failed to fetch categories: ${error.message}`);\n }\n\n const counts: Record<string, number> = {};\n data?.forEach((row: any) => {\n if (row.category) {\n counts[row.category] = (counts[row.category] || 0) + 1;\n }\n });\n\n return Object.entries(counts).map(([name, postCount]) => ({\n name,\n slug: name.toLowerCase().replace(/\\s+/g, \"-\"),\n postCount,\n }));\n },\n\n /**\n * Get all tags with post counts\n */\n async getTags(): Promise<BlogTag[]> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"tags\")\n .eq(\"status\", \"published\");\n\n if (error) {\n throw new Error(`Failed to fetch tags: ${error.message}`);\n }\n\n const counts: Record<string, number> = {};\n data?.forEach((row: any) => {\n row.tags?.forEach((tag: string) => {\n counts[tag] = (counts[tag] || 0) + 1;\n });\n });\n\n return Object.entries(counts)\n .map(([name, postCount]) => ({\n name,\n slug: name.toLowerCase().replace(/\\s+/g, \"-\"),\n postCount,\n }))\n .sort((a, b) => b.postCount - a.postCount);\n },\n },\n\n /**\n * Category management operations (v0.4.0+)\n */\n categories: {\n /**\n * List all categories\n */\n async list(): Promise<import(\"../types/database\").CategoryRow[]> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .select(\"*\")\n .order(\"display_order\", { ascending: true });\n\n if (error) {\n throw new Error(`Failed to fetch categories: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").CategoryRow[]) || [];\n },\n\n /**\n * List categories with post counts\n */\n async listWithCounts(): Promise<import(\"../types/database\").CategoryWithCount[]> {\n const { data, error } = await supabase\n .rpc(\"blog.get_categories_with_counts\");\n\n if (error) {\n throw new Error(`Failed to fetch categories with counts: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").CategoryWithCount[]) || [];\n },\n\n /**\n * Get category by ID\n */\n async getById(id: string): Promise<import(\"../types/database\").CategoryRow | null> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Get category by slug\n */\n async getBySlug(slug: string): Promise<import(\"../types/database\").CategoryRow | null> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .select(\"*\")\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Create a new category\n */\n async create(category: import(\"../types/database\").CategoryInsert): Promise<import(\"../types/database\").CategoryRow> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .insert(category)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Update an existing category\n */\n async update(id: string, updates: import(\"../types/database\").CategoryUpdate): Promise<import(\"../types/database\").CategoryRow> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Delete a category\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(\"blog.categories\")\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete category: ${error.message}`);\n }\n },\n },\n\n /**\n * Tag management operations (v0.4.0+)\n */\n tags: {\n /**\n * List all tags\n */\n async list(): Promise<import(\"../types/database\").TagRow[]> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .select(\"*\")\n .order(\"name\", { ascending: true });\n\n if (error) {\n throw new Error(`Failed to fetch tags: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").TagRow[]) || [];\n },\n\n /**\n * List tags with post counts\n */\n async listWithCounts(): Promise<import(\"../types/database\").TagWithCount[]> {\n const { data, error } = await supabase\n .rpc(\"blog.get_tags_with_counts\");\n\n if (error) {\n throw new Error(`Failed to fetch tags with counts: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").TagWithCount[]) || [];\n },\n\n /**\n * Get tag by ID\n */\n async getById(id: string): Promise<import(\"../types/database\").TagRow | null> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Get tag by slug\n */\n async getBySlug(slug: string): Promise<import(\"../types/database\").TagRow | null> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .select(\"*\")\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Create a new tag\n */\n async create(tag: import(\"../types/database\").TagInsert): Promise<import(\"../types/database\").TagRow> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .insert(tag)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Update an existing tag\n */\n async update(id: string, updates: import(\"../types/database\").TagUpdate): Promise<import(\"../types/database\").TagRow> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Delete a tag\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(\"blog.tags\")\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete tag: ${error.message}`);\n }\n },\n },\n };\n}\n\n/**\n * Type helper to extract the blog client type\n */\nexport type BlogClient = ReturnType<typeof createBlogClient>;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/client/index.ts","../../src/client/supabase.ts"],"sourcesContent":["/**\n * Client exports for m14i-blogging\n *\n * Pre-built data access layer for Supabase integration\n *\n * @example\n * ```typescript\n * import { createBlogClient } from 'm14i-blogging/client';\n * import { createClient } from '@supabase/supabase-js';\n *\n * const supabase = createClient(url, key);\n * const blog = createBlogClient(supabase);\n *\n * // Use the client\n * const { posts } = await blog.posts.list({ status: 'published' });\n * ```\n */\n\nexport { createBlogClient } from './supabase';\nexport type { BlogClient, BlogClientConfig, SupabaseClient } from './supabase';\n","/**\n * Supabase Data Access Layer for m14i-blogging\n *\n * Provides pre-built CRUD operations for blog posts and media.\n * Works with the blog_posts and blog_media tables.\n *\n * @example\n * ```typescript\n * import { createBlogClient } from 'm14i-blogging/client';\n * import { createClient } from '@supabase/supabase-js';\n *\n * const supabase = createClient(url, key);\n * const blog = createBlogClient(supabase);\n *\n * // Use it\n * const posts = await blog.posts.list({ status: 'published' });\n * const post = await blog.posts.getBySlug('my-post');\n * ```\n */\n\nimport type {\n BlogPostRow,\n BlogPostInsert,\n BlogPostUpdate,\n BlogPostWithAuthor,\n BlogFilterParams,\n BlogPostListResponse,\n BlogMediaRow,\n BlogMediaInsert,\n BlogMediaUpdate,\n BlogStats,\n BlogCategory,\n BlogTag,\n} from \"../types/database\";\n\n// ============================================================================\n// Supabase Client Type\n// ============================================================================\n\nexport interface SupabaseClient {\n from(table: string): {\n select(query: string, options?: { count?: string }): any;\n insert(data: any): any;\n update(data: any): any;\n delete(): any;\n upsert(data: any): any;\n };\n rpc(functionName: string, params?: any): any;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport interface BlogClientConfig {\n /**\n * Table name for blog posts (default: \"blog_posts\")\n */\n postsTable?: string;\n /**\n * Table name for blog media (default: \"blog_media\")\n */\n mediaTable?: string;\n /**\n * Enable/disable author joins (default: true)\n */\n includeAuthor?: boolean;\n /**\n * Users table name for author joins (default: \"users\")\n */\n usersTable?: string;\n}\n\nconst DEFAULT_CONFIG: Required<BlogClientConfig> = {\n postsTable: \"blog_posts\",\n mediaTable: \"blog_media\",\n includeAuthor: true,\n usersTable: \"users\",\n};\n\n// ============================================================================\n// Blog Client Factory\n// ============================================================================\n\n/**\n * Creates a blog client with pre-built CRUD operations\n */\nexport function createBlogClient(\n supabase: SupabaseClient,\n config: BlogClientConfig = {}\n) {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n\n return {\n /**\n * Blog post operations\n */\n posts: {\n /**\n * List blog posts with filtering and pagination\n */\n async list(\n params: BlogFilterParams = {}\n ): Promise<BlogPostListResponse> {\n const {\n page = 1,\n pageSize = 10,\n status,\n category,\n tag,\n search,\n orderBy = \"created_at\",\n orderDirection = \"desc\",\n } = params;\n\n const from = (page - 1) * pageSize;\n const to = from + pageSize - 1;\n\n let query = supabase\n .from(cfg.postsTable)\n .select(\n cfg.includeAuthor\n ? `\n *,\n author:${cfg.usersTable}!created_by(full_name, email, avatar_url)\n `\n : \"*\",\n { count: \"exact\" }\n )\n .range(from, to)\n .order(orderBy, { ascending: orderDirection === \"asc\" });\n\n if (status) {\n query = query.eq(\"status\", status);\n }\n\n if (category) {\n query = query.eq(\"category\", category);\n }\n\n if (tag) {\n query = query.contains(\"tags\", [tag]);\n }\n\n if (search) {\n query = query.or(\n `title.ilike.%${search}%,excerpt.ilike.%${search}%,category.ilike.%${search}%`\n );\n }\n\n const { data, error, count } = await query;\n\n if (error) {\n throw new Error(`Failed to fetch blog posts: ${error.message}`);\n }\n\n return {\n posts: (data as unknown as BlogPostWithAuthor[]) || [],\n total: count || 0,\n page,\n pageSize,\n totalPages: Math.ceil((count || 0) / pageSize),\n };\n },\n\n /**\n * Get a single post by slug\n */\n async getBySlug(slug: string): Promise<BlogPostWithAuthor | null> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\n cfg.includeAuthor\n ? `\n *,\n author:${cfg.usersTable}!created_by(full_name, email, avatar_url)\n `\n : \"*\"\n )\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n return null;\n }\n throw new Error(`Failed to fetch blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostWithAuthor;\n },\n\n /**\n * Get a single post by ID\n */\n async getById(id: string): Promise<BlogPostRow | null> {\n const { data, error} = await supabase\n .from(cfg.postsTable)\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n return null;\n }\n throw new Error(`Failed to fetch blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Create a new blog post\n */\n async create(post: BlogPostInsert): Promise<BlogPostRow> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .insert(post)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Update an existing blog post\n */\n async update(\n id: string,\n updates: BlogPostUpdate\n ): Promise<BlogPostRow> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Delete a blog post\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(cfg.postsTable)\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete blog post: ${error.message}`);\n }\n },\n\n /**\n * Publish a draft post\n */\n async publish(id: string): Promise<BlogPostRow> {\n return this.update(id, { status: \"published\" });\n },\n\n /**\n * Unpublish (archive) a post\n */\n async archive(id: string): Promise<BlogPostRow> {\n return this.update(id, { status: \"archived\" });\n },\n\n /**\n * Search posts using full-text search\n */\n async search(query: string, limit: number = 10): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_search_posts\", { search_query: query })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to search blog posts: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get posts by tag\n */\n async getByTag(tag: string, limit: number = 10): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_get_posts_by_tag\", { tag_name: tag })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get posts by tag: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get posts by category\n */\n async getByCategory(\n category: string,\n limit: number = 10\n ): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_get_posts_by_category\", { category_name: category })\n .limit(limit);\n\n if (error) {\n throw new Error(\n `Failed to get posts by category: ${error.message}`\n );\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get related posts (by tags and category)\n */\n async getRelated(postId: string, limit: number = 3): Promise<BlogPostRow[]> {\n const post = await this.getById(postId);\n if (!post) return [];\n\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"*\")\n .eq(\"status\", \"published\")\n .neq(\"id\", postId)\n .or(`category.eq.${post.category},tags.ov.{${post.tags.join(\",\")}}`)\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get related posts: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n },\n\n /**\n * Blog media operations\n */\n media: {\n /**\n * List all media files\n */\n async list(\n type?: string,\n limit: number = 50\n ): Promise<BlogMediaRow[]> {\n let query = supabase\n .from(cfg.mediaTable)\n .select(\"*\")\n .order(\"uploaded_at\", { ascending: false })\n .limit(limit);\n\n if (type) {\n query = query.eq(\"type\", type);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new Error(`Failed to fetch blog media: ${error.message}`);\n }\n\n return (data as unknown as BlogMediaRow[]) || [];\n },\n\n /**\n * Create new media record\n */\n async create(media: BlogMediaInsert): Promise<BlogMediaRow> {\n const { data, error } = await supabase\n .from(cfg.mediaTable)\n .insert(media)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create blog media: ${error.message}`);\n }\n\n return data as unknown as BlogMediaRow;\n },\n\n /**\n * Update media record\n */\n async update(id: string, updates: BlogMediaUpdate): Promise<BlogMediaRow> {\n const { data, error } = await supabase\n .from(cfg.mediaTable)\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update blog media: ${error.message}`);\n }\n\n return data as unknown as BlogMediaRow;\n },\n\n /**\n * Delete media record\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(cfg.mediaTable)\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete blog media: ${error.message}`);\n }\n },\n },\n\n /**\n * Statistics and analytics\n */\n stats: {\n /**\n * Get blog statistics\n */\n async getStats(): Promise<BlogStats> {\n const { data: posts, error } = await supabase\n .from(cfg.postsTable)\n .select(\"status, category, tags\");\n\n if (error) {\n throw new Error(`Failed to fetch blog stats: ${error.message}`);\n }\n\n const stats: BlogStats = {\n totalPosts: posts.length,\n publishedPosts: 0,\n draftPosts: 0,\n archivedPosts: 0,\n categoryCounts: {},\n tagCounts: {},\n };\n\n posts.forEach((post: any) => {\n if (post.status === \"published\") stats.publishedPosts++;\n if (post.status === \"draft\") stats.draftPosts++;\n if (post.status === \"archived\") stats.archivedPosts++;\n\n if (post.category) {\n stats.categoryCounts[post.category] =\n (stats.categoryCounts[post.category] || 0) + 1;\n }\n\n post.tags?.forEach((tag: string) => {\n stats.tagCounts[tag] = (stats.tagCounts[tag] || 0) + 1;\n });\n });\n\n return stats;\n },\n\n /**\n * Get all categories with post counts\n */\n async getCategories(): Promise<BlogCategory[]> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"category\")\n .eq(\"status\", \"published\")\n .not(\"category\", \"is\", null);\n\n if (error) {\n throw new Error(`Failed to fetch categories: ${error.message}`);\n }\n\n const counts: Record<string, number> = {};\n data?.forEach((row: any) => {\n if (row.category) {\n counts[row.category] = (counts[row.category] || 0) + 1;\n }\n });\n\n return Object.entries(counts).map(([name, postCount]) => ({\n name,\n slug: name.toLowerCase().replace(/\\s+/g, \"-\"),\n postCount,\n }));\n },\n\n /**\n * Get all tags with post counts\n */\n async getTags(): Promise<BlogTag[]> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"tags\")\n .eq(\"status\", \"published\");\n\n if (error) {\n throw new Error(`Failed to fetch tags: ${error.message}`);\n }\n\n const counts: Record<string, number> = {};\n data?.forEach((row: any) => {\n row.tags?.forEach((tag: string) => {\n counts[tag] = (counts[tag] || 0) + 1;\n });\n });\n\n return Object.entries(counts)\n .map(([name, postCount]) => ({\n name,\n slug: name.toLowerCase().replace(/\\s+/g, \"-\"),\n postCount,\n }))\n .sort((a, b) => b.postCount - a.postCount);\n },\n },\n\n /**\n * Category management operations (v0.4.0+)\n */\n categories: {\n /**\n * List all categories\n */\n async list(): Promise<import(\"../types/database\").CategoryRow[]> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .select(\"*\")\n .order(\"display_order\", { ascending: true });\n\n if (error) {\n throw new Error(`Failed to fetch categories: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").CategoryRow[]) || [];\n },\n\n /**\n * List categories with post counts\n */\n async listWithCounts(): Promise<import(\"../types/database\").CategoryWithCount[]> {\n const { data, error } = await supabase\n .rpc(\"blog.get_categories_with_counts\");\n\n if (error) {\n throw new Error(`Failed to fetch categories with counts: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").CategoryWithCount[]) || [];\n },\n\n /**\n * Get category by ID\n */\n async getById(id: string): Promise<import(\"../types/database\").CategoryRow | null> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Get category by slug\n */\n async getBySlug(slug: string): Promise<import(\"../types/database\").CategoryRow | null> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .select(\"*\")\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Create a new category\n */\n async create(category: import(\"../types/database\").CategoryInsert): Promise<import(\"../types/database\").CategoryRow> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .insert(category)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Update an existing category\n */\n async update(id: string, updates: import(\"../types/database\").CategoryUpdate): Promise<import(\"../types/database\").CategoryRow> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Delete a category\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(\"blog_categories\")\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete category: ${error.message}`);\n }\n },\n },\n\n /**\n * Tag management operations (v0.4.0+)\n */\n tags: {\n /**\n * List all tags\n */\n async list(): Promise<import(\"../types/database\").TagRow[]> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .select(\"*\")\n .order(\"name\", { ascending: true });\n\n if (error) {\n throw new Error(`Failed to fetch tags: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").TagRow[]) || [];\n },\n\n /**\n * List tags with post counts\n */\n async listWithCounts(): Promise<import(\"../types/database\").TagWithCount[]> {\n const { data, error } = await supabase\n .rpc(\"blog.get_tags_with_counts\");\n\n if (error) {\n throw new Error(`Failed to fetch tags with counts: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").TagWithCount[]) || [];\n },\n\n /**\n * Get tag by ID\n */\n async getById(id: string): Promise<import(\"../types/database\").TagRow | null> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Get tag by slug\n */\n async getBySlug(slug: string): Promise<import(\"../types/database\").TagRow | null> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .select(\"*\")\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Create a new tag\n */\n async create(tag: import(\"../types/database\").TagInsert): Promise<import(\"../types/database\").TagRow> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .insert(tag)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Update an existing tag\n */\n async update(id: string, updates: import(\"../types/database\").TagUpdate): Promise<import(\"../types/database\").TagRow> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Delete a tag\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(\"blog_tags\")\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete tag: ${error.message}`);\n }\n },\n },\n };\n}\n\n/**\n * Type helper to extract the blog client type\n */\nexport type BlogClient = ReturnType<typeof createBlogClient>;\n"],"mappings":"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","names":[]}
|
package/dist/client/index.mjs
CHANGED
|
@@ -308,7 +308,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
308
308
|
* List all categories
|
|
309
309
|
*/
|
|
310
310
|
async list() {
|
|
311
|
-
const { data, error } = await supabase.from("
|
|
311
|
+
const { data, error } = await supabase.from("blog_categories").select("*").order("display_order", { ascending: true });
|
|
312
312
|
if (error) {
|
|
313
313
|
throw new Error(`Failed to fetch categories: ${error.message}`);
|
|
314
314
|
}
|
|
@@ -328,7 +328,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
328
328
|
* Get category by ID
|
|
329
329
|
*/
|
|
330
330
|
async getById(id) {
|
|
331
|
-
const { data, error } = await supabase.from("
|
|
331
|
+
const { data, error } = await supabase.from("blog_categories").select("*").eq("id", id).single();
|
|
332
332
|
if (error) {
|
|
333
333
|
if (error.code === "PGRST116") return null;
|
|
334
334
|
throw new Error(`Failed to fetch category: ${error.message}`);
|
|
@@ -339,7 +339,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
339
339
|
* Get category by slug
|
|
340
340
|
*/
|
|
341
341
|
async getBySlug(slug) {
|
|
342
|
-
const { data, error } = await supabase.from("
|
|
342
|
+
const { data, error } = await supabase.from("blog_categories").select("*").eq("slug", slug).single();
|
|
343
343
|
if (error) {
|
|
344
344
|
if (error.code === "PGRST116") return null;
|
|
345
345
|
throw new Error(`Failed to fetch category: ${error.message}`);
|
|
@@ -350,7 +350,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
350
350
|
* Create a new category
|
|
351
351
|
*/
|
|
352
352
|
async create(category) {
|
|
353
|
-
const { data, error } = await supabase.from("
|
|
353
|
+
const { data, error } = await supabase.from("blog_categories").insert(category).select().single();
|
|
354
354
|
if (error) {
|
|
355
355
|
throw new Error(`Failed to create category: ${error.message}`);
|
|
356
356
|
}
|
|
@@ -360,7 +360,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
360
360
|
* Update an existing category
|
|
361
361
|
*/
|
|
362
362
|
async update(id, updates) {
|
|
363
|
-
const { data, error } = await supabase.from("
|
|
363
|
+
const { data, error } = await supabase.from("blog_categories").update(updates).eq("id", id).select().single();
|
|
364
364
|
if (error) {
|
|
365
365
|
throw new Error(`Failed to update category: ${error.message}`);
|
|
366
366
|
}
|
|
@@ -370,7 +370,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
370
370
|
* Delete a category
|
|
371
371
|
*/
|
|
372
372
|
async delete(id) {
|
|
373
|
-
const { error } = await supabase.from("
|
|
373
|
+
const { error } = await supabase.from("blog_categories").delete().eq("id", id);
|
|
374
374
|
if (error) {
|
|
375
375
|
throw new Error(`Failed to delete category: ${error.message}`);
|
|
376
376
|
}
|
|
@@ -384,7 +384,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
384
384
|
* List all tags
|
|
385
385
|
*/
|
|
386
386
|
async list() {
|
|
387
|
-
const { data, error } = await supabase.from("
|
|
387
|
+
const { data, error } = await supabase.from("blog_tags").select("*").order("name", { ascending: true });
|
|
388
388
|
if (error) {
|
|
389
389
|
throw new Error(`Failed to fetch tags: ${error.message}`);
|
|
390
390
|
}
|
|
@@ -404,7 +404,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
404
404
|
* Get tag by ID
|
|
405
405
|
*/
|
|
406
406
|
async getById(id) {
|
|
407
|
-
const { data, error } = await supabase.from("
|
|
407
|
+
const { data, error } = await supabase.from("blog_tags").select("*").eq("id", id).single();
|
|
408
408
|
if (error) {
|
|
409
409
|
if (error.code === "PGRST116") return null;
|
|
410
410
|
throw new Error(`Failed to fetch tag: ${error.message}`);
|
|
@@ -415,7 +415,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
415
415
|
* Get tag by slug
|
|
416
416
|
*/
|
|
417
417
|
async getBySlug(slug) {
|
|
418
|
-
const { data, error } = await supabase.from("
|
|
418
|
+
const { data, error } = await supabase.from("blog_tags").select("*").eq("slug", slug).single();
|
|
419
419
|
if (error) {
|
|
420
420
|
if (error.code === "PGRST116") return null;
|
|
421
421
|
throw new Error(`Failed to fetch tag: ${error.message}`);
|
|
@@ -426,7 +426,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
426
426
|
* Create a new tag
|
|
427
427
|
*/
|
|
428
428
|
async create(tag) {
|
|
429
|
-
const { data, error } = await supabase.from("
|
|
429
|
+
const { data, error } = await supabase.from("blog_tags").insert(tag).select().single();
|
|
430
430
|
if (error) {
|
|
431
431
|
throw new Error(`Failed to create tag: ${error.message}`);
|
|
432
432
|
}
|
|
@@ -436,7 +436,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
436
436
|
* Update an existing tag
|
|
437
437
|
*/
|
|
438
438
|
async update(id, updates) {
|
|
439
|
-
const { data, error } = await supabase.from("
|
|
439
|
+
const { data, error } = await supabase.from("blog_tags").update(updates).eq("id", id).select().single();
|
|
440
440
|
if (error) {
|
|
441
441
|
throw new Error(`Failed to update tag: ${error.message}`);
|
|
442
442
|
}
|
|
@@ -446,7 +446,7 @@ function createBlogClient(supabase, config = {}) {
|
|
|
446
446
|
* Delete a tag
|
|
447
447
|
*/
|
|
448
448
|
async delete(id) {
|
|
449
|
-
const { error } = await supabase.from("
|
|
449
|
+
const { error } = await supabase.from("blog_tags").delete().eq("id", id);
|
|
450
450
|
if (error) {
|
|
451
451
|
throw new Error(`Failed to delete tag: ${error.message}`);
|
|
452
452
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/supabase.ts"],"sourcesContent":["/**\n * Supabase Data Access Layer for m14i-blogging\n *\n * Provides pre-built CRUD operations for blog posts and media.\n * Works with the blog_posts and blog_media tables.\n *\n * @example\n * ```typescript\n * import { createBlogClient } from 'm14i-blogging/client';\n * import { createClient } from '@supabase/supabase-js';\n *\n * const supabase = createClient(url, key);\n * const blog = createBlogClient(supabase);\n *\n * // Use it\n * const posts = await blog.posts.list({ status: 'published' });\n * const post = await blog.posts.getBySlug('my-post');\n * ```\n */\n\nimport type {\n BlogPostRow,\n BlogPostInsert,\n BlogPostUpdate,\n BlogPostWithAuthor,\n BlogFilterParams,\n BlogPostListResponse,\n BlogMediaRow,\n BlogMediaInsert,\n BlogMediaUpdate,\n BlogStats,\n BlogCategory,\n BlogTag,\n} from \"../types/database\";\n\n// ============================================================================\n// Supabase Client Type\n// ============================================================================\n\nexport interface SupabaseClient {\n from(table: string): {\n select(query: string, options?: { count?: string }): any;\n insert(data: any): any;\n update(data: any): any;\n delete(): any;\n upsert(data: any): any;\n };\n rpc(functionName: string, params?: any): any;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport interface BlogClientConfig {\n /**\n * Table name for blog posts (default: \"blog_posts\")\n */\n postsTable?: string;\n /**\n * Table name for blog media (default: \"blog_media\")\n */\n mediaTable?: string;\n /**\n * Enable/disable author joins (default: true)\n */\n includeAuthor?: boolean;\n /**\n * Users table name for author joins (default: \"users\")\n */\n usersTable?: string;\n}\n\nconst DEFAULT_CONFIG: Required<BlogClientConfig> = {\n postsTable: \"blog_posts\",\n mediaTable: \"blog_media\",\n includeAuthor: true,\n usersTable: \"users\",\n};\n\n// ============================================================================\n// Blog Client Factory\n// ============================================================================\n\n/**\n * Creates a blog client with pre-built CRUD operations\n */\nexport function createBlogClient(\n supabase: SupabaseClient,\n config: BlogClientConfig = {}\n) {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n\n return {\n /**\n * Blog post operations\n */\n posts: {\n /**\n * List blog posts with filtering and pagination\n */\n async list(\n params: BlogFilterParams = {}\n ): Promise<BlogPostListResponse> {\n const {\n page = 1,\n pageSize = 10,\n status,\n category,\n tag,\n search,\n orderBy = \"created_at\",\n orderDirection = \"desc\",\n } = params;\n\n const from = (page - 1) * pageSize;\n const to = from + pageSize - 1;\n\n let query = supabase\n .from(cfg.postsTable)\n .select(\n cfg.includeAuthor\n ? `\n *,\n author:${cfg.usersTable}!created_by(full_name, email, avatar_url)\n `\n : \"*\",\n { count: \"exact\" }\n )\n .range(from, to)\n .order(orderBy, { ascending: orderDirection === \"asc\" });\n\n if (status) {\n query = query.eq(\"status\", status);\n }\n\n if (category) {\n query = query.eq(\"category\", category);\n }\n\n if (tag) {\n query = query.contains(\"tags\", [tag]);\n }\n\n if (search) {\n query = query.or(\n `title.ilike.%${search}%,excerpt.ilike.%${search}%,category.ilike.%${search}%`\n );\n }\n\n const { data, error, count } = await query;\n\n if (error) {\n throw new Error(`Failed to fetch blog posts: ${error.message}`);\n }\n\n return {\n posts: (data as unknown as BlogPostWithAuthor[]) || [],\n total: count || 0,\n page,\n pageSize,\n totalPages: Math.ceil((count || 0) / pageSize),\n };\n },\n\n /**\n * Get a single post by slug\n */\n async getBySlug(slug: string): Promise<BlogPostWithAuthor | null> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\n cfg.includeAuthor\n ? `\n *,\n author:${cfg.usersTable}!created_by(full_name, email, avatar_url)\n `\n : \"*\"\n )\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n return null;\n }\n throw new Error(`Failed to fetch blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostWithAuthor;\n },\n\n /**\n * Get a single post by ID\n */\n async getById(id: string): Promise<BlogPostRow | null> {\n const { data, error} = await supabase\n .from(cfg.postsTable)\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n return null;\n }\n throw new Error(`Failed to fetch blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Create a new blog post\n */\n async create(post: BlogPostInsert): Promise<BlogPostRow> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .insert(post)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Update an existing blog post\n */\n async update(\n id: string,\n updates: BlogPostUpdate\n ): Promise<BlogPostRow> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Delete a blog post\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(cfg.postsTable)\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete blog post: ${error.message}`);\n }\n },\n\n /**\n * Publish a draft post\n */\n async publish(id: string): Promise<BlogPostRow> {\n return this.update(id, { status: \"published\" });\n },\n\n /**\n * Unpublish (archive) a post\n */\n async archive(id: string): Promise<BlogPostRow> {\n return this.update(id, { status: \"archived\" });\n },\n\n /**\n * Search posts using full-text search\n */\n async search(query: string, limit: number = 10): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_search_posts\", { search_query: query })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to search blog posts: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get posts by tag\n */\n async getByTag(tag: string, limit: number = 10): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_get_posts_by_tag\", { tag_name: tag })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get posts by tag: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get posts by category\n */\n async getByCategory(\n category: string,\n limit: number = 10\n ): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_get_posts_by_category\", { category_name: category })\n .limit(limit);\n\n if (error) {\n throw new Error(\n `Failed to get posts by category: ${error.message}`\n );\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get related posts (by tags and category)\n */\n async getRelated(postId: string, limit: number = 3): Promise<BlogPostRow[]> {\n const post = await this.getById(postId);\n if (!post) return [];\n\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"*\")\n .eq(\"status\", \"published\")\n .neq(\"id\", postId)\n .or(`category.eq.${post.category},tags.ov.{${post.tags.join(\",\")}}`)\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get related posts: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n },\n\n /**\n * Blog media operations\n */\n media: {\n /**\n * List all media files\n */\n async list(\n type?: string,\n limit: number = 50\n ): Promise<BlogMediaRow[]> {\n let query = supabase\n .from(cfg.mediaTable)\n .select(\"*\")\n .order(\"uploaded_at\", { ascending: false })\n .limit(limit);\n\n if (type) {\n query = query.eq(\"type\", type);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new Error(`Failed to fetch blog media: ${error.message}`);\n }\n\n return (data as unknown as BlogMediaRow[]) || [];\n },\n\n /**\n * Create new media record\n */\n async create(media: BlogMediaInsert): Promise<BlogMediaRow> {\n const { data, error } = await supabase\n .from(cfg.mediaTable)\n .insert(media)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create blog media: ${error.message}`);\n }\n\n return data as unknown as BlogMediaRow;\n },\n\n /**\n * Update media record\n */\n async update(id: string, updates: BlogMediaUpdate): Promise<BlogMediaRow> {\n const { data, error } = await supabase\n .from(cfg.mediaTable)\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update blog media: ${error.message}`);\n }\n\n return data as unknown as BlogMediaRow;\n },\n\n /**\n * Delete media record\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(cfg.mediaTable)\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete blog media: ${error.message}`);\n }\n },\n },\n\n /**\n * Statistics and analytics\n */\n stats: {\n /**\n * Get blog statistics\n */\n async getStats(): Promise<BlogStats> {\n const { data: posts, error } = await supabase\n .from(cfg.postsTable)\n .select(\"status, category, tags\");\n\n if (error) {\n throw new Error(`Failed to fetch blog stats: ${error.message}`);\n }\n\n const stats: BlogStats = {\n totalPosts: posts.length,\n publishedPosts: 0,\n draftPosts: 0,\n archivedPosts: 0,\n categoryCounts: {},\n tagCounts: {},\n };\n\n posts.forEach((post: any) => {\n if (post.status === \"published\") stats.publishedPosts++;\n if (post.status === \"draft\") stats.draftPosts++;\n if (post.status === \"archived\") stats.archivedPosts++;\n\n if (post.category) {\n stats.categoryCounts[post.category] =\n (stats.categoryCounts[post.category] || 0) + 1;\n }\n\n post.tags?.forEach((tag: string) => {\n stats.tagCounts[tag] = (stats.tagCounts[tag] || 0) + 1;\n });\n });\n\n return stats;\n },\n\n /**\n * Get all categories with post counts\n */\n async getCategories(): Promise<BlogCategory[]> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"category\")\n .eq(\"status\", \"published\")\n .not(\"category\", \"is\", null);\n\n if (error) {\n throw new Error(`Failed to fetch categories: ${error.message}`);\n }\n\n const counts: Record<string, number> = {};\n data?.forEach((row: any) => {\n if (row.category) {\n counts[row.category] = (counts[row.category] || 0) + 1;\n }\n });\n\n return Object.entries(counts).map(([name, postCount]) => ({\n name,\n slug: name.toLowerCase().replace(/\\s+/g, \"-\"),\n postCount,\n }));\n },\n\n /**\n * Get all tags with post counts\n */\n async getTags(): Promise<BlogTag[]> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"tags\")\n .eq(\"status\", \"published\");\n\n if (error) {\n throw new Error(`Failed to fetch tags: ${error.message}`);\n }\n\n const counts: Record<string, number> = {};\n data?.forEach((row: any) => {\n row.tags?.forEach((tag: string) => {\n counts[tag] = (counts[tag] || 0) + 1;\n });\n });\n\n return Object.entries(counts)\n .map(([name, postCount]) => ({\n name,\n slug: name.toLowerCase().replace(/\\s+/g, \"-\"),\n postCount,\n }))\n .sort((a, b) => b.postCount - a.postCount);\n },\n },\n\n /**\n * Category management operations (v0.4.0+)\n */\n categories: {\n /**\n * List all categories\n */\n async list(): Promise<import(\"../types/database\").CategoryRow[]> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .select(\"*\")\n .order(\"display_order\", { ascending: true });\n\n if (error) {\n throw new Error(`Failed to fetch categories: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").CategoryRow[]) || [];\n },\n\n /**\n * List categories with post counts\n */\n async listWithCounts(): Promise<import(\"../types/database\").CategoryWithCount[]> {\n const { data, error } = await supabase\n .rpc(\"blog.get_categories_with_counts\");\n\n if (error) {\n throw new Error(`Failed to fetch categories with counts: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").CategoryWithCount[]) || [];\n },\n\n /**\n * Get category by ID\n */\n async getById(id: string): Promise<import(\"../types/database\").CategoryRow | null> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Get category by slug\n */\n async getBySlug(slug: string): Promise<import(\"../types/database\").CategoryRow | null> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .select(\"*\")\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Create a new category\n */\n async create(category: import(\"../types/database\").CategoryInsert): Promise<import(\"../types/database\").CategoryRow> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .insert(category)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Update an existing category\n */\n async update(id: string, updates: import(\"../types/database\").CategoryUpdate): Promise<import(\"../types/database\").CategoryRow> {\n const { data, error } = await supabase\n .from(\"blog.categories\")\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Delete a category\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(\"blog.categories\")\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete category: ${error.message}`);\n }\n },\n },\n\n /**\n * Tag management operations (v0.4.0+)\n */\n tags: {\n /**\n * List all tags\n */\n async list(): Promise<import(\"../types/database\").TagRow[]> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .select(\"*\")\n .order(\"name\", { ascending: true });\n\n if (error) {\n throw new Error(`Failed to fetch tags: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").TagRow[]) || [];\n },\n\n /**\n * List tags with post counts\n */\n async listWithCounts(): Promise<import(\"../types/database\").TagWithCount[]> {\n const { data, error } = await supabase\n .rpc(\"blog.get_tags_with_counts\");\n\n if (error) {\n throw new Error(`Failed to fetch tags with counts: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").TagWithCount[]) || [];\n },\n\n /**\n * Get tag by ID\n */\n async getById(id: string): Promise<import(\"../types/database\").TagRow | null> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Get tag by slug\n */\n async getBySlug(slug: string): Promise<import(\"../types/database\").TagRow | null> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .select(\"*\")\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Create a new tag\n */\n async create(tag: import(\"../types/database\").TagInsert): Promise<import(\"../types/database\").TagRow> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .insert(tag)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Update an existing tag\n */\n async update(id: string, updates: import(\"../types/database\").TagUpdate): Promise<import(\"../types/database\").TagRow> {\n const { data, error } = await supabase\n .from(\"blog.tags\")\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Delete a tag\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(\"blog.tags\")\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete tag: ${error.message}`);\n }\n },\n },\n };\n}\n\n/**\n * Type helper to extract the blog client type\n */\nexport type BlogClient = ReturnType<typeof createBlogClient>;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/client/supabase.ts"],"sourcesContent":["/**\n * Supabase Data Access Layer for m14i-blogging\n *\n * Provides pre-built CRUD operations for blog posts and media.\n * Works with the blog_posts and blog_media tables.\n *\n * @example\n * ```typescript\n * import { createBlogClient } from 'm14i-blogging/client';\n * import { createClient } from '@supabase/supabase-js';\n *\n * const supabase = createClient(url, key);\n * const blog = createBlogClient(supabase);\n *\n * // Use it\n * const posts = await blog.posts.list({ status: 'published' });\n * const post = await blog.posts.getBySlug('my-post');\n * ```\n */\n\nimport type {\n BlogPostRow,\n BlogPostInsert,\n BlogPostUpdate,\n BlogPostWithAuthor,\n BlogFilterParams,\n BlogPostListResponse,\n BlogMediaRow,\n BlogMediaInsert,\n BlogMediaUpdate,\n BlogStats,\n BlogCategory,\n BlogTag,\n} from \"../types/database\";\n\n// ============================================================================\n// Supabase Client Type\n// ============================================================================\n\nexport interface SupabaseClient {\n from(table: string): {\n select(query: string, options?: { count?: string }): any;\n insert(data: any): any;\n update(data: any): any;\n delete(): any;\n upsert(data: any): any;\n };\n rpc(functionName: string, params?: any): any;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport interface BlogClientConfig {\n /**\n * Table name for blog posts (default: \"blog_posts\")\n */\n postsTable?: string;\n /**\n * Table name for blog media (default: \"blog_media\")\n */\n mediaTable?: string;\n /**\n * Enable/disable author joins (default: true)\n */\n includeAuthor?: boolean;\n /**\n * Users table name for author joins (default: \"users\")\n */\n usersTable?: string;\n}\n\nconst DEFAULT_CONFIG: Required<BlogClientConfig> = {\n postsTable: \"blog_posts\",\n mediaTable: \"blog_media\",\n includeAuthor: true,\n usersTable: \"users\",\n};\n\n// ============================================================================\n// Blog Client Factory\n// ============================================================================\n\n/**\n * Creates a blog client with pre-built CRUD operations\n */\nexport function createBlogClient(\n supabase: SupabaseClient,\n config: BlogClientConfig = {}\n) {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n\n return {\n /**\n * Blog post operations\n */\n posts: {\n /**\n * List blog posts with filtering and pagination\n */\n async list(\n params: BlogFilterParams = {}\n ): Promise<BlogPostListResponse> {\n const {\n page = 1,\n pageSize = 10,\n status,\n category,\n tag,\n search,\n orderBy = \"created_at\",\n orderDirection = \"desc\",\n } = params;\n\n const from = (page - 1) * pageSize;\n const to = from + pageSize - 1;\n\n let query = supabase\n .from(cfg.postsTable)\n .select(\n cfg.includeAuthor\n ? `\n *,\n author:${cfg.usersTable}!created_by(full_name, email, avatar_url)\n `\n : \"*\",\n { count: \"exact\" }\n )\n .range(from, to)\n .order(orderBy, { ascending: orderDirection === \"asc\" });\n\n if (status) {\n query = query.eq(\"status\", status);\n }\n\n if (category) {\n query = query.eq(\"category\", category);\n }\n\n if (tag) {\n query = query.contains(\"tags\", [tag]);\n }\n\n if (search) {\n query = query.or(\n `title.ilike.%${search}%,excerpt.ilike.%${search}%,category.ilike.%${search}%`\n );\n }\n\n const { data, error, count } = await query;\n\n if (error) {\n throw new Error(`Failed to fetch blog posts: ${error.message}`);\n }\n\n return {\n posts: (data as unknown as BlogPostWithAuthor[]) || [],\n total: count || 0,\n page,\n pageSize,\n totalPages: Math.ceil((count || 0) / pageSize),\n };\n },\n\n /**\n * Get a single post by slug\n */\n async getBySlug(slug: string): Promise<BlogPostWithAuthor | null> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\n cfg.includeAuthor\n ? `\n *,\n author:${cfg.usersTable}!created_by(full_name, email, avatar_url)\n `\n : \"*\"\n )\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n return null;\n }\n throw new Error(`Failed to fetch blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostWithAuthor;\n },\n\n /**\n * Get a single post by ID\n */\n async getById(id: string): Promise<BlogPostRow | null> {\n const { data, error} = await supabase\n .from(cfg.postsTable)\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n return null;\n }\n throw new Error(`Failed to fetch blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Create a new blog post\n */\n async create(post: BlogPostInsert): Promise<BlogPostRow> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .insert(post)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Update an existing blog post\n */\n async update(\n id: string,\n updates: BlogPostUpdate\n ): Promise<BlogPostRow> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update blog post: ${error.message}`);\n }\n\n return data as unknown as BlogPostRow;\n },\n\n /**\n * Delete a blog post\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(cfg.postsTable)\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete blog post: ${error.message}`);\n }\n },\n\n /**\n * Publish a draft post\n */\n async publish(id: string): Promise<BlogPostRow> {\n return this.update(id, { status: \"published\" });\n },\n\n /**\n * Unpublish (archive) a post\n */\n async archive(id: string): Promise<BlogPostRow> {\n return this.update(id, { status: \"archived\" });\n },\n\n /**\n * Search posts using full-text search\n */\n async search(query: string, limit: number = 10): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_search_posts\", { search_query: query })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to search blog posts: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get posts by tag\n */\n async getByTag(tag: string, limit: number = 10): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_get_posts_by_tag\", { tag_name: tag })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get posts by tag: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get posts by category\n */\n async getByCategory(\n category: string,\n limit: number = 10\n ): Promise<BlogPostRow[]> {\n const { data, error } = await supabase\n .rpc(\"blog_get_posts_by_category\", { category_name: category })\n .limit(limit);\n\n if (error) {\n throw new Error(\n `Failed to get posts by category: ${error.message}`\n );\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n\n /**\n * Get related posts (by tags and category)\n */\n async getRelated(postId: string, limit: number = 3): Promise<BlogPostRow[]> {\n const post = await this.getById(postId);\n if (!post) return [];\n\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"*\")\n .eq(\"status\", \"published\")\n .neq(\"id\", postId)\n .or(`category.eq.${post.category},tags.ov.{${post.tags.join(\",\")}}`)\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get related posts: ${error.message}`);\n }\n\n return (data as unknown as BlogPostRow[]) || [];\n },\n },\n\n /**\n * Blog media operations\n */\n media: {\n /**\n * List all media files\n */\n async list(\n type?: string,\n limit: number = 50\n ): Promise<BlogMediaRow[]> {\n let query = supabase\n .from(cfg.mediaTable)\n .select(\"*\")\n .order(\"uploaded_at\", { ascending: false })\n .limit(limit);\n\n if (type) {\n query = query.eq(\"type\", type);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new Error(`Failed to fetch blog media: ${error.message}`);\n }\n\n return (data as unknown as BlogMediaRow[]) || [];\n },\n\n /**\n * Create new media record\n */\n async create(media: BlogMediaInsert): Promise<BlogMediaRow> {\n const { data, error } = await supabase\n .from(cfg.mediaTable)\n .insert(media)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create blog media: ${error.message}`);\n }\n\n return data as unknown as BlogMediaRow;\n },\n\n /**\n * Update media record\n */\n async update(id: string, updates: BlogMediaUpdate): Promise<BlogMediaRow> {\n const { data, error } = await supabase\n .from(cfg.mediaTable)\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update blog media: ${error.message}`);\n }\n\n return data as unknown as BlogMediaRow;\n },\n\n /**\n * Delete media record\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(cfg.mediaTable)\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete blog media: ${error.message}`);\n }\n },\n },\n\n /**\n * Statistics and analytics\n */\n stats: {\n /**\n * Get blog statistics\n */\n async getStats(): Promise<BlogStats> {\n const { data: posts, error } = await supabase\n .from(cfg.postsTable)\n .select(\"status, category, tags\");\n\n if (error) {\n throw new Error(`Failed to fetch blog stats: ${error.message}`);\n }\n\n const stats: BlogStats = {\n totalPosts: posts.length,\n publishedPosts: 0,\n draftPosts: 0,\n archivedPosts: 0,\n categoryCounts: {},\n tagCounts: {},\n };\n\n posts.forEach((post: any) => {\n if (post.status === \"published\") stats.publishedPosts++;\n if (post.status === \"draft\") stats.draftPosts++;\n if (post.status === \"archived\") stats.archivedPosts++;\n\n if (post.category) {\n stats.categoryCounts[post.category] =\n (stats.categoryCounts[post.category] || 0) + 1;\n }\n\n post.tags?.forEach((tag: string) => {\n stats.tagCounts[tag] = (stats.tagCounts[tag] || 0) + 1;\n });\n });\n\n return stats;\n },\n\n /**\n * Get all categories with post counts\n */\n async getCategories(): Promise<BlogCategory[]> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"category\")\n .eq(\"status\", \"published\")\n .not(\"category\", \"is\", null);\n\n if (error) {\n throw new Error(`Failed to fetch categories: ${error.message}`);\n }\n\n const counts: Record<string, number> = {};\n data?.forEach((row: any) => {\n if (row.category) {\n counts[row.category] = (counts[row.category] || 0) + 1;\n }\n });\n\n return Object.entries(counts).map(([name, postCount]) => ({\n name,\n slug: name.toLowerCase().replace(/\\s+/g, \"-\"),\n postCount,\n }));\n },\n\n /**\n * Get all tags with post counts\n */\n async getTags(): Promise<BlogTag[]> {\n const { data, error } = await supabase\n .from(cfg.postsTable)\n .select(\"tags\")\n .eq(\"status\", \"published\");\n\n if (error) {\n throw new Error(`Failed to fetch tags: ${error.message}`);\n }\n\n const counts: Record<string, number> = {};\n data?.forEach((row: any) => {\n row.tags?.forEach((tag: string) => {\n counts[tag] = (counts[tag] || 0) + 1;\n });\n });\n\n return Object.entries(counts)\n .map(([name, postCount]) => ({\n name,\n slug: name.toLowerCase().replace(/\\s+/g, \"-\"),\n postCount,\n }))\n .sort((a, b) => b.postCount - a.postCount);\n },\n },\n\n /**\n * Category management operations (v0.4.0+)\n */\n categories: {\n /**\n * List all categories\n */\n async list(): Promise<import(\"../types/database\").CategoryRow[]> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .select(\"*\")\n .order(\"display_order\", { ascending: true });\n\n if (error) {\n throw new Error(`Failed to fetch categories: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").CategoryRow[]) || [];\n },\n\n /**\n * List categories with post counts\n */\n async listWithCounts(): Promise<import(\"../types/database\").CategoryWithCount[]> {\n const { data, error } = await supabase\n .rpc(\"blog.get_categories_with_counts\");\n\n if (error) {\n throw new Error(`Failed to fetch categories with counts: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").CategoryWithCount[]) || [];\n },\n\n /**\n * Get category by ID\n */\n async getById(id: string): Promise<import(\"../types/database\").CategoryRow | null> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Get category by slug\n */\n async getBySlug(slug: string): Promise<import(\"../types/database\").CategoryRow | null> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .select(\"*\")\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Create a new category\n */\n async create(category: import(\"../types/database\").CategoryInsert): Promise<import(\"../types/database\").CategoryRow> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .insert(category)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Update an existing category\n */\n async update(id: string, updates: import(\"../types/database\").CategoryUpdate): Promise<import(\"../types/database\").CategoryRow> {\n const { data, error } = await supabase\n .from(\"blog_categories\")\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update category: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").CategoryRow;\n },\n\n /**\n * Delete a category\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(\"blog_categories\")\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete category: ${error.message}`);\n }\n },\n },\n\n /**\n * Tag management operations (v0.4.0+)\n */\n tags: {\n /**\n * List all tags\n */\n async list(): Promise<import(\"../types/database\").TagRow[]> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .select(\"*\")\n .order(\"name\", { ascending: true });\n\n if (error) {\n throw new Error(`Failed to fetch tags: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").TagRow[]) || [];\n },\n\n /**\n * List tags with post counts\n */\n async listWithCounts(): Promise<import(\"../types/database\").TagWithCount[]> {\n const { data, error } = await supabase\n .rpc(\"blog.get_tags_with_counts\");\n\n if (error) {\n throw new Error(`Failed to fetch tags with counts: ${error.message}`);\n }\n\n return (data as unknown as import(\"../types/database\").TagWithCount[]) || [];\n },\n\n /**\n * Get tag by ID\n */\n async getById(id: string): Promise<import(\"../types/database\").TagRow | null> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .select(\"*\")\n .eq(\"id\", id)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Get tag by slug\n */\n async getBySlug(slug: string): Promise<import(\"../types/database\").TagRow | null> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .select(\"*\")\n .eq(\"slug\", slug)\n .single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null;\n throw new Error(`Failed to fetch tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Create a new tag\n */\n async create(tag: import(\"../types/database\").TagInsert): Promise<import(\"../types/database\").TagRow> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .insert(tag)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Update an existing tag\n */\n async update(id: string, updates: import(\"../types/database\").TagUpdate): Promise<import(\"../types/database\").TagRow> {\n const { data, error } = await supabase\n .from(\"blog_tags\")\n .update(updates)\n .eq(\"id\", id)\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to update tag: ${error.message}`);\n }\n\n return data as unknown as import(\"../types/database\").TagRow;\n },\n\n /**\n * Delete a tag\n */\n async delete(id: string): Promise<void> {\n const { error } = await supabase\n .from(\"blog_tags\")\n .delete()\n .eq(\"id\", id);\n\n if (error) {\n throw new Error(`Failed to delete tag: ${error.message}`);\n }\n },\n },\n };\n}\n\n/**\n * Type helper to extract the blog client type\n */\nexport type BlogClient = ReturnType<typeof createBlogClient>;\n"],"mappings":"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","names":[]}
|