import { createDirectus, rest, staticToken, readItems, readSingleton, readItem, } from '@directus/sdk' import type { Article, Category, SiteSettings } from './types' function createClient() { return createDirectus(process.env.DIRECTUS_URL!) .with(staticToken(process.env.DIRECTUS_TOKEN!)) .with(rest()) } let _client: ReturnType | null = null function getClient() { if (!_client) { _client = createClient() } return _client } export async function getAllCategories(): Promise { return getClient().request( readItems('categories', { fields: ['id', 'name', 'slug', 'description'], sort: ['name'], }) ) as Promise } export async function getCategoryBySlug(slug: string): Promise { const results = await getClient().request( readItems('categories', { fields: ['id', 'name', 'slug', 'description'], filter: { slug: { _eq: slug } }, limit: 1, }) ) as Category[] return results[0] ?? null } export async function getArticles(options: { limit?: number offset?: number categorySlug?: string categoryId?: string } = {}): Promise { const { limit = 12, offset = 0, categorySlug, categoryId } = options const filter: Record = { status: { _eq: 'published' } } if (categoryId) { filter['category'] = { _eq: categoryId } } else if (categorySlug) { const cat = await getCategoryBySlug(categorySlug) if (cat) { filter['category'] = { _eq: cat.id } } } return getClient().request( readItems('articles', { fields: [ 'id', 'title', 'slug', 'status', 'excerpt', 'featured_image', 'published_at', 'is_featured', 'category.id', 'category.name', 'category.slug', ], filter, sort: ['-published_at'], limit, offset, }) ) as Promise } export async function getArticleBySlug(slug: string): Promise
{ const results = await getClient().request( readItems('articles', { fields: [ 'id', 'title', 'slug', 'status', 'content', 'excerpt', 'featured_image', 'published_at', 'is_featured', 'seo_title', 'seo_description', 'category.id', 'category.name', 'category.slug', 'tags.tags_id.id', 'tags.tags_id.name', 'tags.tags_id.slug', ], filter: { slug: { _eq: slug }, status: { _eq: 'published' } }, limit: 1, }) ) as Article[] return results[0] ?? null } export async function getArticlePathById(id: string): Promise<{ slug: string category: { slug: string } } | null> { try { return await getClient().request( readItem('articles', id, { fields: ['slug', 'category.slug'], }) ) as { slug: string; category: { slug: string } } } catch { return null } } export async function getRelatedArticles( categorySlug: string, excludeSlug: string, ): Promise { return getClient().request( readItems('articles', { fields: [ 'id', 'title', 'slug', 'excerpt', 'featured_image', 'published_at', 'category.id', 'category.name', 'category.slug', ], filter: { status: { _eq: 'published' }, category: { slug: { _eq: categorySlug } }, slug: { _neq: excludeSlug }, }, sort: ['-published_at'], limit: 4, }) ) as Promise } export async function getSiteSettings(): Promise { return getClient().request( readSingleton('site_settings', { fields: [ 'id', 'site_name', 'hero_article.id', 'hero_article.title', 'hero_article.slug', 'hero_article.excerpt', 'hero_article.featured_image', 'hero_article.category.slug', 'hero_article.category.name', ], }) ) as Promise } export async function searchArticles(query: string): Promise { return getClient().request( readItems('articles', { fields: ['id', 'title', 'slug', 'category.slug', 'category.name'], filter: { _or: [ { title: { _icontains: query } }, { excerpt: { _icontains: query } }, ], status: { _eq: 'published' }, }, limit: 8, }) ) as Promise } export function getAssetUrl( fileId: string, params?: { width?: number; height?: number; quality?: number }, ): string { const url = new URL(`/assets/${fileId}`, process.env.DIRECTUS_URL!) if (params?.width) url.searchParams.set('width', String(params.width)) if (params?.height) url.searchParams.set('height', String(params.height)) if (params?.quality) url.searchParams.set('quality', String(params.quality)) return url.toString() }