feat: Directus SDK client with typed helpers

This commit is contained in:
achmad
2026-05-28 22:26:13 +07:00
parent 7ffc6cbad6
commit 1ab153c94f
2 changed files with 222 additions and 0 deletions
+147
View File
@@ -0,0 +1,147 @@
import {
createDirectus,
rest,
staticToken,
readItems,
readSingleton,
readItem,
} from '@directus/sdk'
import type { Article, Category, SiteSettings } from './types'
const directus = createDirectus(process.env.DIRECTUS_URL!)
.with(staticToken(process.env.DIRECTUS_TOKEN!))
.with(rest())
export async function getAllCategories(): Promise<Category[]> {
return directus.request(
readItems('categories', {
fields: ['id', 'name', 'slug', 'description'],
sort: ['name'],
})
) as Promise<Category[]>
}
export async function getCategoryBySlug(slug: string): Promise<Category | null> {
const results = await directus.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
} = {}): Promise<Article[]> {
const { limit = 12, offset = 0, categorySlug } = options
const filter: Record<string, unknown> = { status: { _eq: 'published' } }
if (categorySlug) {
filter['category'] = { slug: { _eq: categorySlug } }
}
return directus.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<Article[]>
}
export async function getArticleBySlug(slug: string): Promise<Article | null> {
const results = await directus.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 directus.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<Article[]> {
return directus.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<Article[]>
}
export async function getSiteSettings(): Promise<SiteSettings> {
return directus.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',
'nav_categories.id', 'nav_categories.name', 'nav_categories.slug',
],
})
) as Promise<SiteSettings>
}
export async function searchArticles(query: string): Promise<Article[]> {
return directus.request(
readItems('articles', {
fields: ['id', 'title', 'slug', 'category.slug', 'category.name'],
search: query,
filter: { status: { _eq: 'published' } },
limit: 8,
})
) as Promise<Article[]>
}
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()
}